Skip to content

Commit 2f1d1a8

Browse files
authored
Merge pull request #331 from jeffgbutler/filter-and-map
Refactor the Built-In Conditions
2 parents cb4d3ae + 13a34f9 commit 2f1d1a8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+2295
-1286
lines changed

CHANGELOG.md

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,53 @@ The major themes of this release include the following:
1313
1. Add support for subqueries in select statements - both in a from clause and a join clause.
1414
1. Add support for the "exists" and "not exists" operator. This will work in "where" clauses anywhere
1515
they are supported.
16+
1. Refactor and improve the built-in conditions for consistency (see below)
1617
1. Continue to refine the Kotlin DSL. Most changes to the Kotlin DSL are internal and should be source code
1718
compatible with existing code. There is one breaking change detailed below.
1819
1. Remove deprecated code from prior releases.
1920

21+
### Built-In Condition Refactoring
22+
All built-in conditions have been rafactored. The changes should have no impact for the vast majority of users.
23+
However, there are some changes in behavior and one breaking change.
24+
25+
1. Internally, the conditions no longer hold value Suppliers, they now hold the values themselves. The SqlBuilder
26+
methods that accept Suppliers will call the `Supplier.get()` method when the condition is constructed. This should
27+
have no impact unless you were somehow relying on the delay in obtaining a value until the condition was rendered.
28+
1. The existing "then" and "when" methods have been deprecated and replaced with "map" and "filter" respectively.
29+
The new method names are more familiar and more representative of what these methods actually do. In effect,
30+
these methods mimic the function of the "map" and "filter" methods on "java.util.Optional" and they are used
31+
for a similar purpose.
32+
1. The new "filter" method works a bit differently than the "when" method it replaces. The "when" method could not
33+
be chained - if it was called multiple times, only the last call would take effect. The new "filter" methods works
34+
as it should and every call will take effect.
35+
1. All the "WhenPresent" conditions have been removed as separate classes. The methods that produced these conditions
36+
in the SqlBuilder remain, and they will now produce a condition with a "NotNull" filter applied. So at the API level,
37+
things will function exactly as before, but the intermediate classes will be different.
38+
1. One breaking change is that the builder for List value conditions has been removed without replacement. If you
39+
were using this builder to supply a "value stream transformer", then the replacement is to build a new List value
40+
condition and then call the "map" and "filter" methods as needed. For example, prior code looked like this
41+
42+
```java
43+
public static IsIn<String> isIn(String...values) {
44+
return new IsIn.Builder<String>()
45+
.withValues(Arrays.asList(values))
46+
.withValueStreamTransformer(s -> s.filter(Objects::nonNull)
47+
.map(String::trim)
48+
.filter(st -> !st.isEmpty()))
49+
.build();
50+
}
51+
```
52+
New code should look like this:
53+
```java
54+
public static IsIn<String> isIn(String...values) {
55+
return SqlBuilder.isIn(values)
56+
.filter(Objects::nonNull)
57+
.map(String::trim)
58+
.filter(st -> !st.isEmpty());
59+
}
60+
```
61+
We think this is a marked improvement!
62+
2063
### Breaking Change for Kotlin
2164

2265
In this release the Kotlin support for `select` and `count` statements has been refactored. This will not impact code
@@ -50,7 +93,7 @@ Kotlin DSL.
5093
- Added Kotlin DSL updates to support sub-queries in select statements, where clauses, and insert statements ([#282](https://github.com/mybatis/mybatis-dynamic-sql/pull/282))
5194
- Added subquery support for "join" clauses in a select statement ([#293](https://github.com/mybatis/mybatis-dynamic-sql/pull/293))
5295
- Added support for the "exists" and "not exists" operator in where clauses ([#296](https://github.com/mybatis/mybatis-dynamic-sql/pull/296))
53-
96+
- Refactored the built-in conditions ([#331](https://github.com/mybatis/mybatis-dynamic-sql/pull/331))
5497

5598
## Release 1.2.1 - September 29, 2020
5699

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@ For example, a typical search can be coded with a query like this (the following
2323
select(Customer.id, Customer.firstName, Customer.lastName) {
2424
from(Customer)
2525
where(Customer.active, isEqualTo(true))
26-
and(Customer.id, isEqualToWhenPresent(id).then{ it?.padStart(5, '0') })
26+
and(Customer.id, isEqualToWhenPresent(id).map{ it?.padStart(5, '0') })
2727
and(Customer.firstName, isLikeCaseInsensitiveWhenPresent(firstName)
28-
.then{ "%" + it.trim() + "%" })
28+
.map{ "%" + it.trim() + "%" })
2929
and(Customer.lastName, isLikeCaseInsensitiveWhenPresent(lastName)
30-
.then{ "%" + it.trim() + "%" })
30+
.map{ "%" + it.trim() + "%" })
3131
orderBy(Customer.lastName, Customer.firstName)
3232
limit(500)
3333
}
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/AbstractNoValueCondition.java

Lines changed: 1 addition & 19 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,26 +15,8 @@
1515
*/
1616
package org.mybatis.dynamic.sql;
1717

18-
import java.util.Objects;
19-
import java.util.function.BooleanSupplier;
20-
2118
public abstract class AbstractNoValueCondition<T> implements VisitableCondition<T> {
2219

23-
private final BooleanSupplier booleanSupplier;
24-
25-
protected AbstractNoValueCondition() {
26-
booleanSupplier = () -> true;
27-
}
28-
29-
protected AbstractNoValueCondition(BooleanSupplier booleanSupplier) {
30-
this.booleanSupplier = Objects.requireNonNull(booleanSupplier);
31-
}
32-
33-
@Override
34-
public boolean shouldRender() {
35-
return booleanSupplier.getAsBoolean();
36-
}
37-
3820
@Override
3921
public <R> R accept(ConditionVisitor<T, R> visitor) {
4022
return visitor.visit(this);

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

Lines changed: 5 additions & 21 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,31 +15,15 @@
1515
*/
1616
package org.mybatis.dynamic.sql;
1717

18-
import java.util.Objects;
19-
import java.util.function.Predicate;
20-
import java.util.function.Supplier;
21-
2218
public abstract class AbstractSingleValueCondition<T> implements VisitableCondition<T> {
23-
protected final Supplier<T> valueSupplier;
24-
private final Predicate<T> predicate;
25-
26-
protected AbstractSingleValueCondition(Supplier<T> valueSupplier) {
27-
this.valueSupplier = Objects.requireNonNull(valueSupplier);
28-
predicate = v -> true;
29-
}
19+
protected final T value;
3020

31-
protected AbstractSingleValueCondition(Supplier<T> valueSupplier, Predicate<T> predicate) {
32-
this.valueSupplier = Objects.requireNonNull(valueSupplier);
33-
this.predicate = Objects.requireNonNull(predicate);
21+
protected AbstractSingleValueCondition(T value) {
22+
this.value = value;
3423
}
3524

3625
public T value() {
37-
return valueSupplier.get();
38-
}
39-
40-
@Override
41-
public boolean shouldRender() {
42-
return predicate.test(value());
26+
return value;
4327
}
4428

4529
@Override

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

Lines changed: 8 additions & 26 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,39 +15,21 @@
1515
*/
1616
package org.mybatis.dynamic.sql;
1717

18-
import java.util.Objects;
19-
import java.util.function.BiPredicate;
20-
import java.util.function.Supplier;
21-
2218
public abstract class AbstractTwoValueCondition<T> implements VisitableCondition<T> {
23-
protected final Supplier<T> valueSupplier1;
24-
protected final Supplier<T> valueSupplier2;
25-
private final BiPredicate<T, T> predicate;
26-
27-
protected AbstractTwoValueCondition(Supplier<T> valueSupplier1, Supplier<T> valueSupplier2) {
28-
this.valueSupplier1 = Objects.requireNonNull(valueSupplier1);
29-
this.valueSupplier2 = Objects.requireNonNull(valueSupplier2);
30-
predicate = (v1, v2) -> true;
31-
}
19+
protected final T value1;
20+
protected final T value2;
3221

33-
protected AbstractTwoValueCondition(Supplier<T> valueSupplier1, Supplier<T> valueSupplier2,
34-
BiPredicate<T, T> predicate) {
35-
this.valueSupplier1 = Objects.requireNonNull(valueSupplier1);
36-
this.valueSupplier2 = Objects.requireNonNull(valueSupplier2);
37-
this.predicate = Objects.requireNonNull(predicate);
22+
protected AbstractTwoValueCondition(T value1, T value2) {
23+
this.value1 = value1;
24+
this.value2 = value2;
3825
}
3926

4027
public T value1() {
41-
return valueSupplier1.get();
28+
return value1;
4229
}
4330

4431
public T value2() {
45-
return valueSupplier2.get();
46-
}
47-
48-
@Override
49-
public boolean shouldRender() {
50-
return predicate.test(value1(), value2());
32+
return value2;
5133
}
5234

5335
@Override

0 commit comments

Comments
 (0)