Skip to content

Commit 15a2f38

Browse files
committed
Implement filter/map for List value conditions
1 parent 12557c2 commit 15a2f38

File tree

12 files changed

+313
-444
lines changed

12 files changed

+313
-444
lines changed
Lines changed: 19 additions & 31 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.
@@ -15,25 +15,26 @@
1515
*/
1616
package org.mybatis.dynamic.sql;
1717

18-
import java.util.ArrayList;
1918
import java.util.Collection;
2019
import java.util.Objects;
2120
import java.util.function.Function;
21+
import java.util.function.Predicate;
2222
import java.util.function.UnaryOperator;
2323
import java.util.stream.Collectors;
2424
import java.util.stream.Stream;
2525

2626
public abstract class AbstractListValueCondition<T, S extends AbstractListValueCondition<T, S>>
2727
implements VisitableCondition<T> {
2828
protected final Collection<T> values;
29-
protected final UnaryOperator<Stream<T>> valueStreamTransformer;
3029
protected final Callback emptyCallback;
3130

32-
protected AbstractListValueCondition(AbstractListConditionBuilder<T, ?> builder) {
33-
this.valueStreamTransformer = Objects.requireNonNull(builder.valueStreamTransformer);
34-
this.values = valueStreamTransformer.apply(builder.values.stream())
35-
.collect(Collectors.toList());
36-
this.emptyCallback = Objects.requireNonNull(builder.emptyCallback);
31+
protected AbstractListValueCondition(Collection<T> values) {
32+
this(values, () -> { });
33+
}
34+
35+
protected AbstractListValueCondition(Collection<T> values, Callback emptyCallback) {
36+
this.values = Objects.requireNonNull(values);
37+
this.emptyCallback = Objects.requireNonNull(emptyCallback);
3738
}
3839

3940
public final <R> Stream<R> mapValues(Function<T, R> mapper) {
@@ -55,30 +56,17 @@ public <R> R accept(ConditionVisitor<T, R> visitor) {
5556
return visitor.visit(this);
5657
}
5758

58-
public abstract S withListEmptyCallback(Callback callback);
59-
60-
public abstract String renderCondition(String columnName, Stream<String> placeholders);
61-
62-
public abstract static class AbstractListConditionBuilder<T, S extends AbstractListConditionBuilder<T, S>> {
63-
protected Collection<T> values = new ArrayList<>();
64-
protected UnaryOperator<Stream<T>> valueStreamTransformer = UnaryOperator.identity();
65-
protected Callback emptyCallback = () -> { };
66-
67-
public S withValues(Collection<T> values) {
68-
this.values.addAll(values);
69-
return getThis();
70-
}
59+
protected Collection<T> applyMapper(UnaryOperator<T> mapper) {
60+
Objects.requireNonNull(mapper);
61+
return values.stream().map(mapper).collect(Collectors.toList());
62+
}
7163

72-
public S withValueStreamTransformer(UnaryOperator<Stream<T>> valueStreamTransformer) {
73-
this.valueStreamTransformer = valueStreamTransformer;
74-
return getThis();
75-
}
64+
protected Collection<T> applyFilter(Predicate<T> predicate) {
65+
Objects.requireNonNull(predicate);
66+
return values.stream().filter(predicate).collect(Collectors.toList());
67+
}
7668

77-
public S withEmptyCallback(Callback emptyCallback) {
78-
this.emptyCallback = emptyCallback;
79-
return getThis();
80-
}
69+
public abstract S withListEmptyCallback(Callback callback);
8170

82-
protected abstract S getThis();
83-
}
71+
public abstract String renderCondition(String columnName, Stream<String> placeholders);
8472
}

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

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,6 @@
7070
import org.mybatis.dynamic.sql.where.condition.IsGreaterThanWithSubselect;
7171
import org.mybatis.dynamic.sql.where.condition.IsIn;
7272
import org.mybatis.dynamic.sql.where.condition.IsInCaseInsensitive;
73-
import org.mybatis.dynamic.sql.where.condition.IsInCaseInsensitiveWhenPresent;
74-
import org.mybatis.dynamic.sql.where.condition.IsInWhenPresent;
7573
import org.mybatis.dynamic.sql.where.condition.IsInWithSubselect;
7674
import org.mybatis.dynamic.sql.where.condition.IsLessThan;
7775
import org.mybatis.dynamic.sql.where.condition.IsLessThanColumn;
@@ -88,8 +86,6 @@
8886
import org.mybatis.dynamic.sql.where.condition.IsNotEqualToWithSubselect;
8987
import org.mybatis.dynamic.sql.where.condition.IsNotIn;
9088
import org.mybatis.dynamic.sql.where.condition.IsNotInCaseInsensitive;
91-
import org.mybatis.dynamic.sql.where.condition.IsNotInCaseInsensitiveWhenPresent;
92-
import org.mybatis.dynamic.sql.where.condition.IsNotInWhenPresent;
9389
import org.mybatis.dynamic.sql.where.condition.IsNotInWithSubselect;
9490
import org.mybatis.dynamic.sql.where.condition.IsNotLike;
9591
import org.mybatis.dynamic.sql.where.condition.IsNotLikeCaseInsensitive;
@@ -578,12 +574,12 @@ static <T> IsInWithSubselect<T> isIn(Buildable<SelectModel> selectModelBuilder)
578574
}
579575

580576
@SafeVarargs
581-
static <T> IsInWhenPresent<T> isInWhenPresent(T...values) {
582-
return IsInWhenPresent.of(values);
577+
static <T> IsIn<T> isInWhenPresent(T...values) {
578+
return IsIn.of(values).filter(Objects::nonNull);
583579
}
584580

585-
static <T> IsInWhenPresent<T> isInWhenPresent(Collection<T> values) {
586-
return IsInWhenPresent.of(values);
581+
static <T> IsIn<T> isInWhenPresent(Collection<T> values) {
582+
return IsIn.of(values).filter(Objects::nonNull);
587583
}
588584

589585
@SafeVarargs
@@ -600,12 +596,12 @@ static <T> IsNotInWithSubselect<T> isNotIn(Buildable<SelectModel> selectModelBui
600596
}
601597

602598
@SafeVarargs
603-
static <T> IsNotInWhenPresent<T> isNotInWhenPresent(T...values) {
604-
return IsNotInWhenPresent.of(values);
599+
static <T> IsNotIn<T> isNotInWhenPresent(T...values) {
600+
return IsNotIn.of(values).filter(Objects::nonNull);
605601
}
606602

607-
static <T> IsNotInWhenPresent<T> isNotInWhenPresent(Collection<T> values) {
608-
return IsNotInWhenPresent.of(values);
603+
static <T> IsNotIn<T> isNotInWhenPresent(Collection<T> values) {
604+
return IsNotIn.of(values).filter(Objects::nonNull);
609605
}
610606

611607
static <T> IsBetween.Builder<T> isBetween(T value1) {
@@ -723,12 +719,12 @@ static IsInCaseInsensitive isInCaseInsensitive(Collection<String> values) {
723719
return IsInCaseInsensitive.of(values);
724720
}
725721

726-
static IsInCaseInsensitiveWhenPresent isInCaseInsensitiveWhenPresent(String...values) {
727-
return IsInCaseInsensitiveWhenPresent.of(values);
722+
static IsInCaseInsensitive isInCaseInsensitiveWhenPresent(String...values) {
723+
return IsInCaseInsensitive.of(values).filter(Objects::nonNull);
728724
}
729725

730-
static IsInCaseInsensitiveWhenPresent isInCaseInsensitiveWhenPresent(Collection<String> values) {
731-
return IsInCaseInsensitiveWhenPresent.of(values);
726+
static IsInCaseInsensitive isInCaseInsensitiveWhenPresent(Collection<String> values) {
727+
return IsInCaseInsensitive.of(values).filter(Objects::nonNull);
732728
}
733729

734730
static IsNotInCaseInsensitive isNotInCaseInsensitive(String...values) {
@@ -739,12 +735,12 @@ static IsNotInCaseInsensitive isNotInCaseInsensitive(Collection<String> values)
739735
return IsNotInCaseInsensitive.of(values);
740736
}
741737

742-
static IsNotInCaseInsensitiveWhenPresent isNotInCaseInsensitiveWhenPresent(String...values) {
743-
return IsNotInCaseInsensitiveWhenPresent.of(values);
738+
static IsNotInCaseInsensitive isNotInCaseInsensitiveWhenPresent(String...values) {
739+
return IsNotInCaseInsensitive.of(values).filter(Objects::nonNull);
744740
}
745741

746-
static IsNotInCaseInsensitiveWhenPresent isNotInCaseInsensitiveWhenPresent(Collection<String> values) {
747-
return IsNotInCaseInsensitiveWhenPresent.of(values);
742+
static IsNotInCaseInsensitive isNotInCaseInsensitiveWhenPresent(Collection<String> values) {
743+
return IsNotInCaseInsensitive.of(values).filter(Objects::nonNull);
748744
}
749745

750746
// order by support
Lines changed: 49 additions & 25 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.
@@ -19,6 +19,8 @@
1919

2020
import java.util.Arrays;
2121
import java.util.Collection;
22+
import java.util.List;
23+
import java.util.function.Predicate;
2224
import java.util.function.UnaryOperator;
2325
import java.util.stream.Collectors;
2426
import java.util.stream.Stream;
@@ -28,8 +30,12 @@
2830

2931
public class IsIn<T> extends AbstractListValueCondition<T, IsIn<T>> {
3032

31-
protected IsIn(Builder<T> builder) {
32-
super(builder);
33+
protected IsIn(Collection<T> values) {
34+
super(values);
35+
}
36+
37+
protected IsIn(Collection<T> values, Callback emptyCallback) {
38+
super(values, emptyCallback);
3339
}
3440

3541
@Override
@@ -40,11 +46,7 @@ public String renderCondition(String columnName, Stream<String> placeholders) {
4046

4147
@Override
4248
public IsIn<T> withListEmptyCallback(Callback callback) {
43-
return new Builder<T>()
44-
.withValues(values)
45-
.withValueStreamTransformer(valueStreamTransformer)
46-
.withEmptyCallback(callback)
47-
.build();
49+
return new IsIn<>(values, callback);
4850
}
4951

5052
/**
@@ -53,16 +55,49 @@ public IsIn<T> withListEmptyCallback(Callback callback) {
5355
* If you filter values out of the stream, then final condition will not reference those values. If you filter all
5456
* values out of the stream, then the condition will not render.
5557
*
58+
* @deprecated replaced by {@link IsIn#map(UnaryOperator)} and {@link IsIn#filter(Predicate)}
5659
* @param valueStreamTransformer a UnaryOperator that will transform the value stream before
5760
* the values are placed in the parameter map
5861
* @return new condition with the specified transformer
5962
*/
63+
@Deprecated
6064
public IsIn<T> then(UnaryOperator<Stream<T>> valueStreamTransformer) {
61-
return new Builder<T>()
62-
.withValues(values)
63-
.withValueStreamTransformer(valueStreamTransformer)
64-
.withEmptyCallback(emptyCallback)
65-
.build();
65+
List<T> mapped = valueStreamTransformer.apply(values.stream())
66+
.collect(Collectors.toList());
67+
return new IsIn<>(mapped, emptyCallback);
68+
}
69+
70+
/**
71+
* If renderable, apply the predicate to each value in the list and return a new condition with the filtered values.
72+
* Else returns a condition that will not render (this). If all values are filtered out of the value
73+
* list, then the condition will not render.
74+
*
75+
* @param predicate predicate applied to the values, if renderable
76+
* @return a new condition with filtered values if renderable, otherwise a condition
77+
* that will not render.
78+
*/
79+
public IsIn<T> filter(Predicate<T> predicate) {
80+
if (shouldRender()) {
81+
return new IsIn<>(applyFilter(predicate), emptyCallback);
82+
} else {
83+
return this;
84+
}
85+
}
86+
87+
/**
88+
* If renderable, apply the mapping to each value in the list return a new condition with the mapped values.
89+
* Else return a condition that will not render (this).
90+
*
91+
* @param mapper a mapping function to apply to the values, if renderable
92+
* @return a new condition with mapped values if renderable, otherwise a condition
93+
* that will not render.
94+
*/
95+
public IsIn<T> map(UnaryOperator<T> mapper) {
96+
if (shouldRender()) {
97+
return new IsIn<>(applyMapper(mapper), emptyCallback);
98+
} else {
99+
return this;
100+
}
66101
}
67102

68103
@SafeVarargs
@@ -71,17 +106,6 @@ public static <T> IsIn<T> of(T... values) {
71106
}
72107

73108
public static <T> IsIn<T> of(Collection<T> values) {
74-
return new Builder<T>().withValues(values).build();
75-
}
76-
77-
public static class Builder<T> extends AbstractListConditionBuilder<T, Builder<T>> {
78-
@Override
79-
protected Builder<T> getThis() {
80-
return this;
81-
}
82-
83-
public IsIn<T> build() {
84-
return new IsIn<>(this);
85-
}
109+
return new IsIn<>(values);
86110
}
87111
}
Lines changed: 44 additions & 23 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.
@@ -17,6 +17,8 @@
1717

1818
import java.util.Arrays;
1919
import java.util.Collection;
20+
import java.util.function.Predicate;
21+
import java.util.function.UnaryOperator;
2022
import java.util.stream.Collectors;
2123
import java.util.stream.Stream;
2224

@@ -26,8 +28,12 @@
2628

2729
public class IsInCaseInsensitive extends AbstractListValueCondition<String, IsInCaseInsensitive> {
2830

29-
protected IsInCaseInsensitive(Builder builder) {
30-
super(builder);
31+
protected IsInCaseInsensitive(Collection<String> values) {
32+
super(values);
33+
}
34+
35+
protected IsInCaseInsensitive(Collection<String> values, Callback emptyCallback) {
36+
super(values, emptyCallback);
3137
}
3238

3339
@Override
@@ -38,32 +44,47 @@ public String renderCondition(String columnName, Stream<String> placeholders) {
3844

3945
@Override
4046
public IsInCaseInsensitive withListEmptyCallback(Callback callback) {
41-
return new Builder()
42-
.withValues(values)
43-
.withValueStreamTransformer(valueStreamTransformer)
44-
.withEmptyCallback(callback)
45-
.build();
46-
}
47-
48-
public static IsInCaseInsensitive of(String... values) {
49-
return of(Arrays.asList(values));
47+
return new IsInCaseInsensitive(values, callback);
5048
}
5149

52-
public static IsInCaseInsensitive of(Collection<String> values) {
53-
return new Builder()
54-
.withValues(values)
55-
.withValueStreamTransformer(s -> s.map(StringUtilities::safelyUpperCase))
56-
.build();
50+
/**
51+
* If renderable apply the predicate to each value in the list and return a new condition with the filtered values.
52+
* Else returns a condition that will not render (this). If all values are filtered out of the value
53+
* list, then the condition will not render.
54+
*
55+
* @param predicate predicate applied to the values, if renderable
56+
* @return a new condition with filtered values if renderable, otherwise a condition
57+
* that will not render.
58+
*/
59+
public IsInCaseInsensitive filter(Predicate<String> predicate) {
60+
if (shouldRender()) {
61+
return new IsInCaseInsensitive(applyFilter(predicate), emptyCallback);
62+
} else {
63+
return this;
64+
}
5765
}
5866

59-
public static class Builder extends AbstractListConditionBuilder<String, Builder> {
60-
@Override
61-
protected Builder getThis() {
67+
/**
68+
* If renderable, apply the mapping to each value in the list return a new condition with the mapped values.
69+
* Else return a condition that will not render (this).
70+
*
71+
* @param mapper a mapping function to apply to the values, if renderable
72+
* @return a new condition with mapped values if renderable, otherwise a condition
73+
* that will not render.
74+
*/
75+
public IsInCaseInsensitive map(UnaryOperator<String> mapper) {
76+
if (shouldRender()) {
77+
return new IsInCaseInsensitive(applyMapper(mapper), emptyCallback);
78+
} else {
6279
return this;
6380
}
81+
}
6482

65-
protected IsInCaseInsensitive build() {
66-
return new IsInCaseInsensitive(this);
67-
}
83+
public static IsInCaseInsensitive of(String... values) {
84+
return of(Arrays.asList(values));
85+
}
86+
87+
public static IsInCaseInsensitive of(Collection<String> values) {
88+
return new IsInCaseInsensitive(values).map(StringUtilities::safelyUpperCase);
6889
}
6990
}

0 commit comments

Comments
 (0)