Skip to content

Commit 707dfdb

Browse files
committed
Implement a callback for empty "in" conditions
1 parent 12e1ca8 commit 707dfdb

File tree

13 files changed

+146
-162
lines changed

13 files changed

+146
-162
lines changed

.github/dependabot.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,19 @@
1+
#
2+
# Copyright 2016-2020 the original author or authors.
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
#
16+
117
version: 2
218
updates:
319
- package-ecosystem: maven

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

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,19 +22,26 @@
2222
import java.util.stream.Collectors;
2323
import java.util.stream.Stream;
2424

25-
public abstract class AbstractListValueCondition<T> implements VisitableCondition<T> {
25+
public abstract class AbstractListValueCondition<T, S extends AbstractListValueCondition<T, S>>
26+
implements VisitableCondition<T> {
2627
protected final Collection<T> values;
2728
protected final UnaryOperator<Stream<T>> valueStreamTransformer;
28-
protected boolean renderWhenEmpty = false;
29+
protected final Callback emptyCallback;
2930

3031
protected AbstractListValueCondition(Collection<T> values) {
31-
this(values, UnaryOperator.identity());
32+
this(values, UnaryOperator.identity(), () -> { });
3233
}
3334

3435
protected AbstractListValueCondition(Collection<T> values, UnaryOperator<Stream<T>> valueStreamTransformer) {
36+
this(values, valueStreamTransformer, () -> { });
37+
}
38+
39+
protected AbstractListValueCondition(Collection<T> values, UnaryOperator<Stream<T>> valueStreamTransformer,
40+
Callback emptyCallback) {
3541
this.valueStreamTransformer = Objects.requireNonNull(valueStreamTransformer);
3642
this.values = valueStreamTransformer.apply(Objects.requireNonNull(values).stream())
3743
.collect(Collectors.toList());
44+
this.emptyCallback = Objects.requireNonNull(emptyCallback);
3845
}
3946

4047
public final <R> Stream<R> mapValues(Function<T, R> mapper) {
@@ -43,20 +50,20 @@ public final <R> Stream<R> mapValues(Function<T, R> mapper) {
4350

4451
@Override
4552
public boolean shouldRender() {
46-
return !values.isEmpty() || renderWhenEmpty;
53+
if (values.isEmpty()) {
54+
emptyCallback.call();
55+
return false;
56+
} else {
57+
return true;
58+
}
4759
}
4860

49-
/**
50-
* Use with caution - this could cause the library to render invalid SQL like "where column in ()".
51-
*/
52-
protected void forceRenderingWhenEmpty() {
53-
renderWhenEmpty = true;
54-
}
55-
5661
@Override
5762
public <R> R accept(ConditionVisitor<T, R> visitor) {
5863
return visitor.visit(this);
5964
}
6065

66+
public abstract S withListEmptyCallback(Callback callback);
67+
6168
public abstract String renderCondition(String columnName, Stream<String> placeholders);
6269
}

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,18 @@
1+
/**
2+
* Copyright 2016-2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
116
package org.mybatis.dynamic.sql;
217

318
import java.util.function.Function;

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright 2016-2018 the original author or authors.
2+
* Copyright 2016-2020 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.

src/main/java/org/mybatis/dynamic/sql/util/StringUtilities.java

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@
1616
package org.mybatis.dynamic.sql.util;
1717

1818
import java.util.Optional;
19-
import java.util.function.UnaryOperator;
20-
import java.util.stream.Stream;
2119

2220
public interface StringUtilities {
2321

@@ -42,9 +40,4 @@ static String spaceBefore(String in) {
4240
static String safelyUpperCase(String s) {
4341
return s == null ? null : s.toUpperCase();
4442
}
45-
46-
static UnaryOperator<Stream<String>> upperCaseAfter(UnaryOperator<Stream<String>> valueModifier) {
47-
UnaryOperator<Stream<String>> ua = s -> s.map(StringUtilities::safelyUpperCase);
48-
return t -> ua.apply(valueModifier.apply(t));
49-
}
5043
}

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

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,20 @@
2323
import java.util.stream.Stream;
2424

2525
import org.mybatis.dynamic.sql.AbstractListValueCondition;
26+
import org.mybatis.dynamic.sql.Callback;
2627

27-
public class IsIn<T> extends AbstractListValueCondition<T> {
28+
public class IsIn<T> extends AbstractListValueCondition<T, IsIn<T>> {
29+
30+
protected IsIn(Collection<T> values) {
31+
super(values);
32+
}
2833

2934
protected IsIn(Collection<T> values, UnaryOperator<Stream<T>> valueStreamTransformer) {
3035
super(values, valueStreamTransformer);
3136
}
3237

33-
protected IsIn(Collection<T> values) {
34-
super(values);
38+
protected IsIn(Collection<T> values, UnaryOperator<Stream<T>> valueStreamTransformer, Callback emptyCallback) {
39+
super(values, valueStreamTransformer, emptyCallback);
3540
}
3641

3742
@Override
@@ -40,6 +45,11 @@ public String renderCondition(String columnName, Stream<String> placeholders) {
4045
+ placeholders.collect(Collectors.joining(",", "in (", ")")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
4146
}
4247

48+
@Override
49+
public IsIn<T> withListEmptyCallback(Callback callback) {
50+
return new IsIn<>(values, valueStreamTransformer, callback);
51+
}
52+
4353
/**
4454
* This method allows you to modify the condition's values before they are placed into the parameter map.
4555
* For example, you could filter nulls, or trim strings, etc. This process will run before final rendering of SQL.
@@ -51,9 +61,7 @@ public String renderCondition(String columnName, Stream<String> placeholders) {
5161
* @return new condition with the specified transformer
5262
*/
5363
public IsIn<T> then(UnaryOperator<Stream<T>> valueStreamTransformer) {
54-
IsIn<T> answer = new IsIn<>(values, valueStreamTransformer);
55-
answer.renderWhenEmpty = renderWhenEmpty;
56-
return answer;
64+
return new IsIn<>(values, valueStreamTransformer, emptyCallback);
5765
}
5866

5967
public static <T> IsIn<T> of(Collection<T> values) {

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

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,22 @@
2121
import java.util.stream.Stream;
2222

2323
import org.mybatis.dynamic.sql.AbstractListValueCondition;
24+
import org.mybatis.dynamic.sql.Callback;
2425
import org.mybatis.dynamic.sql.util.StringUtilities;
2526

26-
public class IsInCaseInsensitive extends AbstractListValueCondition<String> {
27+
public class IsInCaseInsensitive extends AbstractListValueCondition<String, IsInCaseInsensitive> {
2728

2829
protected IsInCaseInsensitive(Collection<String> values) {
2930
super(values, s -> s.map(StringUtilities::safelyUpperCase));
3031
}
3132

3233
protected IsInCaseInsensitive(Collection<String> values, UnaryOperator<Stream<String>> valueStreamTransformer) {
33-
super(values, StringUtilities.upperCaseAfter(valueStreamTransformer));
34+
super(values, valueStreamTransformer);
35+
}
36+
37+
protected IsInCaseInsensitive(Collection<String> values, UnaryOperator<Stream<String>> valueStreamTransformer,
38+
Callback emptyCallback) {
39+
super(values, valueStreamTransformer, emptyCallback);
3440
}
3541

3642
@Override
@@ -39,20 +45,9 @@ public String renderCondition(String columnName, Stream<String> placeholders) {
3945
placeholders.collect(Collectors.joining(",", "in (", ")")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
4046
}
4147

42-
/**
43-
* This method allows you to modify the condition's values before they are placed into the parameter map.
44-
* For example, you could filter nulls, or trim strings, etc. This process will run before final rendering of SQL.
45-
* If you filter values out of the stream, then final condition will not reference those values. If you filter all
46-
* values out of the stream, then the condition will not render.
47-
*
48-
* @param valueStreamTransformer a UnaryOperator that will transform the value stream before
49-
* the values are placed in the parameter map
50-
* @return new condition with the specified transformer
51-
*/
52-
public IsInCaseInsensitive then(UnaryOperator<Stream<String>> valueStreamTransformer) {
53-
IsInCaseInsensitive answer = new IsInCaseInsensitive(values, valueStreamTransformer);
54-
answer.renderWhenEmpty = renderWhenEmpty;
55-
return answer;
48+
@Override
49+
public IsInCaseInsensitive withListEmptyCallback(Callback callback) {
50+
return new IsInCaseInsensitive(values, valueStreamTransformer, callback);
5651
}
5752

5853
public static IsInCaseInsensitive of(Collection<String> values) {

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

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright 2016-2019 the original author or authors.
2+
* Copyright 2016-2020 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,22 +15,21 @@
1515
*/
1616
package org.mybatis.dynamic.sql.where.condition;
1717

18-
import org.mybatis.dynamic.sql.Callback;
19-
import org.mybatis.dynamic.sql.util.StringUtilities;
20-
2118
import java.util.Collection;
2219
import java.util.Objects;
2320
import java.util.function.UnaryOperator;
2421
import java.util.stream.Stream;
22+
import org.mybatis.dynamic.sql.Callback;
23+
import org.mybatis.dynamic.sql.util.StringUtilities;
2524

2625
public class IsInCaseInsensitiveWhenPresent extends IsInCaseInsensitive {
2726

2827
protected IsInCaseInsensitiveWhenPresent(Collection<String> values) {
2928
super(values, s -> s.filter(Objects::nonNull).map(StringUtilities::safelyUpperCase));
3029
}
3130

32-
protected IsInCaseInsensitiveWhenPresent(Collection<String> values, UnaryOperator<Stream<String>> valueStreamTransformer,
33-
Callback callback) {
31+
protected IsInCaseInsensitiveWhenPresent(Collection<String> values,
32+
UnaryOperator<Stream<String>> valueStreamTransformer, Callback callback) {
3433
super(values, valueStreamTransformer, callback);
3534
}
3635

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

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,20 @@
2323
import java.util.stream.Stream;
2424

2525
import org.mybatis.dynamic.sql.AbstractListValueCondition;
26+
import org.mybatis.dynamic.sql.Callback;
2627

27-
public class IsNotIn<T> extends AbstractListValueCondition<T> {
28+
public class IsNotIn<T> extends AbstractListValueCondition<T, IsNotIn<T>> {
29+
30+
protected IsNotIn(Collection<T> values) {
31+
super(values);
32+
}
2833

2934
protected IsNotIn(Collection<T> values, UnaryOperator<Stream<T>> valueStreamTransformer) {
3035
super(values, valueStreamTransformer);
3136
}
3237

33-
protected IsNotIn(Collection<T> values) {
34-
super(values);
38+
protected IsNotIn(Collection<T> values, UnaryOperator<Stream<T>> valueStreamTransformer, Callback emptyCallback) {
39+
super(values, valueStreamTransformer, emptyCallback);
3540
}
3641

3742
@Override
@@ -41,6 +46,11 @@ public String renderCondition(String columnName, Stream<String> placeholders) {
4146
Collectors.joining(",", "not in (", ")")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
4247
}
4348

49+
@Override
50+
public IsNotIn<T> withListEmptyCallback(Callback callback) {
51+
return new IsNotIn<>(values, valueStreamTransformer, callback);
52+
}
53+
4454
/**
4555
* This method allows you to modify the condition's values before they are placed into the parameter map.
4656
* For example, you could filter nulls, or trim strings, etc. This process will run before final rendering of SQL.
@@ -52,9 +62,7 @@ public String renderCondition(String columnName, Stream<String> placeholders) {
5262
* @return new condition with the specified transformer
5363
*/
5464
public IsNotIn<T> then(UnaryOperator<Stream<T>> valueStreamTransformer) {
55-
IsNotIn<T> answer = new IsNotIn<>(values, valueStreamTransformer);
56-
answer.renderWhenEmpty = renderWhenEmpty;
57-
return answer;
65+
return new IsNotIn<>(values, valueStreamTransformer, emptyCallback);
5866
}
5967

6068
public static <T> IsNotIn<T> of(Collection<T> values) {

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

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,22 @@
2121
import java.util.stream.Stream;
2222

2323
import org.mybatis.dynamic.sql.AbstractListValueCondition;
24+
import org.mybatis.dynamic.sql.Callback;
2425
import org.mybatis.dynamic.sql.util.StringUtilities;
2526

26-
public class IsNotInCaseInsensitive extends AbstractListValueCondition<String> {
27+
public class IsNotInCaseInsensitive extends AbstractListValueCondition<String, IsNotInCaseInsensitive> {
2728

2829
protected IsNotInCaseInsensitive(Collection<String> values) {
2930
super(values, s -> s.map(StringUtilities::safelyUpperCase));
3031
}
3132

3233
protected IsNotInCaseInsensitive(Collection<String> values, UnaryOperator<Stream<String>> valueStreamTransformer) {
33-
super(values, StringUtilities.upperCaseAfter(valueStreamTransformer));
34+
super(values, valueStreamTransformer);
35+
}
36+
37+
protected IsNotInCaseInsensitive(Collection<String> values, UnaryOperator<Stream<String>> valueStreamTransformer,
38+
Callback emptyCallback) {
39+
super(values, valueStreamTransformer, emptyCallback);
3440
}
3541

3642
@Override
@@ -40,20 +46,9 @@ public String renderCondition(String columnName, Stream<String> placeholders) {
4046
Collectors.joining(",", "not in (", ")")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
4147
}
4248

43-
/**
44-
* This method allows you to modify the condition's values before they are placed into the parameter map.
45-
* For example, you could filter nulls, or trim strings, etc. This process will run before final rendering of SQL.
46-
* If you filter values out of the stream, then final condition will not reference those values. If you filter all
47-
* values out of the stream, then the condition will not render.
48-
*
49-
* @param valueStreamTransformer a UnaryOperator that will transform the value stream before
50-
* the values are placed in the parameter map
51-
* @return new condition with the specified transformer
52-
*/
53-
public IsNotInCaseInsensitive then(UnaryOperator<Stream<String>> valueStreamTransformer) {
54-
IsNotInCaseInsensitive answer = new IsNotInCaseInsensitive(values, valueStreamTransformer);
55-
answer.renderWhenEmpty = renderWhenEmpty;
56-
return answer;
49+
@Override
50+
public IsNotInCaseInsensitive withListEmptyCallback(Callback callback) {
51+
return new IsNotInCaseInsensitive(values, valueStreamTransformer, callback);
5752
}
5853

5954
public static IsNotInCaseInsensitive of(Collection<String> values) {

0 commit comments

Comments
 (0)