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