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.exception.FlexExceptions;
019import com.mybatisflex.core.table.TableDef;
020import com.mybatisflex.core.util.ArrayUtil;
021import com.mybatisflex.core.util.CollectionUtil;
022import com.mybatisflex.core.util.StringUtil;
023
024import java.util.*;
025
026public class QueryWrapper extends BaseQueryWrapper<QueryWrapper> {
027
028
029    public static QueryWrapper create() {
030        return new QueryWrapper();
031    }
032
033    public QueryWrapper select(QueryColumn... queryColumns) {
034        for (QueryColumn column : queryColumns) {
035            if (column != null) {
036                addSelectColumn(column);
037            }
038        }
039        return this;
040    }
041
042
043    public QueryWrapper from(TableDef... tableDefs) {
044        for (TableDef tableDef : tableDefs) {
045            from(new QueryTable(tableDef.getTableName()));
046        }
047        return this;
048    }
049
050
051    public QueryWrapper from(String... tables) {
052        for (String table : tables) {
053            if (StringUtil.isBlank(table)) {
054                throw new IllegalArgumentException("table must not be null or blank.");
055            }
056            from(new QueryTable(table));
057        }
058        return this;
059    }
060
061
062    public QueryWrapper from(QueryTable... tables) {
063        if (CollectionUtil.isEmpty(queryTables)) {
064            queryTables = new ArrayList<>();
065            queryTables.addAll(Arrays.asList(tables));
066        } else {
067            for (QueryTable table : tables) {
068                boolean contains = false;
069                for (QueryTable queryTable : queryTables) {
070                    if (queryTable.isSameTable(table)) {
071                        contains = true;
072                    }
073                }
074                if (!contains) {
075                    queryTables.add(table);
076                }
077            }
078        }
079        return this;
080    }
081
082
083    public QueryWrapper from(QueryWrapper queryWrapper) {
084        return from(new SelectQueryTable(queryWrapper));
085    }
086
087
088    public QueryWrapper as(String alias) {
089        if (CollectionUtil.isEmpty(queryTables)) {
090            throw new IllegalArgumentException("query table must not be empty.");
091        }
092        if (queryTables.size() > 1) {
093            throw FlexExceptions.wrap("QueryWrapper.as(...) only support 1 table");
094        }
095        queryTables.get(0).alias = alias;
096        return this;
097    }
098
099
100    public QueryWrapper where(QueryCondition queryCondition) {
101        this.setWhereQueryCondition(queryCondition);
102        return this;
103    }
104
105    public QueryWrapper where(String sql) {
106        this.setWhereQueryCondition(new StringQueryCondition(sql));
107        return this;
108    }
109
110
111    public QueryWrapper where(String sql, Object... params) {
112        this.setWhereQueryCondition(new StringQueryCondition(sql, params));
113        return this;
114    }
115
116
117    public QueryWrapper where(Map<String, Object> whereConditions) {
118        if (whereConditions != null) {
119            whereConditions.forEach((s, o) -> and(QueryCondition.create(new QueryColumn(s), o)));
120        }
121        return this;
122    }
123
124    public QueryWrapper and(QueryCondition queryCondition) {
125        return addWhereQueryCondition(queryCondition, SqlConnector.AND);
126    }
127
128    public QueryWrapper and(String sql) {
129        this.addWhereQueryCondition(new StringQueryCondition(sql), SqlConnector.AND);
130        return this;
131    }
132
133    public QueryWrapper and(String sql, Object... params) {
134        this.addWhereQueryCondition(new StringQueryCondition(sql, params), SqlConnector.AND);
135        return this;
136    }
137
138    public QueryWrapper or(QueryCondition queryCondition) {
139        return addWhereQueryCondition(queryCondition, SqlConnector.OR);
140    }
141
142    public QueryWrapper or(String sql) {
143        this.addWhereQueryCondition(new StringQueryCondition(sql), SqlConnector.OR);
144        return this;
145    }
146
147    public QueryWrapper or(String sql, Object... params) {
148        this.addWhereQueryCondition(new StringQueryCondition(sql, params), SqlConnector.OR);
149        return this;
150    }
151
152
153    public Joiner<QueryWrapper> leftJoin(String table) {
154        return joining(Join.TYPE_LEFT, table, true);
155    }
156
157
158    public Joiner<QueryWrapper> leftJoinIf(String table, boolean condition) {
159        return joining(Join.TYPE_LEFT, table, condition);
160    }
161
162    public Joiner<QueryWrapper> leftJoin(TableDef table) {
163        return joining(Join.TYPE_LEFT, table.getTableName(), true);
164    }
165
166
167    public Joiner<QueryWrapper> leftJoinIf(TableDef table, boolean condition) {
168        return joining(Join.TYPE_LEFT, table.getTableName(), condition);
169    }
170
171    public Joiner<QueryWrapper> leftJoin(QueryWrapper table) {
172        return joining(Join.TYPE_LEFT, table, true);
173    }
174
175    public Joiner<QueryWrapper> leftJoinIf(QueryWrapper table, boolean condition) {
176        return joining(Join.TYPE_LEFT, table, condition);
177    }
178
179    public Joiner<QueryWrapper> rightJoin(String table) {
180        return joining(Join.TYPE_RIGHT, table, true);
181    }
182
183    public Joiner<QueryWrapper> rightJoinIf(String table, boolean condition) {
184        return joining(Join.TYPE_RIGHT, table, condition);
185    }
186
187    public Joiner<QueryWrapper> rightJoin(QueryWrapper table) {
188        return joining(Join.TYPE_RIGHT, table, true);
189    }
190
191    public Joiner<QueryWrapper> rightJoinIf(QueryWrapper table, boolean condition) {
192        return joining(Join.TYPE_RIGHT, table, condition);
193    }
194
195    public Joiner<QueryWrapper> innerJoin(String table) {
196        return joining(Join.TYPE_INNER, table, true);
197    }
198
199    public Joiner<QueryWrapper> innerJoinIf(String table, boolean condition) {
200        return joining(Join.TYPE_INNER, table, condition);
201    }
202
203    public Joiner<QueryWrapper> innerJoin(TableDef table) {
204        return innerJoinIf(table, true);
205    }
206
207    public Joiner<QueryWrapper> innerJoinIf(TableDef table, boolean condition) {
208        return joining(Join.TYPE_INNER, table.getTableName(), condition);
209    }
210
211    public Joiner<QueryWrapper> innerJoin(QueryWrapper table) {
212        return joining(Join.TYPE_INNER, table, true);
213    }
214
215    public Joiner<QueryWrapper> innerJoinIf(QueryWrapper table, boolean condition) {
216        return joining(Join.TYPE_INNER, table, condition);
217    }
218
219    public Joiner<QueryWrapper> fullJoin(String table) {
220        return joining(Join.TYPE_FULL, table, true);
221    }
222
223    public Joiner<QueryWrapper> fullJoinIf(String table, boolean condition) {
224        return joining(Join.TYPE_FULL, table, condition);
225    }
226
227    public Joiner<QueryWrapper> fullJoin(QueryWrapper table) {
228        return joining(Join.TYPE_FULL, table, true);
229    }
230
231    public Joiner<QueryWrapper> fullJoinIf(QueryWrapper table, boolean condition) {
232        return joining(Join.TYPE_FULL, table, condition);
233    }
234
235    public Joiner<QueryWrapper> crossJoin(String table) {
236        return joining(Join.TYPE_CROSS, table, true);
237    }
238
239    public Joiner<QueryWrapper> crossJoinIf(String table, boolean condition) {
240        return joining(Join.TYPE_CROSS, table, condition);
241    }
242
243    public Joiner<QueryWrapper> crossJoin(QueryWrapper table) {
244        return joining(Join.TYPE_CROSS, table, true);
245    }
246
247    public Joiner<QueryWrapper> crossJoinIf(QueryWrapper table, boolean condition) {
248        return joining(Join.TYPE_CROSS, table, condition);
249    }
250
251    public QueryWrapper union(QueryWrapper unionQuery) {
252        if (unions == null) {
253            unions = new ArrayList<>();
254        }
255        unions.add(UnionWrapper.union(unionQuery));
256        return this;
257    }
258
259    public QueryWrapper unionAll(QueryWrapper unionQuery) {
260        if (unions == null) {
261            unions = new ArrayList<>();
262        }
263        unions.add(UnionWrapper.unionAll(unionQuery));
264        return this;
265    }
266
267    protected Joiner<QueryWrapper> joining(String type, String table, boolean condition) {
268        Join join = new Join(type, table, condition);
269        addJoinTable(join.getQueryTable());
270        return new Joiner<>(AddJoin(join), join);
271    }
272
273    protected Joiner<QueryWrapper> joining(String type, QueryWrapper queryWrapper, boolean condition) {
274        Join join = new Join(type, queryWrapper, condition);
275        addJoinTable(join.getQueryTable());
276        return new Joiner<>(AddJoin(join), join);
277    }
278
279
280    public QueryWrapper groupBy(String name) {
281        addGroupByColumns(new QueryColumn(name));
282        return this;
283    }
284
285    public QueryWrapper groupBy(String... names) {
286        for (String name : names) {
287            groupBy(name);
288        }
289        return this;
290    }
291
292    public QueryWrapper groupBy(QueryColumn column) {
293        addGroupByColumns(column);
294        return this;
295    }
296
297    public QueryWrapper groupBy(QueryColumn... columns) {
298        for (QueryColumn column : columns) {
299            groupBy(column);
300        }
301        return this;
302    }
303
304
305    public QueryWrapper having(QueryCondition queryCondition) {
306        addHavingQueryCondition(queryCondition, SqlConnector.AND);
307        return this;
308    }
309
310    public QueryWrapper orderBy(QueryOrderBy... orderBys) {
311        for (QueryOrderBy queryOrderBy : orderBys) {
312            addOrderBy(queryOrderBy);
313        }
314        return this;
315    }
316
317    public QueryWrapper orderBy(String... orderBys) {
318        for (String queryOrderBy : orderBys) {
319            addOrderBy(new StringQueryOrderBy(queryOrderBy));
320        }
321        return this;
322    }
323
324
325    public QueryWrapper limit(Integer rows) {
326        setLimitRows(rows);
327        return this;
328    }
329
330    public QueryWrapper offset(Integer offset) {
331        setLimitOffset(offset);
332        return this;
333    }
334
335    public QueryWrapper limit(Integer offset, Integer rows) {
336        setLimitOffset(offset);
337        setLimitRows(rows);
338        return this;
339    }
340
341    public QueryWrapper datasource(String datasource) {
342        setDatasource(datasource);
343        return this;
344    }
345
346    /**
347     * 获取 queryWrapper 的参数
348     * 在构建 sql 的时候,需要保证 where 在 having 的前面
349     */
350    Object[] getValueArray() {
351        Object[] whereValues = WrapperUtil.getValues(whereQueryCondition);
352        Object[] havingValues = WrapperUtil.getValues(havingQueryCondition);
353        Object[] values = ArrayUtil.concat(whereValues, havingValues);
354        if (CollectionUtil.isNotEmpty(unions)) {
355            for (UnionWrapper union : unions) {
356                QueryWrapper queryWrapper = union.getQueryWrapper();
357                values = ArrayUtil.concat(values, queryWrapper.getValueArray());
358            }
359        }
360        return values;
361    }
362
363
364    List<QueryWrapper> getChildSelect() {
365
366        List<QueryWrapper> whereChildQuery= WrapperUtil.getChildSelect(whereQueryCondition);
367        List<QueryWrapper> havingChildQuery = WrapperUtil.getChildSelect(havingQueryCondition);
368
369        if (whereChildQuery.isEmpty() && havingChildQuery.isEmpty()){
370            return Collections.emptyList();
371        }
372
373        List<QueryWrapper> childQueryWrappers = new ArrayList<>(whereChildQuery);
374        childQueryWrappers.addAll(havingChildQuery);
375
376        return childQueryWrappers;
377    }
378
379
380}