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