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