001/*
002 *  Copyright (c) 2022-2025, 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.FlexConsts;
020import com.mybatisflex.core.constant.SqlConsts;
021import com.mybatisflex.core.dialect.DialectFactory;
022import com.mybatisflex.core.dialect.IDialect;
023import com.mybatisflex.core.dialect.impl.OracleDialect;
024import com.mybatisflex.core.util.ClassUtil;
025import com.mybatisflex.core.util.EnumWrapper;
026import com.mybatisflex.core.util.StringUtil;
027
028import java.lang.reflect.Array;
029import java.util.ArrayList;
030import java.util.Arrays;
031import java.util.Collections;
032import java.util.List;
033
034class WrapperUtil {
035
036    private WrapperUtil() {
037    }
038
039    static List<QueryWrapper> getChildQueryWrapper(QueryCondition condition) {
040        List<QueryWrapper> list = null;
041        while (condition != null) {
042            if (condition.checkEffective()) {
043                if (condition instanceof Brackets) {
044                    List<QueryWrapper> childQueryWrapper = getChildQueryWrapper(((Brackets) condition).getChildCondition());
045                    if (!childQueryWrapper.isEmpty()) {
046                        if (list == null) {
047                            list = new ArrayList<>();
048                        }
049                        list.addAll(childQueryWrapper);
050                    }
051                }
052                // not Brackets
053                else {
054                    Object value = condition.getValue();
055                    if (value instanceof QueryWrapper) {
056                        if (list == null) {
057                            list = new ArrayList<>();
058                        }
059                        list.add((QueryWrapper) value);
060                        list.addAll(((QueryWrapper) value).getChildSelect());
061                    } else if (value != null && value.getClass().isArray()) {
062                        for (int i = 0; i < Array.getLength(value); i++) {
063                            Object arrayValue = Array.get(value, i);
064                            if (arrayValue instanceof QueryWrapper) {
065                                if (list == null) {
066                                    list = new ArrayList<>();
067                                }
068                                list.add((QueryWrapper) arrayValue);
069                                list.addAll(((QueryWrapper) arrayValue).getChildSelect());
070                            }
071                        }
072                    }
073                }
074            }
075            condition = condition.next;
076        }
077        return list == null ? Collections.emptyList() : list;
078    }
079
080
081    static Object[] getValues(QueryCondition condition) {
082        if (condition == null) {
083            return FlexConsts.EMPTY_ARRAY;
084        }
085
086        List<Object> params = new ArrayList<>();
087        getValues(condition, params);
088
089        return params.isEmpty() ? FlexConsts.EMPTY_ARRAY : params.toArray();
090    }
091
092
093    private static void getValues(QueryCondition condition, List<Object> params) {
094        if (condition == null) {
095            return;
096        }
097
098        QueryColumn column = condition.getColumn();
099        if (column instanceof HasParamsColumn) {
100            addParam(params, ((HasParamsColumn) column).getParamValues());
101        }
102
103        Object value = condition.getValue();
104
105        if (value == null) {
106            // column = user_name; logic = eq; value = null
107            // sql: user_name = null
108            String logic;
109            if (condition.checkEffective()
110                && (logic = condition.getLogic()) != null
111                && !logic.equals(SqlConsts.IS_NULL)
112                && !logic.equals(SqlConsts.IS_NOT_NULL)) {
113                params.add(null);
114            }
115            getValues(condition.next, params);
116            return;
117        }
118
119        if (value instanceof QueryColumn || value instanceof RawQueryCondition) {
120            getValues(condition.next, params);
121            return;
122        }
123
124        addParam(params, value);
125        getValues(condition.next, params);
126    }
127
128    @SuppressWarnings("all")
129    private static void addParam(List<Object> paras, Object value) {
130        if (value == null) {
131            paras.add(null);
132        } else if (ClassUtil.isArray(value.getClass())) {
133            for (int i = 0; i < Array.getLength(value); i++) {
134                addParam(paras, Array.get(value, i));
135            }
136        } else if (value instanceof QueryWrapper) {
137            Object[] valueArray = ((QueryWrapper) value).getAllValueArray();
138            paras.addAll(Arrays.asList(valueArray));
139        } else if (value instanceof Enum) {
140            // 枚举类型,处理枚举实际值
141            EnumWrapper enumWrapper = EnumWrapper.of(value.getClass());
142            // 如果是使用注解标识枚举实际值,则直接获取实际值,但如果是依靠全局枚举TypeHandler处理,则此处只能先存入枚举实例,在SQL执行时才能处理实际值
143            value = enumWrapper.hasEnumValueAnnotation() ? enumWrapper.getEnumValue((Enum) value) : value;
144            paras.add(value);
145        } else {
146            paras.add(value);
147        }
148
149    }
150
151    static String buildValue(List<QueryTable> queryTables, Object value) {
152        if (value instanceof Number || value instanceof Boolean) {
153            return String.valueOf(value);
154        } else if (value instanceof RawQueryCondition) {
155            return ((RawQueryCondition) value).getContent();
156        } else if (value instanceof QueryColumn) {
157            return ((QueryColumn) value).toConditionSql(queryTables, DialectFactory.getDialect());
158        } else {
159            return SqlConsts.SINGLE_QUOTE + value + SqlConsts.SINGLE_QUOTE;
160        }
161    }
162
163
164    static String withBracket(String sql) {
165        return SqlConsts.BRACKET_LEFT + sql + SqlConsts.BRACKET_RIGHT;
166    }
167
168    static String withAlias(String sql, String alias, IDialect dialect) {
169        return SqlConsts.BRACKET_LEFT + sql + SqlConsts.BRACKET_RIGHT + buildColumnAlias(alias, dialect);
170    }
171
172    static String buildAlias(String alias, IDialect dialect) {
173        return StringUtil.noText(alias) ? SqlConsts.EMPTY : getAsKeyWord(dialect) + dialect.wrap(alias);
174    }
175
176    static String buildColumnAlias(String alias, IDialect dialect) {
177        return StringUtil.noText(alias) ? SqlConsts.EMPTY : getAsKeyWord(dialect) + dialect.wrapColumnAlias(alias);
178    }
179
180    private static String getAsKeyWord(IDialect dialect) {
181        return dialect instanceof OracleDialect ? SqlConsts.BLANK : SqlConsts.AS;
182    }
183
184}