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
018import com.mybatisflex.core.FlexConsts;
019import com.mybatisflex.core.dialect.DialectFactory;
020import com.mybatisflex.core.table.TableDef;
021import com.mybatisflex.core.table.TableInfo;
022import com.mybatisflex.core.table.TableInfoFactory;
023import com.mybatisflex.core.util.*;
024
025import java.util.*;
026import java.util.function.Consumer;
027
028public class QueryWrapper extends BaseQueryWrapper<QueryWrapper> {
029
030
031    public static QueryWrapper create() {
032        return new QueryWrapper();
033    }
034
035    public QueryWrapper select(QueryColumn... queryColumns) {
036        for (QueryColumn column : queryColumns) {
037            if (column != null) {
038                addSelectColumn(column);
039            }
040        }
041        return this;
042    }
043
044
045    public QueryWrapper from(TableDef... tableDefs) {
046        for (TableDef tableDef : tableDefs) {
047            from(new QueryTable(tableDef));
048        }
049        return this;
050    }
051
052
053    public QueryWrapper from(Class<?>... entityClasses) {
054        for (Class<?> entityClass : entityClasses) {
055            TableInfo tableInfo = TableInfoFactory.ofEntityClass(entityClass);
056            from(new QueryTable(tableInfo.getSchema(), tableInfo.getTableName()));
057        }
058        return this;
059    }
060
061
062    public QueryWrapper from(String... tables) {
063        for (String table : tables) {
064            if (StringUtil.isBlank(table)) {
065                throw new IllegalArgumentException("table must not be null or blank.");
066            }
067            int indexOf = table.indexOf(".");
068            if (indexOf > 0) {
069                String schema = table.substring(0, indexOf);
070                table = table.substring(indexOf + 1);
071                from(new QueryTable(schema, table));
072            } else {
073                from(new QueryTable(table));
074            }
075        }
076        return this;
077    }
078
079
080    public QueryWrapper from(QueryTable... tables) {
081        if (CollectionUtil.isEmpty(queryTables)) {
082            queryTables = new ArrayList<>();
083            queryTables.addAll(Arrays.asList(tables));
084        } else {
085            for (QueryTable table : tables) {
086                boolean contains = false;
087                for (QueryTable queryTable : queryTables) {
088                    if (queryTable.isSameTable(table)) {
089                        contains = true;
090                    }
091                }
092                if (!contains) {
093                    queryTables.add(table);
094                }
095            }
096        }
097        return this;
098    }
099
100
101    public QueryWrapper from(QueryWrapper queryWrapper) {
102        return from(new SelectQueryTable(queryWrapper));
103    }
104
105
106    public QueryWrapper as(String alias) {
107        if (CollectionUtil.isEmpty(queryTables)) {
108            throw new IllegalArgumentException("query table must not be empty.");
109        }
110
111        queryTables.get(queryTables.size() - 1).alias = alias;
112        return this;
113    }
114
115
116    public QueryWrapper where(QueryCondition queryCondition) {
117        this.setWhereQueryCondition(queryCondition);
118        return this;
119    }
120
121    public QueryWrapper where(String sql) {
122        this.setWhereQueryCondition(new RawFragment(sql));
123        return this;
124    }
125
126
127    public QueryWrapper where(String sql, Object... params) {
128        this.setWhereQueryCondition(new RawFragment(sql, params));
129        return this;
130    }
131
132
133    public QueryWrapper where(Map<String, Object> whereConditions) {
134        if (whereConditions != null) {
135            whereConditions.forEach((s, o) -> and(QueryCondition.create(new QueryColumn(s), o)));
136        }
137        return this;
138    }
139
140    public <T> QueryConditionBuilder where(LambdaGetter<T> fn) {
141        return new QueryConditionBuilder(this, LambdaUtil.getQueryColumn(fn), SqlConnector.AND);
142    }
143
144    public QueryWrapper and(QueryCondition queryCondition) {
145        return addWhereQueryCondition(queryCondition, SqlConnector.AND);
146    }
147
148    public QueryWrapper and(String sql) {
149        this.addWhereQueryCondition(new RawFragment(sql), SqlConnector.AND);
150        return this;
151    }
152
153    public QueryWrapper and(String sql, Object... params) {
154        this.addWhereQueryCondition(new RawFragment(sql, params), SqlConnector.AND);
155        return this;
156    }
157
158    public <T> QueryConditionBuilder and(LambdaGetter<T> fn) {
159        return new QueryConditionBuilder(this, LambdaUtil.getQueryColumn(fn), SqlConnector.AND);
160    }
161
162
163    public QueryWrapper and(Consumer<QueryWrapper> consumer) {
164        QueryWrapper newWrapper = new QueryWrapper();
165        consumer.accept(newWrapper);
166        QueryCondition whereQueryCondition = newWrapper.whereQueryCondition;
167        if (whereQueryCondition != null) {
168            and(new Brackets(whereQueryCondition));
169        }
170        return this;
171    }
172
173    public QueryWrapper or(QueryCondition queryCondition) {
174        return addWhereQueryCondition(queryCondition, SqlConnector.OR);
175    }
176
177    public QueryWrapper or(String sql) {
178        this.addWhereQueryCondition(new RawFragment(sql), SqlConnector.OR);
179        return this;
180    }
181
182    public QueryWrapper or(String sql, Object... params) {
183        this.addWhereQueryCondition(new RawFragment(sql, params), SqlConnector.OR);
184        return this;
185    }
186
187    public <T> QueryConditionBuilder or(LambdaGetter<T> fn) {
188        return new QueryConditionBuilder(this, LambdaUtil.getQueryColumn(fn), SqlConnector.OR);
189    }
190
191    public QueryWrapper or(Consumer<QueryWrapper> consumer) {
192        QueryWrapper newWrapper = new QueryWrapper();
193        consumer.accept(newWrapper);
194        QueryCondition whereQueryCondition = newWrapper.whereQueryCondition;
195        if (whereQueryCondition != null) {
196            or(new Brackets(whereQueryCondition));
197        }
198        return this;
199    }
200
201    public Joiner<QueryWrapper> leftJoin(String table) {
202        return joining(Join.TYPE_LEFT, new QueryTable(table), true);
203    }
204
205
206    public Joiner<QueryWrapper> leftJoin(String table, boolean when) {
207        return joining(Join.TYPE_LEFT, new QueryTable(table), when);
208    }
209
210    public Joiner<QueryWrapper> leftJoin(Class<?> entityClass) {
211        return joining(Join.TYPE_LEFT, entityClass, true);
212    }
213
214    public Joiner<QueryWrapper> leftJoin(Class<?> entityClass, boolean when) {
215        return joining(Join.TYPE_LEFT, entityClass, when);
216    }
217
218    public Joiner<QueryWrapper> leftJoin(TableDef table) {
219        return joining(Join.TYPE_LEFT, new QueryTable(table), true);
220    }
221
222    public Joiner<QueryWrapper> leftJoin(TableDef table, boolean when) {
223        return joining(Join.TYPE_LEFT, new QueryTable(table), when);
224    }
225
226    public Joiner<QueryWrapper> leftJoin(QueryWrapper table) {
227        return joining(Join.TYPE_LEFT, table, true);
228    }
229
230    public Joiner<QueryWrapper> leftJoin(QueryWrapper table, boolean when) {
231        return joining(Join.TYPE_LEFT, table, when);
232    }
233
234
235    public Joiner<QueryWrapper> rightJoin(String table) {
236        return joining(Join.TYPE_RIGHT, new QueryTable(table), true);
237    }
238
239    public Joiner<QueryWrapper> rightJoin(String table, boolean when) {
240        return joining(Join.TYPE_RIGHT, new QueryTable(table), when);
241    }
242
243    public Joiner<QueryWrapper> rightJoin(Class<?> entityClass) {
244        return joining(Join.TYPE_RIGHT, entityClass, true);
245    }
246
247    public Joiner<QueryWrapper> rightJoin(Class<?> entityClass, boolean when) {
248        return joining(Join.TYPE_RIGHT, entityClass, when);
249    }
250
251    public Joiner<QueryWrapper> rightJoin(TableDef table) {
252        return joining(Join.TYPE_RIGHT, new QueryTable(table), true);
253    }
254
255    public Joiner<QueryWrapper> rightJoin(TableDef table, boolean when) {
256        return joining(Join.TYPE_RIGHT, new QueryTable(table), when);
257    }
258
259    public Joiner<QueryWrapper> rightJoin(QueryWrapper table) {
260        return joining(Join.TYPE_RIGHT, table, true);
261    }
262
263    public Joiner<QueryWrapper> rightJoin(QueryWrapper table, boolean when) {
264        return joining(Join.TYPE_RIGHT, table, when);
265    }
266
267
268    public Joiner<QueryWrapper> innerJoin(String table) {
269        return joining(Join.TYPE_INNER, new QueryTable(table), true);
270    }
271
272    public Joiner<QueryWrapper> innerJoin(String table, boolean when) {
273        return joining(Join.TYPE_INNER, new QueryTable(table), when);
274    }
275
276    public Joiner<QueryWrapper> innerJoin(Class<?> entityClass) {
277        return joining(Join.TYPE_INNER, entityClass, true);
278    }
279
280    public Joiner<QueryWrapper> innerJoin(Class<?> entityClass, boolean when) {
281        return joining(Join.TYPE_INNER, entityClass, when);
282    }
283
284    public Joiner<QueryWrapper> innerJoin(TableDef table) {
285        return innerJoin(table, true);
286    }
287
288    public Joiner<QueryWrapper> innerJoin(TableDef table, boolean when) {
289        return joining(Join.TYPE_INNER, new QueryTable(table), when);
290    }
291
292    public Joiner<QueryWrapper> innerJoin(QueryWrapper table) {
293        return joining(Join.TYPE_INNER, table, true);
294    }
295
296    public Joiner<QueryWrapper> innerJoin(QueryWrapper table, boolean when) {
297        return joining(Join.TYPE_INNER, table, when);
298    }
299
300
301    public Joiner<QueryWrapper> fullJoin(String table) {
302        return joining(Join.TYPE_FULL, new QueryTable(table), true);
303    }
304
305    public Joiner<QueryWrapper> fullJoin(String table, boolean when) {
306        return joining(Join.TYPE_FULL, new QueryTable(table), when);
307    }
308
309    public Joiner<QueryWrapper> fullJoin(Class<?> entityClass) {
310        return joining(Join.TYPE_FULL, entityClass, true);
311    }
312
313    public Joiner<QueryWrapper> fullJoin(Class<?> entityClass, boolean when) {
314        return joining(Join.TYPE_FULL, entityClass, when);
315    }
316
317    public Joiner<QueryWrapper> fullJoin(TableDef table) {
318        return joining(Join.TYPE_FULL, new QueryTable(table), true);
319    }
320
321    public Joiner<QueryWrapper> fullJoin(TableDef table, boolean when) {
322        return joining(Join.TYPE_FULL, new QueryTable(table), when);
323    }
324
325    public Joiner<QueryWrapper> fullJoin(QueryWrapper table) {
326        return joining(Join.TYPE_FULL, table, true);
327    }
328
329    public Joiner<QueryWrapper> fullJoin(QueryWrapper table, boolean when) {
330        return joining(Join.TYPE_FULL, table, when);
331    }
332
333
334    public Joiner<QueryWrapper> crossJoin(String table) {
335        return joining(Join.TYPE_CROSS, new QueryTable(table), true);
336    }
337
338    public Joiner<QueryWrapper> crossJoin(String table, boolean when) {
339        return joining(Join.TYPE_CROSS, new QueryTable(table), when);
340    }
341
342    public Joiner<QueryWrapper> crossJoin(Class<?> entityClass) {
343        return joining(Join.TYPE_CROSS, entityClass, true);
344    }
345
346    public Joiner<QueryWrapper> crossJoin(Class<?> entityClass, boolean when) {
347        return joining(Join.TYPE_CROSS, entityClass, when);
348    }
349
350    public Joiner<QueryWrapper> crossJoin(TableDef table) {
351        return joining(Join.TYPE_CROSS, new QueryTable(table), true);
352    }
353
354    public Joiner<QueryWrapper> crossJoin(TableDef table, boolean when) {
355        return joining(Join.TYPE_CROSS, new QueryTable(table), when);
356    }
357
358    public Joiner<QueryWrapper> crossJoin(QueryWrapper table) {
359        return joining(Join.TYPE_CROSS, table, true);
360    }
361
362    public Joiner<QueryWrapper> crossJoin(QueryWrapper table, boolean when) {
363        return joining(Join.TYPE_CROSS, table, when);
364    }
365
366
367    public Joiner<QueryWrapper> join(String table) {
368        return joining(Join.TYPE_JOIN, new QueryTable(table), true);
369    }
370
371    public Joiner<QueryWrapper> join(String table, boolean when) {
372        return joining(Join.TYPE_JOIN, new QueryTable(table), when);
373    }
374
375    public Joiner<QueryWrapper> join(Class<?> entityClass) {
376        return joining(Join.TYPE_JOIN, entityClass, true);
377    }
378
379    public Joiner<QueryWrapper> join(Class<?> entityClass, boolean when) {
380        return joining(Join.TYPE_JOIN, entityClass, when);
381    }
382
383    public Joiner<QueryWrapper> join(TableDef table) {
384        return joining(Join.TYPE_JOIN, new QueryTable(table), true);
385    }
386
387    public Joiner<QueryWrapper> join(TableDef table, boolean when) {
388        return joining(Join.TYPE_JOIN, new QueryTable(table), when);
389    }
390
391    public Joiner<QueryWrapper> join(QueryWrapper table) {
392        return joining(Join.TYPE_JOIN, table, true);
393    }
394
395    public Joiner<QueryWrapper> join(QueryWrapper table, boolean when) {
396        return joining(Join.TYPE_JOIN, table, when);
397    }
398
399
400    public QueryWrapper union(QueryWrapper unionQuery) {
401        if (unions == null) {
402            unions = new ArrayList<>();
403        }
404        unions.add(UnionWrapper.union(unionQuery));
405        return this;
406    }
407
408    public QueryWrapper unionAll(QueryWrapper unionQuery) {
409        if (unions == null) {
410            unions = new ArrayList<>();
411        }
412        unions.add(UnionWrapper.unionAll(unionQuery));
413        return this;
414    }
415
416    public QueryWrapper forUpdate() {
417        addEndFragment("FOR UPDATE");
418        return this;
419    }
420
421    public QueryWrapper forUpdateNoWait() {
422        addEndFragment("FOR UPDATE NOWAIT");
423        return this;
424    }
425
426
427//    public QueryWrapper end(String sqlPart){
428//        addEndFragment(sqlPart);
429//        return this;
430//    }
431
432
433    protected Joiner<QueryWrapper> joining(String type, QueryTable table, boolean when) {
434        Join join = new Join(type, table, when);
435        addJoinTable(join.getQueryTable());
436        return new Joiner<>(addJoin(join), join);
437    }
438
439    protected Joiner<QueryWrapper> joining(String type, Class<?> entityClass, boolean when) {
440        TableInfo tableInfo = TableInfoFactory.ofEntityClass(entityClass);
441        QueryTable queryTable = new QueryTable(tableInfo.getSchema(), tableInfo.getTableName());
442        return joining(type, queryTable, when);
443    }
444
445    protected Joiner<QueryWrapper> joining(String type, QueryWrapper queryWrapper, boolean when) {
446        Join join = new Join(type, queryWrapper, when);
447        addJoinTable(join.getQueryTable());
448        return new Joiner<>(addJoin(join), join);
449    }
450
451
452    public QueryWrapper groupBy(String name) {
453        addGroupByColumns(new QueryColumn(name));
454        return this;
455    }
456
457    public QueryWrapper groupBy(String... names) {
458        for (String name : names) {
459            groupBy(name);
460        }
461        return this;
462    }
463
464    public QueryWrapper groupBy(QueryColumn column) {
465        addGroupByColumns(column);
466        return this;
467    }
468
469    public QueryWrapper groupBy(QueryColumn... columns) {
470        for (QueryColumn column : columns) {
471            groupBy(column);
472        }
473        return this;
474    }
475
476
477    public QueryWrapper having(QueryCondition queryCondition) {
478        addHavingQueryCondition(queryCondition, SqlConnector.AND);
479        return this;
480    }
481
482    public QueryWrapper orderBy(QueryOrderBy... orderBys) {
483        for (QueryOrderBy queryOrderBy : orderBys) {
484            addOrderBy(queryOrderBy);
485        }
486        return this;
487    }
488
489    public QueryWrapper orderBy(String... orderBys) {
490        if (orderBys == null || orderBys.length == 0) {
491            //ignore
492            return this;
493        }
494        for (String queryOrderBy : orderBys) {
495            if (StringUtil.isNotBlank(queryOrderBy)) {
496                addOrderBy(new StringQueryOrderBy(queryOrderBy));
497            }
498        }
499        return this;
500    }
501
502
503    public QueryWrapper limit(Integer rows) {
504        setLimitRows(rows);
505        return this;
506    }
507
508    public QueryWrapper offset(Integer offset) {
509        setLimitOffset(offset);
510        return this;
511    }
512
513    public QueryWrapper limit(Integer offset, Integer rows) {
514        setLimitOffset(offset);
515        setLimitRows(rows);
516        return this;
517    }
518
519    public QueryWrapper datasource(String datasource) {
520        setDataSource(datasource);
521        return this;
522    }
523
524    public QueryWrapper hint(String hint) {
525        setHint(hint);
526        return this;
527    }
528
529    /**
530     * 获取 queryWrapper 的参数
531     * 在构建 sql 的时候,需要保证 where 在 having 的前面
532     */
533    Object[] getValueArray() {
534
535        List<Object> columnValues = null;
536        List<QueryColumn> selectColumns = getSelectColumns();
537        if (CollectionUtil.isNotEmpty(selectColumns)) {
538            for (QueryColumn selectColumn : selectColumns) {
539                if (selectColumn instanceof HasParamsColumn) {
540                    Object[] paramValues = ((HasParamsColumn) selectColumn).getParamValues();
541                    if (ArrayUtil.isNotEmpty(paramValues)) {
542                        if (columnValues == null) {
543                            columnValues = new ArrayList<>();
544                        }
545                        columnValues.addAll(Arrays.asList(paramValues));
546                    }
547                }
548            }
549        }
550
551        //select 子查询的参数:select * from (select ....)
552        List<Object> tableValues = null;
553        List<QueryTable> queryTables = getQueryTables();
554        if (CollectionUtil.isNotEmpty(queryTables)) {
555            for (QueryTable queryTable : queryTables) {
556                Object[] tableValueArray = queryTable.getValueArray();
557                if (tableValueArray.length > 0) {
558                    if (tableValues == null) {
559                        tableValues = new ArrayList<>();
560                    }
561                    tableValues.addAll(Arrays.asList(tableValueArray));
562                }
563            }
564        }
565
566        //join 子查询的参数:left join (select ...)
567        List<Object> joinValues = null;
568        List<Join> joins = getJoins();
569        if (CollectionUtil.isNotEmpty(joins)) {
570            for (Join join : joins) {
571                QueryTable joinTable = join.getQueryTable();
572                Object[] valueArray = joinTable.getValueArray();
573                if (valueArray.length > 0) {
574                    if (joinValues == null) {
575                        joinValues = new ArrayList<>();
576                    }
577                    joinValues.addAll(Arrays.asList(valueArray));
578                }
579                QueryCondition onCondition = join.getOnCondition();
580                Object[] values = WrapperUtil.getValues(onCondition);
581                if (values.length > 0) {
582                    if (joinValues == null) {
583                        joinValues = new ArrayList<>();
584                    }
585                    joinValues.addAll(Arrays.asList(values));
586                }
587            }
588        }
589
590        //where 参数
591        Object[] whereValues = WrapperUtil.getValues(whereQueryCondition);
592
593        //having 参数
594        Object[] havingValues = WrapperUtil.getValues(havingQueryCondition);
595
596        Object[] paramValues = ArrayUtil.concat(whereValues, havingValues);
597
598        //unions 参数
599        if (CollectionUtil.isNotEmpty(unions)) {
600            for (UnionWrapper union : unions) {
601                QueryWrapper queryWrapper = union.getQueryWrapper();
602                paramValues = ArrayUtil.concat(paramValues, queryWrapper.getValueArray());
603            }
604        }
605
606        Object[] returnValues = columnValues == null ? FlexConsts.EMPTY_ARRAY : columnValues.toArray();
607        returnValues = tableValues != null ? ArrayUtil.concat(returnValues, tableValues.toArray()) : returnValues;
608        returnValues = joinValues != null ? ArrayUtil.concat(returnValues, joinValues.toArray()) : returnValues;
609        returnValues = ArrayUtil.concat(returnValues, paramValues);
610
611        return returnValues;
612    }
613
614
615    List<QueryWrapper> getChildSelect() {
616
617        List<QueryWrapper> whereChildQuery = WrapperUtil.getChildQueryWrapper(whereQueryCondition);
618        List<QueryWrapper> havingChildQuery = WrapperUtil.getChildQueryWrapper(havingQueryCondition);
619
620        if (whereChildQuery.isEmpty() && havingChildQuery.isEmpty()) {
621            return Collections.emptyList();
622        }
623
624        List<QueryWrapper> childQueryWrappers = new ArrayList<>(whereChildQuery);
625        childQueryWrappers.addAll(havingChildQuery);
626
627        return childQueryWrappers;
628    }
629
630
631    public String toSQL() {
632        String sql = DialectFactory.getDialect().forSelectByQuery(this);
633        return SqlUtil.replaceSqlParams(sql, getValueArray());
634    }
635
636
637}