1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.mybatis.dynamic.sql.dsl;
17
18 import java.util.ArrayList;
19 import java.util.Arrays;
20 import java.util.Collection;
21 import java.util.List;
22 import java.util.Objects;
23 import java.util.function.Consumer;
24
25 import org.jspecify.annotations.Nullable;
26 import org.mybatis.dynamic.sql.AndOrCriteriaGroup;
27 import org.mybatis.dynamic.sql.BasicColumn;
28 import org.mybatis.dynamic.sql.NullCriterion;
29 import org.mybatis.dynamic.sql.SortSpecification;
30 import org.mybatis.dynamic.sql.SqlCriterion;
31 import org.mybatis.dynamic.sql.SqlTable;
32 import org.mybatis.dynamic.sql.TableExpression;
33 import org.mybatis.dynamic.sql.common.OrderByModel;
34 import org.mybatis.dynamic.sql.configuration.StatementConfiguration;
35 import org.mybatis.dynamic.sql.select.GroupByModel;
36 import org.mybatis.dynamic.sql.select.HavingApplier;
37 import org.mybatis.dynamic.sql.select.HavingModel;
38 import org.mybatis.dynamic.sql.select.PagingModel;
39 import org.mybatis.dynamic.sql.select.QueryExpressionModel;
40 import org.mybatis.dynamic.sql.select.SelectModel;
41 import org.mybatis.dynamic.sql.select.join.JoinType;
42 import org.mybatis.dynamic.sql.util.Buildable;
43 import org.mybatis.dynamic.sql.util.ConfigurableStatement;
44 import org.mybatis.dynamic.sql.util.Validator;
45 import org.mybatis.dynamic.sql.where.WhereApplier;
46 import org.mybatis.dynamic.sql.where.WhereModel;
47
48 public class SelectDSL implements
49 JoinOperations<SelectDSL.JoinSpecificationFinisher>,
50 WhereOperations<SelectDSL.QueryExpressionWhereBuilder>,
51 OrderByOperations<SelectDSL>,
52 GroupByOperations<SelectDSL>,
53 HavingOperations<SelectDSL.QueryExpressionHavingBuilder>,
54 LimitAndOffsetOperations<SelectDSL, SelectModel>,
55 ForAndWaitOperations<SelectDSL>,
56 ConfigurableStatement<SelectDSL>,
57 Buildable<SelectModel> {
58 private final StatementConfiguration statementConfiguration = new StatementConfiguration();
59 private CurrentQueryValues currentQueryValues = new CurrentQueryValues();
60 private final List<QueryExpressionModel> unionQueries = new ArrayList<>();
61 private @Nullable OrderByModel orderByModel;
62 private final LimitAndOffsetSupport limitAndOffsetSupport = new LimitAndOffsetSupport();
63 private @Nullable String forClause;
64 private @Nullable String waitClause;
65
66 private static class CurrentQueryValues extends AbstractQueryingDSL {
67 QueryExpressionModel.Builder builder = new QueryExpressionModel.Builder();
68 @Nullable QueryExpressionWhereBuilder whereBuilder;
69 @Nullable QueryExpressionHavingBuilder havingBuilder;
70
71 QueryExpressionModel toQueryExpressionModel() {
72 return builder
73 .withTableAliases(tableAliases())
74 .withTable(table())
75 .withJoinModel(buildJoinModel())
76 .withWhereModel(whereBuilder == null ? null : whereBuilder.buildWhereModel())
77 .withHavingModel(havingBuilder == null ? null : havingBuilder.buildHavingModel())
78 .build();
79 }
80 }
81
82 private SelectDSL(Collection<? extends BasicColumn> selectList, boolean isDistinct) {
83 currentQueryValues.builder.withSelectList(selectList);
84 currentQueryValues.builder.isDistinct(isDistinct);
85 }
86
87 public static SelectDSL select(BasicColumn... selectList) {
88 return select(Arrays.asList(selectList));
89 }
90
91 public static SelectDSL select(Collection<? extends BasicColumn> selectList) {
92 return new SelectDSL(selectList, false);
93 }
94
95 public static SelectDSL selectDistinct(BasicColumn... selectList) {
96 return selectDistinct(Arrays.asList(selectList));
97 }
98
99 public static SelectDSL selectDistinct(Collection<? extends BasicColumn> selectList) {
100 return new SelectDSL(selectList, true);
101 }
102
103 public SelectDSL from(Buildable<SelectModel> select) {
104 currentQueryValues.setTable(select);
105 return this;
106 }
107
108 public SelectDSL from(Buildable<SelectModel> select, String tableAlias) {
109 currentQueryValues.setTable(select, tableAlias);
110 return this;
111 }
112
113 public SelectDSL from(SqlTable table) {
114 currentQueryValues.setTable(table);
115 return this;
116 }
117
118 public SelectDSL from(SqlTable table, String tableAlias) {
119 currentQueryValues.setTable(table, tableAlias);
120 return this;
121 }
122
123 @Override
124 public JoinSpecificationFinisher join(JoinType joinType, TableExpression joinTable,
125 SqlCriterion initialCriterion) {
126 JoinSpecificationFinisher finisher = new JoinSpecificationFinisher(joinType, joinTable, initialCriterion);
127 currentQueryValues.addJoinSpecification(finisher);
128 return finisher;
129 }
130
131 @Override
132 public JoinSpecificationFinisher join(JoinType joinType, SqlTable joinTable, String tableAlias,
133 SqlCriterion initialCriterion) {
134 currentQueryValues.addTableAlias(joinTable, tableAlias);
135 return join(joinType, joinTable, initialCriterion);
136 }
137
138 @Override
139 public QueryExpressionWhereBuilder where() {
140 currentQueryValues.whereBuilder = Objects.requireNonNullElseGet(currentQueryValues.whereBuilder,
141 () -> new QueryExpressionWhereBuilder(new NullCriterion()));
142 return currentQueryValues.whereBuilder;
143 }
144
145 @Override
146 public QueryExpressionWhereBuilder where(SqlCriterion initialCriterion) {
147 Validator.assertNull(currentQueryValues.whereBuilder, Validator.ERROR_32);
148 currentQueryValues.whereBuilder = new QueryExpressionWhereBuilder(initialCriterion);
149 return currentQueryValues.whereBuilder;
150 }
151
152 @Override
153 public QueryExpressionWhereBuilder applyWhere(WhereApplier whereApplier) {
154 Validator.assertNull(currentQueryValues.whereBuilder, Validator.ERROR_32);
155 currentQueryValues.whereBuilder =
156 new QueryExpressionWhereBuilder(whereApplier.initialCriterion(), whereApplier.subCriteria());
157 return currentQueryValues.whereBuilder;
158 }
159
160 @Override
161 public SelectDSL orderBy(Collection<? extends SortSpecification> columns) {
162 orderByModel = OrderByModel.of(columns);
163 return this;
164 }
165
166 @Override
167 public SelectDSL groupBy(Collection<? extends BasicColumn> columns) {
168 currentQueryValues.builder.withGroupByModel(GroupByModel.of(columns));
169 return this;
170 }
171
172 @Override
173 public QueryExpressionHavingBuilder having(SqlCriterion initialCriterion) {
174 Validator.assertNull(currentQueryValues.havingBuilder, "ERROR.31");
175 currentQueryValues.havingBuilder = new QueryExpressionHavingBuilder(initialCriterion);
176 return currentQueryValues.havingBuilder;
177 }
178
179 @Override
180 public QueryExpressionHavingBuilder applyHaving(HavingApplier havingApplier) {
181 Validator.assertNull(currentQueryValues.havingBuilder, "ERROR.31");
182 currentQueryValues.havingBuilder =
183 new QueryExpressionHavingBuilder(havingApplier.initialCriterion(), havingApplier.subCriteria());
184 return currentQueryValues.havingBuilder;
185 }
186
187 @Override
188 public LimitFinisher<SelectDSL, SelectModel> limitWhenPresent(@Nullable Long limit) {
189 return limitAndOffsetSupport.limitWhenPresent(limit);
190 }
191
192 @Override
193 public OffsetFirstFinisher<SelectDSL, SelectModel> offsetWhenPresent(@Nullable Long offset) {
194 return limitAndOffsetSupport.offsetWhenPresent(offset);
195 }
196
197 @Override
198 public FetchFirstFinisher<SelectDSL> fetchFirstWhenPresent(@Nullable Long fetchFirstRows) {
199 return limitAndOffsetSupport.fetchFirstWhenPresent(fetchFirstRows);
200 }
201
202 @Override
203 public SelectDSL setWaitClause(String waitClause) {
204 Validator.assertNull(this.waitClause, "ERROR.49");
205 this.waitClause = waitClause;
206 return this;
207 }
208
209 @Override
210 public SelectDSL setForClause(String forClause) {
211 Validator.assertNull(this.forClause, "ERROR.48");
212 this.forClause = forClause;
213 return this;
214 }
215
216 public UnionBuilder union() {
217 return new UnionBuilder("union");
218 }
219
220 public UnionBuilder unionAll() {
221 return new UnionBuilder("union all");
222 }
223
224 @Override
225 public SelectDSL configureStatement(Consumer<StatementConfiguration> consumer) {
226 consumer.accept(statementConfiguration);
227 return this;
228 }
229
230 @Override
231 public SelectModel build() {
232 return new SelectModel.Builder()
233 .withStatementConfiguration(statementConfiguration)
234 .withQueryExpressions(unionQueries)
235 .withQueryExpression(currentQueryValues.toQueryExpressionModel())
236 .withOrderByModel(orderByModel)
237 .withPagingModel(limitAndOffsetSupport.buildPagingModel())
238 .withForClause(forClause)
239 .withWaitClause(waitClause)
240 .build();
241 }
242
243 public class QueryExpressionWhereBuilder implements BooleanOperations<QueryExpressionWhereBuilder>,
244 ConfigurableStatement<QueryExpressionWhereBuilder>,
245 OrderByOperations<SelectDSL>,
246 GroupByOperations<SelectDSL>,
247 LimitAndOffsetOperations<SelectDSL, SelectModel>,
248 ForAndWaitOperations<SelectDSL>,
249 Buildable<SelectModel> {
250 private final SqlCriterion initialCriterion;
251 private final List<AndOrCriteriaGroup> subCriteria = new ArrayList<>();
252
253 public QueryExpressionWhereBuilder(SqlCriterion initialCriterion) {
254 this.initialCriterion = initialCriterion;
255 }
256
257 public QueryExpressionWhereBuilder(SqlCriterion initialCriterion, List<AndOrCriteriaGroup> subCriteria) {
258 this(initialCriterion);
259 this.subCriteria.addAll(subCriteria);
260 }
261
262 @Override
263 public QueryExpressionWhereBuilder addSubCriterion(AndOrCriteriaGroup subCriterion) {
264 subCriteria.add(subCriterion);
265 return this;
266 }
267
268 public UnionBuilder union() {
269 return SelectDSL.this.union();
270 }
271
272 public UnionBuilder unionAll() {
273 return SelectDSL.this.unionAll();
274 }
275
276 @Override
277 public LimitFinisher<SelectDSL, SelectModel> limitWhenPresent(@Nullable Long limit) {
278 return SelectDSL.this.limitWhenPresent(limit);
279 }
280
281 @Override
282 public OffsetFirstFinisher<SelectDSL, SelectModel> offsetWhenPresent(@Nullable Long offset) {
283 return SelectDSL.this.offsetWhenPresent(offset);
284 }
285
286 @Override
287 public FetchFirstFinisher<SelectDSL> fetchFirstWhenPresent(@Nullable Long fetchFirstRows) {
288 return SelectDSL.this.fetchFirstWhenPresent(fetchFirstRows);
289 }
290
291 @Override
292 public SelectDSL orderBy(Collection<? extends SortSpecification> columns) {
293 return SelectDSL.this.orderBy(columns);
294 }
295
296 @Override
297 public SelectDSL groupBy(Collection<? extends BasicColumn> columns) {
298 return SelectDSL.this.groupBy(columns);
299 }
300
301 @Override
302 public SelectModel build() {
303 return SelectDSL.this.build();
304 }
305
306 protected WhereModel buildWhereModel() {
307 return new WhereModel.Builder()
308 .withInitialCriterion(initialCriterion)
309 .withSubCriteria(subCriteria)
310 .build();
311 }
312
313 @Override
314 public QueryExpressionWhereBuilder configureStatement(Consumer<StatementConfiguration> consumer) {
315 SelectDSL.this.configureStatement(consumer);
316 return this;
317 }
318
319 @Override
320 public SelectDSL setWaitClause(String waitClause) {
321 return SelectDSL.this.setWaitClause(waitClause);
322 }
323
324 @Override
325 public SelectDSL setForClause(String forClause) {
326 return SelectDSL.this.setForClause(forClause);
327 }
328 }
329
330 public class JoinSpecificationFinisher
331 extends AbstractJoinSupport<SelectDSL, JoinSpecificationFinisher>
332 implements WhereOperations<QueryExpressionWhereBuilder>,
333 ConfigurableStatement<JoinSpecificationFinisher>,
334 GroupByOperations<SelectDSL>,
335 OrderByOperations<SelectDSL>,
336 LimitAndOffsetOperations<SelectDSL, SelectModel>,
337 ForAndWaitOperations<SelectDSL>,
338 Buildable<SelectModel> {
339
340 protected JoinSpecificationFinisher(JoinType joinType, TableExpression joinTable,
341 SqlCriterion initialCriterion) {
342 super(joinType, joinTable, initialCriterion);
343 }
344
345 @Override
346 public SelectModel build() {
347 return SelectDSL.this.build();
348 }
349
350 @Override
351 public JoinSpecificationFinisher configureStatement(Consumer<StatementConfiguration> consumer) {
352 SelectDSL.this.configureStatement(consumer);
353 return this;
354 }
355
356 @Override
357 public QueryExpressionWhereBuilder where() {
358 return SelectDSL.this.where();
359 }
360
361 @Override
362 public QueryExpressionWhereBuilder where(SqlCriterion initialCriterion) {
363 return SelectDSL.this.where(initialCriterion);
364 }
365
366 @Override
367 public QueryExpressionWhereBuilder applyWhere(WhereApplier whereApplier) {
368 return SelectDSL.this.applyWhere(whereApplier);
369 }
370
371 @Override
372 public SelectDSL groupBy(Collection<? extends BasicColumn> columns) {
373 return SelectDSL.this.groupBy(columns);
374 }
375
376 public UnionBuilder union() {
377 return SelectDSL.this.union();
378 }
379
380 public UnionBuilder unionAll() {
381 return SelectDSL.this.unionAll();
382 }
383
384 @Override
385 public SelectDSL orderBy(Collection<? extends SortSpecification> columns) {
386 return SelectDSL.this.orderBy(columns);
387 }
388
389 @Override
390 protected JoinSpecificationFinisher getThis() {
391 return this;
392 }
393
394 @Override
395 public LimitFinisher<SelectDSL, SelectModel> limitWhenPresent(@Nullable Long limit) {
396 return SelectDSL.this.limitWhenPresent(limit);
397 }
398
399 @Override
400 public OffsetFirstFinisher<SelectDSL, SelectModel> offsetWhenPresent(@Nullable Long offset) {
401 return SelectDSL.this.offsetWhenPresent(offset);
402 }
403
404 @Override
405 public FetchFirstFinisher<SelectDSL> fetchFirstWhenPresent(@Nullable Long fetchFirstRows) {
406 return SelectDSL.this.fetchFirstWhenPresent(fetchFirstRows);
407 }
408
409 @Override
410 public SelectDSL setWaitClause(String waitClause) {
411 return SelectDSL.this.setWaitClause(waitClause);
412 }
413
414 @Override
415 public SelectDSL setForClause(String forClause) {
416 return SelectDSL.this.setForClause(forClause);
417 }
418
419 @Override
420 public JoinSpecificationFinisher join(JoinType joinType, TableExpression joinTable,
421 SqlCriterion initialCriterion) {
422 return SelectDSL.this.join(joinType, joinTable, initialCriterion);
423 }
424
425 @Override
426 public JoinSpecificationFinisher join(JoinType joinType, SqlTable joinTable, String tableAlias,
427 SqlCriterion initialCriterion) {
428 return SelectDSL.this.join(joinType, joinTable, tableAlias, initialCriterion);
429 }
430
431 @Override
432 public SelectDSL endJoin() {
433 return SelectDSL.this;
434 }
435 }
436
437 public class QueryExpressionHavingBuilder
438 implements BooleanOperations<QueryExpressionHavingBuilder>,
439 OrderByOperations<SelectDSL>,
440 LimitAndOffsetOperations<SelectDSL, SelectModel>,
441 ForAndWaitOperations<SelectDSL>,
442 Buildable<SelectModel> {
443 private final SqlCriterion initialCriterion;
444 private final List<AndOrCriteriaGroup> subCriteria = new ArrayList<>();
445
446 public QueryExpressionHavingBuilder(SqlCriterion initialCriterion) {
447 this.initialCriterion = initialCriterion;
448 }
449
450 public QueryExpressionHavingBuilder(SqlCriterion initialCriterion, List<AndOrCriteriaGroup> subCriteria) {
451 this(initialCriterion);
452 this.subCriteria.addAll(subCriteria);
453 }
454
455 @Override
456 public QueryExpressionHavingBuilder addSubCriterion(AndOrCriteriaGroup subCriterion) {
457 subCriteria.add(subCriterion);
458 return this;
459 }
460
461 @Override
462 public SelectDSL orderBy(Collection<? extends SortSpecification> columns) {
463 return SelectDSL.this.orderBy(columns);
464 }
465
466 public UnionBuilder union() {
467 return SelectDSL.this.union();
468 }
469
470 public UnionBuilder unionAll() {
471 return SelectDSL.this.unionAll();
472 }
473
474 @Override
475 public SelectModel build() {
476 return SelectDSL.this.build();
477 }
478
479 protected HavingModel buildHavingModel() {
480 return new HavingModel.Builder()
481 .withInitialCriterion(initialCriterion)
482 .withSubCriteria(subCriteria)
483 .build();
484 }
485
486 @Override
487 public LimitFinisher<SelectDSL, SelectModel> limitWhenPresent(@Nullable Long limit) {
488 return SelectDSL.this.limitWhenPresent(limit);
489 }
490
491 @Override
492 public OffsetFirstFinisher<SelectDSL, SelectModel> offsetWhenPresent(@Nullable Long offset) {
493 return SelectDSL.this.offsetWhenPresent(offset);
494 }
495
496 @Override
497 public FetchFirstFinisher<SelectDSL> fetchFirstWhenPresent(@Nullable Long fetchFirstRows) {
498 return SelectDSL.this.fetchFirstWhenPresent(fetchFirstRows);
499 }
500
501 @Override
502 public SelectDSL setWaitClause(String waitClause) {
503 return SelectDSL.this.setWaitClause(waitClause);
504 }
505
506 @Override
507 public SelectDSL setForClause(String forClause) {
508 return SelectDSL.this.setForClause(forClause);
509 }
510 }
511
512 private class LimitAndOffsetSupport extends AbstractLimitAndOffsetSupport<SelectDSL, SelectModel> {
513 public LimitAndOffsetSupport() {
514 super(SelectDSL.this);
515 }
516
517 protected @Nullable PagingModel buildPagingModel() {
518 return toPagingModel().orElse(null);
519 }
520
521 @Override
522 protected SelectDSL getThis() {
523 return SelectDSL.this;
524 }
525 }
526
527 public class UnionBuilder {
528 protected final String connector;
529
530 public UnionBuilder(String connector) {
531 this.connector = connector;
532 }
533
534 public SelectDSL select(BasicColumn... selectList) {
535 return select(Arrays.asList(selectList));
536 }
537
538 public SelectDSL select(List<BasicColumn> selectList) {
539 unionQueries.add(currentQueryValues.toQueryExpressionModel());
540 currentQueryValues = new CurrentQueryValues();
541 currentQueryValues.builder.withConnector(connector);
542 currentQueryValues.builder.withSelectList(selectList);
543 return SelectDSL.this;
544 }
545
546 public SelectDSL selectDistinct(BasicColumn... selectList) {
547 return selectDistinct(Arrays.asList(selectList));
548 }
549
550 public SelectDSL selectDistinct(List<BasicColumn> selectList) {
551 select(selectList);
552 currentQueryValues.builder.isDistinct(true);
553 return SelectDSL.this;
554 }
555 }
556 }