Skip to content

Commit 9ead78e

Browse files
authored
Merge pull request #333 from jeffgbutler/further-refactoring
Further Condition Refactoring
2 parents cae7976 + 239abff commit 9ead78e

25 files changed

+456
-684
lines changed

src/main/java/org/mybatis/dynamic/sql/AbstractListValueCondition.java

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import java.util.Collection;
1919
import java.util.Objects;
20+
import java.util.function.BiFunction;
2021
import java.util.function.Function;
2122
import java.util.function.Predicate;
2223
import java.util.function.UnaryOperator;
@@ -56,16 +57,53 @@ public <R> R accept(ConditionVisitor<T, R> visitor) {
5657
return visitor.visit(this);
5758
}
5859

59-
protected Collection<T> applyMapper(UnaryOperator<T> mapper) {
60+
private Collection<T> applyMapper(UnaryOperator<T> mapper) {
6061
Objects.requireNonNull(mapper);
6162
return values.stream().map(mapper).collect(Collectors.toList());
6263
}
6364

64-
protected Collection<T> applyFilter(Predicate<T> predicate) {
65+
private Collection<T> applyFilter(Predicate<T> predicate) {
6566
Objects.requireNonNull(predicate);
6667
return values.stream().filter(predicate).collect(Collectors.toList());
6768
}
6869

70+
protected S filter(Predicate<T> predicate, BiFunction<Collection<T>, Callback, S> constructor, S self) {
71+
if (shouldRender()) {
72+
return constructor.apply(applyFilter(predicate), emptyCallback);
73+
} else {
74+
return self;
75+
}
76+
}
77+
78+
/**
79+
* If renderable, apply the predicate to each value in the list and return a new condition with the filtered values.
80+
* Else returns a condition that will not render (this). If all values are filtered out of the value
81+
* list, then the condition will not render.
82+
*
83+
* @param predicate predicate applied to the values, if renderable
84+
* @return a new condition with filtered values if renderable, otherwise a condition
85+
* that will not render.
86+
*/
87+
public abstract S filter(Predicate<T> predicate);
88+
89+
protected S map(UnaryOperator<T> mapper, BiFunction<Collection<T>, Callback, S> constructor, S self) {
90+
if (shouldRender()) {
91+
return constructor.apply(applyMapper(mapper), emptyCallback);
92+
} else {
93+
return self;
94+
}
95+
}
96+
97+
/**
98+
* If renderable, apply the mapping to each value in the list return a new condition with the mapped values.
99+
* Else return a condition that will not render (this).
100+
*
101+
* @param mapper a mapping function to apply to the values, if renderable
102+
* @return a new condition with mapped values if renderable, otherwise a condition
103+
* that will not render.
104+
*/
105+
public abstract S map(UnaryOperator<T> mapper);
106+
69107
public abstract S withListEmptyCallback(Callback callback);
70108

71109
public abstract String renderCondition(String columnName, Stream<String> placeholders);

src/main/java/org/mybatis/dynamic/sql/AbstractNoValueCondition.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,23 @@
1515
*/
1616
package org.mybatis.dynamic.sql;
1717

18+
import java.util.function.BooleanSupplier;
19+
import java.util.function.Supplier;
20+
1821
public abstract class AbstractNoValueCondition<T> implements VisitableCondition<T> {
1922

2023
@Override
2124
public <R> R accept(ConditionVisitor<T, R> visitor) {
2225
return visitor.visit(this);
2326
}
2427

28+
protected <S> S filter(BooleanSupplier booleanSupplier, Supplier<S> empty, S self) {
29+
if (shouldRender()) {
30+
return booleanSupplier.getAsBoolean() ? self : empty.get();
31+
} else {
32+
return self;
33+
}
34+
}
35+
2536
public abstract String renderCondition(String columnName);
2637
}

src/main/java/org/mybatis/dynamic/sql/AbstractSingleValueCondition.java

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,13 @@
1515
*/
1616
package org.mybatis.dynamic.sql;
1717

18-
public abstract class AbstractSingleValueCondition<T> implements VisitableCondition<T> {
18+
import java.util.function.Function;
19+
import java.util.function.Predicate;
20+
import java.util.function.Supplier;
21+
import java.util.function.UnaryOperator;
22+
23+
public abstract class AbstractSingleValueCondition<T, S extends AbstractSingleValueCondition<T, S>>
24+
implements VisitableCondition<T> {
1925
protected final T value;
2026

2127
protected AbstractSingleValueCondition(T value) {
@@ -31,5 +37,41 @@ public <R> R accept(ConditionVisitor<T, R> visitor) {
3137
return visitor.visit(this);
3238
}
3339

40+
protected S filter(Predicate<T> predicate, Supplier<S> empty, S self) {
41+
if (shouldRender()) {
42+
return predicate.test(value) ? self : empty.get();
43+
} else {
44+
return self;
45+
}
46+
}
47+
48+
/**
49+
* If renderable and the value matches the predicate, returns this condition. Else returns a condition
50+
* that will not render.
51+
*
52+
* @param predicate predicate applied to the value, if renderable
53+
* @return this condition if renderable and the value matches the predicate, otherwise a condition
54+
* that will not render.
55+
*/
56+
public abstract S filter(Predicate<T> predicate);
57+
58+
protected S map(UnaryOperator<T> mapper, Function<T, S> constructor, S self) {
59+
if (shouldRender()) {
60+
return constructor.apply(mapper.apply(value));
61+
} else {
62+
return self;
63+
}
64+
}
65+
66+
/**
67+
* If renderable, apply the mapping to the value and return a new condition with the new value. Else return a
68+
* condition that will not render (this).
69+
*
70+
* @param mapper a mapping function to apply to the value, if renderable
71+
* @return a new condition with the result of applying the mapper to the value of this condition,
72+
* if renderable, otherwise a condition that will not render.
73+
*/
74+
public abstract S map(UnaryOperator<T> mapper);
75+
3476
public abstract String renderCondition(String columnName, String placeholder);
3577
}

src/main/java/org/mybatis/dynamic/sql/AbstractTwoValueCondition.java

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,13 @@
1515
*/
1616
package org.mybatis.dynamic.sql;
1717

18-
public abstract class AbstractTwoValueCondition<T> implements VisitableCondition<T> {
18+
import java.util.function.BiFunction;
19+
import java.util.function.BiPredicate;
20+
import java.util.function.Supplier;
21+
import java.util.function.UnaryOperator;
22+
23+
public abstract class AbstractTwoValueCondition<T, S extends AbstractTwoValueCondition<T, S>>
24+
implements VisitableCondition<T> {
1925
protected final T value1;
2026
protected final T value2;
2127

@@ -37,5 +43,42 @@ public <R> R accept(ConditionVisitor<T, R> visitor) {
3743
return visitor.visit(this);
3844
}
3945

46+
protected S filter(BiPredicate<T, T> predicate, Supplier<S> empty, S self) {
47+
if (shouldRender()) {
48+
return predicate.test(value1, value2) ? self : empty.get();
49+
} else {
50+
return self;
51+
}
52+
}
53+
54+
/**
55+
* If renderable and the values match the predicate, returns this condition. Else returns a condition
56+
* that will not render.
57+
*
58+
* @param predicate predicate applied to the values, if renderable
59+
* @return this condition if renderable and the values match the predicate, otherwise a condition
60+
* that will not render.
61+
*/
62+
public abstract S filter(BiPredicate<T, T> predicate);
63+
64+
protected S map(UnaryOperator<T> mapper1, UnaryOperator<T> mapper2, BiFunction<T, T, S> constructor, S self) {
65+
if (shouldRender()) {
66+
return constructor.apply(mapper1.apply(value1), mapper2.apply(value2));
67+
} else {
68+
return self;
69+
}
70+
}
71+
72+
/**
73+
* If renderable, apply the mappings to the values and return a new condition with the new values. Else return a
74+
* condition that will not render (this).
75+
*
76+
* @param mapper1 a mapping function to apply to the first value, if renderable
77+
* @param mapper2 a mapping function to apply to the second value, if renderable
78+
* @return a new condition with the result of applying the mappers to the values of this condition,
79+
* if renderable, otherwise a condition that will not render.
80+
*/
81+
public abstract S map(UnaryOperator<T> mapper1, UnaryOperator<T> mapper2);
82+
4083
public abstract String renderCondition(String columnName, String placeholder1, String placeholder2);
4184
}

src/main/java/org/mybatis/dynamic/sql/ConditionVisitor.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2016-2020 the original author or authors.
2+
* Copyright 2016-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -20,9 +20,9 @@ public interface ConditionVisitor<T, R> {
2020

2121
R visit(AbstractNoValueCondition<T> condition);
2222

23-
R visit(AbstractSingleValueCondition<T> condition);
23+
R visit(AbstractSingleValueCondition<T, ?> condition);
2424

25-
R visit(AbstractTwoValueCondition<T> condition);
25+
R visit(AbstractTwoValueCondition<T, ?> condition);
2626

2727
R visit(AbstractSubselectCondition<T> condition);
2828

src/main/java/org/mybatis/dynamic/sql/where/condition/IsBetween.java

Lines changed: 17 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,19 @@
2121
import org.mybatis.dynamic.sql.AbstractTwoValueCondition;
2222
import org.mybatis.dynamic.sql.util.Predicates;
2323

24-
public class IsBetween<T> extends AbstractTwoValueCondition<T> {
24+
public class IsBetween<T> extends AbstractTwoValueCondition<T, IsBetween<T>> {
25+
private static final IsBetween<?> EMPTY = new IsBetween<Object>(null, null) {
26+
@Override
27+
public boolean shouldRender() {
28+
return false;
29+
}
30+
};
31+
32+
public static <T> IsBetween<T> empty() {
33+
@SuppressWarnings("unchecked")
34+
IsBetween<T> t = (IsBetween<T>) EMPTY;
35+
return t;
36+
}
2537

2638
protected IsBetween(T value1, T value2) {
2739
super(value1, value2);
@@ -61,33 +73,14 @@ public IsBetween<T> then(UnaryOperator<T> mapper1, UnaryOperator<T> mapper2) {
6173
return map(mapper1, mapper2);
6274
}
6375

64-
/**
65-
* If renderable and the values match the predicate, returns this condition. Else returns a condition
66-
* that will not render.
67-
*
68-
* @param predicate predicate applied to the values, if renderable
69-
* @return this condition if renderable and the values match the predicate, otherwise a condition
70-
* that will not render.
71-
*/
76+
@Override
7277
public IsBetween<T> filter(BiPredicate<T, T> predicate) {
73-
if (shouldRender()) {
74-
return predicate.test(value1, value2) ? this : EmptyIsBetween.empty();
75-
} else {
76-
return this;
77-
}
78+
return filter(predicate, IsBetween::empty, this);
7879
}
7980

80-
/**
81-
* If renderable, apply the mappings to the values and return a new condition with the new values. Else return a
82-
* condition that will not render (this).
83-
*
84-
* @param mapper1 a mapping function to apply to the first value, if renderable
85-
* @param mapper2 a mapping function to apply to the second value, if renderable
86-
* @return a new condition with the result of applying the mappers to the values of this condition,
87-
* if renderable, otherwise a condition that will not render.
88-
*/
81+
@Override
8982
public IsBetween<T> map(UnaryOperator<T> mapper1, UnaryOperator<T> mapper2) {
90-
return shouldRender() ? new IsBetween<>(mapper1.apply(value1), mapper2.apply(value2)) : this;
83+
return map(mapper1, mapper2, IsBetween::new, this);
9184
}
9285

9386
public static <T> Builder<T> isBetween(T value1) {
@@ -119,23 +112,4 @@ protected IsBetween<T> build() {
119112
return new IsBetween<>(value1, value2).filter(Predicates.bothPresent());
120113
}
121114
}
122-
123-
public static class EmptyIsBetween<T> extends IsBetween<T> {
124-
private static final EmptyIsBetween<?> EMPTY = new EmptyIsBetween<>();
125-
126-
public static <T> EmptyIsBetween<T> empty() {
127-
@SuppressWarnings("unchecked")
128-
EmptyIsBetween<T> t = (EmptyIsBetween<T>) EMPTY;
129-
return t;
130-
}
131-
132-
private EmptyIsBetween() {
133-
super(null, null);
134-
}
135-
136-
@Override
137-
public boolean shouldRender() {
138-
return false;
139-
}
140-
}
141115
}

src/main/java/org/mybatis/dynamic/sql/where/condition/IsEqualTo.java

Lines changed: 18 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,20 @@
2020

2121
import org.mybatis.dynamic.sql.AbstractSingleValueCondition;
2222

23-
public class IsEqualTo<T> extends AbstractSingleValueCondition<T> {
23+
public class IsEqualTo<T> extends AbstractSingleValueCondition<T, IsEqualTo<T>> {
24+
25+
private static final IsEqualTo<?> EMPTY = new IsEqualTo<Object>(null) {
26+
@Override
27+
public boolean shouldRender() {
28+
return false;
29+
}
30+
};
31+
32+
public static <T> IsEqualTo<T> empty() {
33+
@SuppressWarnings("unchecked")
34+
IsEqualTo<T> t = (IsEqualTo<T>) EMPTY;
35+
return t;
36+
}
2437

2538
protected IsEqualTo(T value) {
2639
super(value);
@@ -63,50 +76,13 @@ public IsEqualTo<T> then(UnaryOperator<T> mapper) {
6376
return map(mapper);
6477
}
6578

66-
/**
67-
* If renderable and the value matches the predicate, returns this condition. Else returns a condition
68-
* that will not render.
69-
*
70-
* @param predicate predicate applied to the value, if renderable
71-
* @return this condition if renderable and the value matches the predicate, otherwise a condition
72-
* that will not render.
73-
*/
79+
@Override
7480
public IsEqualTo<T> filter(Predicate<T> predicate) {
75-
if (shouldRender()) {
76-
return predicate.test(value) ? this : EmptyIsEqualTo.empty();
77-
} else {
78-
return this;
79-
}
81+
return filter(predicate, IsEqualTo::empty, this);
8082
}
8183

82-
/**
83-
* If renderable, apply the mapping to the value and return a new condition with the new value. Else return a
84-
* condition that will not render (this).
85-
*
86-
* @param mapper a mapping function to apply to the value, if renderable
87-
* @return a new condition with the result of applying the mapper to the value of this condition,
88-
* if renderable, otherwise a condition that will not render.
89-
*/
84+
@Override
9085
public IsEqualTo<T> map(UnaryOperator<T> mapper) {
91-
return shouldRender() ? new IsEqualTo<>(mapper.apply(value)) : this;
92-
}
93-
94-
public static class EmptyIsEqualTo<T> extends IsEqualTo<T> {
95-
private static final EmptyIsEqualTo<?> EMPTY = new EmptyIsEqualTo<>();
96-
97-
public static <T> EmptyIsEqualTo<T> empty() {
98-
@SuppressWarnings("unchecked")
99-
EmptyIsEqualTo<T> t = (EmptyIsEqualTo<T>) EMPTY;
100-
return t;
101-
}
102-
103-
private EmptyIsEqualTo() {
104-
super(null);
105-
}
106-
107-
@Override
108-
public boolean shouldRender() {
109-
return false;
110-
}
86+
return map(mapper, IsEqualTo::new, this);
11187
}
11288
}

0 commit comments

Comments
 (0)