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
018import com.mybatisflex.core.constant.SqlConsts;
019import com.mybatisflex.core.constant.SqlOperator;
020
021import java.util.Iterator;
022import java.util.Objects;
023import java.util.function.Function;
024import java.util.function.Predicate;
025
026/**
027 * 默认 {@link QueryColumn} 行为。
028 *
029 * @author michael
030 * @author 王帅
031 * @author CloudPlayer
032 */
033public class QueryColumnBehavior {
034
035    private QueryColumnBehavior() {
036    }
037
038    /**
039     * 内置的可选的忽略规则
040     */
041    public static final Predicate<Object> IGNORE_NULL = Objects::isNull;
042    public static final Predicate<Object> IGNORE_NONE = o -> Boolean.FALSE;
043    public static final Predicate<Object> IGNORE_EMPTY = o -> o == null || "".equals(o);
044    public static final Predicate<Object> IGNORE_BLANK = o -> o == null || o.toString().trim().isEmpty();
045
046    /**
047     * 在满足输入的数组或可迭代对象中的容量为 1 (即只有一个元素)时,自动将条件中的 in 转换为 =
048     */
049    public static final Function<? super QueryCondition, ? extends QueryCondition> CONVERT_IN_TO_EQUALS = it -> {
050        Object value = it.value;
051        if (it.logic.equalsIgnoreCase(SqlConsts.IN) || it.logic.equalsIgnoreCase(SqlConsts.NOT_IN)) {
052            Object firstValue;
053            if (value instanceof Iterable<?>) {
054                Iterator<?> iter = ((Iterable<?>) value).iterator();
055                if (!iter.hasNext()) {  // 没有元素,直接返回原条件
056                    return it;
057                }
058                firstValue = iter.next();  // 取第一个元素
059                if (iter.hasNext()) {  // 如果有后续元素,则直接返回原条件
060                    return it;
061                }
062            } else if (value instanceof Object[]) {
063                Object[] array = (Object[]) value;
064                if (array.length != 1) {  // 如果不是单元素的数组就直接返回
065                    return it;
066                }
067                firstValue = array[0];  // 取第一个元素
068            } else {
069                return it;
070            }
071
072            SqlOperator operator = it.logic.equalsIgnoreCase(SqlConsts.IN) ? SqlOperator.EQUALS : SqlOperator.NOT_EQUALS;
073            return QueryCondition.create(it.column, operator, firstValue);  // 将 in 转换为 =
074        } else {
075            return it;
076        }
077    };
078
079    /**
080     * 如果使用了 = 来比较 null ,则将其转为 is null 。
081     */
082    public static final Function<? super QueryCondition, ? extends QueryCondition> CONVERT_EQUALS_TO_IS_NULL = it ->
083        it.value == null && it.logic.equalsIgnoreCase(SqlConsts.EQUALS) ? it.column.isNull() : it;
084    /**
085     * 自定义全局的自动忽略参数的方法。
086     */
087    private static Predicate<Object> ignoreFunction = IGNORE_NULL;
088
089    /**
090     * 自定义全局的自动转换条件的方法。
091     */
092    private static Function<? super QueryCondition, ? extends QueryCondition> conditionCaster = Function.identity();
093
094    /**
095     * 当 {@code IN(...)} 条件只有 1 个参数时,是否自动把的内容转换为相等。
096     */
097    private static boolean smartConvertInToEquals = true;
098
099    /**
100     * 当 {@code BETWEEN ... AND ...} 条件只有 1 个参数时,是否自动把的内容转换为小于等于或大于等于。
101     */
102    private static boolean smartConvertBetweenToLeOrGe = true;
103
104    public static Predicate<Object> getIgnoreFunction() {
105        return ignoreFunction;
106    }
107
108    public static void setIgnoreFunction(Predicate<Object> ignoreFunction) {
109        QueryColumnBehavior.ignoreFunction = ignoreFunction;
110    }
111
112    public static boolean isSmartConvertInToEquals() {
113        return smartConvertInToEquals;
114    }
115
116    public static void setSmartConvertInToEquals(boolean smartConvertInToEquals) {
117        QueryColumnBehavior.smartConvertInToEquals = smartConvertInToEquals;
118    }
119
120    public static boolean isSmartConvertBetweenToLeOrGe() {
121        return smartConvertBetweenToLeOrGe;
122    }
123
124    public static void setSmartConvertBetweenToLeOrGe(boolean smartConvertBetweenToLeOrGe) {
125        QueryColumnBehavior.smartConvertBetweenToLeOrGe = smartConvertBetweenToLeOrGe;
126    }
127
128    static boolean shouldIgnoreValue(Object value) {
129        return ignoreFunction.test(value);
130    }
131
132    public static Function<? super QueryCondition, ? extends QueryCondition> getConditionCaster() {
133        return smartConvertInToEquals ? CONVERT_IN_TO_EQUALS.andThen(conditionCaster) : conditionCaster;
134    }
135
136    public static void setConditionCaster(Function<? super QueryCondition, ? extends QueryCondition> conditionCaster) {
137        QueryColumnBehavior.conditionCaster = conditionCaster;
138    }
139
140    public static QueryCondition castCondition(QueryCondition condition) {
141        return getConditionCaster().apply(condition);
142    }
143
144}