Skip to content

Commit 90cd2cc

Browse files
committed
Use late initialization for where builders
This solves a corner case for configuration when a where() method is called, but no criteria are added
1 parent ebfa8b2 commit 90cd2cc

File tree

6 files changed

+218
-32
lines changed

6 files changed

+218
-32
lines changed

src/main/java/org/mybatis/dynamic/sql/delete/DeleteDSL.java

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,18 +31,20 @@ public class DeleteDSL<R> extends AbstractWhereSupport<DeleteDSL<R>.DeleteWhereB
3131
private final Function<DeleteModel, R> adapterFunction;
3232
private final SqlTable table;
3333
private final String tableAlias;
34-
private final DeleteWhereBuilder whereBuilder;
34+
private DeleteWhereBuilder whereBuilder;
3535
private final StatementConfiguration statementConfiguration = new StatementConfiguration();
3636

3737
private DeleteDSL(SqlTable table, String tableAlias, Function<DeleteModel, R> adapterFunction) {
3838
this.table = Objects.requireNonNull(table);
3939
this.tableAlias = tableAlias;
4040
this.adapterFunction = Objects.requireNonNull(adapterFunction);
41-
whereBuilder = new DeleteWhereBuilder();
4241
}
4342

4443
@Override
4544
public DeleteWhereBuilder where() {
45+
if (whereBuilder == null) {
46+
whereBuilder = new DeleteWhereBuilder();
47+
}
4648
return whereBuilder;
4749
}
4850

@@ -55,11 +57,13 @@ public DeleteWhereBuilder where() {
5557
@NotNull
5658
@Override
5759
public R build() {
58-
DeleteModel deleteModel = DeleteModel.withTable(table)
59-
.withTableAlias(tableAlias)
60-
.withWhereModel(whereBuilder.buildWhereModel())
61-
.build();
62-
return adapterFunction.apply(deleteModel);
60+
DeleteModel.Builder deleteModelBuilder = DeleteModel.withTable(table)
61+
.withTableAlias(tableAlias);
62+
if (whereBuilder != null) {
63+
deleteModelBuilder.withWhereModel(whereBuilder.buildWhereModel());
64+
}
65+
66+
return adapterFunction.apply(deleteModelBuilder.build());
6367
}
6468

6569
public static <R> DeleteDSL<R> deleteFrom(Function<DeleteModel, R> adapterFunction, SqlTable table,

src/main/java/org/mybatis/dynamic/sql/select/CountDSL.java

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,19 +40,21 @@ public class CountDSL<R> extends AbstractQueryExpressionDSL<CountDSL<R>.CountWhe
4040
implements Buildable<R> {
4141

4242
private final Function<SelectModel, R> adapterFunction;
43-
private final CountWhereBuilder whereBuilder;
43+
private CountWhereBuilder whereBuilder;
4444
private final BasicColumn countColumn;
4545
private final StatementConfiguration statementConfiguration = new StatementConfiguration();
4646

4747
private CountDSL(BasicColumn countColumn, SqlTable table, Function<SelectModel, R> adapterFunction) {
4848
super(table);
4949
this.countColumn = Objects.requireNonNull(countColumn);
5050
this.adapterFunction = Objects.requireNonNull(adapterFunction);
51-
whereBuilder = new CountWhereBuilder(statementConfiguration);
5251
}
5352

5453
@Override
5554
public CountWhereBuilder where() {
55+
if (whereBuilder == null) {
56+
whereBuilder = new CountWhereBuilder();
57+
}
5658
return whereBuilder;
5759
}
5860

@@ -66,8 +68,11 @@ private SelectModel buildModel() {
6668
QueryExpressionModel.Builder b = new QueryExpressionModel.Builder()
6769
.withSelectColumn(countColumn)
6870
.withTable(table())
69-
.withTableAliases(tableAliases())
70-
.withWhereModel(whereBuilder.buildWhereModel());
71+
.withTableAliases(tableAliases());
72+
73+
if (whereBuilder != null){
74+
b.withWhereModel(whereBuilder.buildWhereModel());
75+
}
7176

7277
buildJoinModel().ifPresent(b::withJoinModel);
7378

@@ -121,7 +126,7 @@ public CountDSL<R> from(SqlTable table) {
121126

122127
public class CountWhereBuilder extends AbstractWhereDSL<CountWhereBuilder>
123128
implements Buildable<R> {
124-
private CountWhereBuilder(StatementConfiguration statementConfiguration) {
129+
private CountWhereBuilder() {
125130
super(statementConfiguration);
126131
}
127132

src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionDSL.java

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public class QueryExpressionDSL<R>
4646
private final SelectDSL<R> selectDSL;
4747
private final boolean isDistinct;
4848
private final List<BasicColumn> selectList;
49-
private final QueryExpressionWhereBuilder whereBuilder;
49+
private QueryExpressionWhereBuilder whereBuilder;
5050
private GroupByModel groupByModel;
5151
private final StatementConfiguration statementConfiguration = new StatementConfiguration();
5252

@@ -56,7 +56,6 @@ public class QueryExpressionDSL<R>
5656
selectList = fromGatherer.selectList;
5757
isDistinct = fromGatherer.isDistinct;
5858
selectDSL = Objects.requireNonNull(fromGatherer.selectDSL);
59-
whereBuilder = new QueryExpressionWhereBuilder(statementConfiguration);
6059
}
6160

6261
QueryExpressionDSL(FromGatherer<R> fromGatherer, SqlTable table, String tableAlias) {
@@ -66,6 +65,9 @@ public class QueryExpressionDSL<R>
6665

6766
@Override
6867
public QueryExpressionWhereBuilder where() {
68+
if (whereBuilder == null) {
69+
whereBuilder = new QueryExpressionWhereBuilder();
70+
}
6971
return whereBuilder;
7072
}
7173

@@ -160,15 +162,19 @@ public UnionBuilder unionAll() {
160162
}
161163

162164
protected QueryExpressionModel buildModel() {
163-
return QueryExpressionModel.withSelectList(selectList)
165+
QueryExpressionModel.Builder builder = QueryExpressionModel.withSelectList(selectList)
164166
.withConnector(connector)
165167
.withTable(table())
166168
.isDistinct(isDistinct)
167169
.withTableAliases(tableAliases())
168-
.withWhereModel(whereBuilder.buildWhereModel())
169170
.withJoinModel(buildJoinModel().orElse(null))
170-
.withGroupByModel(groupByModel)
171-
.build();
171+
.withGroupByModel(groupByModel);
172+
173+
if (whereBuilder != null) {
174+
builder.withWhereModel(whereBuilder.buildWhereModel());
175+
}
176+
177+
return builder.build();
172178
}
173179

174180
public SelectDSL<R>.LimitFinisher limit(long limit) {
@@ -251,7 +257,7 @@ public FromGatherer<R> build() {
251257

252258
public class QueryExpressionWhereBuilder extends AbstractWhereDSL<QueryExpressionWhereBuilder>
253259
implements Buildable<R> {
254-
private QueryExpressionWhereBuilder(StatementConfiguration statementConfiguration) {
260+
private QueryExpressionWhereBuilder() {
255261
super(statementConfiguration);
256262
}
257263

src/main/java/org/mybatis/dynamic/sql/update/UpdateDSL.java

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,13 @@ public class UpdateDSL<R> extends AbstractWhereSupport<UpdateDSL<R>.UpdateWhereB
4747
private final List<AbstractColumnMapping> columnMappings = new ArrayList<>();
4848
private final SqlTable table;
4949
private final String tableAlias;
50-
private final UpdateWhereBuilder whereBuilder;
50+
private UpdateWhereBuilder whereBuilder;
5151
private final StatementConfiguration statementConfiguration = new StatementConfiguration();
5252

5353
private UpdateDSL(SqlTable table, String tableAlias, Function<UpdateModel, R> adapterFunction) {
5454
this.table = Objects.requireNonNull(table);
5555
this.tableAlias = tableAlias;
5656
this.adapterFunction = Objects.requireNonNull(adapterFunction);
57-
whereBuilder = new UpdateWhereBuilder(statementConfiguration);
5857
}
5958

6059
public <T> SetClauseFinisher<T> set(SqlColumn<T> column) {
@@ -63,6 +62,10 @@ public <T> SetClauseFinisher<T> set(SqlColumn<T> column) {
6362

6463
@Override
6564
public UpdateWhereBuilder where() {
65+
if (whereBuilder == null) {
66+
whereBuilder = new UpdateWhereBuilder();
67+
}
68+
6669
return whereBuilder;
6770
}
6871

@@ -75,12 +78,15 @@ public UpdateWhereBuilder where() {
7578
@NotNull
7679
@Override
7780
public R build() {
78-
UpdateModel updateModel = UpdateModel.withTable(table)
81+
UpdateModel.Builder updateModelBuilder = UpdateModel.withTable(table)
7982
.withTableAlias(tableAlias)
80-
.withColumnMappings(columnMappings)
81-
.withWhereModel(whereBuilder.buildWhereModel())
82-
.build();
83-
return adapterFunction.apply(updateModel);
83+
.withColumnMappings(columnMappings);
84+
85+
if (whereBuilder != null) {
86+
updateModelBuilder.withWhereModel(whereBuilder.buildWhereModel());
87+
}
88+
89+
return adapterFunction.apply(updateModelBuilder.build());
8490
}
8591

8692
public static <R> UpdateDSL<R> update(Function<UpdateModel, R> adapterFunction, SqlTable table, String tableAlias) {
@@ -158,7 +164,7 @@ public UpdateDSL<R> equalToWhenPresent(Supplier<T> valueSupplier) {
158164

159165
public class UpdateWhereBuilder extends AbstractWhereDSL<UpdateWhereBuilder> implements Buildable<R> {
160166

161-
private UpdateWhereBuilder(StatementConfiguration statementConfiguration) {
167+
private UpdateWhereBuilder() {
162168
super(statementConfiguration);
163169
}
164170

src/main/java/org/mybatis/dynamic/sql/where/WhereModel.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,6 @@ public List<AndOrCriteriaGroup> subCriteria() {
5555
}
5656

5757
public boolean isUnrenderableClauseAllowed() {
58-
// if no criteria were specified, then no where clause was expected
59-
if (initialCriterion == null && subCriteria.isEmpty()) {
60-
return true;
61-
}
62-
6358
return statementConfiguration.getUnrenderableWhereClauseAllowed();
6459
}
6560

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
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;
17+
18+
import static examples.complexquery.PersonDynamicSqlSupport.firstName;
19+
import static examples.complexquery.PersonDynamicSqlSupport.id;
20+
import static examples.complexquery.PersonDynamicSqlSupport.lastName;
21+
import static examples.complexquery.PersonDynamicSqlSupport.person;
22+
import static org.assertj.core.api.Assertions.assertThat;
23+
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
24+
import static org.mybatis.dynamic.sql.SqlBuilder.countFrom;
25+
import static org.mybatis.dynamic.sql.SqlBuilder.deleteFrom;
26+
import static org.mybatis.dynamic.sql.SqlBuilder.select;
27+
import static org.mybatis.dynamic.sql.SqlBuilder.update;
28+
29+
import org.junit.jupiter.api.Test;
30+
import org.mybatis.dynamic.sql.delete.render.DeleteStatementProvider;
31+
import org.mybatis.dynamic.sql.exception.UnrenderableWhereClauseException;
32+
import org.mybatis.dynamic.sql.render.RenderingStrategies;
33+
import org.mybatis.dynamic.sql.select.render.SelectStatementProvider;
34+
import org.mybatis.dynamic.sql.update.render.UpdateStatementProvider;
35+
36+
public class StatementConfigurationTest {
37+
@Test
38+
void testCountWhereCalledButNoCriteriaThrowsException() {
39+
assertThatExceptionOfType(UnrenderableWhereClauseException.class).isThrownBy(() ->
40+
countFrom(person)
41+
.where()
42+
.build()
43+
.render(RenderingStrategies.MYBATIS3)
44+
);
45+
}
46+
47+
@Test
48+
void testCountWhereCalledButNoCriteriaRequiresConfiguration() {
49+
SelectStatementProvider selectStatement = countFrom(person)
50+
.where()
51+
.configureStatement(c -> c.setUnrenderableWhereClauseAllowed(true))
52+
.build()
53+
.render(RenderingStrategies.MYBATIS3);
54+
55+
assertThat(selectStatement.getSelectStatement())
56+
.isEqualTo("select count(*) from Person");
57+
}
58+
59+
@Test
60+
void testCountWhereNotCalledIsOK() {
61+
SelectStatementProvider selectStatement = countFrom(person)
62+
.build()
63+
.render(RenderingStrategies.MYBATIS3);
64+
65+
assertThat(selectStatement.getSelectStatement())
66+
.isEqualTo("select count(*) from Person");
67+
}
68+
69+
@Test
70+
void testDeleteWhereCalledButNoCriteriaThrowsException() {
71+
assertThatExceptionOfType(UnrenderableWhereClauseException.class).isThrownBy(() ->
72+
deleteFrom(person)
73+
.where()
74+
.build()
75+
.render(RenderingStrategies.MYBATIS3)
76+
);
77+
}
78+
79+
@Test
80+
void testDeleteWhereCalledButNoCriteriaRequiresConfiguration() {
81+
DeleteStatementProvider deleteStatement = deleteFrom(person)
82+
.where()
83+
.configureStatement(c -> c.setUnrenderableWhereClauseAllowed(true))
84+
.build()
85+
.render(RenderingStrategies.MYBATIS3);
86+
87+
assertThat(deleteStatement.getDeleteStatement())
88+
.isEqualTo("delete from Person");
89+
}
90+
91+
@Test
92+
void testDeleteWhereNotCalledIsOK() {
93+
DeleteStatementProvider deleteStatement = deleteFrom(person)
94+
.build()
95+
.render(RenderingStrategies.MYBATIS3);
96+
97+
assertThat(deleteStatement.getDeleteStatement())
98+
.isEqualTo("delete from Person");
99+
}
100+
101+
@Test
102+
void testSelectWhereCalledButNoCriteriaThrowsException() {
103+
assertThatExceptionOfType(UnrenderableWhereClauseException.class).isThrownBy(() ->
104+
select(id, firstName, lastName)
105+
.from(person)
106+
.where()
107+
.build()
108+
.render(RenderingStrategies.MYBATIS3)
109+
);
110+
}
111+
112+
@Test
113+
void testSelectWhereCalledButNoCriteriaRequiresConfiguration() {
114+
SelectStatementProvider selectStatement = select(id, firstName, lastName)
115+
.from(person)
116+
.where()
117+
.configureStatement(c -> c.setUnrenderableWhereClauseAllowed(true))
118+
.build()
119+
.render(RenderingStrategies.MYBATIS3);
120+
121+
assertThat(selectStatement.getSelectStatement())
122+
.isEqualTo("select person_id, first_name, last_name from Person");
123+
}
124+
125+
@Test
126+
void testSelectWhereNotCalledIsOK() {
127+
SelectStatementProvider selectStatement = select(id, firstName, lastName)
128+
.from(person)
129+
.build()
130+
.render(RenderingStrategies.MYBATIS3);
131+
132+
assertThat(selectStatement.getSelectStatement())
133+
.isEqualTo("select person_id, first_name, last_name from Person");
134+
}
135+
136+
@Test
137+
void testUpdateWhereCalledButNoCriteriaThrowsException() {
138+
assertThatExceptionOfType(UnrenderableWhereClauseException.class).isThrownBy(() ->
139+
update(person)
140+
.set(id).equalTo(1)
141+
.where()
142+
.build()
143+
.render(RenderingStrategies.MYBATIS3)
144+
);
145+
}
146+
147+
@Test
148+
void testUpdateWhereCalledButNoCriteriaRequiresConfiguration() {
149+
UpdateStatementProvider updateStatement = update(person)
150+
.set(id).equalTo(1)
151+
.where()
152+
.configureStatement(c -> c.setUnrenderableWhereClauseAllowed(true))
153+
.build()
154+
.render(RenderingStrategies.MYBATIS3);
155+
156+
assertThat(updateStatement.getUpdateStatement())
157+
.isEqualTo("update Person set person_id = #{parameters.p1}");
158+
}
159+
160+
@Test
161+
void testUpdateWhereNotCalledIsOK() {
162+
UpdateStatementProvider updateStatement = update(person)
163+
.set(id).equalTo(1)
164+
.build()
165+
.render(RenderingStrategies.MYBATIS3);
166+
167+
assertThat(updateStatement.getUpdateStatement())
168+
.isEqualTo("update Person set person_id = #{parameters.p1}");
169+
}
170+
}

0 commit comments

Comments
 (0)