Skip to content

Commit 57762ca

Browse files
authored
Merge 96a1b72 into cf62191
2 parents cf62191 + 96a1b72 commit 57762ca

File tree

21 files changed

+2377
-235
lines changed

21 files changed

+2377
-235
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,15 @@ GitHub milestone: [https://github.com/mybatis/mybatis-dynamic-sql/issues?q=miles
1818
`where (a < 5 and B = 3) and (not (C = 4 or D = 5) and E = 6)`. With this enhancement (and the enhancement for
1919
arbitrary grouping) it should now be possible to write virtually any where clause imaginable.
2020
([#438](https://github.com/mybatis/mybatis-dynamic-sql/pull/438))
21+
4. Major update to the Kotlin where clause DSL. Where clauses now support the "group" and "not" features from above. In
22+
addition, the where clause DSL has been fully updated to make it feel more like natural SQL. The previous version
23+
of the where clause DSL yielded almost unreadable code when the "group" and "not" functions were added. This update
24+
is better all around and yields a DSL that is very similar to native SQL. The new DSL includes many Kotlin DSL
25+
construction features including infix functions, operator overloads, and functions with receivers. We believe it
26+
will be well worth the effort to migrate to the new DSL. The prior where clause DSL remains in the library for now,
27+
but is deprecated. It will be removed in version 1.5.0 of the library. Documentation for the new DSL is here:
28+
https://github.com/mybatis/mybatis-dynamic-sql/blob/master/src/site/markdown/docs/kotlinWhereClauses.md
29+
([#442](https://github.com/mybatis/mybatis-dynamic-sql/pull/442))
2130

2231
## Release 1.3.1 - December 18, 2021
2332

README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@ For example, a typical search can be coded with a query like this (the following
2222
fun search(id: String?, firstName: String?, lastName: String?) =
2323
select(Customer.id, Customer.firstName, Customer.lastName) {
2424
from(Customer)
25-
where(Customer.active, isEqualTo(true))
26-
and(Customer.id, isEqualToWhenPresent(id).map{ it?.padStart(5, '0') })
27-
and(Customer.firstName, isLikeCaseInsensitiveWhenPresent(firstName)
28-
.map{ "%" + it.trim() + "%" })
29-
and(Customer.lastName, isLikeCaseInsensitiveWhenPresent(lastName)
30-
.map{ "%" + it.trim() + "%" })
25+
where { Customer.active.isTrue() }
26+
and { Customer.id (isEqualToWhenPresent(id).map{ it?.padStart(5, '0') }) }
27+
and { Customer.firstName (isLikeCaseInsensitiveWhenPresent(firstName)
28+
.map{ "%" + it.trim() + "%" }) }
29+
and { Customer.lastName (isLikeCaseInsensitiveWhenPresent(lastName)
30+
.map{ "%" + it.trim() + "%" }) }
3131
orderBy(Customer.lastName, Customer.firstName)
3232
limit(500)
3333
}

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.util.Collections;
2020
import java.util.List;
2121
import java.util.Objects;
22+
import java.util.Optional;
2223

2324
/**
2425
* This class represents a criteria group with either an AND or an OR connector.
@@ -35,16 +36,16 @@ public class AndOrCriteriaGroup {
3536

3637
private AndOrCriteriaGroup(Builder builder) {
3738
connector = Objects.requireNonNull(builder.connector);
38-
initialCriterion = Objects.requireNonNull(builder.initialCriterion);
39+
initialCriterion = builder.initialCriterion;
3940
subCriteria = builder.subCriteria;
4041
}
4142

4243
public String connector() {
4344
return connector;
4445
}
4546

46-
public SqlCriterion initialCriterion() {
47-
return initialCriterion;
47+
public Optional<SqlCriterion> initialCriterion() {
48+
return Optional.ofNullable(initialCriterion);
4849
}
4950

5051
public List<AndOrCriteriaGroup> subCriteria() {

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

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,8 @@ private List<RenderedCriterion> renderSubCriteria(List<AndOrCriteriaGroup> subCr
149149
}
150150

151151
private Optional<RenderedCriterion> renderAndOrCriteriaGroup(AndOrCriteriaGroup criterion) {
152-
return render(criterion.initialCriterion(), criterion.subCriteria(), this::calculateFragment)
152+
return criterion.initialCriterion().map(ic -> render(ic, criterion.subCriteria(), this::calculateFragment))
153+
.orElseGet(() -> render(criterion.subCriteria(), this::calculateFragment))
153154
.map(rc -> rc.withConnector(criterion.connector()));
154155
}
155156

@@ -159,6 +160,18 @@ private Optional<RenderedCriterion> calculateRenderedCriterion(FragmentAndParame
159160
collectSqlFragments(initialCriterion, renderedSubCriteria), fragmentCalculator));
160161
}
161162

163+
private RenderedCriterion calculateRenderedCriterion(FragmentCollector fragmentCollector,
164+
Function<FragmentCollector, String> fragmentCalculator) {
165+
FragmentAndParameters fragmentAndParameters = FragmentAndParameters
166+
.withFragment(fragmentCalculator.apply(fragmentCollector))
167+
.withParameters(fragmentCollector.parameters())
168+
.build();
169+
170+
return new RenderedCriterion.Builder()
171+
.withFragmentAndParameters(fragmentAndParameters)
172+
.build();
173+
}
174+
162175
private Optional<RenderedCriterion> calculateRenderedCriterion(List<RenderedCriterion> renderedSubCriteria,
163176
Function<FragmentCollector, String> fragmentCalculator) {
164177
return collectSqlFragments(renderedSubCriteria).map(fc -> calculateRenderedCriterion(fc, fragmentCalculator));
@@ -180,8 +193,7 @@ private <T> FragmentAndParameters renderCondition(ColumnAndConditionCriterion<T>
180193
* and there may be subcriteria. The collector will contain the initial condition and any rendered subcriteria
181194
* in order.
182195
*
183-
* @param initialCondition - may be null if there is no rendered initial condition (as can be the case of
184-
* optional conditions like isEqualToWhenPresent)
196+
* @param initialCondition - may not be null. If there is no initial condition, then use the other overload
185197
* @param renderedSubCriteria - a list of previously rendered sub criteria. The sub criteria will all
186198
* have connectors (either an AND or an OR)
187199
* @return a fragment collector whose fragments represent the final calculated list of fragments and parameters.
@@ -222,18 +234,6 @@ private Optional<FragmentCollector> collectSqlFragments(List<RenderedCriterion>
222234
return Optional.of(fc);
223235
}
224236

225-
private RenderedCriterion calculateRenderedCriterion(FragmentCollector fragmentCollector,
226-
Function<FragmentCollector, String> fragmentCalculator) {
227-
FragmentAndParameters fragmentAndParameters = FragmentAndParameters
228-
.withFragment(fragmentCalculator.apply(fragmentCollector))
229-
.withParameters(fragmentCollector.parameters())
230-
.build();
231-
232-
return new RenderedCriterion.Builder()
233-
.withFragmentAndParameters(fragmentAndParameters)
234-
.build();
235-
}
236-
237237
private String calculateFragment(FragmentCollector collector) {
238238
if (collector.hasMultipleFragments()) {
239239
return collector.fragments()

src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/CriteriaCollector.kt

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,16 @@ package org.mybatis.dynamic.sql.util.kotlin
1717

1818
import org.mybatis.dynamic.sql.BindableColumn
1919
import org.mybatis.dynamic.sql.ColumnAndConditionCriterion
20-
import org.mybatis.dynamic.sql.CriteriaGroup
2120
import org.mybatis.dynamic.sql.AndOrCriteriaGroup
2221
import org.mybatis.dynamic.sql.ExistsCriterion
2322
import org.mybatis.dynamic.sql.ExistsPredicate
2423
import org.mybatis.dynamic.sql.SqlCriterion
2524
import org.mybatis.dynamic.sql.VisitableCondition
2625

26+
@Deprecated("Deprecated in favor of the new where clause DSL. Please see the documentation for new usage.")
2727
typealias CriteriaReceiver = CriteriaCollector.() -> Unit
2828

29+
@Deprecated("Deprecated in favor of the new where clause DSL. Please see the documentation for new usage.")
2930
@MyBatisDslMarker
3031
class CriteriaCollector {
3132
val criteria = mutableListOf<AndOrCriteriaGroup>()
@@ -40,9 +41,6 @@ class CriteriaCollector {
4041
fun and(existsPredicate: ExistsPredicate, criteriaReceiver: CriteriaReceiver = {}): CriteriaCollector =
4142
addCriteriaGroup("and", buildCriterion(existsPredicate), criteriaReceiver)
4243

43-
fun and(criteriaGroup: CriteriaGroup, criteriaReceiver: CriteriaReceiver): CriteriaCollector =
44-
addCriteriaGroup("and", buildCriterion(criteriaGroup), criteriaReceiver)
45-
4644
fun <T> or(
4745
column: BindableColumn<T>,
4846
condition: VisitableCondition<T>,
@@ -53,9 +51,6 @@ class CriteriaCollector {
5351
fun or(existsPredicate: ExistsPredicate, criteriaReceiver: CriteriaReceiver = {}): CriteriaCollector =
5452
addCriteriaGroup("or", buildCriterion(existsPredicate), criteriaReceiver)
5553

56-
fun or(criteriaGroup: CriteriaGroup, criteriaReceiver: CriteriaReceiver): CriteriaCollector =
57-
addCriteriaGroup("or", buildCriterion(criteriaGroup), criteriaReceiver)
58-
5954
private fun <T> buildCriterion(
6055
column: BindableColumn<T>,
6156
condition: VisitableCondition<T>
@@ -65,9 +60,6 @@ class CriteriaCollector {
6560
private fun buildCriterion(existsPredicate: ExistsPredicate): ExistsCriterion =
6661
ExistsCriterion.Builder().withExistsPredicate(existsPredicate).build()
6762

68-
private fun buildCriterion(criteriaGroup: CriteriaGroup): CriteriaGroup =
69-
CriteriaGroup.Builder().withInitialCriterion(criteriaGroup).build()
70-
7163
private fun addCriteriaGroup(
7264
connector: String,
7365
initialCriterion: SqlCriterion,
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright 2016-2022 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+
package org.mybatis.dynamic.sql.util.kotlin
17+
18+
/**
19+
* This exception is thrown when a where clause contains more than one criterion and there
20+
* is not an "and" or an "or" to connect them.
21+
*
22+
* @since 1.4.0
23+
*/
24+
class DuplicateInitialCriterionException : RuntimeException(
25+
"Setting more than one initial criterion is not allowed. " +
26+
"Additional criteria should be added with \"and\" or \"or\" expression")

0 commit comments

Comments
 (0)