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.SqlConsts;
019import com.mybatisflex.core.dialect.IDialect;
020import com.mybatisflex.core.dialect.OperateType;
021import com.mybatisflex.core.exception.FlexExceptions;
022import com.mybatisflex.core.util.ObjectUtil;
023
024import java.util.ArrayList;
025import java.util.List;
026import java.util.function.Supplier;
027
028/**
029 * @author michael yang (fuhai999@gmail.com)
030 * @Date: 2020/1/14
031 */
032public class Join implements CloneSupport<Join> {
033
034    private static final long serialVersionUID = 1L;
035
036
037    protected final String type;
038    protected QueryTable queryTable;
039    protected QueryCondition on;
040    protected boolean effective;
041
042    public Join(String type, QueryTable table, boolean when) {
043        this.type = type;
044        this.queryTable = table;
045        this.effective = when;
046    }
047
048    public Join(String type, QueryWrapper queryWrapper, boolean when) {
049        this.type = type;
050        this.queryTable = new SelectQueryTable(queryWrapper);
051        this.effective = when;
052    }
053
054
055    QueryTable getQueryTable() {
056        return queryTable;
057    }
058
059
060    public void on(QueryCondition condition) {
061        replaceConditionColumn(condition);
062        this.on = condition;
063    }
064
065    private void replaceConditionColumn(QueryCondition condition) {
066        if (condition != null) {
067            if (condition.checkEffective() && condition.column != null) {
068                QueryTable table = condition.column.getTable();
069                if (queryTable.isSameTable(table)) {
070                    QueryColumn newColumn = condition.column.clone();
071                    newColumn.table.alias = queryTable.alias;
072                    condition.column = newColumn;
073                }
074            } else if (condition instanceof Brackets) {
075                replaceConditionColumn(((Brackets) condition).getChildCondition());
076            } else if (condition instanceof OperatorQueryCondition) {
077                replaceConditionColumn(((OperatorQueryCondition) condition).getChildCondition());
078            } else if (condition instanceof OperatorSelectCondition) {
079                QueryWrapper qw = ((OperatorSelectCondition) condition).getQueryWrapper();
080                replaceConditionColumn(qw.whereQueryCondition);
081            }
082            replaceConditionColumn(condition.next);
083        }
084    }
085
086
087    QueryCondition getOnCondition() {
088        return on;
089    }
090
091    public boolean checkEffective() {
092        return effective;
093    }
094
095    public void when(boolean when) {
096        this.effective = when;
097    }
098
099    public void when(Supplier<Boolean> fn) {
100        this.effective = fn.get();
101    }
102
103    public String toSql(List<QueryTable> queryTables, IDialect dialect, OperateType operateType) {
104        //left join, right join,  inner join ...
105        StringBuilder sql = new StringBuilder(type);
106        sql.append(queryTable.toSql(dialect,operateType));
107
108        //left join xxx as xxx2 on xxx2.id = xxx3.other
109        List<QueryTable> newQueryTables = new ArrayList<>(queryTables);
110        newQueryTables.add(queryTable);
111        sql.append(SqlConsts.ON).append(on.toSql(newQueryTables, dialect));
112        return sql.toString();
113    }
114
115    @Override
116    public Join clone() {
117        try {
118            Join clone = (Join) super.clone();
119            // deep clone ...
120            clone.queryTable = ObjectUtil.clone(this.queryTable);
121            clone.on = ObjectUtil.clone(this.on);
122            return clone;
123        } catch (CloneNotSupportedException e) {
124            throw FlexExceptions.wrap(e);
125        }
126    }
127
128}