JoinOperations.java
/*
* Copyright 2016-2026 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mybatis.dynamic.sql.dsl;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import org.jspecify.annotations.Nullable;
import org.mybatis.dynamic.sql.AndOrCriteriaGroup;
import org.mybatis.dynamic.sql.BindableColumn;
import org.mybatis.dynamic.sql.ColumnAndConditionCriterion;
import org.mybatis.dynamic.sql.RenderableCondition;
import org.mybatis.dynamic.sql.SqlCriterion;
import org.mybatis.dynamic.sql.SqlTable;
import org.mybatis.dynamic.sql.TableExpression;
import org.mybatis.dynamic.sql.select.SelectModel;
import org.mybatis.dynamic.sql.select.SubQuery;
import org.mybatis.dynamic.sql.select.join.JoinType;
import org.mybatis.dynamic.sql.util.Buildable;
public interface JoinOperations<F extends BooleanOperations<F>> {
F join(JoinType joinType, TableExpression joinTable, SqlCriterion initialCriterion);
F join(JoinType joinType, SqlTable joinTable, String tableAlias, SqlCriterion initialCriterion);
default JoinOnGatherer<F> join(SqlTable joinTable) {
return new JoinOnGatherer<>(ic -> join(JoinType.INNER, joinTable, ic));
}
default JoinOnGatherer<F> join(SqlTable joinTable, String tableAlias) {
return new JoinOnGatherer<>(ic -> join(JoinType.INNER, joinTable, tableAlias, ic));
}
default JoinOnGatherer<F> join(Buildable<SelectModel> joinTable, @Nullable String tableAlias) {
return new JoinOnGatherer<>(ic -> join(JoinType.INNER, buildSubQuery(joinTable, tableAlias), ic));
}
default F join(SqlTable joinTable, SqlCriterion onJoinCriterion,
AndOrCriteriaGroup... andJoinCriteria) {
return join(joinTable, onJoinCriterion, Arrays.asList(andJoinCriteria));
}
default F join(SqlTable joinTable, String tableAlias, SqlCriterion onJoinCriterion,
AndOrCriteriaGroup... andJoinCriteria) {
return join(joinTable, tableAlias, onJoinCriterion, Arrays.asList(andJoinCriteria));
}
default F join(SqlTable joinTable, SqlCriterion onJoinCriterion,
List<AndOrCriteriaGroup> andJoinCriteria) {
return join(joinTable).on(onJoinCriterion).and(andJoinCriteria);
}
default F join(SqlTable joinTable, String tableAlias, SqlCriterion onJoinCriterion,
List<AndOrCriteriaGroup> andJoinCriteria) {
return join(joinTable, tableAlias).on(onJoinCriterion).and(andJoinCriteria);
}
default F join(Buildable<SelectModel> subQuery, @Nullable String tableAlias, SqlCriterion onJoinCriterion,
List<AndOrCriteriaGroup> andJoinCriteria) {
return join(subQuery, tableAlias).on(onJoinCriterion).and(andJoinCriteria);
}
default JoinOnGatherer<F> leftJoin(SqlTable joinTable) {
return new JoinOnGatherer<>(ic -> join(JoinType.LEFT, joinTable, ic));
}
default JoinOnGatherer<F> leftJoin(SqlTable joinTable, String tableAlias) {
return new JoinOnGatherer<>(ic -> join(JoinType.LEFT, joinTable, tableAlias, ic));
}
default JoinOnGatherer<F> leftJoin(Buildable<SelectModel> joinTable, @Nullable String tableAlias) {
return new JoinOnGatherer<>(ic -> join(JoinType.LEFT, buildSubQuery(joinTable, tableAlias), ic));
}
default F leftJoin(SqlTable joinTable, SqlCriterion onJoinCriterion,
AndOrCriteriaGroup... andJoinCriteria) {
return leftJoin(joinTable, onJoinCriterion, Arrays.asList(andJoinCriteria));
}
default F leftJoin(SqlTable joinTable, String tableAlias, SqlCriterion onJoinCriterion,
AndOrCriteriaGroup... andJoinCriteria) {
return leftJoin(joinTable, tableAlias, onJoinCriterion, Arrays.asList(andJoinCriteria));
}
default F leftJoin(SqlTable joinTable, SqlCriterion onJoinCriterion,
List<AndOrCriteriaGroup> andJoinCriteria) {
return leftJoin(joinTable).on(onJoinCriterion).and(andJoinCriteria);
}
default F leftJoin(SqlTable joinTable, String tableAlias, SqlCriterion onJoinCriterion,
List<AndOrCriteriaGroup> andJoinCriteria) {
return leftJoin(joinTable, tableAlias).on(onJoinCriterion).and(andJoinCriteria);
}
default F leftJoin(Buildable<SelectModel> subQuery, @Nullable String tableAlias,
SqlCriterion onJoinCriterion, List<AndOrCriteriaGroup> andJoinCriteria) {
return leftJoin(subQuery, tableAlias).on(onJoinCriterion).and(andJoinCriteria);
}
default JoinOnGatherer<F> rightJoin(SqlTable joinTable) {
return new JoinOnGatherer<>(ic -> join(JoinType.RIGHT, joinTable, ic));
}
default JoinOnGatherer<F> rightJoin(SqlTable joinTable, String tableAlias) {
return new JoinOnGatherer<>(ic -> join(JoinType.RIGHT, joinTable, tableAlias, ic));
}
default JoinOnGatherer<F> rightJoin(Buildable<SelectModel> joinTable, @Nullable String tableAlias) {
return new JoinOnGatherer<>(ic -> join(JoinType.RIGHT, buildSubQuery(joinTable, tableAlias), ic));
}
default F rightJoin(SqlTable joinTable, SqlCriterion onJoinCriterion,
AndOrCriteriaGroup... andJoinCriteria) {
return rightJoin(joinTable, onJoinCriterion, Arrays.asList(andJoinCriteria));
}
default F rightJoin(SqlTable joinTable, String tableAlias, SqlCriterion onJoinCriterion,
AndOrCriteriaGroup... andJoinCriteria) {
return rightJoin(joinTable, tableAlias, onJoinCriterion, Arrays.asList(andJoinCriteria));
}
default F rightJoin(SqlTable joinTable, SqlCriterion onJoinCriterion,
List<AndOrCriteriaGroup> andJoinCriteria) {
return rightJoin(joinTable).on(onJoinCriterion).and(andJoinCriteria);
}
default F rightJoin(SqlTable joinTable, String tableAlias, SqlCriterion onJoinCriterion,
List<AndOrCriteriaGroup> andJoinCriteria) {
return rightJoin(joinTable, tableAlias).on(onJoinCriterion).and(andJoinCriteria);
}
default F rightJoin(Buildable<SelectModel> subQuery, @Nullable String tableAlias,
SqlCriterion onJoinCriterion, List<AndOrCriteriaGroup> andJoinCriteria) {
return rightJoin(subQuery, tableAlias).on(onJoinCriterion).and(andJoinCriteria);
}
default JoinOnGatherer<F> fullJoin(SqlTable joinTable) {
return new JoinOnGatherer<>(ic -> join(JoinType.FULL, joinTable, ic));
}
default JoinOnGatherer<F> fullJoin(SqlTable joinTable, String tableAlias) {
return new JoinOnGatherer<>(ic -> join(JoinType.FULL, joinTable, tableAlias, ic));
}
default JoinOnGatherer<F> fullJoin(Buildable<SelectModel> joinTable, @Nullable String tableAlias) {
return new JoinOnGatherer<>(ic -> join(JoinType.FULL, buildSubQuery(joinTable, tableAlias), ic));
}
default F fullJoin(SqlTable joinTable, SqlCriterion onJoinCriterion,
AndOrCriteriaGroup... andJoinCriteria) {
return fullJoin(joinTable, onJoinCriterion, Arrays.asList(andJoinCriteria));
}
default F fullJoin(SqlTable joinTable, String tableAlias, SqlCriterion onJoinCriterion,
AndOrCriteriaGroup... andJoinCriteria) {
return fullJoin(joinTable, tableAlias, onJoinCriterion, Arrays.asList(andJoinCriteria));
}
default F fullJoin(SqlTable joinTable, SqlCriterion onJoinCriterion,
List<AndOrCriteriaGroup> andJoinCriteria) {
return fullJoin(joinTable).on(onJoinCriterion).and(andJoinCriteria);
}
default F fullJoin(SqlTable joinTable, String tableAlias, SqlCriterion onJoinCriterion,
List<AndOrCriteriaGroup> andJoinCriteria) {
return fullJoin(joinTable, tableAlias).on(onJoinCriterion).and(andJoinCriteria);
}
default F fullJoin(Buildable<SelectModel> subQuery, @Nullable String tableAlias,
SqlCriterion onJoinCriterion, List<AndOrCriteriaGroup> andJoinCriteria) {
return fullJoin(subQuery, tableAlias).on(onJoinCriterion).and(andJoinCriteria);
}
private SubQuery buildSubQuery(Buildable<SelectModel> selectModel, @Nullable String alias) {
return new SubQuery.Builder()
.withSelectModel(selectModel.build())
.withAlias(alias)
.build();
}
class JoinOnGatherer<F extends BooleanOperations<?>> {
private final Function<SqlCriterion, F> builder;
public JoinOnGatherer(Function<SqlCriterion, F> builder) {
this.builder = builder;
}
public <T> F on(BindableColumn<T> joinColumn, RenderableCondition<T> joinCondition) {
return on(ColumnAndConditionCriterion.withColumn(joinColumn)
.withCondition(joinCondition)
.build());
}
public <T> F on(BindableColumn<T> joinColumn, RenderableCondition<T> onJoinCondition,
AndOrCriteriaGroup... subCriteria) {
return on(ColumnAndConditionCriterion.withColumn(joinColumn)
.withCondition(onJoinCondition)
.withSubCriteria(Arrays.asList(subCriteria))
.build());
}
public F on(SqlCriterion initialCriterion) {
return builder.apply(initialCriterion);
}
}
}