001/*
002 *  Copyright (c) 2022-2024, 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.constant.SqlConsts;
020import com.mybatisflex.core.dialect.IDialect;
021import com.mybatisflex.core.exception.FlexExceptions;
022import com.mybatisflex.core.util.ArrayUtil;
023import com.mybatisflex.core.util.CollectionUtil;
024import com.mybatisflex.core.util.ObjectUtil;
025import com.mybatisflex.core.util.StringUtil;
026
027import java.util.ArrayList;
028import java.util.List;
029
030public class CaseQueryColumn extends QueryColumn implements HasParamsColumn {
031
032    private List<When> whens;
033    private Object elseValue;
034
035    void addWhen(When when) {
036        if (whens == null) {
037            whens = new ArrayList<>();
038        }
039        whens.add(when);
040    }
041
042
043    @Override
044    protected String toSelectSql(List<QueryTable> queryTables, IDialect dialect) {
045        String sql = buildSql(queryTables, dialect);
046        if (StringUtil.isNotBlank(alias)) {
047            return WrapperUtil.withAlias(sql, alias, dialect);
048        }
049        return sql;
050    }
051
052    @Override
053    public CaseQueryColumn clone() {
054        CaseQueryColumn clone = (CaseQueryColumn) super.clone();
055        // deep clone ...
056        clone.whens = CollectionUtil.cloneArrayList(this.whens);
057        clone.elseValue = ObjectUtil.cloneObject(this.elseValue);
058        return clone;
059    }
060
061
062    @Override
063    protected String toConditionSql(List<QueryTable> queryTables, IDialect dialect) {
064        return WrapperUtil.withBracket(buildSql(queryTables, dialect));
065    }
066
067    private String buildSql(List<QueryTable> queryTables, IDialect dialect) {
068        StringBuilder sql = new StringBuilder(SqlConsts.CASE);
069        for (When when : whens) {
070            sql.append(SqlConsts.WHEN).append(when.whenCondition.toSql(queryTables, dialect));
071            sql.append(SqlConsts.THEN).append(WrapperUtil.buildValue(queryTables, when.thenValue));
072        }
073        if (elseValue != null) {
074            sql.append(SqlConsts.ELSE).append(WrapperUtil.buildValue(queryTables, elseValue));
075        }
076        sql.append(SqlConsts.END);
077        return sql.toString();
078    }
079
080    @Override
081    public Object[] getParamValues() {
082        Object[] values = FlexConsts.EMPTY_ARRAY;
083        for (When when : whens) {
084            values = ArrayUtil.concat(values, WrapperUtil.getValues(when.whenCondition));
085        }
086        if (elseValue instanceof HasParamsColumn) {
087            values = ArrayUtil.concat(values, ((HasParamsColumn) elseValue).getParamValues());
088        }
089        return values;
090    }
091
092
093    public static class When implements CloneSupport<When> {
094
095        private QueryCondition whenCondition;
096        private Object thenValue;
097
098        public When(QueryCondition whenCondition) {
099            this.whenCondition = whenCondition;
100        }
101
102        public void setThenValue(Object thenValue) {
103            this.thenValue = thenValue;
104        }
105
106        @Override
107        public When clone() {
108            try {
109                When clone = (When) super.clone();
110                // deep clone ...
111                clone.whenCondition = ObjectUtil.clone(this.whenCondition);
112                clone.thenValue = ObjectUtil.cloneObject(this.thenValue);
113                return clone;
114            } catch (CloneNotSupportedException e) {
115                throw FlexExceptions.wrap(e);
116            }
117        }
118
119    }
120
121    public static class Builder {
122
123        private CaseQueryColumn caseQueryColumn = new CaseQueryColumn();
124        private When lastWhen;
125
126        public Then when(QueryCondition condition) {
127            lastWhen = new When(condition);
128            return new Then(this);
129        }
130
131        public Builder else_(Object elseValue) {
132            caseQueryColumn.elseValue = elseValue;
133            return this;
134        }
135
136        public CaseQueryColumn end() {
137            return caseQueryColumn;
138        }
139
140        public static class Then {
141
142            private Builder builder;
143
144            public Then(Builder builder) {
145                this.builder = builder;
146            }
147
148            public Builder then(Object thenValue) {
149                this.builder.lastWhen.setThenValue(thenValue);
150                this.builder.caseQueryColumn.addWhen(builder.lastWhen);
151                return builder;
152            }
153
154        }
155
156    }
157
158}