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