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