Skip to content

Commit 2e0ef3a

Browse files
committed
Map functions can change data types - List Value Conditions
1 parent 1c4bdbb commit 2e0ef3a

File tree

7 files changed

+104
-54
lines changed

7 files changed

+104
-54
lines changed

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

Lines changed: 18 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,11 @@
1717

1818
import java.util.Collection;
1919
import java.util.Objects;
20-
import java.util.function.BiFunction;
21-
import java.util.function.Function;
22-
import java.util.function.Predicate;
23-
import java.util.function.UnaryOperator;
20+
import java.util.function.*;
2421
import java.util.stream.Collectors;
2522
import java.util.stream.Stream;
2623

27-
public abstract class AbstractListValueCondition<T, S extends AbstractListValueCondition<T, S>>
24+
public abstract class AbstractListValueCondition<T>
2825
implements VisitableCondition<T> {
2926
protected final Collection<T> values;
3027
protected final Callback emptyCallback;
@@ -57,54 +54,47 @@ public <R> R accept(ConditionVisitor<T, R> visitor) {
5754
return visitor.visit(this);
5855
}
5956

60-
private Collection<T> applyMapper(UnaryOperator<T> mapper) {
57+
private <R> Collection<R> applyMapper(Function<? super T, ? extends R> mapper) {
6158
Objects.requireNonNull(mapper);
6259
return values.stream().map(mapper).collect(Collectors.toList());
6360
}
6461

65-
private Collection<T> applyFilter(Predicate<T> predicate) {
62+
private Collection<T> applyFilter(Predicate<? super T> predicate) {
6663
Objects.requireNonNull(predicate);
6764
return values.stream().filter(predicate).collect(Collectors.toList());
6865
}
6966

70-
protected S filter(Predicate<T> predicate, BiFunction<Collection<T>, Callback, S> constructor, S self) {
67+
protected <S> S filterSupport(Predicate<? super T> predicate,
68+
BiFunction<Collection<T>, Callback, S> constructor, S self, Supplier<S> empty) {
7169
if (shouldRender()) {
72-
return constructor.apply(applyFilter(predicate), emptyCallback);
70+
Collection<T> filtered = applyFilter(predicate);
71+
return filtered.isEmpty() ? empty.get() : constructor.apply(filtered, emptyCallback);
7372
} else {
7473
return self;
7574
}
7675
}
7776

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) {
77+
protected <R, S> S mapSupport(Function<? super T, ? extends R> mapper,
78+
BiFunction<Collection<R>, Callback, S> constructor, Supplier<S> empty) {
9079
if (shouldRender()) {
9180
return constructor.apply(applyMapper(mapper), emptyCallback);
9281
} else {
93-
return self;
82+
return empty.get();
9483
}
9584
}
9685

9786
/**
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).
87+
* If renderable, apply the predicate to each value in the list and return a new condition with the filtered values.
88+
* Else returns a condition that will not render (this). If all values are filtered out of the value
89+
* list, then the condition will not render.
10090
*
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
91+
* @param predicate predicate applied to the values, if renderable
92+
* @return a new condition with filtered values if renderable, otherwise a condition
10393
* that will not render.
10494
*/
105-
public abstract S map(UnaryOperator<T> mapper);
95+
public abstract AbstractListValueCondition<T> filter(Predicate<? super T> predicate);
10696

107-
public abstract S withListEmptyCallback(Callback callback);
97+
public abstract AbstractListValueCondition<T> withListEmptyCallback(Callback callback);
10898

10999
public abstract String renderCondition(String columnName, Stream<String> placeholders);
110100
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
package org.mybatis.dynamic.sql;
1717

1818
public interface ConditionVisitor<T, R> {
19-
R visit(AbstractListValueCondition<T, ?> condition);
19+
R visit(AbstractListValueCondition<T> condition);
2020

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

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

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@
1919

2020
import java.util.Arrays;
2121
import java.util.Collection;
22+
import java.util.Collections;
2223
import java.util.List;
24+
import java.util.function.Function;
2325
import java.util.function.Predicate;
2426
import java.util.function.UnaryOperator;
2527
import java.util.stream.Collectors;
@@ -28,7 +30,14 @@
2830
import org.mybatis.dynamic.sql.AbstractListValueCondition;
2931
import org.mybatis.dynamic.sql.Callback;
3032

31-
public class IsIn<T> extends AbstractListValueCondition<T, IsIn<T>> {
33+
public class IsIn<T> extends AbstractListValueCondition<T> {
34+
private static final IsIn<?> EMPTY = new IsIn<>(Collections.emptyList());
35+
36+
public static <T> IsIn<T> empty() {
37+
@SuppressWarnings("unchecked")
38+
IsIn<T> t = (IsIn<T>) EMPTY;
39+
return t;
40+
}
3241

3342
protected IsIn(Collection<T> values) {
3443
super(values);
@@ -55,7 +64,7 @@ public IsIn<T> withListEmptyCallback(Callback callback) {
5564
* If you filter values out of the stream, then final condition will not reference those values. If you filter all
5665
* values out of the stream, then the condition will not render.
5766
*
58-
* @deprecated replaced by {@link IsIn#map(UnaryOperator)} and {@link IsIn#filter(Predicate)}
67+
* @deprecated replaced by {@link IsIn#map(Function)} and {@link IsIn#filter(Predicate)}
5968
* @param valueStreamTransformer a UnaryOperator that will transform the value stream before
6069
* the values are placed in the parameter map
6170
* @return new condition with the specified transformer
@@ -68,13 +77,21 @@ public IsIn<T> then(UnaryOperator<Stream<T>> valueStreamTransformer) {
6877
}
6978

7079
@Override
71-
public IsIn<T> filter(Predicate<T> predicate) {
72-
return filter(predicate, IsIn::new, this);
80+
public IsIn<T> filter(Predicate<? super T> predicate) {
81+
return filterSupport(predicate, IsIn::new, this, IsIn::empty);
7382
}
7483

75-
@Override
76-
public IsIn<T> map(UnaryOperator<T> mapper) {
77-
return map(mapper, IsIn::new, this);
84+
/**
85+
* If renderable, apply the mapping to each value in the list return a new condition with the mapped values.
86+
* Else return a condition that will not render (this).
87+
*
88+
* @param mapper a mapping function to apply to the values, if renderable
89+
* @param <R> type of the new condition
90+
* @return a new condition with mapped values if renderable, otherwise a condition
91+
* that will not render.
92+
*/
93+
public <R> IsIn<R> map(Function<? super T, ? extends R> mapper) {
94+
return mapSupport(mapper, IsIn::new, IsIn::empty);
7895
}
7996

8097
@SafeVarargs

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

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

1818
import java.util.Arrays;
1919
import java.util.Collection;
20+
import java.util.Collections;
2021
import java.util.function.Predicate;
2122
import java.util.function.UnaryOperator;
2223
import java.util.stream.Collectors;
@@ -26,7 +27,12 @@
2627
import org.mybatis.dynamic.sql.Callback;
2728
import org.mybatis.dynamic.sql.util.StringUtilities;
2829

29-
public class IsInCaseInsensitive extends AbstractListValueCondition<String, IsInCaseInsensitive> {
30+
public class IsInCaseInsensitive extends AbstractListValueCondition<String> {
31+
private static final IsInCaseInsensitive EMPTY = new IsInCaseInsensitive(Collections.emptyList());
32+
33+
public static IsInCaseInsensitive empty() {
34+
return EMPTY;
35+
}
3036

3137
protected IsInCaseInsensitive(Collection<String> values) {
3238
super(values);
@@ -48,13 +54,20 @@ public IsInCaseInsensitive withListEmptyCallback(Callback callback) {
4854
}
4955

5056
@Override
51-
public IsInCaseInsensitive filter(Predicate<String> predicate) {
52-
return filter(predicate, IsInCaseInsensitive::new, this);
57+
public IsInCaseInsensitive filter(Predicate<? super String> predicate) {
58+
return filterSupport(predicate, IsInCaseInsensitive::new, this, IsInCaseInsensitive::empty);
5359
}
5460

55-
@Override
61+
/**
62+
* If renderable, apply the mapping to each value in the list return a new condition with the mapped values.
63+
* Else return a condition that will not render (this).
64+
*
65+
* @param mapper a mapping function to apply to the values, if renderable
66+
* @return a new condition with mapped values if renderable, otherwise a condition
67+
* that will not render.
68+
*/
5669
public IsInCaseInsensitive map(UnaryOperator<String> mapper) {
57-
return map(mapper, IsInCaseInsensitive::new, this);
70+
return mapSupport(mapper, IsInCaseInsensitive::new, IsInCaseInsensitive::empty);
5871
}
5972

6073
public static IsInCaseInsensitive of(String... values) {

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

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@
1919

2020
import java.util.Arrays;
2121
import java.util.Collection;
22+
import java.util.Collections;
2223
import java.util.List;
24+
import java.util.function.Function;
2325
import java.util.function.Predicate;
2426
import java.util.function.UnaryOperator;
2527
import java.util.stream.Collectors;
@@ -28,7 +30,14 @@
2830
import org.mybatis.dynamic.sql.AbstractListValueCondition;
2931
import org.mybatis.dynamic.sql.Callback;
3032

31-
public class IsNotIn<T> extends AbstractListValueCondition<T, IsNotIn<T>> {
33+
public class IsNotIn<T> extends AbstractListValueCondition<T> {
34+
private static final IsNotIn<?> EMPTY = new IsNotIn<>(Collections.emptyList());
35+
36+
public static <T> IsNotIn<T> empty() {
37+
@SuppressWarnings("unchecked")
38+
IsNotIn<T> t = (IsNotIn<T>) EMPTY;
39+
return t;
40+
}
3241

3342
protected IsNotIn(Collection<T> values) {
3443
super(values);
@@ -56,7 +65,7 @@ public IsNotIn<T> withListEmptyCallback(Callback callback) {
5665
* If you filter values out of the stream, then final condition will not reference those values. If you filter all
5766
* values out of the stream, then the condition will not render.
5867
*
59-
* @deprecated replaced by {@link IsNotIn#map(UnaryOperator)} and {@link IsNotIn#filter(Predicate)}
68+
* @deprecated replaced by {@link IsNotIn#map(Function)} and {@link IsNotIn#filter(Predicate)}
6069
* @param valueStreamTransformer a UnaryOperator that will transform the value stream before
6170
* the values are placed in the parameter map
6271
* @return new condition with the specified transformer
@@ -70,13 +79,21 @@ public IsNotIn<T> then(UnaryOperator<Stream<T>> valueStreamTransformer) {
7079
}
7180

7281
@Override
73-
public IsNotIn<T> filter(Predicate<T> predicate) {
74-
return filter(predicate, IsNotIn::new, this);
82+
public IsNotIn<T> filter(Predicate<? super T> predicate) {
83+
return filterSupport(predicate, IsNotIn::new, this, IsNotIn::empty);
7584
}
7685

77-
@Override
78-
public IsNotIn<T> map(UnaryOperator<T> mapper) {
79-
return map(mapper, IsNotIn::new, this);
86+
/**
87+
* If renderable, apply the mapping to each value in the list return a new condition with the mapped values.
88+
* Else return a condition that will not render (this).
89+
*
90+
* @param mapper a mapping function to apply to the values, if renderable
91+
* @param <R> type of the new condition
92+
* @return a new condition with mapped values if renderable, otherwise a condition
93+
* that will not render.
94+
*/
95+
public <R> IsNotIn<R> map(Function<? super T, ? extends R> mapper) {
96+
return mapSupport(mapper, IsNotIn::new, IsNotIn::empty);
8097
}
8198

8299
@SafeVarargs

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

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

1818
import java.util.Arrays;
1919
import java.util.Collection;
20+
import java.util.Collections;
2021
import java.util.function.Predicate;
2122
import java.util.function.UnaryOperator;
2223
import java.util.stream.Collectors;
@@ -26,7 +27,12 @@
2627
import org.mybatis.dynamic.sql.Callback;
2728
import org.mybatis.dynamic.sql.util.StringUtilities;
2829

29-
public class IsNotInCaseInsensitive extends AbstractListValueCondition<String, IsNotInCaseInsensitive> {
30+
public class IsNotInCaseInsensitive extends AbstractListValueCondition<String> {
31+
private static final IsNotInCaseInsensitive EMPTY = new IsNotInCaseInsensitive(Collections.emptyList());
32+
33+
public static IsNotInCaseInsensitive empty() {
34+
return EMPTY;
35+
}
3036

3137
protected IsNotInCaseInsensitive(Collection<String> values) {
3238
super(values);
@@ -49,13 +55,20 @@ public IsNotInCaseInsensitive withListEmptyCallback(Callback callback) {
4955
}
5056

5157
@Override
52-
public IsNotInCaseInsensitive filter(Predicate<String> predicate) {
53-
return filter(predicate, IsNotInCaseInsensitive::new, this);
58+
public IsNotInCaseInsensitive filter(Predicate<? super String> predicate) {
59+
return filterSupport(predicate, IsNotInCaseInsensitive::new, this, IsNotInCaseInsensitive::empty);
5460
}
5561

56-
@Override
62+
/**
63+
* If renderable, apply the mapping to each value in the list return a new condition with the mapped values.
64+
* Else return a condition that will not render (this).
65+
*
66+
* @param mapper a mapping function to apply to the values, if renderable
67+
* @return a new condition with mapped values if renderable, otherwise a condition
68+
* that will not render.
69+
*/
5770
public IsNotInCaseInsensitive map(UnaryOperator<String> mapper) {
58-
return map(mapper, IsNotInCaseInsensitive::new, this);
71+
return mapSupport(mapper, IsNotInCaseInsensitive::new, IsNotInCaseInsensitive::empty);
5972
}
6073

6174
public static IsNotInCaseInsensitive of(String... values) {

src/main/java/org/mybatis/dynamic/sql/where/render/WhereConditionVisitor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ private WhereConditionVisitor(Builder<T> builder) {
5050
}
5151

5252
@Override
53-
public FragmentAndParameters visit(AbstractListValueCondition<T, ?> condition) {
53+
public FragmentAndParameters visit(AbstractListValueCondition<T> condition) {
5454
FragmentCollector fc = condition.mapValues(this::toFragmentAndParameters)
5555
.collect(FragmentCollector.collect());
5656

0 commit comments

Comments
 (0)