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.SqlConnector;
019import com.mybatisflex.core.constant.SqlConsts;
020import com.mybatisflex.core.dialect.IDialect;
021import com.mybatisflex.core.util.ObjectUtil;
022import com.mybatisflex.core.util.StringUtil;
023
024import java.util.List;
025
026/**
027 * 括号
028 */
029public class Brackets extends QueryCondition {
030
031    private QueryCondition childCondition;
032
033    public Brackets(QueryCondition childCondition) {
034        this.childCondition = childCondition;
035    }
036
037    @Override
038    public QueryColumn getColumn() {
039        return childCondition.getColumn();
040    }
041
042    @Override
043    public void setColumn(QueryColumn column) {
044        childCondition.setColumn(column);
045    }
046
047    @Override
048    public void setValue(Object value) {
049        childCondition.setValue(value);
050    }
051
052    @Override
053    public String getLogic() {
054        return childCondition.getLogic();
055    }
056
057    @Override
058    public void setLogic(String logic) {
059        childCondition.setLogic(logic);
060    }
061
062    @Override
063    protected QueryCondition getNextEffectiveCondition() {
064        return childCondition.getNextEffectiveCondition();
065    }
066
067    @Override
068    public QueryCondition and(QueryCondition nextCondition) {
069        connectToChild(nextCondition, SqlConnector.AND);
070        return this;
071    }
072
073    @Override
074    public QueryCondition or(QueryCondition nextCondition) {
075        connectToChild(nextCondition, SqlConnector.OR);
076        return this;
077    }
078
079    protected void connectToChild(QueryCondition nextCondition, SqlConnector connector) {
080        childCondition.connect(nextCondition, connector);
081    }
082
083    @Override
084    public Object getValue() {
085        return checkEffective() ? WrapperUtil.getValues(childCondition) : null;
086    }
087
088    public QueryCondition getChildCondition() {
089        return childCondition;
090    }
091
092    @Override
093    public boolean checkEffective() {
094        boolean effective = super.checkEffective();
095        if (!effective) {
096            return false;
097        }
098        QueryCondition condition = this.childCondition;
099        while (condition != null) {
100            if (condition.checkEffective()) {
101                return true;
102            }
103            condition = condition.next;
104        }
105        return false;
106    }
107
108    @Override
109    public String toSql(List<QueryTable> queryTables, IDialect dialect) {
110
111        String sqlNext = next == null ? null : next.toSql(queryTables, dialect);
112
113        StringBuilder sql = new StringBuilder();
114        if (checkEffective()) {
115            String childSql = childCondition.toSql(queryTables, dialect);
116            if (StringUtil.hasText(childSql)) {
117                QueryCondition prevEffectiveCondition = getPrevEffectiveCondition();
118                if (prevEffectiveCondition != null && this.connector != null) {
119                    childSql = this.connector + SqlConsts.BRACKET_LEFT + childSql + SqlConsts.BRACKET_RIGHT;
120                } else if (StringUtil.hasText(sqlNext)) {
121                    childSql = SqlConsts.BRACKET_LEFT + childSql + SqlConsts.BRACKET_RIGHT;
122                }
123                sql.append(childSql);
124            } else {
125                //all child conditions are not effective
126                //fixed gitee #I6W89G
127                this.effective = false;
128            }
129        }
130
131        return sqlNext != null ? sql + sqlNext : sql.toString();
132    }
133
134
135    @Override
136    boolean containsTable(String... tables) {
137        if (childCondition != null && childCondition.containsTable(tables)) {
138            return true;
139        }
140        return nextContainsTable(tables);
141    }
142
143    @Override
144    public String toString() {
145        return "Brackets{" +
146            "childCondition=" + childCondition +
147            '}';
148    }
149
150    @Override
151    public Brackets clone() {
152        Brackets clone = (Brackets) super.clone();
153        // deep clone ...
154        clone.childCondition = ObjectUtil.clone(this.childCondition);
155        return clone;
156    }
157
158}