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 CaseQueryColumn extends QueryColumn implements HasParamsColumn {
030
031    private List<When> whens;
032    private Object elseValue;
033
034    void addWhen(When when) {
035        if (whens == null) {
036            whens = new ArrayList<>();
037        }
038        whens.add(when);
039    }
040
041
042    @Override
043    String toSelectSql(List<QueryTable> queryTables, IDialect dialect) {
044        StringBuilder sql = new StringBuilder("CASE");
045        for (When when : whens) {
046            sql.append(" WHEN ").append(when.whenCondition.toSql(queryTables, dialect));
047            sql.append(" THEN ").append(buildValue(when.thenValue));
048        }
049        if (elseValue != null) {
050            sql.append(" ELSE ").append(buildValue(elseValue));
051        }
052        sql.append(" END");
053        if (StringUtil.isNotBlank(alias)) {
054            return "(" + sql + ") AS " + dialect.wrap(alias);
055        }
056        return sql.toString();
057    }
058
059
060    @Override
061    String toConditionSql(List<QueryTable> queryTables, IDialect dialect) {
062        StringBuilder sql = new StringBuilder("CASE");
063        for (When when : whens) {
064            sql.append(" WHEN ").append(when.whenCondition.toSql(queryTables, dialect));
065            sql.append(" THEN ").append(buildValue(when.thenValue));
066        }
067        if (elseValue != null) {
068            sql.append(" ELSE ").append(buildValue(elseValue));
069        }
070        sql.append(" END");
071        return "(" + sql + ")";
072    }
073
074    @Override
075    public QueryColumn as(String alias) {
076        this.alias = alias;
077        return this;
078    }
079
080    @Override
081    public <T> QueryColumn as(LambdaGetter<T> fn) {
082        return as(LambdaUtil.getFieldName(fn));
083    }
084
085    private String buildValue(Object value) {
086        if (value instanceof Number || value instanceof Boolean) {
087            return String.valueOf(value);
088        } else if (value instanceof RawFragment) {
089            return ((RawFragment) value).getContent();
090        } else if (value instanceof QueryColumn) {
091            return ((QueryColumn) value).toConditionSql(null, DialectFactory.getDialect());
092        } else {
093            return "'" + value + "'";
094        }
095    }
096
097    @Override
098    public Object[] getParamValues() {
099        Object[] values = FlexConsts.EMPTY_ARRAY;
100        for (When when : whens) {
101            values = ArrayUtil.concat(values, WrapperUtil.getValues(when.whenCondition));
102        }
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 QueryCondition whenCondition;
113        private Object thenValue;
114
115        public When(Builder builder, QueryCondition whenCondition) {
116            this.builder = builder;
117            this.whenCondition = whenCondition;
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 CaseQueryColumn caseQueryColumn = new CaseQueryColumn();
130
131        public When when(QueryCondition condition) {
132            return new When(this, condition);
133        }
134
135        public Builder else_(Object elseValue) {
136            caseQueryColumn.elseValue = elseValue;
137            return this;
138        }
139
140        public CaseQueryColumn end() {
141            return caseQueryColumn;
142        }
143    }
144}