001/*
002 *  Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com).
003 *  <p>
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *  <p>
008 *  http://www.apache.org/licenses/LICENSE-2.0
009 *  <p>
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package com.mybatisflex.core.query;
017
018
019import com.mybatisflex.core.constant.SqlConsts;
020import com.mybatisflex.core.dialect.IDialect;
021import com.mybatisflex.core.exception.FlexExceptions;
022import com.mybatisflex.core.table.TableDef;
023import com.mybatisflex.core.util.*;
024
025import java.util.Collection;
026import java.util.List;
027import java.util.function.Predicate;
028
029/**
030 * 查询列,描述的是一张表的字段
031 */
032public class QueryColumn implements CloneSupport<QueryColumn> {
033
034    protected QueryTable table;
035    protected String name;
036    protected String alias;
037
038    private boolean returnCopyByAsMethod = false;
039
040
041    public QueryColumn() {
042    }
043
044    public QueryColumn(String name) {
045        SqlUtil.keepColumnSafely(name);
046        this.name = StringUtil.tryTrim(name);
047    }
048
049    public QueryColumn(String tableName, String name) {
050        SqlUtil.keepColumnSafely(name);
051        this.table = new QueryTable(tableName);
052        this.name = StringUtil.tryTrim(name);
053    }
054
055    public QueryColumn(String schema, String tableName, String name) {
056        SqlUtil.keepColumnSafely(name);
057        this.table = new QueryTable(schema, tableName);
058        this.name = StringUtil.tryTrim(name);
059    }
060
061    public QueryColumn(String schema, String tableName, String name, String alias) {
062        SqlUtil.keepColumnSafely(name);
063        this.returnCopyByAsMethod = true;
064        this.table = new QueryTable(schema, tableName);
065        this.name = StringUtil.tryTrim(name);
066        this.alias = StringUtil.tryTrim(alias);
067    }
068
069    public QueryColumn(QueryTable queryTable, String name) {
070        SqlUtil.keepColumnSafely(name);
071        this.table = queryTable;
072        this.name = StringUtil.tryTrim(name);
073    }
074
075    public QueryColumn(TableDef tableDef, String name) {
076        this(tableDef, name, null);
077    }
078
079    public QueryColumn(TableDef tableDef, String name, String alias) {
080        SqlUtil.keepColumnSafely(name);
081        this.returnCopyByAsMethod = true;
082        this.table = new QueryTable(tableDef);
083        this.name = name;
084        this.alias = alias;
085    }
086
087
088    public QueryTable getTable() {
089        return table;
090    }
091
092    public void setTable(QueryTable table) {
093        this.table = table;
094    }
095
096    public String getName() {
097        return name;
098    }
099
100    public void setName(String name) {
101        this.name = name;
102    }
103
104    public String getAlias() {
105        return alias;
106    }
107
108    public void setAlias(String alias) {
109        this.alias = alias;
110    }
111
112    public <T> QueryColumn as(LambdaGetter<T> fn) {
113        return as(fn, false);
114    }
115
116    public <T> QueryColumn as(LambdaGetter<T> fn, boolean withPrefix) {
117        return as(LambdaUtil.getAliasName(fn, withPrefix));
118    }
119
120    public QueryColumn as(String alias) {
121        SqlUtil.keepColumnSafely(alias);
122        if (returnCopyByAsMethod) {
123            QueryColumn newColumn = new QueryColumn();
124            newColumn.table = this.table;
125            newColumn.name = this.name;
126            newColumn.alias = alias;
127            return newColumn;
128        } else {
129            this.alias = alias;
130            return this;
131        }
132    }
133
134
135    // query methods ///////
136
137    /**
138     * equals
139     *
140     * @param value
141     */
142    public QueryCondition eq(Object value) {
143        if (value == null) {
144            return QueryCondition.createEmpty();
145        }
146        return QueryCondition.create(this, SqlConsts.EQUALS, value);
147    }
148
149
150    public <T> QueryCondition eq(Object value, Predicate<T> fn) {
151        if (value == null) {
152            return QueryCondition.createEmpty();
153        }
154        return QueryCondition.create(this, SqlConsts.EQUALS, value).when(fn);
155    }
156
157
158    /**
159     * not equals !=
160     *
161     * @param value
162     */
163    public QueryCondition ne(Object value) {
164        if (value == null) {
165            return QueryCondition.createEmpty();
166        }
167        return QueryCondition.create(this, SqlConsts.NOT_EQUALS, value);
168    }
169
170    public <T> QueryCondition ne(Object value, Predicate<T> fn) {
171        if (value == null) {
172            return QueryCondition.createEmpty();
173        }
174        return QueryCondition.create(this, SqlConsts.NOT_EQUALS, value).when(fn);
175    }
176
177
178    /**
179     * like %%
180     *
181     * @param value
182     */
183    public QueryCondition like(Object value) {
184        if (value == null) {
185            return QueryCondition.createEmpty();
186        }
187        return QueryCondition.create(this, SqlConsts.LIKE, "%" + value + "%");
188    }
189
190    public <T> QueryCondition like(Object value, Predicate<T> fn) {
191        if (value == null) {
192            return QueryCondition.createEmpty();
193        }
194        return QueryCondition.create(this, SqlConsts.LIKE, "%" + value + "%").when(fn);
195    }
196
197
198    public QueryCondition likeLeft(Object value) {
199        if (value == null) {
200            return QueryCondition.createEmpty();
201        }
202        return QueryCondition.create(this, SqlConsts.LIKE, value + "%");
203    }
204
205    public <T> QueryCondition likeLeft(Object value, Predicate<T> fn) {
206        if (value == null) {
207            return QueryCondition.createEmpty();
208        }
209        return QueryCondition.create(this, SqlConsts.LIKE, value + "%").when(fn);
210    }
211
212
213    public QueryCondition likeRight(Object value) {
214        if (value == null) {
215            return QueryCondition.createEmpty();
216        }
217        return QueryCondition.create(this, SqlConsts.LIKE, "%" + value);
218    }
219
220    public <T> QueryCondition likeRight(Object value, Predicate<T> fn) {
221        if (value == null) {
222            return QueryCondition.createEmpty();
223        }
224        return QueryCondition.create(this, SqlConsts.LIKE, "%" + value).when(fn);
225    }
226
227    public QueryCondition likeRaw(Object value) {
228        if (value == null) {
229            return QueryCondition.createEmpty();
230        }
231        return QueryCondition.create(this, SqlConsts.LIKE, value);
232    }
233
234    public <T> QueryCondition likeRaw(Object value, Predicate<T> fn) {
235        if (value == null) {
236            return QueryCondition.createEmpty();
237        }
238        return QueryCondition.create(this, SqlConsts.LIKE, value).when(fn);
239    }
240
241    /**
242     * 大于 greater than
243     *
244     * @param value
245     */
246    public QueryCondition gt(Object value) {
247        if (value == null) {
248            return QueryCondition.createEmpty();
249        }
250        return QueryCondition.create(this, SqlConsts.GT, value);
251    }
252
253    public <T> QueryCondition gt(Object value, Predicate<T> fn) {
254        if (value == null) {
255            return QueryCondition.createEmpty();
256        }
257        return QueryCondition.create(this, SqlConsts.GT, value).when(fn);
258    }
259
260    /**
261     * 大于等于 greater or equal
262     *
263     * @param value
264     */
265    public QueryCondition ge(Object value) {
266        if (value == null) {
267            return QueryCondition.createEmpty();
268        }
269        return QueryCondition.create(this, SqlConsts.GE, value);
270    }
271
272    public <T> QueryCondition ge(Object value, Predicate<T> fn) {
273        if (value == null) {
274            return QueryCondition.createEmpty();
275        }
276        return QueryCondition.create(this, SqlConsts.GE, value).when(fn);
277    }
278
279    /**
280     * 小于 less than
281     *
282     * @param value
283     */
284    public QueryCondition lt(Object value) {
285        if (value == null) {
286            return QueryCondition.createEmpty();
287        }
288        return QueryCondition.create(this, SqlConsts.LT, value);
289    }
290
291    public <T> QueryCondition lt(Object value, Predicate<T> fn) {
292        if (value == null) {
293            return QueryCondition.createEmpty();
294        }
295        return QueryCondition.create(this, SqlConsts.LT, value).when(fn);
296    }
297
298    /**
299     * 小于等于 less or equal
300     *
301     * @param value
302     */
303    public QueryCondition le(Object value) {
304        if (value == null) {
305            return QueryCondition.createEmpty();
306        }
307        return QueryCondition.create(this, SqlConsts.LE, value);
308    }
309
310    public <T> QueryCondition le(Object value, Predicate<T> fn) {
311        if (value == null) {
312            return QueryCondition.createEmpty();
313        }
314        return QueryCondition.create(this, SqlConsts.LE, value).when(fn);
315    }
316
317
318    /**
319     * IS NULL
320     *
321     * @return
322     */
323    public QueryCondition isNull() {
324        return QueryCondition.create(this, SqlConsts.IS_NULL, null);
325    }
326
327    public <T> QueryCondition isNull(Predicate<T> fn) {
328        return QueryCondition.create(this, SqlConsts.IS_NULL, null).when(fn);
329    }
330
331
332    /**
333     * IS NOT NULL
334     *
335     * @return
336     */
337    public QueryCondition isNotNull() {
338        return QueryCondition.create(this, SqlConsts.IS_NOT_NULL, null);
339    }
340
341    public <T> QueryCondition isNotNull(Predicate<T> fn) {
342        return QueryCondition.create(this, SqlConsts.IS_NOT_NULL, null).when(fn);
343    }
344
345
346    /**
347     * in arrays
348     *
349     * @param arrays
350     * @return
351     */
352    public QueryCondition in(Object... arrays) {
353        //忽略 QueryWrapper.in("name", null) 的情况
354        if (arrays == null || arrays.length == 0 || (arrays.length == 1 && arrays[0] == null)) {
355            return QueryCondition.createEmpty();
356        }
357        return QueryCondition.create(this, SqlConsts.IN, arrays);
358    }
359
360    public <T> QueryCondition in(Object[] arrays, Predicate<T> fn) {
361        //忽略 QueryWrapper.in("name", null) 的情况
362        if (arrays == null || arrays.length == 0 || (arrays.length == 1 && arrays[0] == null)) {
363            return QueryCondition.createEmpty();
364        }
365        return QueryCondition.create(this, SqlConsts.IN, arrays).when(fn);
366    }
367
368    /**
369     * in child select
370     *
371     * @param queryWrapper
372     * @return
373     */
374    public QueryCondition in(QueryWrapper queryWrapper) {
375        return QueryCondition.create(this, SqlConsts.IN, queryWrapper);
376    }
377
378    public <T> QueryCondition in(QueryWrapper queryWrapper, Predicate<T> fn) {
379        return QueryCondition.create(this, SqlConsts.IN, queryWrapper).when(fn);
380    }
381
382
383    /**
384     * in Collection
385     *
386     * @param collection
387     * @return
388     */
389    public QueryCondition in(Collection<?> collection) {
390        if (collection != null && !collection.isEmpty()) {
391            return in(collection.toArray());
392        }
393        return QueryCondition.createEmpty();
394    }
395
396    public <T> QueryCondition in(Collection<?> collection, Predicate<T> fn) {
397        if (collection != null && !collection.isEmpty()) {
398            return in(collection.toArray(), fn);
399        }
400        return QueryCondition.createEmpty();
401    }
402
403    /**
404     * not int arrays
405     *
406     * @param arrays
407     * @return
408     */
409    public QueryCondition notIn(Object... arrays) {
410        //忽略 QueryWrapper.notIn("name", null) 的情况
411        if (arrays == null || arrays.length == 0 || (arrays.length == 1 && arrays[0] == null)) {
412            return QueryCondition.createEmpty();
413        }
414        return QueryCondition.create(this, SqlConsts.NOT_IN, arrays);
415    }
416
417    public <T> QueryCondition notIn(Object[] arrays, Predicate<T> fn) {
418        //忽略 QueryWrapper.notIn("name", null) 的情况
419        if (arrays == null || arrays.length == 0 || (arrays.length == 1 && arrays[0] == null)) {
420            return QueryCondition.createEmpty();
421        }
422        return QueryCondition.create(this, SqlConsts.NOT_IN, arrays).when(fn);
423    }
424
425
426    /**
427     * not in Collection
428     *
429     * @param collection
430     * @return
431     */
432    public QueryCondition notIn(Collection<?> collection) {
433        if (collection != null && !collection.isEmpty()) {
434            return notIn(collection.toArray());
435        }
436        return QueryCondition.createEmpty();
437    }
438
439    public <T> QueryCondition notIn(Collection<?> collection, Predicate<T> fn) {
440        if (collection != null && !collection.isEmpty()) {
441            return notIn(collection.toArray(), fn);
442        }
443        return QueryCondition.createEmpty();
444    }
445
446    /**
447     * not in child select
448     *
449     * @param queryWrapper
450     */
451    public QueryCondition notIn(QueryWrapper queryWrapper) {
452        return QueryCondition.create(this, SqlConsts.NOT_IN, queryWrapper);
453    }
454
455    public <T> QueryCondition notIn(QueryWrapper queryWrapper, Predicate<T> fn) {
456        return QueryCondition.create(this, SqlConsts.NOT_IN, queryWrapper).when(fn);
457    }
458
459
460    /**
461     * between
462     *
463     * @param start
464     * @param end
465     */
466    public QueryCondition between(Object start, Object end) {
467        return QueryCondition.create(this, SqlConsts.BETWEEN, new Object[]{start, end});
468    }
469
470    public <T> QueryCondition between(Object start, Object end, Predicate<T> fn) {
471        return QueryCondition.create(this, SqlConsts.BETWEEN, new Object[]{start, end}).when(fn);
472    }
473
474
475    /**
476     * not between
477     *
478     * @param start
479     * @param end
480     */
481    public QueryCondition notBetween(Object start, Object end) {
482        return QueryCondition.create(this, SqlConsts.NOT_BETWEEN, new Object[]{start, end});
483    }
484
485    public <T> QueryCondition notBetween(Object start, Object end, Predicate<T> fn) {
486        return QueryCondition.create(this, SqlConsts.NOT_BETWEEN, new Object[]{start, end}).when(fn);
487    }
488
489
490    ////order by ////
491    public QueryOrderBy asc() {
492        return new QueryOrderBy(this, SqlConsts.ASC);
493    }
494
495
496    public QueryOrderBy desc() {
497        return new QueryOrderBy(this, SqlConsts.DESC);
498    }
499
500
501    // 运算 加减乘除 + - * /
502    public QueryColumn add(QueryColumn queryColumn) {
503        return new ArithmeticQueryColumn(this).add(queryColumn);
504    }
505
506    public QueryColumn add(Number number) {
507        return new ArithmeticQueryColumn(this).add(number);
508    }
509
510    public QueryColumn subtract(QueryColumn queryColumn) {
511        return new ArithmeticQueryColumn(this).subtract(queryColumn);
512    }
513
514    public QueryColumn subtract(Number number) {
515        return new ArithmeticQueryColumn(this).subtract(number);
516    }
517
518    public QueryColumn multiply(QueryColumn queryColumn) {
519        return new ArithmeticQueryColumn(this).multiply(queryColumn);
520    }
521
522    public QueryColumn multiply(Number number) {
523        return new ArithmeticQueryColumn(this).multiply(number);
524    }
525
526    public QueryColumn divide(QueryColumn queryColumn) {
527        return new ArithmeticQueryColumn(this).divide(queryColumn);
528    }
529
530    public QueryColumn divide(Number number) {
531        return new ArithmeticQueryColumn(this).divide(number);
532    }
533
534
535    String toConditionSql(List<QueryTable> queryTables, IDialect dialect) {
536        QueryTable selectTable = getSelectTable(queryTables, table);
537        if (selectTable == null) {
538            return dialect.wrap(name);
539        } else {
540            if (StringUtil.isNotBlank(selectTable.alias)) {
541                return dialect.wrap(selectTable.alias) + SqlConsts.REFERENCE + dialect.wrap(name);
542            } else if (StringUtil.isNotBlank(selectTable.getSchema()) && StringUtil.isNotBlank(selectTable.getName())) {
543                return dialect.wrap(dialect.getRealSchema(selectTable.schema)) + SqlConsts.REFERENCE + dialect.wrap(dialect.getRealTable(selectTable.getName())) + SqlConsts.REFERENCE + dialect.wrap(name);
544            } else if (StringUtil.isNotBlank(selectTable.getName())) {
545                return dialect.wrap(dialect.getRealTable(selectTable.getName())) + SqlConsts.REFERENCE + dialect.wrap(name);
546            } else {
547                return dialect.wrap(name);
548            }
549        }
550    }
551
552
553    String toSelectSql(List<QueryTable> queryTables, IDialect dialect) {
554        return toConditionSql(queryTables, dialect) + WrapperUtil.buildAlias(alias, dialect);
555    }
556
557
558    QueryTable getSelectTable(List<QueryTable> queryTables, QueryTable selfTable) {
559        //未查询任何表
560        if (queryTables == null || queryTables.isEmpty()) {
561            return null;
562        }
563
564        if (selfTable != null && StringUtil.isNotBlank(selfTable.alias)){
565            return selfTable;
566        }
567
568        if (queryTables.size() == 1 && queryTables.get(0).isSameTable(selfTable)) {
569            //ignore table
570            return null;
571        }
572
573        if (CollectionUtil.isEmpty(queryTables)) {
574            return selfTable;
575        }
576
577        if (selfTable == null && queryTables.size() == 1) {
578            return queryTables.get(0);
579        }
580
581        for (QueryTable table : queryTables) {
582            if (table.isSameTable(selfTable)) {
583                return table;
584            }
585        }
586        return selfTable;
587    }
588
589
590    @Override
591    public String toString() {
592        return "QueryColumn{" +
593            "table=" + table +
594            ", name='" + name + '\'' +
595            ", alias='" + alias + '\'' +
596            '}';
597    }
598
599
600    @Override
601    public QueryColumn clone() {
602        try {
603            QueryColumn clone = (QueryColumn) super.clone();
604            // deep clone ...
605            clone.table = ObjectUtil.clone(this.table);
606            return clone;
607        } catch (CloneNotSupportedException e) {
608            throw FlexExceptions.wrap(e);
609        }
610    }
611
612}