View Javadoc
1   /*
2    *    Copyright 2016-2026 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    *       https://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 java.util.Arrays;
19  import java.util.Collection;
20  import java.util.List;
21  import java.util.Objects;
22  import java.util.function.Supplier;
23  
24  import org.jspecify.annotations.Nullable;
25  import org.mybatis.dynamic.sql.delete.DeleteDSL;
26  import org.mybatis.dynamic.sql.delete.DeleteModel;
27  import org.mybatis.dynamic.sql.dsl.HavingDSL;
28  import org.mybatis.dynamic.sql.dsl.WhereDSL;
29  import org.mybatis.dynamic.sql.insert.BatchInsertDSL;
30  import org.mybatis.dynamic.sql.insert.GeneralInsertDSL;
31  import org.mybatis.dynamic.sql.insert.InsertDSL;
32  import org.mybatis.dynamic.sql.insert.InsertSelectDSL;
33  import org.mybatis.dynamic.sql.insert.MultiRowInsertDSL;
34  import org.mybatis.dynamic.sql.select.ColumnSortSpecification;
35  import org.mybatis.dynamic.sql.select.CountDSL;
36  import org.mybatis.dynamic.sql.select.MultiSelectDSL;
37  import org.mybatis.dynamic.sql.select.QueryExpressionDSL;
38  import org.mybatis.dynamic.sql.select.SelectDSL;
39  import org.mybatis.dynamic.sql.select.SelectModel;
40  import org.mybatis.dynamic.sql.select.SimpleSortSpecification;
41  import org.mybatis.dynamic.sql.select.aggregate.Avg;
42  import org.mybatis.dynamic.sql.select.aggregate.Count;
43  import org.mybatis.dynamic.sql.select.aggregate.CountAll;
44  import org.mybatis.dynamic.sql.select.aggregate.CountDistinct;
45  import org.mybatis.dynamic.sql.select.aggregate.Max;
46  import org.mybatis.dynamic.sql.select.aggregate.Min;
47  import org.mybatis.dynamic.sql.select.aggregate.Sum;
48  import org.mybatis.dynamic.sql.select.caseexpression.SearchedCaseDSL;
49  import org.mybatis.dynamic.sql.select.caseexpression.SimpleCaseDSL;
50  import org.mybatis.dynamic.sql.select.function.Add;
51  import org.mybatis.dynamic.sql.select.function.Cast;
52  import org.mybatis.dynamic.sql.select.function.Concat;
53  import org.mybatis.dynamic.sql.select.function.Concatenate;
54  import org.mybatis.dynamic.sql.select.function.Divide;
55  import org.mybatis.dynamic.sql.select.function.Lower;
56  import org.mybatis.dynamic.sql.select.function.Multiply;
57  import org.mybatis.dynamic.sql.select.function.OperatorFunction;
58  import org.mybatis.dynamic.sql.select.function.Substring;
59  import org.mybatis.dynamic.sql.select.function.Subtract;
60  import org.mybatis.dynamic.sql.select.function.Upper;
61  import org.mybatis.dynamic.sql.update.UpdateDSL;
62  import org.mybatis.dynamic.sql.update.UpdateModel;
63  import org.mybatis.dynamic.sql.util.Buildable;
64  import org.mybatis.dynamic.sql.where.condition.IsBetween;
65  import org.mybatis.dynamic.sql.where.condition.IsBetweenWhenPresent;
66  import org.mybatis.dynamic.sql.where.condition.IsEqualTo;
67  import org.mybatis.dynamic.sql.where.condition.IsEqualToColumn;
68  import org.mybatis.dynamic.sql.where.condition.IsEqualToWhenPresent;
69  import org.mybatis.dynamic.sql.where.condition.IsEqualToWithSubselect;
70  import org.mybatis.dynamic.sql.where.condition.IsGreaterThan;
71  import org.mybatis.dynamic.sql.where.condition.IsGreaterThanColumn;
72  import org.mybatis.dynamic.sql.where.condition.IsGreaterThanOrEqualTo;
73  import org.mybatis.dynamic.sql.where.condition.IsGreaterThanOrEqualToColumn;
74  import org.mybatis.dynamic.sql.where.condition.IsGreaterThanOrEqualToWhenPresent;
75  import org.mybatis.dynamic.sql.where.condition.IsGreaterThanOrEqualToWithSubselect;
76  import org.mybatis.dynamic.sql.where.condition.IsGreaterThanWhenPresent;
77  import org.mybatis.dynamic.sql.where.condition.IsGreaterThanWithSubselect;
78  import org.mybatis.dynamic.sql.where.condition.IsIn;
79  import org.mybatis.dynamic.sql.where.condition.IsInCaseInsensitive;
80  import org.mybatis.dynamic.sql.where.condition.IsInCaseInsensitiveWhenPresent;
81  import org.mybatis.dynamic.sql.where.condition.IsInWhenPresent;
82  import org.mybatis.dynamic.sql.where.condition.IsInWithSubselect;
83  import org.mybatis.dynamic.sql.where.condition.IsLessThan;
84  import org.mybatis.dynamic.sql.where.condition.IsLessThanColumn;
85  import org.mybatis.dynamic.sql.where.condition.IsLessThanOrEqualTo;
86  import org.mybatis.dynamic.sql.where.condition.IsLessThanOrEqualToColumn;
87  import org.mybatis.dynamic.sql.where.condition.IsLessThanOrEqualToWhenPresent;
88  import org.mybatis.dynamic.sql.where.condition.IsLessThanOrEqualToWithSubselect;
89  import org.mybatis.dynamic.sql.where.condition.IsLessThanWhenPresent;
90  import org.mybatis.dynamic.sql.where.condition.IsLessThanWithSubselect;
91  import org.mybatis.dynamic.sql.where.condition.IsLike;
92  import org.mybatis.dynamic.sql.where.condition.IsLikeCaseInsensitive;
93  import org.mybatis.dynamic.sql.where.condition.IsLikeCaseInsensitiveWhenPresent;
94  import org.mybatis.dynamic.sql.where.condition.IsLikeWhenPresent;
95  import org.mybatis.dynamic.sql.where.condition.IsNotBetween;
96  import org.mybatis.dynamic.sql.where.condition.IsNotBetweenWhenPresent;
97  import org.mybatis.dynamic.sql.where.condition.IsNotEqualTo;
98  import org.mybatis.dynamic.sql.where.condition.IsNotEqualToColumn;
99  import org.mybatis.dynamic.sql.where.condition.IsNotEqualToWhenPresent;
100 import org.mybatis.dynamic.sql.where.condition.IsNotEqualToWithSubselect;
101 import org.mybatis.dynamic.sql.where.condition.IsNotIn;
102 import org.mybatis.dynamic.sql.where.condition.IsNotInCaseInsensitive;
103 import org.mybatis.dynamic.sql.where.condition.IsNotInCaseInsensitiveWhenPresent;
104 import org.mybatis.dynamic.sql.where.condition.IsNotInWhenPresent;
105 import org.mybatis.dynamic.sql.where.condition.IsNotInWithSubselect;
106 import org.mybatis.dynamic.sql.where.condition.IsNotLike;
107 import org.mybatis.dynamic.sql.where.condition.IsNotLikeCaseInsensitive;
108 import org.mybatis.dynamic.sql.where.condition.IsNotLikeCaseInsensitiveWhenPresent;
109 import org.mybatis.dynamic.sql.where.condition.IsNotLikeWhenPresent;
110 import org.mybatis.dynamic.sql.where.condition.IsNotNull;
111 import org.mybatis.dynamic.sql.where.condition.IsNull;
112 
113 public interface SqlBuilder {
114 
115     // statements
116 
117     /**
118      * Renders as select count(distinct column) from table...
119      *
120      * @param column
121      *            the column to count
122      *
123      * @return the next step in the DSL
124      */
125     static CountDSL<SelectModel> countDistinctColumn(BasicColumn column) {
126         return CountDSL.countDistinct(column);
127     }
128 
129     /**
130      * Renders as select count(column) from table...
131      *
132      * @param column
133      *            the column to count
134      *
135      * @return the next step in the DSL
136      */
137     static CountDSL<SelectModel> countColumn(BasicColumn column) {
138         return CountDSL.count(column);
139     }
140 
141     /**
142      * Renders as select count(*) from table...
143      *
144      * @param table
145      *            the table to count
146      *
147      * @return the next step in the DSL
148      */
149     static CountDSL<SelectModel> countFrom(SqlTable table) {
150         return CountDSL.countFrom(table);
151     }
152 
153     static CountDSL<SelectModel> countFrom(SqlTable table, String tableAlias) {
154         return CountDSL.countFrom(table, tableAlias);
155     }
156 
157     static DeleteDSL<DeleteModel> deleteFrom(SqlTable table) {
158         return DeleteDSL.deleteFrom(table);
159     }
160 
161     static DeleteDSL<DeleteModel> deleteFrom(SqlTable table, String tableAlias) {
162         return DeleteDSL.deleteFrom(table, tableAlias);
163     }
164 
165     static <T> InsertDSL.IntoGatherer<T> insert(T row) {
166         return InsertDSL.insert(row);
167     }
168 
169     /**
170      * Insert a Batch of records. The model object is structured to support bulk inserts with JDBC batch support.
171      *
172      * @param records
173      *            records to insert
174      * @param <T>
175      *            the type of record to insert
176      *
177      * @return the next step in the DSL
178      */
179     @SafeVarargs
180     static <T> BatchInsertDSL.IntoGatherer<T> insertBatch(T... records) {
181         return BatchInsertDSL.insert(records);
182     }
183 
184     /**
185      * Insert a Batch of records. The model object is structured to support bulk inserts with JDBC batch support.
186      *
187      * @param records
188      *            records to insert
189      * @param <T>
190      *            the type of record to insert
191      *
192      * @return the next step in the DSL
193      */
194     static <T> BatchInsertDSL.IntoGatherer<T> insertBatch(Collection<T> records) {
195         return BatchInsertDSL.insert(records);
196     }
197 
198     /**
199      * Insert multiple records in a single statement. The model object is structured as a single insert statement with
200      * multiple values clauses. This statement is suitable for use with a small number of records. It is not suitable
201      * for large bulk inserts as it is possible to exceed the limit of parameter markers in a prepared statement.
202      *
203      * <p>For large bulk inserts, see {@link SqlBuilder#insertBatch(Object[])}
204      * @param records
205      *            records to insert
206      * @param <T>
207      *            the type of record to insert
208      *
209      * @return the next step in the DSL
210      */
211     @SafeVarargs
212     static <T> MultiRowInsertDSL.IntoGatherer<T> insertMultiple(T... records) {
213         return MultiRowInsertDSL.insert(records);
214     }
215 
216     /**
217      * Insert multiple records in a single statement. The model object is structured as a single insert statement with
218      * multiple values clauses. This statement is suitable for use with a small number of records. It is not suitable
219      * for large bulk inserts as it is possible to exceed the limit of parameter markers in a prepared statement.
220      *
221      * <p>For large bulk inserts, see {@link SqlBuilder#insertBatch(Collection)}
222      * @param records
223      *            records to insert
224      * @param <T>
225      *            the type of record to insert
226      *
227      * @return the next step in the DSL
228      */
229     static <T> MultiRowInsertDSL.IntoGatherer<T> insertMultiple(Collection<T> records) {
230         return MultiRowInsertDSL.insert(records);
231     }
232 
233     static InsertIntoNextStep insertInto(SqlTable table) {
234         return new InsertIntoNextStep(table);
235     }
236 
237     static QueryExpressionDSL<SelectModel> select(BasicColumn... selectList) {
238         return select(Arrays.asList(selectList));
239     }
240 
241     static QueryExpressionDSL<SelectModel> select(Collection<? extends BasicColumn> selectList) {
242         return SelectDSL.select(selectList);
243     }
244 
245     static QueryExpressionDSL<SelectModel> selectDistinct(BasicColumn... selectList) {
246         return selectDistinct(Arrays.asList(selectList));
247     }
248 
249     static QueryExpressionDSL<SelectModel> selectDistinct(Collection<? extends BasicColumn> selectList) {
250         return SelectDSL.selectDistinct(selectList);
251     }
252 
253     static MultiSelectDSL multiSelect(Buildable<SelectModel> selectModelBuilder) {
254         return new MultiSelectDSL(selectModelBuilder);
255     }
256 
257     static UpdateDSL<UpdateModel> update(SqlTable table) {
258         return UpdateDSL.update(table);
259     }
260 
261     static UpdateDSL<UpdateModel> update(SqlTable table, String tableAlias) {
262         return UpdateDSL.update(table, tableAlias);
263     }
264 
265     static WhereDSL where() {
266         return new WhereDSL();
267     }
268 
269     static <T> WhereDSL where(BindableColumn<T> column, RenderableCondition<T> condition,
270                               AndOrCriteriaGroup... subCriteria) {
271         ColumnAndConditionCriterion<T> initialCriterion = ColumnAndConditionCriterion.withColumn(column)
272                 .withCondition(condition)
273                 .build();
274 
275         return where(initialCriterion, subCriteria);
276     }
277 
278     static WhereDSL where(SqlCriterion initialCriterion, AndOrCriteriaGroup... subCriteria) {
279         return new WhereDSL(initialCriterion, Arrays.asList(subCriteria));
280     }
281 
282     static WhereDSL where(ExistsPredicate existsPredicate, AndOrCriteriaGroup... subCriteria) {
283         ExistsCriterion existsCriterion = new ExistsCriterion.Builder()
284                 .withExistsPredicate(existsPredicate).build();
285         return where(existsCriterion, subCriteria);
286     }
287 
288     static <T> HavingDSL having(BindableColumn<T> column, RenderableCondition<T> condition,
289                                 AndOrCriteriaGroup... subCriteria) {
290         SqlCriterion initialCriterion = ColumnAndConditionCriterion.withColumn(column).withCondition(condition).build();
291         return having(initialCriterion, subCriteria);
292     }
293 
294     static HavingDSL having(SqlCriterion initialCriterion, AndOrCriteriaGroup... subCriteria) {
295         return new HavingDSL(initialCriterion, Arrays.asList(subCriteria));
296     }
297 
298     // where condition connectors
299     static <T> CriteriaGroup group(BindableColumn<T> column, RenderableCondition<T> condition,
300                                    AndOrCriteriaGroup... subCriteria) {
301         return group(column, condition, Arrays.asList(subCriteria));
302     }
303 
304     static <T> CriteriaGroup group(BindableColumn<T> column, RenderableCondition<T> condition,
305                                    List<AndOrCriteriaGroup> subCriteria) {
306         return new CriteriaGroup.Builder()
307                 .withInitialCriterion(new ColumnAndConditionCriterion.Builder<T>().withColumn(column)
308                         .withCondition(condition).build())
309                 .withSubCriteria(subCriteria)
310                 .build();
311     }
312 
313     static CriteriaGroup group(ExistsPredicate existsPredicate, AndOrCriteriaGroup... subCriteria) {
314         return group(existsPredicate, Arrays.asList(subCriteria));
315     }
316 
317     static CriteriaGroup group(ExistsPredicate existsPredicate, List<AndOrCriteriaGroup> subCriteria) {
318         return new CriteriaGroup.Builder()
319                 .withInitialCriterion(new ExistsCriterion.Builder()
320                         .withExistsPredicate(existsPredicate).build())
321                 .withSubCriteria(subCriteria)
322                 .build();
323     }
324 
325     static CriteriaGroup group(SqlCriterion initialCriterion, AndOrCriteriaGroup... subCriteria) {
326         return group(initialCriterion, Arrays.asList(subCriteria));
327     }
328 
329     static CriteriaGroup group(SqlCriterion initialCriterion, List<AndOrCriteriaGroup> subCriteria) {
330         return new CriteriaGroup.Builder()
331                 .withInitialCriterion(initialCriterion)
332                 .withSubCriteria(subCriteria)
333                 .build();
334     }
335 
336     static CriteriaGroup group(List<AndOrCriteriaGroup> subCriteria) {
337         return new CriteriaGroup.Builder()
338                 .withInitialCriterion(new NullCriterion())
339                 .withSubCriteria(subCriteria)
340                 .build();
341     }
342 
343     static <T> NotCriterion not(BindableColumn<T> column, RenderableCondition<T> condition,
344                                 AndOrCriteriaGroup... subCriteria) {
345         return not(column, condition, Arrays.asList(subCriteria));
346     }
347 
348     static <T> NotCriterion not(BindableColumn<T> column, RenderableCondition<T> condition,
349                                 List<AndOrCriteriaGroup> subCriteria) {
350         return new NotCriterion.Builder()
351                 .withInitialCriterion(new ColumnAndConditionCriterion.Builder<T>().withColumn(column)
352                         .withCondition(condition).build())
353                 .withSubCriteria(subCriteria)
354                 .build();
355     }
356 
357     static NotCriterion not(ExistsPredicate existsPredicate, AndOrCriteriaGroup... subCriteria) {
358         return not(existsPredicate, Arrays.asList(subCriteria));
359     }
360 
361     static NotCriterion not(ExistsPredicate existsPredicate, List<AndOrCriteriaGroup> subCriteria) {
362         return new NotCriterion.Builder()
363                 .withInitialCriterion(new ExistsCriterion.Builder()
364                         .withExistsPredicate(existsPredicate).build())
365                 .withSubCriteria(subCriteria)
366                 .build();
367     }
368 
369     static NotCriterion not(SqlCriterion initialCriterion, AndOrCriteriaGroup... subCriteria) {
370         return not(initialCriterion, Arrays.asList(subCriteria));
371     }
372 
373     static NotCriterion not(SqlCriterion initialCriterion, List<AndOrCriteriaGroup> subCriteria) {
374         return new NotCriterion.Builder()
375                 .withInitialCriterion(initialCriterion)
376                 .withSubCriteria(subCriteria)
377                 .build();
378     }
379 
380     static NotCriterion not(List<AndOrCriteriaGroup> subCriteria) {
381         return new NotCriterion.Builder()
382                 .withInitialCriterion(new NullCriterion())
383                 .withSubCriteria(subCriteria)
384                 .build();
385     }
386 
387     static <T> AndOrCriteriaGroup or(BindableColumn<T> column, RenderableCondition<T> condition,
388                                      AndOrCriteriaGroup... subCriteria) {
389         return new AndOrCriteriaGroup.Builder()
390                 .withInitialCriterion(ColumnAndConditionCriterion.withColumn(column)
391                         .withCondition(condition)
392                         .build())
393                 .withConnector("or") //$NON-NLS-1$
394                 .withSubCriteria(Arrays.asList(subCriteria))
395                 .build();
396     }
397 
398     static AndOrCriteriaGroup or(ExistsPredicate existsPredicate, AndOrCriteriaGroup... subCriteria) {
399         return new AndOrCriteriaGroup.Builder()
400                 .withInitialCriterion(new ExistsCriterion.Builder()
401                         .withExistsPredicate(existsPredicate).build())
402                 .withConnector("or") //$NON-NLS-1$
403                 .withSubCriteria(Arrays.asList(subCriteria))
404                 .build();
405     }
406 
407     static AndOrCriteriaGroup or(SqlCriterion initialCriterion, AndOrCriteriaGroup... subCriteria) {
408         return new AndOrCriteriaGroup.Builder()
409                 .withConnector("or") //$NON-NLS-1$
410                 .withInitialCriterion(initialCriterion)
411                 .withSubCriteria(Arrays.asList(subCriteria))
412                 .build();
413     }
414 
415     static AndOrCriteriaGroup or(List<AndOrCriteriaGroup> subCriteria) {
416         return new AndOrCriteriaGroup.Builder()
417                 .withConnector("or") //$NON-NLS-1$
418                 .withInitialCriterion(new NullCriterion())
419                 .withSubCriteria(subCriteria)
420                 .build();
421     }
422 
423     static <T> AndOrCriteriaGroup and(BindableColumn<T> column, RenderableCondition<T> condition,
424                                       AndOrCriteriaGroup... subCriteria) {
425         return new AndOrCriteriaGroup.Builder()
426                 .withInitialCriterion(ColumnAndConditionCriterion.withColumn(column)
427                         .withCondition(condition)
428                         .build())
429                 .withConnector("and") //$NON-NLS-1$
430                 .withSubCriteria(Arrays.asList(subCriteria))
431                 .build();
432     }
433 
434     static AndOrCriteriaGroup and(ExistsPredicate existsPredicate, AndOrCriteriaGroup... subCriteria) {
435         return new AndOrCriteriaGroup.Builder()
436                 .withInitialCriterion(new ExistsCriterion.Builder()
437                         .withExistsPredicate(existsPredicate).build())
438                 .withConnector("and") //$NON-NLS-1$
439                 .withSubCriteria(Arrays.asList(subCriteria))
440                 .build();
441     }
442 
443     static AndOrCriteriaGroup and(SqlCriterion initialCriterion, AndOrCriteriaGroup... subCriteria) {
444         return new AndOrCriteriaGroup.Builder()
445                 .withConnector("and") //$NON-NLS-1$
446                 .withInitialCriterion(initialCriterion)
447                 .withSubCriteria(Arrays.asList(subCriteria))
448                 .build();
449     }
450 
451     static AndOrCriteriaGroup and(List<AndOrCriteriaGroup> subCriteria) {
452         return new AndOrCriteriaGroup.Builder()
453                 .withConnector("and") //$NON-NLS-1$
454                 .withInitialCriterion(new NullCriterion())
455                 .withSubCriteria(subCriteria)
456                 .build();
457     }
458 
459     // join support
460     static <T> ColumnAndConditionCriterion<T> on(BindableColumn<T> joinColumn, RenderableCondition<T> joinCondition) {
461         return ColumnAndConditionCriterion.withColumn(joinColumn)
462                 .withCondition(joinCondition)
463                 .build();
464     }
465 
466     /**
467      * Starting in version 2.0.0, this function is a synonym for {@link SqlBuilder#isEqualTo(BasicColumn)}.
468      *
469      * @param column the column
470      * @param <T> the column type
471      * @return an IsEqualToColumn condition
472      * @deprecated since 2.0.0. Please replace with isEqualTo(column)
473      */
474     @Deprecated(since = "2.0.0", forRemoval = true)
475     static <T> IsEqualToColumn<T> equalTo(BindableColumn<T> column) {
476         return isEqualTo(column);
477     }
478 
479     /**
480      * Starting in version 2.0.0, this function is a synonym for {@link SqlBuilder#isEqualTo(Object)}.
481      *
482      * @param value the value
483      * @param <T> the column type
484      * @return an IsEqualTo condition
485      * @deprecated since 2.0.0. Please replace with isEqualTo(value)
486      */
487     @Deprecated(since = "2.0.0", forRemoval = true)
488     static <T> IsEqualTo<T> equalTo(T value) {
489         return isEqualTo(value);
490     }
491 
492     // case expressions
493     @SuppressWarnings("java:S100")
494     static <T> SimpleCaseDSL<T> case_(BindableColumn<T> column) {
495         return SimpleCaseDSL.simpleCase(column);
496     }
497 
498     @SuppressWarnings("java:S100")
499     static SearchedCaseDSL case_() {
500         return SearchedCaseDSL.searchedCase();
501     }
502 
503     // aggregate support
504     static CountAll count() {
505         return new CountAll();
506     }
507 
508     static Count count(BasicColumn column) {
509         return Count.of(column);
510     }
511 
512     static CountDistinct countDistinct(BasicColumn column) {
513         return CountDistinct.of(column);
514     }
515 
516     static SubQueryColumn subQuery(Buildable<SelectModel> subQuery) {
517         return SubQueryColumn.of(subQuery.build());
518     }
519 
520     static <T> Max<T> max(BindableColumn<T> column) {
521         return Max.of(column);
522     }
523 
524     static <T> Min<T> min(BindableColumn<T> column) {
525         return Min.of(column);
526     }
527 
528     static <T> Avg<T> avg(BindableColumn<T> column) {
529         return Avg.of(column);
530     }
531 
532     static <T> Sum<T> sum(BindableColumn<T> column) {
533         return Sum.of(column);
534     }
535 
536     static Sum<Object> sum(BasicColumn column) {
537         return Sum.of(column);
538     }
539 
540     static <T> Sum<T> sum(BindableColumn<T> column, RenderableCondition<T> condition) {
541         return Sum.of(column, condition);
542     }
543 
544     // constants
545     static <T> Constant<T> constant(String constant) {
546         return Constant.of(constant);
547     }
548 
549     static StringConstant stringConstant(String constant) {
550         return StringConstant.of(constant);
551     }
552 
553     static <T> BoundValue<T> value(T value) {
554         return BoundValue.of(value);
555     }
556 
557     // functions
558     static <T> Add<T> add(BindableColumn<T> firstColumn, BasicColumn secondColumn,
559             BasicColumn... subsequentColumns) {
560         return Add.of(firstColumn, secondColumn, subsequentColumns);
561     }
562 
563     static <T> Divide<T> divide(BindableColumn<T> firstColumn, BasicColumn secondColumn,
564             BasicColumn... subsequentColumns) {
565         return Divide.of(firstColumn, secondColumn, subsequentColumns);
566     }
567 
568     static <T> Multiply<T> multiply(BindableColumn<T> firstColumn, BasicColumn secondColumn,
569             BasicColumn... subsequentColumns) {
570         return Multiply.of(firstColumn, secondColumn, subsequentColumns);
571     }
572 
573     static <T> Subtract<T> subtract(BindableColumn<T> firstColumn, BasicColumn secondColumn,
574             BasicColumn... subsequentColumns) {
575         return Subtract.of(firstColumn, secondColumn, subsequentColumns);
576     }
577 
578     static CastFinisher cast(String value) {
579         return cast(stringConstant(value));
580     }
581 
582     static CastFinisher cast(Double value) {
583         return cast(constant(value.toString()));
584     }
585 
586     static CastFinisher cast(BasicColumn column) {
587         return new CastFinisher(column);
588     }
589 
590     /**
591      * Concatenate function that renders as "(x || y || z)". This will not work on some
592      * databases like MySql. In that case, use {@link SqlBuilder#concat(BindableColumn, BasicColumn...)}
593      *
594      * @param firstColumn first column
595      * @param secondColumn second column
596      * @param subsequentColumns subsequent columns
597      * @param <T> type of column
598      * @return a Concatenate instance
599      */
600     static <T> Concatenate<T> concatenate(BindableColumn<T> firstColumn, BasicColumn secondColumn,
601             BasicColumn... subsequentColumns) {
602         return Concatenate.concatenate(firstColumn, secondColumn, subsequentColumns);
603     }
604 
605     /**
606      * Concatenate function that renders as "concat(x, y, z)". This version works on more databases
607      * than {@link SqlBuilder#concatenate(BindableColumn, BasicColumn, BasicColumn...)}
608      *
609      * @param firstColumn first column
610      * @param subsequentColumns subsequent columns
611      * @param <T> type of column
612      * @return a Concat instance
613      */
614     static <T> Concat<T> concat(BindableColumn<T> firstColumn, BasicColumn... subsequentColumns) {
615         return Concat.concat(firstColumn, subsequentColumns);
616     }
617 
618     static <T> OperatorFunction<T> applyOperator(String operator, BindableColumn<T> firstColumn,
619             BasicColumn secondColumn, BasicColumn... subsequentColumns) {
620         return OperatorFunction.of(operator, firstColumn, secondColumn, subsequentColumns);
621     }
622 
623     static <T> Lower<T> lower(BindableColumn<T> column) {
624         return Lower.of(column);
625     }
626 
627     static <T> Substring<T> substring(BindableColumn<T> column, int offset, int length) {
628         return Substring.of(column, offset, length);
629     }
630 
631     static <T> Upper<T> upper(BindableColumn<T> column) {
632         return Upper.of(column);
633     }
634 
635     // conditions for all data types
636     static ExistsPredicate exists(Buildable<SelectModel> selectModelBuilder) {
637         return ExistsPredicate.exists(selectModelBuilder);
638     }
639 
640     static ExistsPredicate notExists(Buildable<SelectModel> selectModelBuilder) {
641         return ExistsPredicate.notExists(selectModelBuilder);
642     }
643 
644     static <T> IsNull<T> isNull() {
645         return new IsNull<>();
646     }
647 
648     static <T> IsNotNull<T> isNotNull() {
649         return new IsNotNull<>();
650     }
651 
652     static <T> IsEqualTo<T> isEqualTo(T value) {
653         return IsEqualTo.of(value);
654     }
655 
656     static <T> IsEqualTo<T> isEqualTo(Supplier<T> valueSupplier) {
657         return isEqualTo(valueSupplier.get());
658     }
659 
660     static <T> IsEqualToWithSubselect<T> isEqualTo(Buildable<SelectModel> selectModelBuilder) {
661         return IsEqualToWithSubselect.of(selectModelBuilder);
662     }
663 
664     static <T> IsEqualToColumn<T> isEqualTo(BasicColumn column) {
665         return IsEqualToColumn.of(column);
666     }
667 
668     static <T> IsEqualToWhenPresent<T> isEqualToWhenPresent(@Nullable T value) {
669         return IsEqualToWhenPresent.of(value);
670     }
671 
672     static <T> IsEqualToWhenPresent<T> isEqualToWhenPresent(Supplier<@Nullable T> valueSupplier) {
673         return isEqualToWhenPresent(valueSupplier.get());
674     }
675 
676     static <T> IsNotEqualTo<T> isNotEqualTo(T value) {
677         return IsNotEqualTo.of(value);
678     }
679 
680     static <T> IsNotEqualTo<T> isNotEqualTo(Supplier<T> valueSupplier) {
681         return isNotEqualTo(valueSupplier.get());
682     }
683 
684     static <T> IsNotEqualToWithSubselect<T> isNotEqualTo(Buildable<SelectModel> selectModelBuilder) {
685         return IsNotEqualToWithSubselect.of(selectModelBuilder);
686     }
687 
688     static <T> IsNotEqualToColumn<T> isNotEqualTo(BasicColumn column) {
689         return IsNotEqualToColumn.of(column);
690     }
691 
692     static <T> IsNotEqualToWhenPresent<T> isNotEqualToWhenPresent(@Nullable T value) {
693         return IsNotEqualToWhenPresent.of(value);
694     }
695 
696     static <T> IsNotEqualToWhenPresent<T> isNotEqualToWhenPresent(Supplier<@Nullable T> valueSupplier) {
697         return isNotEqualToWhenPresent(valueSupplier.get());
698     }
699 
700     static <T> IsGreaterThan<T> isGreaterThan(T value) {
701         return IsGreaterThan.of(value);
702     }
703 
704     static <T> IsGreaterThan<T> isGreaterThan(Supplier<T> valueSupplier) {
705         return isGreaterThan(valueSupplier.get());
706     }
707 
708     static <T> IsGreaterThanWithSubselect<T> isGreaterThan(Buildable<SelectModel> selectModelBuilder) {
709         return IsGreaterThanWithSubselect.of(selectModelBuilder);
710     }
711 
712     static <T> IsGreaterThanColumn<T> isGreaterThan(BasicColumn column) {
713         return IsGreaterThanColumn.of(column);
714     }
715 
716     static <T> IsGreaterThanWhenPresent<T> isGreaterThanWhenPresent(@Nullable T value) {
717         return IsGreaterThanWhenPresent.of(value);
718     }
719 
720     static <T> IsGreaterThanWhenPresent<T> isGreaterThanWhenPresent(Supplier<@Nullable T> valueSupplier) {
721         return isGreaterThanWhenPresent(valueSupplier.get());
722     }
723 
724     static <T> IsGreaterThanOrEqualTo<T> isGreaterThanOrEqualTo(T value) {
725         return IsGreaterThanOrEqualTo.of(value);
726     }
727 
728     static <T> IsGreaterThanOrEqualTo<T> isGreaterThanOrEqualTo(Supplier<T> valueSupplier) {
729         return isGreaterThanOrEqualTo(valueSupplier.get());
730     }
731 
732     static <T> IsGreaterThanOrEqualToWithSubselect<T> isGreaterThanOrEqualTo(
733             Buildable<SelectModel> selectModelBuilder) {
734         return IsGreaterThanOrEqualToWithSubselect.of(selectModelBuilder);
735     }
736 
737     static <T> IsGreaterThanOrEqualToColumn<T> isGreaterThanOrEqualTo(BasicColumn column) {
738         return IsGreaterThanOrEqualToColumn.of(column);
739     }
740 
741     static <T> IsGreaterThanOrEqualToWhenPresent<T> isGreaterThanOrEqualToWhenPresent(@Nullable T value) {
742         return IsGreaterThanOrEqualToWhenPresent.of(value);
743     }
744 
745     static <T> IsGreaterThanOrEqualToWhenPresent<T> isGreaterThanOrEqualToWhenPresent(
746             Supplier<@Nullable T> valueSupplier) {
747         return isGreaterThanOrEqualToWhenPresent(valueSupplier.get());
748     }
749 
750     static <T> IsLessThan<T> isLessThan(T value) {
751         return IsLessThan.of(value);
752     }
753 
754     static <T> IsLessThan<T> isLessThan(Supplier<T> valueSupplier) {
755         return isLessThan(valueSupplier.get());
756     }
757 
758     static <T> IsLessThanWithSubselect<T> isLessThan(Buildable<SelectModel> selectModelBuilder) {
759         return IsLessThanWithSubselect.of(selectModelBuilder);
760     }
761 
762     static <T> IsLessThanColumn<T> isLessThan(BasicColumn column) {
763         return IsLessThanColumn.of(column);
764     }
765 
766     static <T> IsLessThanWhenPresent<T> isLessThanWhenPresent(@Nullable T value) {
767         return IsLessThanWhenPresent.of(value);
768     }
769 
770     static <T> IsLessThanWhenPresent<T> isLessThanWhenPresent(Supplier<@Nullable T> valueSupplier) {
771         return isLessThanWhenPresent(valueSupplier.get());
772     }
773 
774     static <T> IsLessThanOrEqualTo<T> isLessThanOrEqualTo(T value) {
775         return IsLessThanOrEqualTo.of(value);
776     }
777 
778     static <T> IsLessThanOrEqualTo<T> isLessThanOrEqualTo(Supplier<T> valueSupplier) {
779         return isLessThanOrEqualTo(valueSupplier.get());
780     }
781 
782     static <T> IsLessThanOrEqualToWithSubselect<T> isLessThanOrEqualTo(Buildable<SelectModel> selectModelBuilder) {
783         return IsLessThanOrEqualToWithSubselect.of(selectModelBuilder);
784     }
785 
786     static <T> IsLessThanOrEqualToColumn<T> isLessThanOrEqualTo(BasicColumn column) {
787         return IsLessThanOrEqualToColumn.of(column);
788     }
789 
790     static <T> IsLessThanOrEqualToWhenPresent<T> isLessThanOrEqualToWhenPresent(@Nullable T value) {
791         return IsLessThanOrEqualToWhenPresent.of(value);
792     }
793 
794     static <T> IsLessThanOrEqualToWhenPresent<T> isLessThanOrEqualToWhenPresent(Supplier<@Nullable T> valueSupplier) {
795         return isLessThanOrEqualToWhenPresent(valueSupplier.get());
796     }
797 
798     @SafeVarargs
799     static <T> IsIn<T> isIn(T... values) {
800         return IsIn.of(values);
801     }
802 
803     static <T> IsIn<T> isIn(Collection<T> values) {
804         return IsIn.of(values);
805     }
806 
807     static <T> IsInWithSubselect<T> isIn(Buildable<SelectModel> selectModelBuilder) {
808         return IsInWithSubselect.of(selectModelBuilder);
809     }
810 
811     @SafeVarargs
812     static <T> IsInWhenPresent<T> isInWhenPresent(@Nullable T... values) {
813         return IsInWhenPresent.of(values);
814     }
815 
816     static <T> IsInWhenPresent<T> isInWhenPresent(@Nullable Collection<@Nullable T> values) {
817         return IsInWhenPresent.of(values);
818     }
819 
820     @SafeVarargs
821     static <T> IsNotIn<T> isNotIn(T... values) {
822         return IsNotIn.of(values);
823     }
824 
825     static <T> IsNotIn<T> isNotIn(Collection<T> values) {
826         return IsNotIn.of(values);
827     }
828 
829     static <T> IsNotInWithSubselect<T> isNotIn(Buildable<SelectModel> selectModelBuilder) {
830         return IsNotInWithSubselect.of(selectModelBuilder);
831     }
832 
833     @SafeVarargs
834     static <T> IsNotInWhenPresent<T> isNotInWhenPresent(@Nullable T... values) {
835         return IsNotInWhenPresent.of(values);
836     }
837 
838     static <T> IsNotInWhenPresent<T> isNotInWhenPresent(@Nullable Collection<@Nullable T> values) {
839         return IsNotInWhenPresent.of(values);
840     }
841 
842     static <T> IsBetween.Builder<T> isBetween(T value1) {
843         return IsBetween.isBetween(value1);
844     }
845 
846     static <T> IsBetween.Builder<T> isBetween(Supplier<T> valueSupplier1) {
847         return isBetween(valueSupplier1.get());
848     }
849 
850     static <T> IsBetweenWhenPresent.Builder<T> isBetweenWhenPresent(@Nullable T value1) {
851         return IsBetweenWhenPresent.isBetweenWhenPresent(value1);
852     }
853 
854     static <T> IsBetweenWhenPresent.Builder<T> isBetweenWhenPresent(Supplier<@Nullable T> valueSupplier1) {
855         return isBetweenWhenPresent(valueSupplier1.get());
856     }
857 
858     static <T> IsNotBetween.Builder<T> isNotBetween(T value1) {
859         return IsNotBetween.isNotBetween(value1);
860     }
861 
862     static <T> IsNotBetween.Builder<T> isNotBetween(Supplier<T> valueSupplier1) {
863         return isNotBetween(valueSupplier1.get());
864     }
865 
866     static <T> IsNotBetweenWhenPresent.Builder<T> isNotBetweenWhenPresent(@Nullable T value1) {
867         return IsNotBetweenWhenPresent.isNotBetweenWhenPresent(value1);
868     }
869 
870     static <T> IsNotBetweenWhenPresent.Builder<T> isNotBetweenWhenPresent(Supplier<@Nullable T> valueSupplier1) {
871         return isNotBetweenWhenPresent(valueSupplier1.get());
872     }
873 
874     // for string columns, but generic for columns with type handlers
875     static <T> IsLike<T> isLike(T value) {
876         return IsLike.of(value);
877     }
878 
879     static <T> IsLike<T> isLike(Supplier<T> valueSupplier) {
880         return isLike(valueSupplier.get());
881     }
882 
883     static <T> IsLikeWhenPresent<T> isLikeWhenPresent(@Nullable T value) {
884         return IsLikeWhenPresent.of(value);
885     }
886 
887     static <T> IsLikeWhenPresent<T> isLikeWhenPresent(Supplier<@Nullable T> valueSupplier) {
888         return isLikeWhenPresent(valueSupplier.get());
889     }
890 
891     static <T> IsNotLike<T> isNotLike(T value) {
892         return IsNotLike.of(value);
893     }
894 
895     static <T> IsNotLike<T> isNotLike(Supplier<T> valueSupplier) {
896         return isNotLike(valueSupplier.get());
897     }
898 
899     static <T> IsNotLikeWhenPresent<T> isNotLikeWhenPresent(@Nullable T value) {
900         return IsNotLikeWhenPresent.of(value);
901     }
902 
903     static <T> IsNotLikeWhenPresent<T> isNotLikeWhenPresent(Supplier<@Nullable T> valueSupplier) {
904         return isNotLikeWhenPresent(valueSupplier.get());
905     }
906 
907     // shortcuts for booleans
908     static IsEqualTo<Boolean> isTrue() {
909         return isEqualTo(Boolean.TRUE);
910     }
911 
912     static IsEqualTo<Boolean> isFalse() {
913         return isEqualTo(Boolean.FALSE);
914     }
915 
916     // conditions for strings only
917     static IsLikeCaseInsensitive<String> isLikeCaseInsensitive(String value) {
918         return IsLikeCaseInsensitive.of(value);
919     }
920 
921     static IsLikeCaseInsensitive<String> isLikeCaseInsensitive(Supplier<String> valueSupplier) {
922         return isLikeCaseInsensitive(valueSupplier.get());
923     }
924 
925     static IsLikeCaseInsensitiveWhenPresent<String> isLikeCaseInsensitiveWhenPresent(@Nullable String value) {
926         return IsLikeCaseInsensitiveWhenPresent.of(value);
927     }
928 
929     static IsLikeCaseInsensitiveWhenPresent<String> isLikeCaseInsensitiveWhenPresent(
930             Supplier<@Nullable String> valueSupplier) {
931         return isLikeCaseInsensitiveWhenPresent(valueSupplier.get());
932     }
933 
934     static IsNotLikeCaseInsensitive<String> isNotLikeCaseInsensitive(String value) {
935         return IsNotLikeCaseInsensitive.of(value);
936     }
937 
938     static IsNotLikeCaseInsensitive<String> isNotLikeCaseInsensitive(Supplier<String> valueSupplier) {
939         return isNotLikeCaseInsensitive(valueSupplier.get());
940     }
941 
942     static IsNotLikeCaseInsensitiveWhenPresent<String> isNotLikeCaseInsensitiveWhenPresent(@Nullable String value) {
943         return IsNotLikeCaseInsensitiveWhenPresent.of(value);
944     }
945 
946     static IsNotLikeCaseInsensitiveWhenPresent<String> isNotLikeCaseInsensitiveWhenPresent(
947             Supplier<@Nullable String> valueSupplier) {
948         return isNotLikeCaseInsensitiveWhenPresent(valueSupplier.get());
949     }
950 
951     static IsInCaseInsensitive<String> isInCaseInsensitive(String... values) {
952         return IsInCaseInsensitive.of(values);
953     }
954 
955     static IsInCaseInsensitive<String> isInCaseInsensitive(Collection<String> values) {
956         return IsInCaseInsensitive.of(values);
957     }
958 
959     static IsInCaseInsensitiveWhenPresent<String> isInCaseInsensitiveWhenPresent(@Nullable String... values) {
960         return IsInCaseInsensitiveWhenPresent.of(values);
961     }
962 
963     static IsInCaseInsensitiveWhenPresent<String> isInCaseInsensitiveWhenPresent(
964             @Nullable Collection<@Nullable String> values) {
965         return IsInCaseInsensitiveWhenPresent.of(values);
966     }
967 
968     static IsNotInCaseInsensitive<String> isNotInCaseInsensitive(String... values) {
969         return IsNotInCaseInsensitive.of(values);
970     }
971 
972     static IsNotInCaseInsensitive<String> isNotInCaseInsensitive(Collection<String> values) {
973         return IsNotInCaseInsensitive.of(values);
974     }
975 
976     static IsNotInCaseInsensitiveWhenPresent<String> isNotInCaseInsensitiveWhenPresent(@Nullable String... values) {
977         return IsNotInCaseInsensitiveWhenPresent.of(values);
978     }
979 
980     static IsNotInCaseInsensitiveWhenPresent<String> isNotInCaseInsensitiveWhenPresent(
981             @Nullable Collection<@Nullable String> values) {
982         return IsNotInCaseInsensitiveWhenPresent.of(values);
983     }
984 
985     // order by support
986 
987     /**
988      * Creates a sort specification based on a String. This is useful when a column has been
989      * aliased in the select list. For example:
990      *
991      * <pre>
992      *     select(foo.as("bar"))
993      *     .from(baz)
994      *     .orderBy(sortColumn("bar"))
995      * </pre>
996      *
997      * @param name the string to use as a sort specification
998      * @return a sort specification
999      */
1000     static SortSpecification sortColumn(String name) {
1001         return SimpleSortSpecification.of(name);
1002     }
1003 
1004     /**
1005      * Creates a sort specification based on a column and a table alias. This can be useful in a join
1006      * where the desired sort order is based on a column not in the select list. This will likely
1007      * fail in union queries depending on database support.
1008      *
1009      * @param tableAlias the table alias
1010      * @param column the column
1011      * @return a sort specification
1012      */
1013     static SortSpecification sortColumn(String tableAlias, SqlColumn<?> column) {
1014         return new ColumnSortSpecification(tableAlias, column);
1015     }
1016 
1017     class InsertIntoNextStep {
1018 
1019         private final SqlTable table;
1020 
1021         private InsertIntoNextStep(SqlTable table) {
1022             this.table = Objects.requireNonNull(table);
1023         }
1024 
1025         public InsertSelectDSL withSelectStatement(Buildable<SelectModel> selectModelBuilder) {
1026             return InsertSelectDSL.insertInto(table)
1027                     .withSelectStatement(selectModelBuilder);
1028         }
1029 
1030         public InsertSelectDSL.SelectGatherer withColumnList(SqlColumn<?>... columns) {
1031             return InsertSelectDSL.insertInto(table)
1032                     .withColumnList(columns);
1033         }
1034 
1035         public InsertSelectDSL.SelectGatherer withColumnList(List<SqlColumn<?>> columns) {
1036             return InsertSelectDSL.insertInto(table)
1037                     .withColumnList(columns);
1038         }
1039 
1040         public <T> GeneralInsertDSL.SetClauseFinisher<T> set(SqlColumn<T> column) {
1041             return GeneralInsertDSL.insertInto(table)
1042                     .set(column);
1043         }
1044     }
1045 
1046     class CastFinisher {
1047         private final BasicColumn column;
1048 
1049         public CastFinisher(BasicColumn column) {
1050             this.column = column;
1051         }
1052 
1053         public Cast as(String targetType) {
1054             return new Cast.Builder()
1055                     .withColumn(column)
1056                     .withTargetType(targetType)
1057                     .build();
1058         }
1059     }
1060 }