diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5affe6ae2..7c4a95341 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,34 @@
This log will detail notable changes to MyBatis Dynamic SQL. Full details are available on the GitHub milestone pages.
+## Release 1.5.1 - Unreleased
+
+This is a minor release with a few small enhancements.
+
+GitHub milestone: [https://github.com/mybatis/mybatis-dynamic-sql/milestone/13](https://github.com/mybatis/mybatis-dynamic-sql/milestone/13)
+
+### Parameter Values in Joins
+
+We've added the ability to specify typed values in equi-joins. This allows you to avoid the use of constants, and it is
+type safe. For example:
+
+```java
+SelectStatementProvider selectStatement = select(orderLine.orderId, orderLine.quantity, itemMaster.itemId, itemMaster.description)
+ .from(itemMaster, "im")
+ .join(orderLine, "ol").on(orderLine.itemId, equalTo(itemMaster.itemId))
+ .and(orderLine.orderId, equalTo(1))
+ .build()
+ .render(RenderingStrategies.MYBATIS3);
+```
+
+Note the phrase `and(orderLine.orderId, equalTo(1))` which will be rendered with a bound SQL parameter. Currently, this
+capability is limited to equality only. If you have a use for other functions (not equal, less then, greater than, etc.)
+please let us know.
+
+In order to add this capability, we've modified the join DSL to add type information to the join columns. This should
+be source code compatible with most uses. There could be an issue if you are joining tables with columns of different
+types - which is a rare usage. Please let us know if this causes an undo hardship.
+
## Release 1.5.0 - April 21, 2023
GitHub milestone: [https://github.com/mybatis/mybatis-dynamic-sql/milestone/12?closed=1](https://github.com/mybatis/mybatis-dynamic-sql/milestone/12?closed=1)
diff --git a/pom.xml b/pom.xml
index 9113b386d..db2938b1b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -57,7 +57,7 @@
checkstyle-override.xml
- 1.2.0
+ 1.5.0
org.mybatis.dynamic.sql
diff --git a/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java b/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java
index 4ed0de186..d77b0b026 100644
--- a/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java
+++ b/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java
@@ -54,6 +54,7 @@
import org.mybatis.dynamic.sql.select.function.Subtract;
import org.mybatis.dynamic.sql.select.function.Upper;
import org.mybatis.dynamic.sql.select.join.EqualTo;
+import org.mybatis.dynamic.sql.select.join.EqualToValue;
import org.mybatis.dynamic.sql.select.join.JoinCondition;
import org.mybatis.dynamic.sql.select.join.JoinCriterion;
import org.mybatis.dynamic.sql.update.UpdateDSL;
@@ -425,24 +426,28 @@ static AndOrCriteriaGroup and(List subCriteria) {
}
// join support
- static JoinCriterion and(BasicColumn joinColumn, JoinCondition joinCondition) {
- return new JoinCriterion.Builder()
+ static JoinCriterion and(BindableColumn joinColumn, JoinCondition joinCondition) {
+ return new JoinCriterion.Builder()
.withConnector("and") //$NON-NLS-1$
.withJoinColumn(joinColumn)
.withJoinCondition(joinCondition)
.build();
}
- static JoinCriterion on(BasicColumn joinColumn, JoinCondition joinCondition) {
- return new JoinCriterion.Builder()
+ static JoinCriterion on(BindableColumn joinColumn, JoinCondition joinCondition) {
+ return new JoinCriterion.Builder()
.withConnector("on") //$NON-NLS-1$
.withJoinColumn(joinColumn)
.withJoinCondition(joinCondition)
.build();
}
- static EqualTo equalTo(BasicColumn column) {
- return new EqualTo(column);
+ static EqualTo equalTo(BindableColumn column) {
+ return new EqualTo<>(column);
+ }
+
+ static EqualToValue equalTo(T value) {
+ return new EqualToValue<>(value);
}
// aggregate support
diff --git a/src/main/java/org/mybatis/dynamic/sql/select/AbstractQueryExpressionDSL.java b/src/main/java/org/mybatis/dynamic/sql/select/AbstractQueryExpressionDSL.java
index 6fdac9fd7..e6ec1d17b 100644
--- a/src/main/java/org/mybatis/dynamic/sql/select/AbstractQueryExpressionDSL.java
+++ b/src/main/java/org/mybatis/dynamic/sql/select/AbstractQueryExpressionDSL.java
@@ -52,132 +52,132 @@ public TableExpression table() {
return table;
}
- public T join(SqlTable joinTable, JoinCriterion onJoinCriterion,
- JoinCriterion... andJoinCriteria) {
+ public T join(SqlTable joinTable, JoinCriterion> onJoinCriterion,
+ JoinCriterion>... andJoinCriteria) {
addJoinSpecificationBuilder(joinTable, onJoinCriterion, JoinType.INNER, Arrays.asList(andJoinCriteria));
return getThis();
}
- public T join(SqlTable joinTable, String tableAlias, JoinCriterion onJoinCriterion,
- JoinCriterion... andJoinCriteria) {
+ public T join(SqlTable joinTable, String tableAlias, JoinCriterion> onJoinCriterion,
+ JoinCriterion>... andJoinCriteria) {
addTableAlias(joinTable, tableAlias);
return join(joinTable, onJoinCriterion, andJoinCriteria);
}
- public T join(SqlTable joinTable, JoinCriterion onJoinCriterion,
- List andJoinCriteria) {
+ public T join(SqlTable joinTable, JoinCriterion> onJoinCriterion,
+ List> andJoinCriteria) {
addJoinSpecificationBuilder(joinTable, onJoinCriterion, JoinType.INNER, andJoinCriteria);
return getThis();
}
- public T join(SqlTable joinTable, String tableAlias, JoinCriterion onJoinCriterion,
- List andJoinCriteria) {
+ public T join(SqlTable joinTable, String tableAlias, JoinCriterion> onJoinCriterion,
+ List> andJoinCriteria) {
addTableAlias(joinTable, tableAlias);
return join(joinTable, onJoinCriterion, andJoinCriteria);
}
- public T join(Buildable subQuery, String tableAlias, JoinCriterion onJoinCriterion,
- List andJoinCriteria) {
+ public T join(Buildable subQuery, String tableAlias, JoinCriterion> onJoinCriterion,
+ List> andJoinCriteria) {
addJoinSpecificationBuilder(buildSubQuery(subQuery, tableAlias), onJoinCriterion, JoinType.INNER,
andJoinCriteria);
return getThis();
}
- public T leftJoin(SqlTable joinTable, JoinCriterion onJoinCriterion,
- JoinCriterion... andJoinCriteria) {
+ public T leftJoin(SqlTable joinTable, JoinCriterion> onJoinCriterion,
+ JoinCriterion>... andJoinCriteria) {
addJoinSpecificationBuilder(joinTable, onJoinCriterion, JoinType.LEFT, Arrays.asList(andJoinCriteria));
return getThis();
}
- public T leftJoin(SqlTable joinTable, String tableAlias, JoinCriterion onJoinCriterion,
- JoinCriterion... andJoinCriteria) {
+ public T leftJoin(SqlTable joinTable, String tableAlias, JoinCriterion> onJoinCriterion,
+ JoinCriterion>... andJoinCriteria) {
addTableAlias(joinTable, tableAlias);
return leftJoin(joinTable, onJoinCriterion, andJoinCriteria);
}
- public T leftJoin(SqlTable joinTable, JoinCriterion onJoinCriterion,
- List andJoinCriteria) {
+ public T leftJoin(SqlTable joinTable, JoinCriterion> onJoinCriterion,
+ List> andJoinCriteria) {
addJoinSpecificationBuilder(joinTable, onJoinCriterion, JoinType.LEFT, andJoinCriteria);
return getThis();
}
- public T leftJoin(SqlTable joinTable, String tableAlias, JoinCriterion onJoinCriterion,
- List andJoinCriteria) {
+ public T leftJoin(SqlTable joinTable, String tableAlias, JoinCriterion> onJoinCriterion,
+ List> andJoinCriteria) {
addTableAlias(joinTable, tableAlias);
return leftJoin(joinTable, onJoinCriterion, andJoinCriteria);
}
- public T leftJoin(Buildable subQuery, String tableAlias, JoinCriterion onJoinCriterion,
- List andJoinCriteria) {
+ public T leftJoin(Buildable subQuery, String tableAlias, JoinCriterion> onJoinCriterion,
+ List> andJoinCriteria) {
addJoinSpecificationBuilder(buildSubQuery(subQuery, tableAlias), onJoinCriterion, JoinType.LEFT,
andJoinCriteria);
return getThis();
}
- public T rightJoin(SqlTable joinTable, JoinCriterion onJoinCriterion,
- JoinCriterion... andJoinCriteria) {
+ public T rightJoin(SqlTable joinTable, JoinCriterion> onJoinCriterion,
+ JoinCriterion>... andJoinCriteria) {
addJoinSpecificationBuilder(joinTable, onJoinCriterion, JoinType.RIGHT, Arrays.asList(andJoinCriteria));
return getThis();
}
- public T rightJoin(SqlTable joinTable, String tableAlias, JoinCriterion onJoinCriterion,
- JoinCriterion... andJoinCriteria) {
+ public T rightJoin(SqlTable joinTable, String tableAlias, JoinCriterion> onJoinCriterion,
+ JoinCriterion>... andJoinCriteria) {
addTableAlias(joinTable, tableAlias);
return rightJoin(joinTable, onJoinCriterion, andJoinCriteria);
}
- public T rightJoin(SqlTable joinTable, JoinCriterion onJoinCriterion,
- List andJoinCriteria) {
+ public T rightJoin(SqlTable joinTable, JoinCriterion> onJoinCriterion,
+ List> andJoinCriteria) {
addJoinSpecificationBuilder(joinTable, onJoinCriterion, JoinType.RIGHT, andJoinCriteria);
return getThis();
}
- public T rightJoin(SqlTable joinTable, String tableAlias, JoinCriterion onJoinCriterion,
- List andJoinCriteria) {
+ public T rightJoin(SqlTable joinTable, String tableAlias, JoinCriterion> onJoinCriterion,
+ List> andJoinCriteria) {
addTableAlias(joinTable, tableAlias);
return rightJoin(joinTable, onJoinCriterion, andJoinCriteria);
}
- public T rightJoin(Buildable subQuery, String tableAlias, JoinCriterion onJoinCriterion,
- List andJoinCriteria) {
+ public T rightJoin(Buildable subQuery, String tableAlias, JoinCriterion> onJoinCriterion,
+ List> andJoinCriteria) {
addJoinSpecificationBuilder(buildSubQuery(subQuery, tableAlias), onJoinCriterion, JoinType.RIGHT,
andJoinCriteria);
return getThis();
}
- public T fullJoin(SqlTable joinTable, JoinCriterion onJoinCriterion,
- JoinCriterion... andJoinCriteria) {
+ public T fullJoin(SqlTable joinTable, JoinCriterion> onJoinCriterion,
+ JoinCriterion>... andJoinCriteria) {
addJoinSpecificationBuilder(joinTable, onJoinCriterion, JoinType.FULL, Arrays.asList(andJoinCriteria));
return getThis();
}
- public T fullJoin(SqlTable joinTable, String tableAlias, JoinCriterion onJoinCriterion,
- JoinCriterion... andJoinCriteria) {
+ public T fullJoin(SqlTable joinTable, String tableAlias, JoinCriterion> onJoinCriterion,
+ JoinCriterion>... andJoinCriteria) {
addTableAlias(joinTable, tableAlias);
return fullJoin(joinTable, onJoinCriterion, andJoinCriteria);
}
- public T fullJoin(SqlTable joinTable, JoinCriterion onJoinCriterion,
- List andJoinCriteria) {
+ public T fullJoin(SqlTable joinTable, JoinCriterion> onJoinCriterion,
+ List> andJoinCriteria) {
addJoinSpecificationBuilder(joinTable, onJoinCriterion, JoinType.FULL, andJoinCriteria);
return getThis();
}
- public T fullJoin(SqlTable joinTable, String tableAlias, JoinCriterion onJoinCriterion,
- List andJoinCriteria) {
+ public T fullJoin(SqlTable joinTable, String tableAlias, JoinCriterion> onJoinCriterion,
+ List> andJoinCriteria) {
addTableAlias(joinTable, tableAlias);
return fullJoin(joinTable, onJoinCriterion, andJoinCriteria);
}
- public T fullJoin(Buildable subQuery, String tableAlias, JoinCriterion onJoinCriterion,
- List andJoinCriteria) {
+ public T fullJoin(Buildable subQuery, String tableAlias, JoinCriterion> onJoinCriterion,
+ List> andJoinCriteria) {
addJoinSpecificationBuilder(buildSubQuery(subQuery, tableAlias), onJoinCriterion, JoinType.FULL,
andJoinCriteria);
return getThis();
}
- private void addJoinSpecificationBuilder(TableExpression joinTable, JoinCriterion onJoinCriterion,
- JoinType joinType, List andJoinCriteria) {
+ private void addJoinSpecificationBuilder(TableExpression joinTable, JoinCriterion> onJoinCriterion,
+ JoinType joinType, List> andJoinCriteria) {
joinSpecificationBuilders.add(new JoinSpecification.Builder()
.withJoinTable(joinTable)
.withJoinType(joinType)
diff --git a/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionDSL.java b/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionDSL.java
index 422f915f2..22647f230 100644
--- a/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionDSL.java
+++ b/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionDSL.java
@@ -24,6 +24,7 @@
import org.jetbrains.annotations.NotNull;
import org.mybatis.dynamic.sql.BasicColumn;
+import org.mybatis.dynamic.sql.BindableColumn;
import org.mybatis.dynamic.sql.CriteriaGroup;
import org.mybatis.dynamic.sql.SortSpecification;
import org.mybatis.dynamic.sql.SqlTable;
@@ -349,12 +350,12 @@ public JoinSpecificationStarter(TableExpression joinTable, JoinType joinType) {
this.joinType = joinType;
}
- public JoinSpecificationFinisher on(BasicColumn joinColumn, JoinCondition joinCondition) {
+ public JoinSpecificationFinisher on(BindableColumn joinColumn, JoinCondition joinCondition) {
return new JoinSpecificationFinisher(joinTable, joinColumn, joinCondition, joinType);
}
- public JoinSpecificationFinisher on(BasicColumn joinColumn, JoinCondition onJoinCondition,
- JoinCriterion... andJoinCriteria) {
+ public JoinSpecificationFinisher on(BindableColumn joinColumn, JoinCondition onJoinCondition,
+ JoinCriterion>... andJoinCriteria) {
return new JoinSpecificationFinisher(joinTable, joinColumn, onJoinCondition, joinType, andJoinCriteria);
}
}
@@ -364,9 +365,9 @@ public class JoinSpecificationFinisher
implements Buildable {
private final JoinSpecification.Builder joinSpecificationBuilder;
- public JoinSpecificationFinisher(TableExpression table, BasicColumn joinColumn,
- JoinCondition joinCondition, JoinType joinType) {
- JoinCriterion joinCriterion = new JoinCriterion.Builder()
+ public JoinSpecificationFinisher(TableExpression table, BindableColumn joinColumn,
+ JoinCondition joinCondition, JoinType joinType) {
+ JoinCriterion joinCriterion = new JoinCriterion.Builder()
.withConnector("on") //$NON-NLS-1$
.withJoinColumn(joinColumn)
.withJoinCondition(joinCondition)
@@ -379,9 +380,9 @@ public JoinSpecificationFinisher(TableExpression table, BasicColumn joinColumn,
addJoinSpecificationBuilder(joinSpecificationBuilder);
}
- public JoinSpecificationFinisher(TableExpression table, BasicColumn joinColumn,
- JoinCondition joinCondition, JoinType joinType, JoinCriterion... andJoinCriteria) {
- JoinCriterion onJoinCriterion = new JoinCriterion.Builder()
+ public JoinSpecificationFinisher(TableExpression table, BindableColumn joinColumn,
+ JoinCondition joinCondition, JoinType joinType, JoinCriterion>... andJoinCriteria) {
+ JoinCriterion onJoinCriterion = new JoinCriterion.Builder()
.withConnector("on") //$NON-NLS-1$
.withJoinColumn(joinColumn)
.withJoinCondition(joinCondition)
@@ -412,8 +413,8 @@ public QueryExpressionWhereBuilder where() {
return QueryExpressionDSL.this.where();
}
- public JoinSpecificationFinisher and(BasicColumn joinColumn, JoinCondition joinCondition) {
- JoinCriterion joinCriterion = new JoinCriterion.Builder()
+ public JoinSpecificationFinisher and(BindableColumn joinColumn, JoinCondition joinCondition) {
+ JoinCriterion joinCriterion = new JoinCriterion.Builder()
.withConnector("and") //$NON-NLS-1$
.withJoinColumn(joinColumn)
.withJoinCondition(joinCondition)
diff --git a/src/main/java/org/mybatis/dynamic/sql/select/join/ColumnBasedJoinCondition.java b/src/main/java/org/mybatis/dynamic/sql/select/join/ColumnBasedJoinCondition.java
new file mode 100644
index 000000000..fda626dbb
--- /dev/null
+++ b/src/main/java/org/mybatis/dynamic/sql/select/join/ColumnBasedJoinCondition.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2016-2023 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.select.join;
+
+import java.util.Objects;
+
+import org.mybatis.dynamic.sql.BasicColumn;
+
+public abstract class ColumnBasedJoinCondition implements JoinCondition {
+ private final BasicColumn rightColumn;
+
+ protected ColumnBasedJoinCondition(BasicColumn rightColumn) {
+ this.rightColumn = Objects.requireNonNull(rightColumn);
+ }
+
+ public BasicColumn rightColumn() {
+ return rightColumn;
+ }
+
+ @Override
+ public R accept(JoinConditionVisitor visitor) {
+ return visitor.visit(this);
+ }
+}
diff --git a/src/main/java/org/mybatis/dynamic/sql/select/join/EqualTo.java b/src/main/java/org/mybatis/dynamic/sql/select/join/EqualTo.java
index d73cec215..4f20ec920 100644
--- a/src/main/java/org/mybatis/dynamic/sql/select/join/EqualTo.java
+++ b/src/main/java/org/mybatis/dynamic/sql/select/join/EqualTo.java
@@ -17,7 +17,7 @@
import org.mybatis.dynamic.sql.BasicColumn;
-public class EqualTo extends JoinCondition {
+public class EqualTo extends ColumnBasedJoinCondition {
public EqualTo(BasicColumn rightColumn) {
super(rightColumn);
diff --git a/src/main/java/org/mybatis/dynamic/sql/select/join/EqualToValue.java b/src/main/java/org/mybatis/dynamic/sql/select/join/EqualToValue.java
new file mode 100644
index 000000000..c7cb39c27
--- /dev/null
+++ b/src/main/java/org/mybatis/dynamic/sql/select/join/EqualToValue.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2016-2023 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.select.join;
+
+public class EqualToValue extends TypedJoinCondition {
+ public EqualToValue(T value) {
+ super(value);
+ }
+
+ @Override
+ public String operator() {
+ return "="; //$NON-NLS-1$
+ }
+}
diff --git a/src/main/java/org/mybatis/dynamic/sql/select/join/JoinCondition.java b/src/main/java/org/mybatis/dynamic/sql/select/join/JoinCondition.java
index 7db8327e2..6965db5b9 100644
--- a/src/main/java/org/mybatis/dynamic/sql/select/join/JoinCondition.java
+++ b/src/main/java/org/mybatis/dynamic/sql/select/join/JoinCondition.java
@@ -15,20 +15,8 @@
*/
package org.mybatis.dynamic.sql.select.join;
-import java.util.Objects;
+public interface JoinCondition {
+ String operator();
-import org.mybatis.dynamic.sql.BasicColumn;
-
-public abstract class JoinCondition {
- private final BasicColumn rightColumn;
-
- protected JoinCondition(BasicColumn rightColumn) {
- this.rightColumn = Objects.requireNonNull(rightColumn);
- }
-
- public BasicColumn rightColumn() {
- return rightColumn;
- }
-
- public abstract String operator();
+ R accept(JoinConditionVisitor visitor);
}
diff --git a/src/main/java/org/mybatis/dynamic/sql/select/join/JoinConditionVisitor.java b/src/main/java/org/mybatis/dynamic/sql/select/join/JoinConditionVisitor.java
new file mode 100644
index 000000000..7cee1a596
--- /dev/null
+++ b/src/main/java/org/mybatis/dynamic/sql/select/join/JoinConditionVisitor.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2016-2023 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.select.join;
+
+public interface JoinConditionVisitor {
+ R visit(TypedJoinCondition condition);
+
+ R visit(ColumnBasedJoinCondition condition);
+}
diff --git a/src/main/java/org/mybatis/dynamic/sql/select/join/JoinCriterion.java b/src/main/java/org/mybatis/dynamic/sql/select/join/JoinCriterion.java
index 269c77c28..e40407b42 100644
--- a/src/main/java/org/mybatis/dynamic/sql/select/join/JoinCriterion.java
+++ b/src/main/java/org/mybatis/dynamic/sql/select/join/JoinCriterion.java
@@ -17,15 +17,15 @@
import java.util.Objects;
-import org.mybatis.dynamic.sql.BasicColumn;
+import org.mybatis.dynamic.sql.BindableColumn;
-public class JoinCriterion {
+public class JoinCriterion {
private final String connector;
- private final BasicColumn leftColumn;
- private final JoinCondition joinCondition;
+ private final BindableColumn leftColumn;
+ private final JoinCondition joinCondition;
- private JoinCriterion(Builder builder) {
+ private JoinCriterion(Builder builder) {
connector = Objects.requireNonNull(builder.connector);
leftColumn = Objects.requireNonNull(builder.joinColumn);
joinCondition = Objects.requireNonNull(builder.joinCondition);
@@ -35,40 +35,36 @@ public String connector() {
return connector;
}
- public BasicColumn leftColumn() {
+ public BindableColumn leftColumn() {
return leftColumn;
}
- public BasicColumn rightColumn() {
- return joinCondition.rightColumn();
+ public JoinCondition joinCondition() {
+ return joinCondition;
}
- public String operator() {
- return joinCondition.operator();
- }
-
- public static class Builder {
+ public static class Builder {
private String connector;
- private BasicColumn joinColumn;
- private JoinCondition joinCondition;
+ private BindableColumn joinColumn;
+ private JoinCondition joinCondition;
- public Builder withConnector(String connector) {
+ public Builder withConnector(String connector) {
this.connector = connector;
return this;
}
- public Builder withJoinColumn(BasicColumn joinColumn) {
+ public Builder withJoinColumn(BindableColumn joinColumn) {
this.joinColumn = joinColumn;
return this;
}
- public Builder withJoinCondition(JoinCondition joinCondition) {
+ public Builder withJoinCondition(JoinCondition joinCondition) {
this.joinCondition = joinCondition;
return this;
}
- public JoinCriterion build() {
- return new JoinCriterion(this);
+ public JoinCriterion build() {
+ return new JoinCriterion<>(this);
}
}
}
diff --git a/src/main/java/org/mybatis/dynamic/sql/select/join/JoinSpecification.java b/src/main/java/org/mybatis/dynamic/sql/select/join/JoinSpecification.java
index c1024f441..7aba7473e 100644
--- a/src/main/java/org/mybatis/dynamic/sql/select/join/JoinSpecification.java
+++ b/src/main/java/org/mybatis/dynamic/sql/select/join/JoinSpecification.java
@@ -28,7 +28,7 @@
public class JoinSpecification {
private final TableExpression table;
- private final List joinCriteria;
+ private final List> joinCriteria;
private final JoinType joinType;
private JoinSpecification(Builder builder) {
@@ -45,7 +45,7 @@ public TableExpression table() {
return table;
}
- public Stream mapJoinCriteria(Function mapper) {
+ public Stream mapJoinCriteria(Function, R> mapper) {
return joinCriteria.stream().map(mapper);
}
@@ -59,7 +59,7 @@ public static Builder withJoinTable(TableExpression table) {
public static class Builder {
private TableExpression table;
- private final List joinCriteria = new ArrayList<>();
+ private final List> joinCriteria = new ArrayList<>();
private JoinType joinType;
public Builder withJoinTable(TableExpression table) {
@@ -67,12 +67,12 @@ public Builder withJoinTable(TableExpression table) {
return this;
}
- public Builder withJoinCriterion(JoinCriterion joinCriterion) {
+ public Builder withJoinCriterion(JoinCriterion> joinCriterion) {
this.joinCriteria.add(joinCriterion);
return this;
}
- public Builder withJoinCriteria(List joinCriteria) {
+ public Builder withJoinCriteria(List> joinCriteria) {
this.joinCriteria.addAll(joinCriteria);
return this;
}
diff --git a/src/main/java/org/mybatis/dynamic/sql/select/join/TypedJoinCondition.java b/src/main/java/org/mybatis/dynamic/sql/select/join/TypedJoinCondition.java
new file mode 100644
index 000000000..0feb6c78c
--- /dev/null
+++ b/src/main/java/org/mybatis/dynamic/sql/select/join/TypedJoinCondition.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2016-2023 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.select.join;
+
+import java.util.Objects;
+
+public abstract class TypedJoinCondition implements JoinCondition {
+ private final T value;
+
+ protected TypedJoinCondition(T value) {
+ this.value = Objects.requireNonNull(value);
+ }
+
+ public T value() {
+ return value;
+ }
+
+ @Override
+ public R accept(JoinConditionVisitor visitor) {
+ return visitor.visit(this);
+ }
+}
diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/JoinConditionRenderer.java b/src/main/java/org/mybatis/dynamic/sql/select/render/JoinConditionRenderer.java
new file mode 100644
index 000000000..75e8e382f
--- /dev/null
+++ b/src/main/java/org/mybatis/dynamic/sql/select/render/JoinConditionRenderer.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2016-2023 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.select.render;
+
+import static org.mybatis.dynamic.sql.util.StringUtilities.spaceBefore;
+
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.mybatis.dynamic.sql.BasicColumn;
+import org.mybatis.dynamic.sql.BindableColumn;
+import org.mybatis.dynamic.sql.render.RenderingStrategy;
+import org.mybatis.dynamic.sql.render.TableAliasCalculator;
+import org.mybatis.dynamic.sql.select.join.ColumnBasedJoinCondition;
+import org.mybatis.dynamic.sql.select.join.JoinConditionVisitor;
+import org.mybatis.dynamic.sql.select.join.TypedJoinCondition;
+import org.mybatis.dynamic.sql.util.FragmentAndParameters;
+
+public class JoinConditionRenderer implements JoinConditionVisitor {
+ private final RenderingStrategy renderingStrategy;
+ private final AtomicInteger sequence;
+ private final BindableColumn leftColumn;
+ private final TableAliasCalculator tableAliasCalculator;
+
+ private JoinConditionRenderer(Builder builder) {
+ renderingStrategy = Objects.requireNonNull(builder.renderingStrategy);
+ sequence = Objects.requireNonNull(builder.sequence);
+ leftColumn = Objects.requireNonNull(builder.leftColumn);
+ tableAliasCalculator = Objects.requireNonNull(builder.tableAliasCalculator);
+ }
+
+ @Override
+ public FragmentAndParameters visit(TypedJoinCondition condition) {
+ String mapKey = renderingStrategy.formatParameterMapKey(sequence);
+
+ String placeHolder = leftColumn.renderingStrategy().orElse(renderingStrategy)
+ .getFormattedJdbcPlaceholder(leftColumn, RenderingStrategy.DEFAULT_PARAMETER_PREFIX, mapKey);
+
+ return FragmentAndParameters.withFragment(condition.operator() + spaceBefore(placeHolder))
+ .withParameter(mapKey, condition.value())
+ .build();
+ }
+
+ @Override
+ public FragmentAndParameters visit(ColumnBasedJoinCondition condition) {
+ return FragmentAndParameters
+ .withFragment(condition.operator() + spaceBefore(applyTableAlias(condition.rightColumn())))
+ .build();
+ }
+
+ private String applyTableAlias(BasicColumn column) {
+ return column.renderWithTableAlias(tableAliasCalculator);
+ }
+
+ public static class Builder {
+ private RenderingStrategy renderingStrategy;
+ private AtomicInteger sequence;
+ private BindableColumn leftColumn;
+ private TableAliasCalculator tableAliasCalculator;
+
+ public Builder withRenderingStrategy(RenderingStrategy renderingStrategy) {
+ this.renderingStrategy = renderingStrategy;
+ return this;
+ }
+
+ public Builder withSequence(AtomicInteger sequence) {
+ this.sequence = sequence;
+ return this;
+ }
+
+ public Builder withLeftColumn(BindableColumn leftColumn) {
+ this.leftColumn = leftColumn;
+ return this;
+ }
+
+ public Builder withTableAliasCalculator(TableAliasCalculator tableAliasCalculator) {
+ this.tableAliasCalculator = tableAliasCalculator;
+ return this;
+ }
+
+ public JoinConditionRenderer build() {
+ return new JoinConditionRenderer<>(this);
+ }
+ }
+}
diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/JoinRenderer.java b/src/main/java/org/mybatis/dynamic/sql/select/render/JoinRenderer.java
index 59efad3b7..8e9e7a04c 100644
--- a/src/main/java/org/mybatis/dynamic/sql/select/render/JoinRenderer.java
+++ b/src/main/java/org/mybatis/dynamic/sql/select/render/JoinRenderer.java
@@ -18,9 +18,11 @@
import static org.mybatis.dynamic.sql.util.StringUtilities.spaceBefore;
import java.util.Objects;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import org.mybatis.dynamic.sql.BasicColumn;
+import org.mybatis.dynamic.sql.render.RenderingStrategy;
import org.mybatis.dynamic.sql.render.TableAliasCalculator;
import org.mybatis.dynamic.sql.select.join.JoinCriterion;
import org.mybatis.dynamic.sql.select.join.JoinModel;
@@ -32,11 +34,15 @@ public class JoinRenderer {
private final JoinModel joinModel;
private final TableExpressionRenderer tableExpressionRenderer;
private final TableAliasCalculator tableAliasCalculator;
+ private final RenderingStrategy renderingStrategy;
+ private final AtomicInteger sequence;
private JoinRenderer(Builder builder) {
joinModel = Objects.requireNonNull(builder.joinModel);
tableExpressionRenderer = Objects.requireNonNull(builder.tableExpressionRenderer);
tableAliasCalculator = Objects.requireNonNull(builder.tableAliasCalculator);
+ renderingStrategy = Objects.requireNonNull(builder.renderingStrategy);
+ sequence = Objects.requireNonNull(builder.sequence);
}
public FragmentAndParameters render() {
@@ -50,26 +56,44 @@ public FragmentAndParameters render() {
private FragmentAndParameters renderJoinSpecification(JoinSpecification joinSpecification) {
FragmentAndParameters renderedTable = joinSpecification.table().accept(tableExpressionRenderer);
+ FragmentAndParameters renderedJoin = renderConditions(joinSpecification);
String fragment = joinSpecification.joinType().type()
+ spaceBefore(renderedTable.fragment())
- + spaceBefore(renderConditions(joinSpecification));
+ + spaceBefore(renderedJoin.fragment());
return FragmentAndParameters.withFragment(fragment)
.withParameters(renderedTable.parameters())
+ .withParameters(renderedJoin.parameters())
.build();
}
- private String renderConditions(JoinSpecification joinSpecification) {
- return joinSpecification.mapJoinCriteria(this::renderCriterion)
- .collect(Collectors.joining(" ")); //$NON-NLS-1$
+ private FragmentAndParameters renderConditions(JoinSpecification joinSpecification) {
+ FragmentCollector fragmentCollector = joinSpecification.mapJoinCriteria(this::renderCriterion)
+ .collect(FragmentCollector.collect());
+
+ return FragmentAndParameters
+ .withFragment(fragmentCollector.fragments().collect(Collectors.joining(" "))) //$NON-NLS-1$
+ .withParameters(fragmentCollector.parameters())
+ .build();
}
- private String renderCriterion(JoinCriterion joinCriterion) {
- return joinCriterion.connector()
- + spaceBefore(applyTableAlias(joinCriterion.leftColumn()))
- + spaceBefore(joinCriterion.operator())
- + spaceBefore(applyTableAlias(joinCriterion.rightColumn()));
+ private FragmentAndParameters renderCriterion(JoinCriterion joinCriterion) {
+ String prefix = joinCriterion.connector()
+ + spaceBefore(applyTableAlias(joinCriterion.leftColumn()));
+
+ JoinConditionRenderer joinConditionRenderer = new JoinConditionRenderer.Builder()
+ .withRenderingStrategy(renderingStrategy)
+ .withSequence(sequence)
+ .withTableAliasCalculator(tableAliasCalculator)
+ .withLeftColumn(joinCriterion.leftColumn())
+ .build();
+
+ FragmentAndParameters suffix = joinCriterion.joinCondition().accept(joinConditionRenderer);
+
+ return FragmentAndParameters.withFragment(prefix + spaceBefore(suffix.fragment()))
+ .withParameters(suffix.parameters())
+ .build();
}
private String applyTableAlias(BasicColumn column) {
@@ -84,6 +108,8 @@ public static class Builder {
private JoinModel joinModel;
private TableExpressionRenderer tableExpressionRenderer;
private TableAliasCalculator tableAliasCalculator;
+ private RenderingStrategy renderingStrategy;
+ private AtomicInteger sequence;
public Builder withJoinModel(JoinModel joinModel) {
this.joinModel = joinModel;
@@ -100,6 +126,16 @@ public Builder withTableAliasCalculator(TableAliasCalculator tableAliasCalculato
return this;
}
+ public Builder withRenderingStrategy(RenderingStrategy renderingStrategy) {
+ this.renderingStrategy = renderingStrategy;
+ return this;
+ }
+
+ public Builder withSequence(AtomicInteger sequence) {
+ this.sequence = sequence;
+ return this;
+ }
+
public JoinRenderer build() {
return new JoinRenderer(this);
}
diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/QueryExpressionRenderer.java b/src/main/java/org/mybatis/dynamic/sql/select/render/QueryExpressionRenderer.java
index 49bb09694..e69d576df 100644
--- a/src/main/java/org/mybatis/dynamic/sql/select/render/QueryExpressionRenderer.java
+++ b/src/main/java/org/mybatis/dynamic/sql/select/render/QueryExpressionRenderer.java
@@ -171,6 +171,8 @@ private FragmentAndParameters renderJoin(JoinModel joinModel) {
return JoinRenderer.withJoinModel(joinModel)
.withTableExpressionRenderer(tableExpressionRenderer)
.withTableAliasCalculator(tableAliasCalculator)
+ .withRenderingStrategy(renderingStrategy)
+ .withSequence(sequence)
.build()
.render();
}
diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/JoinCollector.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/JoinCollector.kt
index 84829f9d6..24473360f 100644
--- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/JoinCollector.kt
+++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/JoinCollector.kt
@@ -15,7 +15,7 @@
*/
package org.mybatis.dynamic.sql.util.kotlin
-import org.mybatis.dynamic.sql.BasicColumn
+import org.mybatis.dynamic.sql.BindableColumn
import org.mybatis.dynamic.sql.SqlBuilder
import org.mybatis.dynamic.sql.select.join.JoinCondition
import org.mybatis.dynamic.sql.select.join.JoinCriterion
@@ -25,23 +25,23 @@ typealias JoinReceiver = JoinCollector.() -> Unit
@MyBatisDslMarker
class JoinCollector {
- private var onJoinCriterion: JoinCriterion? = null
- internal val andJoinCriteria = mutableListOf()
+ private var onJoinCriterion: JoinCriterion<*>? = null
+ internal val andJoinCriteria = mutableListOf>()
- internal fun onJoinCriterion() : JoinCriterion =
+ internal fun onJoinCriterion() : JoinCriterion<*> =
onJoinCriterion?: throw KInvalidSQLException(Messages.getString("ERROR.22")) //$NON-NLS-1$
- fun on(leftColumn: BasicColumn): RightColumnCollector = RightColumnCollector {
- onJoinCriterion = JoinCriterion.Builder()
+ fun on(leftColumn: BindableColumn): RightColumnCollector = RightColumnCollector {
+ onJoinCriterion = JoinCriterion.Builder()
.withConnector("on") //$NON-NLS-1$
.withJoinColumn(leftColumn)
.withJoinCondition(it)
.build()
}
- fun and(leftColumn: BasicColumn): RightColumnCollector = RightColumnCollector {
+ fun and(leftColumn: BindableColumn): RightColumnCollector = RightColumnCollector {
andJoinCriteria.add(
- JoinCriterion.Builder()
+ JoinCriterion.Builder()
.withConnector("and") //$NON-NLS-1$
.withJoinColumn(leftColumn)
.withJoinCondition(it)
@@ -50,6 +50,8 @@ class JoinCollector {
}
}
-class RightColumnCollector(private val joinConditionConsumer: (JoinCondition) -> Unit) {
- infix fun equalTo(rightColumn: BasicColumn) = joinConditionConsumer.invoke(SqlBuilder.equalTo(rightColumn))
+class RightColumnCollector(private val joinConditionConsumer: (JoinCondition) -> Unit) {
+ infix fun equalTo(rightColumn: BindableColumn) = joinConditionConsumer.invoke(SqlBuilder.equalTo(rightColumn))
+
+ infix fun equalTo(value: T) = joinConditionConsumer.invoke(SqlBuilder.equalTo(value))
}
diff --git a/src/test/java/examples/joins/JoinMapperTest.java b/src/test/java/examples/joins/JoinMapperTest.java
index 1b90b06a5..9417e467f 100644
--- a/src/test/java/examples/joins/JoinMapperTest.java
+++ b/src/test/java/examples/joins/JoinMapperTest.java
@@ -1193,4 +1193,72 @@ void testFetchFirstOnlyAfterJoin() {
assertThat(row).containsEntry("ITEM_ID", 22);
}
}
+
+ @Test
+ void testJoinWithParameterValue() {
+ try (SqlSession session = sqlSessionFactory.openSession()) {
+ CommonSelectMapper mapper = session.getMapper(CommonSelectMapper.class);
+
+ SelectStatementProvider selectStatement = select(orderLine.orderId, orderLine.quantity, itemMaster.itemId, itemMaster.description)
+ .from(itemMaster, "im")
+ .join(orderLine, "ol").on(orderLine.itemId, equalTo(itemMaster.itemId))
+ .and(orderLine.orderId, equalTo(1))
+ .build()
+ .render(RenderingStrategies.MYBATIS3);
+
+ String expectedStatement = "select ol.order_id, ol.quantity, im.item_id, im.description"
+ + " from ItemMaster im join OrderLine ol on ol.item_id = im.item_id"
+ + " and ol.order_id = #{parameters.p1,jdbcType=INTEGER}";
+ assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement);
+
+ List