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.dialect.IDialect;
021import com.mybatisflex.core.util.ArrayUtil;
022import com.mybatisflex.core.util.LambdaGetter;
023import com.mybatisflex.core.util.LambdaUtil;
024import com.mybatisflex.core.util.StringUtil;
025
026import java.util.ArrayList;
027import java.util.List;
028
029public class CaseSearchQueryColumn extends QueryColumn implements HasParamsColumn {
030
031    private QueryColumn queryColumn;
032    private List<When> whens;
033    private Object elseValue;
034
035    @Override
036    String toSelectSql(List<QueryTable> queryTables, IDialect dialect) {
037        StringBuilder sql = new StringBuilder("CASE ");
038        sql.append(queryColumn.toSelectSql(queryTables, dialect));
039        for (When when : whens) {
040            sql.append(" WHEN ").append(buildValue(when.searchValue)).append(" THEN ").append(buildValue(when.thenValue));
041        }
042        if (elseValue != null) {
043            sql.append(" ELSE ").append(buildValue(elseValue));
044        }
045        sql.append(" END");
046        if (StringUtil.isNotBlank(alias)) {
047            return "(" + sql + ") AS " + dialect.wrap(alias);
048        }
049        return sql.toString();
050    }
051
052
053    @Override
054    String toConditionSql(List<QueryTable> queryTables, IDialect dialect) {
055        StringBuilder sql = new StringBuilder("CASE ");
056        sql.append(queryColumn.toSelectSql(queryTables, dialect));
057        for (When when : whens) {
058            sql.append(" WHEN ").append(buildValue(when.searchValue)).append(" THEN ").append(buildValue(when.thenValue));
059        }
060        if (elseValue != null) {
061            sql.append(" ELSE ").append(buildValue(elseValue));
062        }
063        sql.append(" END");
064        return "(" + sql + ")";
065    }
066
067
068    private String buildValue(Object value) {
069        if (value instanceof Number || value instanceof Boolean) {
070            return String.valueOf(value);
071        } else if (value instanceof RawFragment) {
072            return ((RawFragment) value).getContent();
073        } else if (value instanceof QueryColumn) {
074            return ((QueryColumn) value).toConditionSql(null, DialectFactory.getDialect());
075        } else {
076            return "'" + value + "'";
077        }
078    }
079
080
081    void addWhen(When when) {
082        if (whens == null) {
083            whens = new ArrayList<>();
084        }
085        whens.add(when);
086    }
087
088    @Override
089    public QueryColumn as(String alias) {
090        this.alias = alias;
091        return this;
092    }
093
094    @Override
095    public <T> QueryColumn as(LambdaGetter<T> fn) {
096        return as(LambdaUtil.getFieldName(fn));
097    }
098
099
100    @Override
101    public Object[] getParamValues() {
102        Object[] values = FlexConsts.EMPTY_ARRAY;
103        if (elseValue instanceof HasParamsColumn) {
104            values = ArrayUtil.concat(values, ((HasParamsColumn) elseValue).getParamValues());
105        }
106        return values;
107    }
108
109
110    public static class When {
111        private Builder builder;
112        private Object searchValue;
113        private Object thenValue;
114
115        public When(Builder builder, Object searchValue) {
116            this.builder = builder;
117            this.searchValue = searchValue;
118        }
119
120        public Builder then(Object thenValue) {
121            this.thenValue = thenValue;
122            this.builder.caseQueryColumn.addWhen(this);
123            return builder;
124        }
125    }
126
127    public static class Builder {
128
129        private CaseSearchQueryColumn caseQueryColumn = new CaseSearchQueryColumn();
130
131        public Builder(QueryColumn queryColumn) {
132            this.caseQueryColumn.queryColumn = queryColumn;
133        }
134
135        public When when(Object searchValue) {
136            return new When(this, searchValue);
137        }
138
139        public Builder else_(Object elseValue) {
140            caseQueryColumn.elseValue = elseValue;
141            return this;
142        }
143
144        public CaseSearchQueryColumn end() {
145            return caseQueryColumn;
146        }
147    }
148}