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.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 CaseSearchQueryColumn extends QueryColumn implements HasParamsColumn {
031
032    private QueryColumn queryColumn;
033    private List<When> whens;
034    private Object elseValue;
035
036    @Override
037    String toSelectSql(List<QueryTable> queryTables, IDialect dialect) {
038        String sql = buildSql(queryTables, dialect);
039        if (StringUtil.isNotBlank(alias)) {
040            return WrapperUtil.withAlias(sql, alias, dialect);
041        }
042        return sql;
043    }
044
045    private String buildSql(List<QueryTable> queryTables, IDialect dialect) {
046        StringBuilder sql = new StringBuilder(SqlConsts.CASE);
047        sql.append(SqlConsts.BLANK).append(queryColumn.toSelectSql(queryTables, dialect));
048        for (When when : whens) {
049            sql.append(SqlConsts.WHEN).append(WrapperUtil.buildValue(queryTables, when.searchValue));
050            sql.append(SqlConsts.THEN).append(WrapperUtil.buildValue(queryTables, when.thenValue));
051        }
052        if (elseValue != null) {
053            sql.append(SqlConsts.ELSE).append(WrapperUtil.buildValue(queryTables, elseValue));
054        }
055        sql.append(SqlConsts.END);
056        return sql.toString();
057    }
058
059    @Override
060    public CaseSearchQueryColumn clone() {
061        CaseSearchQueryColumn clone = (CaseSearchQueryColumn) super.clone();
062        // deep clone ...
063        clone.queryColumn = ObjectUtil.clone(this.queryColumn);
064        clone.whens = CollectionUtil.cloneArrayList(this.whens);
065        clone.elseValue = ObjectUtil.cloneObject(this.elseValue);
066        return clone;
067    }
068
069
070    @Override
071    String toConditionSql(List<QueryTable> queryTables, IDialect dialect) {
072        return WrapperUtil.withBracket(buildSql(queryTables, dialect));
073    }
074
075    void addWhen(When when) {
076        if (whens == null) {
077            whens = new ArrayList<>();
078        }
079        whens.add(when);
080    }
081
082
083    @Override
084    public Object[] getParamValues() {
085        Object[] values = FlexConsts.EMPTY_ARRAY;
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 Object searchValue;
096        private Object thenValue;
097
098        public When(Object searchValue) {
099            this.searchValue = searchValue;
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.searchValue = ObjectUtil.cloneObject(this.searchValue);
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
122    public static class Builder {
123
124        private CaseSearchQueryColumn caseQueryColumn = new CaseSearchQueryColumn();
125        private When lastWhen;
126
127        public Builder(QueryColumn queryColumn) {
128            this.caseQueryColumn.queryColumn = queryColumn;
129        }
130
131        public Then when(Object searchValue) {
132            lastWhen = new When(searchValue);
133            return new Then(this);
134        }
135
136        public Builder else_(Object elseValue) {
137            caseQueryColumn.elseValue = elseValue;
138            return this;
139        }
140
141        public CaseSearchQueryColumn end() {
142            return caseQueryColumn;
143        }
144
145        public static class Then {
146
147            private Builder builder;
148
149            public Then(Builder builder) {
150                this.builder = builder;
151            }
152
153            public Builder then(Object thenValue) {
154                this.builder.lastWhen.setThenValue(thenValue);
155                this.builder.caseQueryColumn.addWhen(builder.lastWhen);
156                return builder;
157            }
158
159        }
160
161    }
162
163}