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