From aa3bd8597f1a473ecb423037620442f5f8d11923 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 9 Nov 2020 14:49:54 -0500 Subject: [PATCH 01/12] Begin work on supporting sub-queries in joins --- .../mybatis/dynamic/sql/TableExpression.java | 4 + .../select/AbstractQueryExpressionDSL.java | 13 + .../sql/select/QueryExpressionDSL.java | 85 +- .../sql/select/QueryExpressionModel.java | 11 +- .../mybatis/dynamic/sql/select/SubQuery.java | 5 + .../dynamic/sql/select/join/JoinModel.java | 8 + .../java/examples/joins/JoinSubQueryTest.java | 1007 +++++++++++++++++ 7 files changed, 1115 insertions(+), 18 deletions(-) create mode 100644 src/test/java/examples/joins/JoinSubQueryTest.java diff --git a/src/main/java/org/mybatis/dynamic/sql/TableExpression.java b/src/main/java/org/mybatis/dynamic/sql/TableExpression.java index e0722894a..87c58023d 100644 --- a/src/main/java/org/mybatis/dynamic/sql/TableExpression.java +++ b/src/main/java/org/mybatis/dynamic/sql/TableExpression.java @@ -18,4 +18,8 @@ public interface TableExpression { R accept(TableExpressionVisitor visitor); + + default boolean isSubQuery() { + return false; + } } 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 33287616e..c0faebd63 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/AbstractQueryExpressionDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/AbstractQueryExpressionDSL.java @@ -166,5 +166,18 @@ protected Optional buildJoinModel() { .collect(Collectors.toList()))); } + protected static SubQuery buildSubQuery(Buildable selectModel) { + return new SubQuery.Builder() + .withSelectModel(selectModel.build()) + .build(); + } + + protected static SubQuery buildSubQuery(Buildable selectModel, String alias) { + return new SubQuery.Builder() + .withSelectModel(selectModel.build()) + .withAlias(alias) + .build(); + } + protected abstract T getThis(); } 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 16204f999..917694753 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionDSL.java @@ -90,6 +90,14 @@ public JoinSpecificationStarter join(SqlTable joinTable, String tableAlias) { return join(joinTable); } + public JoinSpecificationStarter join(Buildable joinTable) { + return new JoinSpecificationStarter(buildSubQuery(joinTable), JoinType.INNER); + } + + public JoinSpecificationStarter join(Buildable joinTable, String tableAlias) { + return new JoinSpecificationStarter(buildSubQuery(joinTable, tableAlias), JoinType.INNER); + } + public JoinSpecificationStarter leftJoin(SqlTable joinTable) { return new JoinSpecificationStarter(joinTable, JoinType.LEFT); } @@ -99,6 +107,14 @@ public JoinSpecificationStarter leftJoin(SqlTable joinTable, String tableAlias) return leftJoin(joinTable); } + public JoinSpecificationStarter leftJoin(Buildable joinTable) { + return new JoinSpecificationStarter(buildSubQuery(joinTable), JoinType.LEFT); + } + + public JoinSpecificationStarter leftJoin(Buildable joinTable, String tableAlias) { + return new JoinSpecificationStarter(buildSubQuery(joinTable, tableAlias), JoinType.LEFT); + } + public JoinSpecificationStarter rightJoin(SqlTable joinTable) { return new JoinSpecificationStarter(joinTable, JoinType.RIGHT); } @@ -108,6 +124,14 @@ public JoinSpecificationStarter rightJoin(SqlTable joinTable, String tableAlias) return rightJoin(joinTable); } + public JoinSpecificationStarter rightJoin(Buildable joinTable) { + return new JoinSpecificationStarter(buildSubQuery(joinTable), JoinType.RIGHT); + } + + public JoinSpecificationStarter rightJoin(Buildable joinTable, String tableAlias) { + return new JoinSpecificationStarter(buildSubQuery(joinTable, tableAlias), JoinType.RIGHT); + } + public JoinSpecificationStarter fullJoin(SqlTable joinTable) { return new JoinSpecificationStarter(joinTable, JoinType.FULL); } @@ -117,6 +141,14 @@ public JoinSpecificationStarter fullJoin(SqlTable joinTable, String tableAlias) return fullJoin(joinTable); } + public JoinSpecificationStarter fullJoin(Buildable joinTable) { + return new JoinSpecificationStarter(buildSubQuery(joinTable), JoinType.FULL); + } + + public JoinSpecificationStarter fullJoin(Buildable joinTable, String tableAlias) { + return new JoinSpecificationStarter(buildSubQuery(joinTable, tableAlias), JoinType.FULL); + } + public GroupByFinisher groupBy(BasicColumn...columns) { return groupBy(Arrays.asList(columns)); } @@ -201,19 +233,6 @@ public QueryExpressionDSL from(SqlTable table, String tableAlias) { return selectDSL.newQueryExpression(this, table, tableAlias); } - private SubQuery buildSubQuery(Buildable selectModel) { - return new SubQuery.Builder() - .withSelectModel(selectModel.build()) - .build(); - } - - private SubQuery buildSubQuery(Buildable selectModel, String alias) { - return new SubQuery.Builder() - .withSelectModel(selectModel.build()) - .withAlias(alias) - .build(); - } - public static class Builder { private String connector; private final List selectList = new ArrayList<>(); @@ -297,10 +316,10 @@ protected WhereModel buildWhereModel() { } public class JoinSpecificationStarter { - private final SqlTable joinTable; + private final TableExpression joinTable; private final JoinType joinType; - public JoinSpecificationStarter(SqlTable joinTable, JoinType joinType) { + public JoinSpecificationStarter(TableExpression joinTable, JoinType joinType) { this.joinTable = joinTable; this.joinType = joinType; } @@ -318,7 +337,7 @@ public JoinSpecificationFinisher on(BasicColumn joinColumn, JoinCondition onJoin public class JoinSpecificationFinisher implements Buildable { private final JoinSpecification.Builder joinSpecificationBuilder; - public JoinSpecificationFinisher(SqlTable table, BasicColumn joinColumn, + public JoinSpecificationFinisher(TableExpression table, BasicColumn joinColumn, JoinCondition joinCondition, JoinType joinType) { JoinCriterion joinCriterion = new JoinCriterion.Builder() .withConnector("on") //$NON-NLS-1$ @@ -333,7 +352,7 @@ public JoinSpecificationFinisher(SqlTable table, BasicColumn joinColumn, addJoinSpecificationBuilder(joinSpecificationBuilder); } - public JoinSpecificationFinisher(SqlTable table, BasicColumn joinColumn, + public JoinSpecificationFinisher(TableExpression table, BasicColumn joinColumn, JoinCondition joinCondition, JoinType joinType, JoinCriterion...andJoinCriteria) { JoinCriterion onJoinCriterion = new JoinCriterion.Builder() .withConnector("on") //$NON-NLS-1$ @@ -386,6 +405,14 @@ public JoinSpecificationStarter join(SqlTable joinTable, String tableAlias) { return QueryExpressionDSL.this.join(joinTable, tableAlias); } + public JoinSpecificationStarter join(Buildable joinTable) { + return QueryExpressionDSL.this.join(joinTable); + } + + public JoinSpecificationStarter join(Buildable joinTable, String tableAlias) { + return QueryExpressionDSL.this.join(joinTable, tableAlias); + } + public JoinSpecificationStarter leftJoin(SqlTable joinTable) { return QueryExpressionDSL.this.leftJoin(joinTable); } @@ -394,6 +421,14 @@ public JoinSpecificationStarter leftJoin(SqlTable joinTable, String tableAlias) return QueryExpressionDSL.this.leftJoin(joinTable, tableAlias); } + public JoinSpecificationStarter leftJoin(Buildable joinTable) { + return QueryExpressionDSL.this.leftJoin(joinTable); + } + + public JoinSpecificationStarter leftJoin(Buildable joinTable, String tableAlias) { + return QueryExpressionDSL.this.leftJoin(joinTable, tableAlias); + } + public JoinSpecificationStarter rightJoin(SqlTable joinTable) { return QueryExpressionDSL.this.rightJoin(joinTable); } @@ -402,6 +437,14 @@ public JoinSpecificationStarter rightJoin(SqlTable joinTable, String tableAlias) return QueryExpressionDSL.this.rightJoin(joinTable, tableAlias); } + public JoinSpecificationStarter rightJoin(Buildable joinTable) { + return QueryExpressionDSL.this.rightJoin(joinTable); + } + + public JoinSpecificationStarter rightJoin(Buildable joinTable, String tableAlias) { + return QueryExpressionDSL.this.rightJoin(joinTable, tableAlias); + } + public JoinSpecificationStarter fullJoin(SqlTable joinTable) { return QueryExpressionDSL.this.fullJoin(joinTable); } @@ -410,6 +453,14 @@ public JoinSpecificationStarter fullJoin(SqlTable joinTable, String tableAlias) return QueryExpressionDSL.this.fullJoin(joinTable, tableAlias); } + public JoinSpecificationStarter fullJoin(Buildable joinTable) { + return QueryExpressionDSL.this.fullJoin(joinTable); + } + + public JoinSpecificationStarter fullJoin(Buildable joinTable, String tableAlias) { + return QueryExpressionDSL.this.fullJoin(joinTable, tableAlias); + } + public GroupByFinisher groupBy(BasicColumn...columns) { return QueryExpressionDSL.this.groupBy(columns); } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionModel.java b/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionModel.java index 6142792ec..f72e97dce 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionModel.java @@ -48,12 +48,21 @@ private QueryExpressionModel(Builder builder) { selectList = Objects.requireNonNull(builder.selectList); table = Objects.requireNonNull(builder.table); joinModel = builder.joinModel; - tableAliasCalculator = joinModel().map(jm -> GuaranteedTableAliasCalculator.of(builder.tableAliases)) + tableAliasCalculator = joinModel().map(jm -> determineJoinTableAliasCalculator(jm, builder.tableAliases)) .orElseGet(() -> TableAliasCalculator.of(builder.tableAliases)); whereModel = builder.whereModel; groupByModel = builder.groupByModel; } + private TableAliasCalculator determineJoinTableAliasCalculator(JoinModel joinModel, Map tableAliases) { + if (joinModel.containsSubQueries()) { + // if there are subQueries, then force explicit qualifiers + return TableAliasCalculator.of(tableAliases); + } else { + return GuaranteedTableAliasCalculator.of(tableAliases); + } + } + public Optional connector() { return Optional.ofNullable(connector); } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/SubQuery.java b/src/main/java/org/mybatis/dynamic/sql/select/SubQuery.java index d22185c72..a2373d9b7 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/SubQuery.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/SubQuery.java @@ -38,6 +38,11 @@ public Optional alias() { return Optional.ofNullable(alias); } + @Override + public boolean isSubQuery() { + return true; + } + @Override public R accept(TableExpressionVisitor visitor) { return visitor.visit(this); diff --git a/src/main/java/org/mybatis/dynamic/sql/select/join/JoinModel.java b/src/main/java/org/mybatis/dynamic/sql/select/join/JoinModel.java index 8baa1038a..79c86d7e7 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/join/JoinModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/join/JoinModel.java @@ -15,6 +15,8 @@ */ package org.mybatis.dynamic.sql.select.join; +import org.mybatis.dynamic.sql.TableExpression; + import java.util.ArrayList; import java.util.List; import java.util.function.Function; @@ -34,4 +36,10 @@ public Stream mapJoinSpecifications(Function mapper public static JoinModel of(List joinSpecifications) { return new JoinModel(joinSpecifications); } + + public boolean containsSubQueries() { + return joinSpecifications.stream() + .map(JoinSpecification::table) + .anyMatch(TableExpression::isSubQuery); + } } diff --git a/src/test/java/examples/joins/JoinSubQueryTest.java b/src/test/java/examples/joins/JoinSubQueryTest.java new file mode 100644 index 000000000..3dd9d9cd3 --- /dev/null +++ b/src/test/java/examples/joins/JoinSubQueryTest.java @@ -0,0 +1,1007 @@ +/* + * Copyright 2016-2020 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 + * + * http://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 examples.joins; + +import org.apache.ibatis.datasource.unpooled.UnpooledDataSource; +import org.apache.ibatis.jdbc.ScriptRunner; +import org.apache.ibatis.mapping.Environment; +import org.apache.ibatis.session.Configuration; +import org.apache.ibatis.session.SqlSession; +import org.apache.ibatis.session.SqlSessionFactory; +import org.apache.ibatis.session.SqlSessionFactoryBuilder; +import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mybatis.dynamic.sql.render.RenderingStrategies; +import org.mybatis.dynamic.sql.select.render.SelectStatementProvider; +import org.mybatis.dynamic.sql.util.mybatis3.CommonSelectMapper; + +import java.io.InputStream; +import java.io.InputStreamReader; +import java.sql.Connection; +import java.sql.DriverManager; +import java.util.List; +import java.util.Map; + +import static examples.joins.ItemMasterDynamicSQLSupport.itemMaster; +import static examples.joins.OrderDetailDynamicSQLSupport.orderDetail; +import static examples.joins.OrderLineDynamicSQLSupport.orderLine; +import static examples.joins.OrderMasterDynamicSQLSupport.orderMaster; +import static examples.joins.UserDynamicSQLSupport.user; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mybatis.dynamic.sql.SqlBuilder.and; +import static org.mybatis.dynamic.sql.SqlBuilder.equalTo; +import static org.mybatis.dynamic.sql.SqlBuilder.isEqualTo; +import static org.mybatis.dynamic.sql.SqlBuilder.on; +import static org.mybatis.dynamic.sql.SqlBuilder.select; +import static org.mybatis.dynamic.sql.SqlBuilder.sortColumn; + +class JoinSubQueryTest { + + private static final String JDBC_URL = "jdbc:hsqldb:mem:aname"; + private static final String JDBC_DRIVER = "org.hsqldb.jdbcDriver"; + + private SqlSessionFactory sqlSessionFactory; + + @BeforeEach + void setup() throws Exception { + Class.forName(JDBC_DRIVER); + InputStream is = getClass().getResourceAsStream("/examples/joins/CreateJoinDB.sql"); + try (Connection connection = DriverManager.getConnection(JDBC_URL, "sa", "")) { + ScriptRunner sr = new ScriptRunner(connection); + sr.setLogWriter(null); + sr.runScript(new InputStreamReader(is)); + } + + UnpooledDataSource ds = new UnpooledDataSource(JDBC_DRIVER, JDBC_URL, "sa", ""); + Environment environment = new Environment("test", new JdbcTransactionFactory(), ds); + Configuration config = new Configuration(environment); + config.addMapper(JoinMapper.class); + config.addMapper(CommonSelectMapper.class); + sqlSessionFactory = new SqlSessionFactoryBuilder().build(config); + } + + @Test + void testSingleTableJoin1() { + try (SqlSession session = sqlSessionFactory.openSession()) { + JoinMapper mapper = session.getMapper(JoinMapper.class); + + SelectStatementProvider selectStatement = select(orderMaster.orderId, orderMaster.orderDate, + orderDetail.lineNumber, orderDetail.description, orderDetail.quantity) + .from(orderMaster, "om") + .join(select(orderDetail.orderId, orderDetail.lineNumber, orderDetail.description, orderDetail.quantity) + .from(orderDetail), + "od").on(orderMaster.orderId, equalTo(orderDetail.orderId.qualifiedWith("od"))) + .build() + .render(RenderingStrategies.MYBATIS3); + + String expectedStatement = "select om.order_id, om.order_date, line_number, description, quantity" + + " from OrderMaster om join " + + "(select order_id, line_number, description, quantity from OrderDetail) od on om.order_id = od.order_id"; + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); + + List rows = mapper.selectMany(selectStatement); + + assertThat(rows).hasSize(2); + OrderMaster orderMaster = rows.get(0); + assertThat(orderMaster.getId()).isEqualTo(1); + assertThat(orderMaster.getDetails()).hasSize(2); + OrderDetail orderDetail = orderMaster.getDetails().get(0); + assertThat(orderDetail.getLineNumber()).isEqualTo(1); + orderDetail = orderMaster.getDetails().get(1); + assertThat(orderDetail.getLineNumber()).isEqualTo(2); + + orderMaster = rows.get(1); + assertThat(orderMaster.getId()).isEqualTo(2); + assertThat(orderMaster.getDetails()).hasSize(1); + orderDetail = orderMaster.getDetails().get(0); + assertThat(orderDetail.getLineNumber()).isEqualTo(1); + } + } + +// @Test +// void testMultipleTableJoinWithWhereClause() { +// try (SqlSession session = sqlSessionFactory.openSession()) { +// JoinMapper mapper = session.getMapper(JoinMapper.class); +// +// SelectStatementProvider selectStatement = select(orderMaster.orderId, orderMaster.orderDate, orderDetail.lineNumber, itemMaster.description, orderLine.quantity) +// .from(orderMaster, "om") +// .join(orderLine, "ol").on(orderMaster.orderId, equalTo(orderLine.orderId)) +// .join(itemMaster, "im").on(orderLine.itemId, equalTo(itemMaster.itemId)) +// .where(orderMaster.orderId, isEqualTo(2)) +// .build() +// .render(RenderingStrategies.MYBATIS3); +// +// String expectedStatment = "select om.order_id, om.order_date, ol.line_number, im.description, ol.quantity" +// + " from OrderMaster om join OrderLine ol on om.order_id = ol.order_id join ItemMaster im on ol.item_id = im.item_id" +// + " where om.order_id = #{parameters.p1,jdbcType=INTEGER}"; +// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); +// +// List rows = mapper.selectMany(selectStatement); +// +// assertThat(rows).hasSize(1); +// OrderMaster orderMaster = rows.get(0); +// assertThat(orderMaster.getId()).isEqualTo(2); +// assertThat(orderMaster.getDetails()).hasSize(2); +// OrderDetail orderDetail = orderMaster.getDetails().get(0); +// assertThat(orderDetail.getLineNumber()).isEqualTo(1); +// orderDetail = orderMaster.getDetails().get(1); +// assertThat(orderDetail.getLineNumber()).isEqualTo(2); +// } +// } +// +// @Test +// void testMultipleTableJoinWithApplyWhere() { +// try (SqlSession session = sqlSessionFactory.openSession()) { +// JoinMapper mapper = session.getMapper(JoinMapper.class); +// +// SelectStatementProvider selectStatement = select(orderMaster.orderId, orderMaster.orderDate, orderLine.lineNumber, itemMaster.description, orderLine.quantity) +// .from(orderMaster, "om") +// .join(orderLine, "ol").on(orderMaster.orderId, equalTo(orderLine.orderId)) +// .join(itemMaster, "im").on(orderLine.itemId, equalTo(itemMaster.itemId)) +// .applyWhere(d -> d.where(orderMaster.orderId, isEqualTo(2))) +// .build() +// .render(RenderingStrategies.MYBATIS3); +// +// String expectedStatment = "select om.order_id, om.order_date, ol.line_number, im.description, ol.quantity" +// + " from OrderMaster om join OrderLine ol on om.order_id = ol.order_id join ItemMaster im on ol.item_id = im.item_id" +// + " where om.order_id = #{parameters.p1,jdbcType=INTEGER}"; +// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); +// +// List rows = mapper.selectMany(selectStatement); +// +// assertThat(rows).hasSize(1); +// OrderMaster orderMaster = rows.get(0); +// assertThat(orderMaster.getId()).isEqualTo(2); +// assertThat(orderMaster.getDetails()).hasSize(2); +// OrderDetail orderDetail = orderMaster.getDetails().get(0); +// assertThat(orderDetail.getLineNumber()).isEqualTo(1); +// orderDetail = orderMaster.getDetails().get(1); +// assertThat(orderDetail.getLineNumber()).isEqualTo(2); +// } +// } +// +// @Test +// void testMultipleTableJoinWithComplexWhereClause() { +// try (SqlSession session = sqlSessionFactory.openSession()) { +// JoinMapper mapper = session.getMapper(JoinMapper.class); +// +// SelectStatementProvider selectStatement = select(orderMaster.orderId, orderMaster.orderDate, orderLine.lineNumber, itemMaster.description, orderLine.quantity) +// .from(orderMaster, "om") +// .join(orderLine, "ol").on(orderMaster.orderId, equalTo(orderLine.orderId)) +// .join(itemMaster, "im").on(orderLine.itemId, equalTo(itemMaster.itemId)) +// .where(orderMaster.orderId, isEqualTo(2), and(orderLine.lineNumber, isEqualTo(2))) +// .build() +// .render(RenderingStrategies.MYBATIS3); +// +// String expectedStatment = "select om.order_id, om.order_date, ol.line_number, im.description, ol.quantity" +// + " from OrderMaster om join OrderLine ol on om.order_id = ol.order_id join ItemMaster im on ol.item_id = im.item_id" +// + " where (om.order_id = #{parameters.p1,jdbcType=INTEGER} and ol.line_number = #{parameters.p2,jdbcType=INTEGER})"; +// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); +// +// List rows = mapper.selectMany(selectStatement); +// +// assertThat(rows).hasSize(1); +// OrderMaster orderMaster = rows.get(0); +// assertThat(orderMaster.getId()).isEqualTo(2); +// assertThat(orderMaster.getDetails()).hasSize(1); +// OrderDetail orderDetail = orderMaster.getDetails().get(0); +// assertThat(orderDetail.getLineNumber()).isEqualTo(2); +// } +// } +// +// @Test +// void testMultipleTableJoinWithOrderBy() { +// try (SqlSession session = sqlSessionFactory.openSession()) { +// JoinMapper mapper = session.getMapper(JoinMapper.class); +// +// SelectStatementProvider selectStatement = select(orderMaster.orderId, orderMaster.orderDate, orderLine.lineNumber, itemMaster.description, orderLine.quantity) +// .from(orderMaster, "om") +// .join(orderLine, "ol").on(orderMaster.orderId, equalTo(orderLine.orderId)) +// .join(itemMaster, "im").on(orderLine.itemId, equalTo(itemMaster.itemId)) +// .orderBy(orderMaster.orderId) +// .build() +// .render(RenderingStrategies.MYBATIS3); +// +// String expectedStatment = "select om.order_id, om.order_date, ol.line_number, im.description, ol.quantity" +// + " from OrderMaster om join OrderLine ol on om.order_id = ol.order_id join ItemMaster im on ol.item_id = im.item_id" +// + " order by order_id"; +// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); +// +// List rows = mapper.selectMany(selectStatement); +// +// assertThat(rows).hasSize(2); +// OrderMaster orderMaster = rows.get(0); +// assertThat(orderMaster.getId()).isEqualTo(1); +// assertThat(orderMaster.getDetails()).hasSize(1); +// OrderDetail orderDetail = orderMaster.getDetails().get(0); +// assertThat(orderDetail.getLineNumber()).isEqualTo(1); +// +// orderMaster = rows.get(1); +// assertThat(orderMaster.getId()).isEqualTo(2); +// assertThat(orderMaster.getDetails()).hasSize(2); +// orderDetail = orderMaster.getDetails().get(0); +// assertThat(orderDetail.getLineNumber()).isEqualTo(1); +// orderDetail = orderMaster.getDetails().get(1); +// assertThat(orderDetail.getLineNumber()).isEqualTo(2); +// } +// } +// +// @Test +// void testMultibleTableJoinNoAliasWithOrderBy() { +// try (SqlSession session = sqlSessionFactory.openSession()) { +// JoinMapper mapper = session.getMapper(JoinMapper.class); +// +// SelectStatementProvider selectStatement = select(orderMaster.orderId, orderMaster.orderDate, orderLine.lineNumber, itemMaster.description, orderLine.quantity) +// .from(orderMaster) +// .join(orderLine).on(orderMaster.orderId, equalTo(orderLine.orderId)) +// .join(itemMaster).on(orderLine.itemId, equalTo(itemMaster.itemId)) +// .where(orderMaster.orderId, isEqualTo(2)) +// .orderBy(orderMaster.orderId) +// .build() +// .render(RenderingStrategies.MYBATIS3); +// +// String expectedStatment = "select OrderMaster.order_id, OrderMaster.order_date, OrderLine.line_number, ItemMaster.description, OrderLine.quantity" +// + " from OrderMaster join OrderLine on OrderMaster.order_id = OrderLine.order_id join ItemMaster on OrderLine.item_id = ItemMaster.item_id" +// + " where OrderMaster.order_id = #{parameters.p1,jdbcType=INTEGER}" +// + " order by order_id"; +// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); +// +// List rows = mapper.selectMany(selectStatement); +// +// assertThat(rows).hasSize(1); +// OrderMaster orderMaster = rows.get(0); +// assertThat(orderMaster.getId()).isEqualTo(2); +// assertThat(orderMaster.getDetails()).hasSize(2); +// OrderDetail orderDetail = orderMaster.getDetails().get(0); +// assertThat(orderDetail.getLineNumber()).isEqualTo(1); +// orderDetail = orderMaster.getDetails().get(1); +// assertThat(orderDetail.getLineNumber()).isEqualTo(2); +// } +// } +// +// @Test +// void testRightJoin() { +// try (SqlSession session = sqlSessionFactory.openSession()) { +// CommonSelectMapper mapper = session.getMapper(CommonSelectMapper.class); +// +// SelectStatementProvider selectStatement = select(orderLine.orderId, orderLine.quantity, itemMaster.itemId, itemMaster.description) +// .from(orderLine, "ol") +// .rightJoin(itemMaster, "im").on(orderLine.itemId, equalTo(itemMaster.itemId)) +// .orderBy(itemMaster.itemId) +// .build() +// .render(RenderingStrategies.MYBATIS3); +// +// String expectedStatment = "select ol.order_id, ol.quantity, im.item_id, im.description" +// + " from OrderLine ol right join ItemMaster im on ol.item_id = im.item_id" +// + " order by item_id"; +// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); +// +// List> rows = mapper.selectManyMappedRows(selectStatement); +// +// assertThat(rows).hasSize(5); +// Map row = rows.get(2); +// assertThat(row).containsEntry("ORDER_ID", 1); +// assertThat(row).containsEntry("QUANTITY", 1); +// assertThat(row).containsEntry("DESCRIPTION", "First Base Glove"); +// assertThat(row).containsEntry("ITEM_ID", 33); +// +// row = rows.get(4); +// assertThat(row).doesNotContainKey("ORDER_ID"); +// assertThat(row).doesNotContainKey("QUANTITY"); +// assertThat(row).containsEntry("DESCRIPTION", "Catcher Glove"); +// assertThat(row).containsEntry("ITEM_ID", 55); +// } +// } +// +// @Test +// void testRightJoin2() { +// try (SqlSession session = sqlSessionFactory.openSession()) { +// CommonSelectMapper mapper = session.getMapper(CommonSelectMapper.class); +// +// SelectStatementProvider selectStatement = select(orderLine.orderId, orderLine.quantity, itemMaster.itemId, itemMaster.description) +// .from(orderMaster, "om") +// .join(orderLine, "ol").on(orderMaster.orderId, equalTo(orderLine.orderId)) +// .rightJoin(itemMaster, "im").on(orderLine.itemId, equalTo(itemMaster.itemId)) +// .orderBy(orderLine.orderId, itemMaster.itemId) +// .build() +// .render(RenderingStrategies.MYBATIS3); +// +// String expectedStatment = "select ol.order_id, ol.quantity, im.item_id, im.description" +// + " from OrderMaster om join OrderLine ol on om.order_id = ol.order_id" +// + " right join ItemMaster im on ol.item_id = im.item_id" +// + " order by order_id, item_id"; +// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); +// +// List> rows = mapper.selectManyMappedRows(selectStatement); +// +// assertThat(rows).hasSize(5); +// Map row = rows.get(0); +// assertThat(row).doesNotContainKey("ORDER_ID"); +// assertThat(row).doesNotContainKey("QUANTITY"); +// assertThat(row).containsEntry("DESCRIPTION", "Catcher Glove"); +// assertThat(row).containsEntry("ITEM_ID", 55); +// +// row = rows.get(4); +// assertThat(row).containsEntry("ORDER_ID", 2); +// assertThat(row).containsEntry("QUANTITY", 1); +// assertThat(row).containsEntry("DESCRIPTION", "Outfield Glove"); +// assertThat(row).containsEntry("ITEM_ID", 44); +// } +// } +// +// @Test +// void testRightJoin3() { +// try (SqlSession session = sqlSessionFactory.openSession()) { +// CommonSelectMapper mapper = session.getMapper(CommonSelectMapper.class); +// +// SelectStatementProvider selectStatement = select(orderLine.orderId, orderLine.quantity, itemMaster.itemId, itemMaster.description) +// .from(orderMaster, "om") +// .join(orderLine, "ol", on(orderMaster.orderId, equalTo(orderLine.orderId))) +// .rightJoin(itemMaster, "im", on(orderLine.itemId, equalTo(itemMaster.itemId))) +// .orderBy(orderLine.orderId, itemMaster.itemId) +// .build() +// .render(RenderingStrategies.MYBATIS3); +// +// String expectedStatment = "select ol.order_id, ol.quantity, im.item_id, im.description" +// + " from OrderMaster om join OrderLine ol on om.order_id = ol.order_id" +// + " right join ItemMaster im on ol.item_id = im.item_id" +// + " order by order_id, item_id"; +// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); +// +// List> rows = mapper.selectManyMappedRows(selectStatement); +// +// assertThat(rows).hasSize(5); +// Map row = rows.get(0); +// assertThat(row).doesNotContainKey("ORDER_ID"); +// assertThat(row).doesNotContainKey("QUANTITY"); +// assertThat(row).containsEntry("DESCRIPTION", "Catcher Glove"); +// assertThat(row).containsEntry("ITEM_ID", 55); +// +// row = rows.get(4); +// assertThat(row).containsEntry("ORDER_ID", 2); +// assertThat(row).containsEntry("QUANTITY", 1); +// assertThat(row).containsEntry("DESCRIPTION", "Outfield Glove"); +// assertThat(row).containsEntry("ITEM_ID", 44); +// } +// } +// +// @Test +// void testRightJoinNoAliases() { +// try (SqlSession session = sqlSessionFactory.openSession()) { +// CommonSelectMapper mapper = session.getMapper(CommonSelectMapper.class); +// +// SelectStatementProvider selectStatement = select(orderLine.orderId, orderLine.quantity, itemMaster.itemId, itemMaster.description) +// .from(orderMaster) +// .join(orderLine).on(orderMaster.orderId, equalTo(orderLine.orderId)) +// .rightJoin(itemMaster).on(orderLine.itemId, equalTo(itemMaster.itemId)) +// .orderBy(orderLine.orderId, itemMaster.itemId) +// .build() +// .render(RenderingStrategies.MYBATIS3); +// +// String expectedStatment = "select OrderLine.order_id, OrderLine.quantity, ItemMaster.item_id, ItemMaster.description" +// + " from OrderMaster join OrderLine on OrderMaster.order_id = OrderLine.order_id" +// + " right join ItemMaster on OrderLine.item_id = ItemMaster.item_id" +// + " order by order_id, item_id"; +// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); +// +// List> rows = mapper.selectManyMappedRows(selectStatement); +// +// assertThat(rows).hasSize(5); +// Map row = rows.get(0); +// assertThat(row).doesNotContainKey("ORDER_ID"); +// assertThat(row).doesNotContainKey("QUANTITY"); +// assertThat(row).containsEntry("DESCRIPTION", "Catcher Glove"); +// assertThat(row).containsEntry("ITEM_ID", 55); +// +// row = rows.get(4); +// assertThat(row).containsEntry("ORDER_ID", 2); +// assertThat(row).containsEntry("QUANTITY", 1); +// assertThat(row).containsEntry("DESCRIPTION", "Outfield Glove"); +// assertThat(row).containsEntry("ITEM_ID", 44); +// } +// } +// +// @Test +// void testLeftJoin() { +// 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") +// .leftJoin(orderLine, "ol").on(orderLine.itemId, equalTo(itemMaster.itemId)) +// .orderBy(itemMaster.itemId) +// .build() +// .render(RenderingStrategies.MYBATIS3); +// +// String expectedStatment = "select ol.order_id, ol.quantity, im.item_id, im.description" +// + " from ItemMaster im left join OrderLine ol on ol.item_id = im.item_id" +// + " order by item_id"; +// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); +// +// List> rows = mapper.selectManyMappedRows(selectStatement); +// +// assertThat(rows).hasSize(5); +// Map row = rows.get(2); +// assertThat(row).containsEntry("ORDER_ID", 1); +// assertThat(row).containsEntry("QUANTITY", 1); +// assertThat(row).containsEntry("DESCRIPTION", "First Base Glove"); +// assertThat(row).containsEntry("ITEM_ID", 33); +// +// row = rows.get(4); +// assertThat(row).doesNotContainKey("ORDER_ID"); +// assertThat(row).doesNotContainKey("QUANTITY"); +// assertThat(row).containsEntry("DESCRIPTION", "Catcher Glove"); +// assertThat(row).containsEntry("ITEM_ID", 55); +// } +// } +// +// @Test +// void testLeftJoin2() { +// try (SqlSession session = sqlSessionFactory.openSession()) { +// CommonSelectMapper mapper = session.getMapper(CommonSelectMapper.class); +// +// SelectStatementProvider selectStatement = select(orderLine.orderId, orderLine.quantity, itemMaster.itemId, itemMaster.description) +// .from(orderMaster, "om") +// .join(orderLine, "ol").on(orderMaster.orderId, equalTo(orderLine.orderId)) +// .leftJoin(itemMaster, "im").on(orderLine.itemId, equalTo(itemMaster.itemId)) +// .orderBy(orderLine.orderId, itemMaster.itemId) +// .build() +// .render(RenderingStrategies.MYBATIS3); +// +// String expectedStatment = "select ol.order_id, ol.quantity, im.item_id, im.description" +// + " from OrderMaster om join OrderLine ol on om.order_id = ol.order_id" +// + " left join ItemMaster im on ol.item_id = im.item_id" +// + " order by order_id, item_id"; +// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); +// +// List> rows = mapper.selectManyMappedRows(selectStatement); +// +// assertThat(rows).hasSize(5); +// Map row = rows.get(2); +// assertThat(row).containsEntry("ORDER_ID", 2); +// assertThat(row).containsEntry("QUANTITY", 6); +// assertThat(row).doesNotContainKey("DESCRIPTION"); +// assertThat(row).doesNotContainKey("ITEM_ID"); +// +// row = rows.get(4); +// assertThat(row).containsEntry("ORDER_ID", 2); +// assertThat(row).containsEntry("QUANTITY", 1); +// assertThat(row).containsEntry("DESCRIPTION", "Outfield Glove"); +// assertThat(row).containsEntry("ITEM_ID", 44); +// } +// } +// +// @Test +// void testLeftJoin3() { +// try (SqlSession session = sqlSessionFactory.openSession()) { +// CommonSelectMapper mapper = session.getMapper(CommonSelectMapper.class); +// +// SelectStatementProvider selectStatement = select(orderLine.orderId, orderLine.quantity, itemMaster.itemId, itemMaster.description) +// .from(orderMaster, "om") +// .join(orderLine, "ol", on(orderMaster.orderId, equalTo(orderLine.orderId))) +// .leftJoin(itemMaster, "im", on(orderLine.itemId, equalTo(itemMaster.itemId))) +// .orderBy(orderLine.orderId, itemMaster.itemId) +// .build() +// .render(RenderingStrategies.MYBATIS3); +// +// String expectedStatment = "select ol.order_id, ol.quantity, im.item_id, im.description" +// + " from OrderMaster om join OrderLine ol on om.order_id = ol.order_id" +// + " left join ItemMaster im on ol.item_id = im.item_id" +// + " order by order_id, item_id"; +// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); +// +// List> rows = mapper.selectManyMappedRows(selectStatement); +// +// assertThat(rows).hasSize(5); +// Map row = rows.get(2); +// assertThat(row).containsEntry("ORDER_ID", 2); +// assertThat(row).containsEntry("QUANTITY", 6); +// assertThat(row).doesNotContainKey("DESCRIPTION"); +// assertThat(row).doesNotContainKey("ITEM_ID"); +// +// row = rows.get(4); +// assertThat(row).containsEntry("ORDER_ID", 2); +// assertThat(row).containsEntry("QUANTITY", 1); +// assertThat(row).containsEntry("DESCRIPTION", "Outfield Glove"); +// assertThat(row).containsEntry("ITEM_ID", 44); +// } +// } +// +// @Test +// void testLeftJoinNoAliases() { +// try (SqlSession session = sqlSessionFactory.openSession()) { +// CommonSelectMapper mapper = session.getMapper(CommonSelectMapper.class); +// +// SelectStatementProvider selectStatement = select(orderLine.orderId, orderLine.quantity, itemMaster.itemId, itemMaster.description) +// .from(orderMaster) +// .join(orderLine).on(orderMaster.orderId, equalTo(orderLine.orderId)) +// .leftJoin(itemMaster).on(orderLine.itemId, equalTo(itemMaster.itemId)) +// .orderBy(orderLine.orderId, itemMaster.itemId) +// .build() +// .render(RenderingStrategies.MYBATIS3); +// +// String expectedStatment = "select OrderLine.order_id, OrderLine.quantity, ItemMaster.item_id, ItemMaster.description" +// + " from OrderMaster join OrderLine on OrderMaster.order_id = OrderLine.order_id" +// + " left join ItemMaster on OrderLine.item_id = ItemMaster.item_id" +// + " order by order_id, item_id"; +// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); +// +// List> rows = mapper.selectManyMappedRows(selectStatement); +// +// assertThat(rows).hasSize(5); +// Map row = rows.get(2); +// assertThat(row).containsEntry("ORDER_ID", 2); +// assertThat(row).containsEntry("QUANTITY", 6); +// assertThat(row).doesNotContainKey("DESCRIPTION"); +// assertThat(row).doesNotContainKey("ITEM_ID"); +// +// row = rows.get(4); +// assertThat(row).containsEntry("ORDER_ID", 2); +// assertThat(row).containsEntry("QUANTITY", 1); +// assertThat(row).containsEntry("DESCRIPTION", "Outfield Glove"); +// assertThat(row).containsEntry("ITEM_ID", 44); +// } +// } +// +// @Test +// void testFullJoin() { +// try (SqlSession session = sqlSessionFactory.openSession()) { +// CommonSelectMapper mapper = session.getMapper(CommonSelectMapper.class); +// +// SelectStatementProvider selectStatement = select(orderLine.orderId, orderLine.quantity, orderLine.itemId.as("ol_itemid"), itemMaster.itemId.as("im_itemid"), itemMaster.description) +// .from(itemMaster, "im") +// .fullJoin(orderLine, "ol").on(itemMaster.itemId, equalTo(orderLine.itemId)) +// .orderBy(sortColumn("im_itemid")) +// .build() +// .render(RenderingStrategies.MYBATIS3); +// +// String expectedStatment = "select ol.order_id, ol.quantity, ol.item_id as ol_itemid, im.item_id as im_itemid, im.description" +// + " from ItemMaster im full join OrderLine ol on im.item_id = ol.item_id" +// + " order by im_itemid"; +// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); +// +// List> rows = mapper.selectManyMappedRows(selectStatement); +// +// assertThat(rows).hasSize(6); +// Map row = rows.get(0); +// assertThat(row).containsEntry("ORDER_ID", 2); +// assertThat(row).containsEntry("QUANTITY", 6); +// assertThat(row).containsEntry("OL_ITEMID", 66); +// assertThat(row).doesNotContainKey("DESCRIPTION"); +// assertThat(row).doesNotContainKey("IM_ITEMID"); +// +// row = rows.get(3); +// assertThat(row).containsEntry("ORDER_ID", 1); +// assertThat(row).containsEntry("QUANTITY", 1); +// assertThat(row).containsEntry("DESCRIPTION", "First Base Glove"); +// assertThat(row).containsEntry("IM_ITEMID", 33); +// +// row = rows.get(5); +// assertThat(row).doesNotContainKey("ORDER_ID"); +// assertThat(row).doesNotContainKey("QUANTITY"); +// assertThat(row).containsEntry("DESCRIPTION", "Catcher Glove"); +// assertThat(row).containsEntry("IM_ITEMID", 55); +// } +// } +// +// @Test +// void testFullJoin2() { +// try (SqlSession session = sqlSessionFactory.openSession()) { +// CommonSelectMapper mapper = session.getMapper(CommonSelectMapper.class); +// +// SelectStatementProvider selectStatement = select(orderLine.orderId, orderLine.quantity, itemMaster.itemId, itemMaster.description) +// .from(orderMaster, "om") +// .join(orderLine, "ol").on(orderMaster.orderId, equalTo(orderLine.orderId)) +// .fullJoin(itemMaster, "im").on(orderLine.itemId, equalTo(itemMaster.itemId)) +// .orderBy(orderLine.orderId, itemMaster.itemId) +// .build() +// .render(RenderingStrategies.MYBATIS3); +// +// String expectedStatment = "select ol.order_id, ol.quantity, im.item_id, im.description" +// + " from OrderMaster om join OrderLine ol on om.order_id = ol.order_id" +// + " full join ItemMaster im on ol.item_id = im.item_id" +// + " order by order_id, item_id"; +// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); +// +// List> rows = mapper.selectManyMappedRows(selectStatement); +// +// assertThat(rows).hasSize(6); +// Map row = rows.get(0); +// assertThat(row).doesNotContainKey("ORDER_ID"); +// assertThat(row).doesNotContainKey("QUANTITY"); +// assertThat(row).containsEntry("DESCRIPTION", "Catcher Glove"); +// assertThat(row).containsEntry("ITEM_ID", 55); +// +// row = rows.get(3); +// assertThat(row).containsEntry("ORDER_ID", 2); +// assertThat(row).containsEntry("QUANTITY", 6); +// assertThat(row).doesNotContainKey("DESCRIPTION"); +// assertThat(row).doesNotContainKey("ITEM_ID"); +// +// row = rows.get(5); +// assertThat(row).containsEntry("ORDER_ID", 2); +// assertThat(row).containsEntry("QUANTITY", 1); +// assertThat(row).containsEntry("DESCRIPTION", "Outfield Glove"); +// assertThat(row).containsEntry("ITEM_ID", 44); +// } +// } +// +// @Test +// void testFullJoin3() { +// try (SqlSession session = sqlSessionFactory.openSession()) { +// CommonSelectMapper mapper = session.getMapper(CommonSelectMapper.class); +// +// SelectStatementProvider selectStatement = select(orderLine.orderId, orderLine.quantity, itemMaster.itemId, itemMaster.description) +// .from(orderMaster, "om") +// .join(orderLine, "ol", on(orderMaster.orderId, equalTo(orderLine.orderId))) +// .fullJoin(itemMaster, "im", on(orderLine.itemId, equalTo(itemMaster.itemId))) +// .orderBy(orderLine.orderId, itemMaster.itemId) +// .build() +// .render(RenderingStrategies.MYBATIS3); +// +// String expectedStatment = "select ol.order_id, ol.quantity, im.item_id, im.description" +// + " from OrderMaster om join OrderLine ol on om.order_id = ol.order_id" +// + " full join ItemMaster im on ol.item_id = im.item_id" +// + " order by order_id, item_id"; +// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); +// +// List> rows = mapper.selectManyMappedRows(selectStatement); +// +// assertThat(rows).hasSize(6); +// Map row = rows.get(0); +// assertThat(row).doesNotContainKey("ORDER_ID"); +// assertThat(row).doesNotContainKey("QUANTITY"); +// assertThat(row).containsEntry("DESCRIPTION", "Catcher Glove"); +// assertThat(row).containsEntry("ITEM_ID", 55); +// +// row = rows.get(3); +// assertThat(row).containsEntry("ORDER_ID", 2); +// assertThat(row).containsEntry("QUANTITY", 6); +// assertThat(row).doesNotContainKey("DESCRIPTION"); +// assertThat(row).doesNotContainKey("ITEM_ID"); +// +// row = rows.get(5); +// assertThat(row).containsEntry("ORDER_ID", 2); +// assertThat(row).containsEntry("QUANTITY", 1); +// assertThat(row).containsEntry("DESCRIPTION", "Outfield Glove"); +// assertThat(row).containsEntry("ITEM_ID", 44); +// } +// } +// +// @Test +// void testFullJoin4() { +// try (SqlSession session = sqlSessionFactory.openSession()) { +// CommonSelectMapper mapper = session.getMapper(CommonSelectMapper.class); +// +// SelectStatementProvider selectStatement = select(orderLine.orderId, orderLine.quantity, itemMaster.description) +// .from(orderMaster, "om") +// .join(orderLine, "ol", on(orderMaster.orderId, equalTo(orderLine.orderId))) +// .fullJoin(itemMaster, "im", on(orderLine.itemId, equalTo(itemMaster.itemId))) +// .orderBy(orderLine.orderId, sortColumn("im", itemMaster.itemId)) +// .build() +// .render(RenderingStrategies.MYBATIS3); +// +// String expectedStatement = "select ol.order_id, ol.quantity, im.description" +// + " from OrderMaster om join OrderLine ol on om.order_id = ol.order_id" +// + " full join ItemMaster im on ol.item_id = im.item_id" +// + " order by order_id, im.item_id"; +// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); +// +// List> rows = mapper.selectManyMappedRows(selectStatement); +// +// assertThat(rows).hasSize(6); +// Map row = rows.get(0); +// assertThat(row).doesNotContainKey("ORDER_ID"); +// assertThat(row).doesNotContainKey("QUANTITY"); +// assertThat(row).containsEntry("DESCRIPTION", "Catcher Glove"); +// +// row = rows.get(3); +// assertThat(row).containsEntry("ORDER_ID", 2); +// assertThat(row).containsEntry("QUANTITY", 6); +// assertThat(row).doesNotContainKey("DESCRIPTION"); +// +// row = rows.get(5); +// assertThat(row).containsEntry("ORDER_ID", 2); +// assertThat(row).containsEntry("QUANTITY", 1); +// assertThat(row).containsEntry("DESCRIPTION", "Outfield Glove"); +// } +// } +// +// @Test +// void testFullJoin5() { +// try (SqlSession session = sqlSessionFactory.openSession()) { +// CommonSelectMapper mapper = session.getMapper(CommonSelectMapper.class); +// +// SelectStatementProvider selectStatement = select(orderLine.orderId, orderLine.quantity, itemMaster.description) +// .from(orderMaster, "om") +// .join(orderLine, "ol", on(orderMaster.orderId, equalTo(orderLine.orderId))) +// .fullJoin(itemMaster, "im", on(orderLine.itemId, equalTo(itemMaster.itemId))) +// .orderBy(orderLine.orderId, sortColumn("im", itemMaster.itemId).descending()) +// .build() +// .render(RenderingStrategies.MYBATIS3); +// +// String expectedStatement = "select ol.order_id, ol.quantity, im.description" +// + " from OrderMaster om join OrderLine ol on om.order_id = ol.order_id" +// + " full join ItemMaster im on ol.item_id = im.item_id" +// + " order by order_id, im.item_id DESC"; +// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); +// +// List> rows = mapper.selectManyMappedRows(selectStatement); +// +// assertThat(rows).hasSize(6); +// Map row = rows.get(0); +// assertThat(row).doesNotContainKey("ORDER_ID"); +// assertThat(row).doesNotContainKey("QUANTITY"); +// assertThat(row).containsEntry("DESCRIPTION", "Catcher Glove"); +// +// row = rows.get(3); +// assertThat(row).containsEntry("ORDER_ID", 2); +// assertThat(row).containsEntry("QUANTITY", 6); +// assertThat(row).doesNotContainKey("DESCRIPTION"); +// +// row = rows.get(5); +// assertThat(row).containsEntry("ORDER_ID", 2); +// assertThat(row).containsEntry("QUANTITY", 1); +// assertThat(row).containsEntry("DESCRIPTION", "Helmet"); +// } +// } +// +// @Test +// void testFullJoinNoAliases() { +// try (SqlSession session = sqlSessionFactory.openSession()) { +// CommonSelectMapper mapper = session.getMapper(CommonSelectMapper.class); +// +// SelectStatementProvider selectStatement = select(orderLine.orderId, orderLine.quantity, itemMaster.itemId, itemMaster.description) +// .from(orderMaster) +// .join(orderLine).on(orderMaster.orderId, equalTo(orderLine.orderId)) +// .fullJoin(itemMaster).on(orderLine.itemId, equalTo(itemMaster.itemId)) +// .orderBy(orderLine.orderId, itemMaster.itemId) +// .build() +// .render(RenderingStrategies.MYBATIS3); +// +// String expectedStatment = "select OrderLine.order_id, OrderLine.quantity, ItemMaster.item_id, ItemMaster.description" +// + " from OrderMaster join OrderLine on OrderMaster.order_id = OrderLine.order_id" +// + " full join ItemMaster on OrderLine.item_id = ItemMaster.item_id" +// + " order by order_id, item_id"; +// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); +// +// List> rows = mapper.selectManyMappedRows(selectStatement); +// +// assertThat(rows).hasSize(6); +// Map row = rows.get(0); +// assertThat(row).doesNotContainKey("ORDER_ID"); +// assertThat(row).doesNotContainKey("QUANTITY"); +// assertThat(row).containsEntry("DESCRIPTION", "Catcher Glove"); +// assertThat(row).containsEntry("ITEM_ID", 55); +// +// row = rows.get(3); +// assertThat(row).containsEntry("ORDER_ID", 2); +// assertThat(row).containsEntry("QUANTITY", 6); +// assertThat(row).doesNotContainKey("DESCRIPTION"); +// assertThat(row).doesNotContainKey("ITEM_ID"); +// +// row = rows.get(5); +// assertThat(row).containsEntry("ORDER_ID", 2); +// assertThat(row).containsEntry("QUANTITY", 1); +// assertThat(row).containsEntry("DESCRIPTION", "Outfield Glove"); +// assertThat(row).containsEntry("ITEM_ID", 44); +// } +// } +// +// @Test +// void testSelf() { +// try (SqlSession session = sqlSessionFactory.openSession()) { +// JoinMapper mapper = session.getMapper(JoinMapper.class); +// +// // create second table instance for self-join +// UserDynamicSQLSupport.User user2 = new UserDynamicSQLSupport.User(); +// +// // get Bamm Bamm's parent - should be Barney +// SelectStatementProvider selectStatement = select(user.userId, user.userName, user.parentId) +// .from(user, "u1") +// .join(user2, "u2").on(user.userId, equalTo(user2.parentId)) +// .where(user2.userId, isEqualTo(4)) +// .build() +// .render(RenderingStrategies.MYBATIS3); +// +// String expectedStatment = "select u1.user_id, u1.user_name, u1.parent_id" +// + " from User u1 join User u2 on u1.user_id = u2.parent_id" +// + " where u2.user_id = #{parameters.p1,jdbcType=INTEGER}"; +// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); +// +// List rows = mapper.selectUsers(selectStatement); +// +// assertThat(rows).hasSize(1); +// User row = rows.get(0); +// assertThat(row.getUserId()).isEqualTo(2); +// assertThat(row.getUserName()).isEqualTo("Barney"); +// assertThat(row.getParentId()).isNull(); +// } +// } +// +// @Test +// void testLimitAndOffsetAfterJoin() { +// 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") +// .leftJoin(orderLine, "ol").on(orderLine.itemId, equalTo(itemMaster.itemId)) +// .limit(2) +// .offset(1) +// .build() +// .render(RenderingStrategies.MYBATIS3); +// +// String expectedStatment = "select ol.order_id, ol.quantity, im.item_id, im.description" +// + " from ItemMaster im left join OrderLine ol on ol.item_id = im.item_id" +// + " limit #{parameters.p1} offset #{parameters.p2}"; +// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); +// +// List> rows = mapper.selectManyMappedRows(selectStatement); +// +// assertThat(rows).hasSize(2); +// Map row = rows.get(0); +// assertThat(row).containsEntry("ORDER_ID", 2); +// assertThat(row).containsEntry("QUANTITY", 1); +// assertThat(row).containsEntry("DESCRIPTION", "Helmet"); +// assertThat(row).containsEntry("ITEM_ID", 22); +// +// row = rows.get(1); +// assertThat(row).containsEntry("ORDER_ID", 1); +// assertThat(row).containsEntry("QUANTITY", 1); +// assertThat(row).containsEntry("DESCRIPTION", "First Base Glove"); +// assertThat(row).containsEntry("ITEM_ID", 33); +// } +// } +// +// @Test +// void testLimitOnlyAfterJoin() { +// 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") +// .leftJoin(orderLine, "ol").on(orderLine.itemId, equalTo(itemMaster.itemId)) +// .limit(2) +// .build() +// .render(RenderingStrategies.MYBATIS3); +// +// String expectedStatment = "select ol.order_id, ol.quantity, im.item_id, im.description" +// + " from ItemMaster im left join OrderLine ol on ol.item_id = im.item_id" +// + " limit #{parameters.p1}"; +// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); +// +// List> rows = mapper.selectManyMappedRows(selectStatement); +// +// assertThat(rows).hasSize(2); +// Map row = rows.get(0); +// assertThat(row).containsEntry("ORDER_ID", 1); +// assertThat(row).containsEntry("QUANTITY", 1); +// assertThat(row).containsEntry("DESCRIPTION", "Helmet"); +// assertThat(row).containsEntry("ITEM_ID", 22); +// +// row = rows.get(1); +// assertThat(row).containsEntry("ORDER_ID", 2); +// assertThat(row).containsEntry("QUANTITY", 1); +// assertThat(row).containsEntry("DESCRIPTION", "Helmet"); +// assertThat(row).containsEntry("ITEM_ID", 22); +// } +// } +// +// @Test +// void testOffsetOnlyAfterJoin() { +// 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") +// .leftJoin(orderLine, "ol").on(orderLine.itemId, equalTo(itemMaster.itemId)) +// .offset(2) +// .build() +// .render(RenderingStrategies.MYBATIS3); +// +// String expectedStatment = "select ol.order_id, ol.quantity, im.item_id, im.description" +// + " from ItemMaster im left join OrderLine ol on ol.item_id = im.item_id" +// + " offset #{parameters.p1} rows"; +// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); +// +// List> rows = mapper.selectManyMappedRows(selectStatement); +// +// assertThat(rows).hasSize(3); +// Map row = rows.get(0); +// assertThat(row).containsEntry("ORDER_ID", 1); +// assertThat(row).containsEntry("QUANTITY", 1); +// assertThat(row).containsEntry("DESCRIPTION", "First Base Glove"); +// assertThat(row).containsEntry("ITEM_ID", 33); +// +// row = rows.get(1); +// assertThat(row).containsEntry("ORDER_ID", 2); +// assertThat(row).containsEntry("QUANTITY", 1); +// assertThat(row).containsEntry("DESCRIPTION", "Outfield Glove"); +// assertThat(row).containsEntry("ITEM_ID", 44); +// } +// } +// +// @Test +// void testOffsetAndFetchFirstAfterJoin() { +// 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") +// .leftJoin(orderLine, "ol").on(orderLine.itemId, equalTo(itemMaster.itemId)) +// .offset(1) +// .fetchFirst(2).rowsOnly() +// .build() +// .render(RenderingStrategies.MYBATIS3); +// +// String expectedStatment = "select ol.order_id, ol.quantity, im.item_id, im.description" +// + " from ItemMaster im left join OrderLine ol on ol.item_id = im.item_id" +// + " offset #{parameters.p1} rows fetch first #{parameters.p2} rows only"; +// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); +// +// List> rows = mapper.selectManyMappedRows(selectStatement); +// +// assertThat(rows).hasSize(2); +// Map row = rows.get(0); +// assertThat(row).containsEntry("ORDER_ID", 2); +// assertThat(row).containsEntry("QUANTITY", 1); +// assertThat(row).containsEntry("DESCRIPTION", "Helmet"); +// assertThat(row).containsEntry("ITEM_ID", 22); +// +// row = rows.get(1); +// assertThat(row).containsEntry("ORDER_ID", 1); +// assertThat(row).containsEntry("QUANTITY", 1); +// assertThat(row).containsEntry("DESCRIPTION", "First Base Glove"); +// assertThat(row).containsEntry("ITEM_ID", 33); +// } +// } +// +// @Test +// void testFetchFirstOnlyAfterJoin() { +// 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") +// .leftJoin(orderLine, "ol").on(orderLine.itemId, equalTo(itemMaster.itemId)) +// .fetchFirst(2).rowsOnly() +// .build() +// .render(RenderingStrategies.MYBATIS3); +// +// String expectedStatment = "select ol.order_id, ol.quantity, im.item_id, im.description" +// + " from ItemMaster im left join OrderLine ol on ol.item_id = im.item_id" +// + " fetch first #{parameters.p1} rows only"; +// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); +// +// List> rows = mapper.selectManyMappedRows(selectStatement); +// +// assertThat(rows).hasSize(2); +// Map row = rows.get(0); +// assertThat(row).containsEntry("ORDER_ID", 1); +// assertThat(row).containsEntry("QUANTITY", 1); +// assertThat(row).containsEntry("DESCRIPTION", "Helmet"); +// assertThat(row).containsEntry("ITEM_ID", 22); +// +// row = rows.get(1); +// assertThat(row).containsEntry("ORDER_ID", 2); +// assertThat(row).containsEntry("QUANTITY", 1); +// assertThat(row).containsEntry("DESCRIPTION", "Helmet"); +// assertThat(row).containsEntry("ITEM_ID", 22); +// } +// } +} From 6620deedb7aefb151ab4b16e97b19d84f1a2ede2 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 9 Nov 2020 18:17:53 -0500 Subject: [PATCH 02/12] Spelling Errors --- .../java/examples/joins/JoinMapperTest.java | 126 +++++++++--------- 1 file changed, 63 insertions(+), 63 deletions(-) diff --git a/src/test/java/examples/joins/JoinMapperTest.java b/src/test/java/examples/joins/JoinMapperTest.java index ada9f33ba..ce63c9873 100644 --- a/src/test/java/examples/joins/JoinMapperTest.java +++ b/src/test/java/examples/joins/JoinMapperTest.java @@ -81,9 +81,9 @@ void testSingleTableJoin1() { .build() .render(RenderingStrategies.MYBATIS3); - String expectedStatment = "select om.order_id, om.order_date, od.line_number, od.description, od.quantity" + String expectedStatement = "select om.order_id, om.order_date, od.line_number, od.description, od.quantity" + " from OrderMaster om join OrderDetail od on om.order_id = od.order_id"; - assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); List rows = mapper.selectMany(selectStatement); @@ -115,9 +115,9 @@ void testSingleTableJoin2() { .build() .render(RenderingStrategies.MYBATIS3); - String expectedStatment = "select om.order_id, om.order_date, od.line_number, od.description, od.quantity" + String expectedStatement = "select om.order_id, om.order_date, od.line_number, od.description, od.quantity" + " from OrderMaster om join OrderDetail od on om.order_id = od.order_id"; - assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); List rows = mapper.selectMany(selectStatement); @@ -147,9 +147,9 @@ void testCompoundJoin1() { .build() .render(RenderingStrategies.MYBATIS3); - String expectedStatment = "select om.order_id, om.order_date, od.line_number, od.description, od.quantity" + String expectedStatement = "select om.order_id, om.order_date, od.line_number, od.description, od.quantity" + " from OrderMaster om join OrderDetail od on om.order_id = od.order_id and om.order_id = od.order_id"; - assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); } @Test @@ -162,9 +162,9 @@ void testCompoundJoin2() { .build() .render(RenderingStrategies.MYBATIS3); - String expectedStatment = "select om.order_id, om.order_date, od.line_number, od.description, od.quantity" + String expectedStatement = "select om.order_id, om.order_date, od.line_number, od.description, od.quantity" + " from OrderMaster om join OrderDetail od on om.order_id = od.order_id and om.order_id = od.order_id"; - assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); } @Test @@ -176,9 +176,9 @@ void testCompoundJoin3() { .build() .render(RenderingStrategies.MYBATIS3); - String expectedStatment = "select om.order_id, om.order_date, od.line_number, od.description, od.quantity" + String expectedStatement = "select om.order_id, om.order_date, od.line_number, od.description, od.quantity" + " from OrderMaster om join OrderDetail od on om.order_id = od.order_id and om.order_id = od.order_id"; - assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); } @Test @@ -190,9 +190,9 @@ void testCompoundJoin4() { .build() .render(RenderingStrategies.MYBATIS3); - String expectedStatment = "select om.order_id, om.order_date, od.line_number, od.description, od.quantity" + String expectedStatement = "select om.order_id, om.order_date, od.line_number, od.description, od.quantity" + " from OrderMaster om left join OrderDetail od on om.order_id = od.order_id and om.order_id = od.order_id"; - assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); } @Test @@ -204,9 +204,9 @@ void testCompoundJoin5() { .build() .render(RenderingStrategies.MYBATIS3); - String expectedStatment = "select om.order_id, om.order_date, od.line_number, od.description, od.quantity" + String expectedStatement = "select om.order_id, om.order_date, od.line_number, od.description, od.quantity" + " from OrderMaster om right join OrderDetail od on om.order_id = od.order_id and om.order_id = od.order_id"; - assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); } @Test @@ -218,9 +218,9 @@ void testCompoundJoin6() { .build() .render(RenderingStrategies.MYBATIS3); - String expectedStatment = "select om.order_id, om.order_date, od.line_number, od.description, od.quantity" + String expectedStatement = "select om.order_id, om.order_date, od.line_number, od.description, od.quantity" + " from OrderMaster om full join OrderDetail od on om.order_id = od.order_id and om.order_id = od.order_id"; - assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); } @Test @@ -236,10 +236,10 @@ void testMultipleTableJoinWithWhereClause() { .build() .render(RenderingStrategies.MYBATIS3); - String expectedStatment = "select om.order_id, om.order_date, ol.line_number, im.description, ol.quantity" + String expectedStatement = "select om.order_id, om.order_date, ol.line_number, im.description, ol.quantity" + " from OrderMaster om join OrderLine ol on om.order_id = ol.order_id join ItemMaster im on ol.item_id = im.item_id" + " where om.order_id = #{parameters.p1,jdbcType=INTEGER}"; - assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); List rows = mapper.selectMany(selectStatement); @@ -267,10 +267,10 @@ void testMultipleTableJoinWithApplyWhere() { .build() .render(RenderingStrategies.MYBATIS3); - String expectedStatment = "select om.order_id, om.order_date, ol.line_number, im.description, ol.quantity" + String expectedStatement = "select om.order_id, om.order_date, ol.line_number, im.description, ol.quantity" + " from OrderMaster om join OrderLine ol on om.order_id = ol.order_id join ItemMaster im on ol.item_id = im.item_id" + " where om.order_id = #{parameters.p1,jdbcType=INTEGER}"; - assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); List rows = mapper.selectMany(selectStatement); @@ -298,10 +298,10 @@ void testMultipleTableJoinWithComplexWhereClause() { .build() .render(RenderingStrategies.MYBATIS3); - String expectedStatment = "select om.order_id, om.order_date, ol.line_number, im.description, ol.quantity" + String expectedStatement = "select om.order_id, om.order_date, ol.line_number, im.description, ol.quantity" + " from OrderMaster om join OrderLine ol on om.order_id = ol.order_id join ItemMaster im on ol.item_id = im.item_id" + " where (om.order_id = #{parameters.p1,jdbcType=INTEGER} and ol.line_number = #{parameters.p2,jdbcType=INTEGER})"; - assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); List rows = mapper.selectMany(selectStatement); @@ -327,10 +327,10 @@ void testMultipleTableJoinWithOrderBy() { .build() .render(RenderingStrategies.MYBATIS3); - String expectedStatment = "select om.order_id, om.order_date, ol.line_number, im.description, ol.quantity" + String expectedStatement = "select om.order_id, om.order_date, ol.line_number, im.description, ol.quantity" + " from OrderMaster om join OrderLine ol on om.order_id = ol.order_id join ItemMaster im on ol.item_id = im.item_id" + " order by order_id"; - assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); List rows = mapper.selectMany(selectStatement); @@ -352,7 +352,7 @@ void testMultipleTableJoinWithOrderBy() { } @Test - void testMultibleTableJoinNoAliasWithOrderBy() { + void testMultipleTableJoinNoAliasWithOrderBy() { try (SqlSession session = sqlSessionFactory.openSession()) { JoinMapper mapper = session.getMapper(JoinMapper.class); @@ -365,11 +365,11 @@ void testMultibleTableJoinNoAliasWithOrderBy() { .build() .render(RenderingStrategies.MYBATIS3); - String expectedStatment = "select OrderMaster.order_id, OrderMaster.order_date, OrderLine.line_number, ItemMaster.description, OrderLine.quantity" + String expectedStatement = "select OrderMaster.order_id, OrderMaster.order_date, OrderLine.line_number, ItemMaster.description, OrderLine.quantity" + " from OrderMaster join OrderLine on OrderMaster.order_id = OrderLine.order_id join ItemMaster on OrderLine.item_id = ItemMaster.item_id" + " where OrderMaster.order_id = #{parameters.p1,jdbcType=INTEGER}" + " order by order_id"; - assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); List rows = mapper.selectMany(selectStatement); @@ -396,10 +396,10 @@ void testRightJoin() { .build() .render(RenderingStrategies.MYBATIS3); - String expectedStatment = "select ol.order_id, ol.quantity, im.item_id, im.description" + String expectedStatement = "select ol.order_id, ol.quantity, im.item_id, im.description" + " from OrderLine ol right join ItemMaster im on ol.item_id = im.item_id" + " order by item_id"; - assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); List> rows = mapper.selectManyMappedRows(selectStatement); @@ -431,11 +431,11 @@ void testRightJoin2() { .build() .render(RenderingStrategies.MYBATIS3); - String expectedStatment = "select ol.order_id, ol.quantity, im.item_id, im.description" + String expectedStatement = "select ol.order_id, ol.quantity, im.item_id, im.description" + " from OrderMaster om join OrderLine ol on om.order_id = ol.order_id" + " right join ItemMaster im on ol.item_id = im.item_id" + " order by order_id, item_id"; - assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); List> rows = mapper.selectManyMappedRows(selectStatement); @@ -467,11 +467,11 @@ void testRightJoin3() { .build() .render(RenderingStrategies.MYBATIS3); - String expectedStatment = "select ol.order_id, ol.quantity, im.item_id, im.description" + String expectedStatement = "select ol.order_id, ol.quantity, im.item_id, im.description" + " from OrderMaster om join OrderLine ol on om.order_id = ol.order_id" + " right join ItemMaster im on ol.item_id = im.item_id" + " order by order_id, item_id"; - assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); List> rows = mapper.selectManyMappedRows(selectStatement); @@ -503,11 +503,11 @@ void testRightJoinNoAliases() { .build() .render(RenderingStrategies.MYBATIS3); - String expectedStatment = "select OrderLine.order_id, OrderLine.quantity, ItemMaster.item_id, ItemMaster.description" + String expectedStatement = "select OrderLine.order_id, OrderLine.quantity, ItemMaster.item_id, ItemMaster.description" + " from OrderMaster join OrderLine on OrderMaster.order_id = OrderLine.order_id" + " right join ItemMaster on OrderLine.item_id = ItemMaster.item_id" + " order by order_id, item_id"; - assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); List> rows = mapper.selectManyMappedRows(selectStatement); @@ -538,10 +538,10 @@ void testLeftJoin() { .build() .render(RenderingStrategies.MYBATIS3); - String expectedStatment = "select ol.order_id, ol.quantity, im.item_id, im.description" + String expectedStatement = "select ol.order_id, ol.quantity, im.item_id, im.description" + " from ItemMaster im left join OrderLine ol on ol.item_id = im.item_id" + " order by item_id"; - assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); List> rows = mapper.selectManyMappedRows(selectStatement); @@ -573,11 +573,11 @@ void testLeftJoin2() { .build() .render(RenderingStrategies.MYBATIS3); - String expectedStatment = "select ol.order_id, ol.quantity, im.item_id, im.description" + String expectedStatement = "select ol.order_id, ol.quantity, im.item_id, im.description" + " from OrderMaster om join OrderLine ol on om.order_id = ol.order_id" + " left join ItemMaster im on ol.item_id = im.item_id" + " order by order_id, item_id"; - assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); List> rows = mapper.selectManyMappedRows(selectStatement); @@ -609,11 +609,11 @@ void testLeftJoin3() { .build() .render(RenderingStrategies.MYBATIS3); - String expectedStatment = "select ol.order_id, ol.quantity, im.item_id, im.description" + String expectedStatement = "select ol.order_id, ol.quantity, im.item_id, im.description" + " from OrderMaster om join OrderLine ol on om.order_id = ol.order_id" + " left join ItemMaster im on ol.item_id = im.item_id" + " order by order_id, item_id"; - assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); List> rows = mapper.selectManyMappedRows(selectStatement); @@ -645,11 +645,11 @@ void testLeftJoinNoAliases() { .build() .render(RenderingStrategies.MYBATIS3); - String expectedStatment = "select OrderLine.order_id, OrderLine.quantity, ItemMaster.item_id, ItemMaster.description" + String expectedStatement = "select OrderLine.order_id, OrderLine.quantity, ItemMaster.item_id, ItemMaster.description" + " from OrderMaster join OrderLine on OrderMaster.order_id = OrderLine.order_id" + " left join ItemMaster on OrderLine.item_id = ItemMaster.item_id" + " order by order_id, item_id"; - assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); List> rows = mapper.selectManyMappedRows(selectStatement); @@ -680,10 +680,10 @@ void testFullJoin() { .build() .render(RenderingStrategies.MYBATIS3); - String expectedStatment = "select ol.order_id, ol.quantity, ol.item_id as ol_itemid, im.item_id as im_itemid, im.description" + String expectedStatement = "select ol.order_id, ol.quantity, ol.item_id as ol_itemid, im.item_id as im_itemid, im.description" + " from ItemMaster im full join OrderLine ol on im.item_id = ol.item_id" + " order by im_itemid"; - assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); List> rows = mapper.selectManyMappedRows(selectStatement); @@ -722,11 +722,11 @@ void testFullJoin2() { .build() .render(RenderingStrategies.MYBATIS3); - String expectedStatment = "select ol.order_id, ol.quantity, im.item_id, im.description" + String expectedStatement = "select ol.order_id, ol.quantity, im.item_id, im.description" + " from OrderMaster om join OrderLine ol on om.order_id = ol.order_id" + " full join ItemMaster im on ol.item_id = im.item_id" + " order by order_id, item_id"; - assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); List> rows = mapper.selectManyMappedRows(selectStatement); @@ -764,11 +764,11 @@ void testFullJoin3() { .build() .render(RenderingStrategies.MYBATIS3); - String expectedStatment = "select ol.order_id, ol.quantity, im.item_id, im.description" + String expectedStatement = "select ol.order_id, ol.quantity, im.item_id, im.description" + " from OrderMaster om join OrderLine ol on om.order_id = ol.order_id" + " full join ItemMaster im on ol.item_id = im.item_id" + " order by order_id, item_id"; - assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); List> rows = mapper.selectManyMappedRows(selectStatement); @@ -884,11 +884,11 @@ void testFullJoinNoAliases() { .build() .render(RenderingStrategies.MYBATIS3); - String expectedStatment = "select OrderLine.order_id, OrderLine.quantity, ItemMaster.item_id, ItemMaster.description" + String expectedStatement = "select OrderLine.order_id, OrderLine.quantity, ItemMaster.item_id, ItemMaster.description" + " from OrderMaster join OrderLine on OrderMaster.order_id = OrderLine.order_id" + " full join ItemMaster on OrderLine.item_id = ItemMaster.item_id" + " order by order_id, item_id"; - assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); List> rows = mapper.selectManyMappedRows(selectStatement); @@ -929,10 +929,10 @@ void testSelf() { .build() .render(RenderingStrategies.MYBATIS3); - String expectedStatment = "select u1.user_id, u1.user_name, u1.parent_id" + String expectedStatement = "select u1.user_id, u1.user_name, u1.parent_id" + " from User u1 join User u2 on u1.user_id = u2.parent_id" + " where u2.user_id = #{parameters.p1,jdbcType=INTEGER}"; - assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); List rows = mapper.selectUsers(selectStatement); @@ -957,10 +957,10 @@ void testLimitAndOffsetAfterJoin() { .build() .render(RenderingStrategies.MYBATIS3); - String expectedStatment = "select ol.order_id, ol.quantity, im.item_id, im.description" + String expectedStatement = "select ol.order_id, ol.quantity, im.item_id, im.description" + " from ItemMaster im left join OrderLine ol on ol.item_id = im.item_id" + " limit #{parameters.p1} offset #{parameters.p2}"; - assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); List> rows = mapper.selectManyMappedRows(selectStatement); @@ -991,10 +991,10 @@ void testLimitOnlyAfterJoin() { .build() .render(RenderingStrategies.MYBATIS3); - String expectedStatment = "select ol.order_id, ol.quantity, im.item_id, im.description" + String expectedStatement = "select ol.order_id, ol.quantity, im.item_id, im.description" + " from ItemMaster im left join OrderLine ol on ol.item_id = im.item_id" + " limit #{parameters.p1}"; - assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); List> rows = mapper.selectManyMappedRows(selectStatement); @@ -1025,10 +1025,10 @@ void testOffsetOnlyAfterJoin() { .build() .render(RenderingStrategies.MYBATIS3); - String expectedStatment = "select ol.order_id, ol.quantity, im.item_id, im.description" + String expectedStatement = "select ol.order_id, ol.quantity, im.item_id, im.description" + " from ItemMaster im left join OrderLine ol on ol.item_id = im.item_id" + " offset #{parameters.p1} rows"; - assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); List> rows = mapper.selectManyMappedRows(selectStatement); @@ -1060,10 +1060,10 @@ void testOffsetAndFetchFirstAfterJoin() { .build() .render(RenderingStrategies.MYBATIS3); - String expectedStatment = "select ol.order_id, ol.quantity, im.item_id, im.description" + String expectedStatement = "select ol.order_id, ol.quantity, im.item_id, im.description" + " from ItemMaster im left join OrderLine ol on ol.item_id = im.item_id" + " offset #{parameters.p1} rows fetch first #{parameters.p2} rows only"; - assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); List> rows = mapper.selectManyMappedRows(selectStatement); @@ -1094,10 +1094,10 @@ void testFetchFirstOnlyAfterJoin() { .build() .render(RenderingStrategies.MYBATIS3); - String expectedStatment = "select ol.order_id, ol.quantity, im.item_id, im.description" + String expectedStatement = "select ol.order_id, ol.quantity, im.item_id, im.description" + " from ItemMaster im left join OrderLine ol on ol.item_id = im.item_id" + " fetch first #{parameters.p1} rows only"; - assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); List> rows = mapper.selectManyMappedRows(selectStatement); From a9a7eed9d8495cdaf88b005eb4954b9645a9d615 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Tue, 10 Nov 2020 13:30:37 -0500 Subject: [PATCH 03/12] SubQueries in Joins must have aliases --- .../sql/select/QueryExpressionDSL.java | 32 -- .../java/examples/joins/JoinSubQueryTest.java | 311 +++++++----------- 2 files changed, 114 insertions(+), 229 deletions(-) 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 917694753..c47b5f51d 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionDSL.java @@ -90,10 +90,6 @@ public JoinSpecificationStarter join(SqlTable joinTable, String tableAlias) { return join(joinTable); } - public JoinSpecificationStarter join(Buildable joinTable) { - return new JoinSpecificationStarter(buildSubQuery(joinTable), JoinType.INNER); - } - public JoinSpecificationStarter join(Buildable joinTable, String tableAlias) { return new JoinSpecificationStarter(buildSubQuery(joinTable, tableAlias), JoinType.INNER); } @@ -107,10 +103,6 @@ public JoinSpecificationStarter leftJoin(SqlTable joinTable, String tableAlias) return leftJoin(joinTable); } - public JoinSpecificationStarter leftJoin(Buildable joinTable) { - return new JoinSpecificationStarter(buildSubQuery(joinTable), JoinType.LEFT); - } - public JoinSpecificationStarter leftJoin(Buildable joinTable, String tableAlias) { return new JoinSpecificationStarter(buildSubQuery(joinTable, tableAlias), JoinType.LEFT); } @@ -124,10 +116,6 @@ public JoinSpecificationStarter rightJoin(SqlTable joinTable, String tableAlias) return rightJoin(joinTable); } - public JoinSpecificationStarter rightJoin(Buildable joinTable) { - return new JoinSpecificationStarter(buildSubQuery(joinTable), JoinType.RIGHT); - } - public JoinSpecificationStarter rightJoin(Buildable joinTable, String tableAlias) { return new JoinSpecificationStarter(buildSubQuery(joinTable, tableAlias), JoinType.RIGHT); } @@ -141,10 +129,6 @@ public JoinSpecificationStarter fullJoin(SqlTable joinTable, String tableAlias) return fullJoin(joinTable); } - public JoinSpecificationStarter fullJoin(Buildable joinTable) { - return new JoinSpecificationStarter(buildSubQuery(joinTable), JoinType.FULL); - } - public JoinSpecificationStarter fullJoin(Buildable joinTable, String tableAlias) { return new JoinSpecificationStarter(buildSubQuery(joinTable, tableAlias), JoinType.FULL); } @@ -405,10 +389,6 @@ public JoinSpecificationStarter join(SqlTable joinTable, String tableAlias) { return QueryExpressionDSL.this.join(joinTable, tableAlias); } - public JoinSpecificationStarter join(Buildable joinTable) { - return QueryExpressionDSL.this.join(joinTable); - } - public JoinSpecificationStarter join(Buildable joinTable, String tableAlias) { return QueryExpressionDSL.this.join(joinTable, tableAlias); } @@ -421,10 +401,6 @@ public JoinSpecificationStarter leftJoin(SqlTable joinTable, String tableAlias) return QueryExpressionDSL.this.leftJoin(joinTable, tableAlias); } - public JoinSpecificationStarter leftJoin(Buildable joinTable) { - return QueryExpressionDSL.this.leftJoin(joinTable); - } - public JoinSpecificationStarter leftJoin(Buildable joinTable, String tableAlias) { return QueryExpressionDSL.this.leftJoin(joinTable, tableAlias); } @@ -437,10 +413,6 @@ public JoinSpecificationStarter rightJoin(SqlTable joinTable, String tableAlias) return QueryExpressionDSL.this.rightJoin(joinTable, tableAlias); } - public JoinSpecificationStarter rightJoin(Buildable joinTable) { - return QueryExpressionDSL.this.rightJoin(joinTable); - } - public JoinSpecificationStarter rightJoin(Buildable joinTable, String tableAlias) { return QueryExpressionDSL.this.rightJoin(joinTable, tableAlias); } @@ -453,10 +425,6 @@ public JoinSpecificationStarter fullJoin(SqlTable joinTable, String tableAlias) return QueryExpressionDSL.this.fullJoin(joinTable, tableAlias); } - public JoinSpecificationStarter fullJoin(Buildable joinTable) { - return QueryExpressionDSL.this.fullJoin(joinTable); - } - public JoinSpecificationStarter fullJoin(Buildable joinTable, String tableAlias) { return QueryExpressionDSL.this.fullJoin(joinTable, tableAlias); } diff --git a/src/test/java/examples/joins/JoinSubQueryTest.java b/src/test/java/examples/joins/JoinSubQueryTest.java index 3dd9d9cd3..6b8c12a41 100644 --- a/src/test/java/examples/joins/JoinSubQueryTest.java +++ b/src/test/java/examples/joins/JoinSubQueryTest.java @@ -112,167 +112,84 @@ void testSingleTableJoin1() { } } -// @Test -// void testMultipleTableJoinWithWhereClause() { -// try (SqlSession session = sqlSessionFactory.openSession()) { -// JoinMapper mapper = session.getMapper(JoinMapper.class); -// -// SelectStatementProvider selectStatement = select(orderMaster.orderId, orderMaster.orderDate, orderDetail.lineNumber, itemMaster.description, orderLine.quantity) -// .from(orderMaster, "om") -// .join(orderLine, "ol").on(orderMaster.orderId, equalTo(orderLine.orderId)) -// .join(itemMaster, "im").on(orderLine.itemId, equalTo(itemMaster.itemId)) -// .where(orderMaster.orderId, isEqualTo(2)) -// .build() -// .render(RenderingStrategies.MYBATIS3); -// -// String expectedStatment = "select om.order_id, om.order_date, ol.line_number, im.description, ol.quantity" -// + " from OrderMaster om join OrderLine ol on om.order_id = ol.order_id join ItemMaster im on ol.item_id = im.item_id" -// + " where om.order_id = #{parameters.p1,jdbcType=INTEGER}"; -// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); -// -// List rows = mapper.selectMany(selectStatement); -// -// assertThat(rows).hasSize(1); -// OrderMaster orderMaster = rows.get(0); -// assertThat(orderMaster.getId()).isEqualTo(2); -// assertThat(orderMaster.getDetails()).hasSize(2); -// OrderDetail orderDetail = orderMaster.getDetails().get(0); -// assertThat(orderDetail.getLineNumber()).isEqualTo(1); -// orderDetail = orderMaster.getDetails().get(1); -// assertThat(orderDetail.getLineNumber()).isEqualTo(2); -// } -// } -// -// @Test -// void testMultipleTableJoinWithApplyWhere() { -// try (SqlSession session = sqlSessionFactory.openSession()) { -// JoinMapper mapper = session.getMapper(JoinMapper.class); -// -// SelectStatementProvider selectStatement = select(orderMaster.orderId, orderMaster.orderDate, orderLine.lineNumber, itemMaster.description, orderLine.quantity) -// .from(orderMaster, "om") -// .join(orderLine, "ol").on(orderMaster.orderId, equalTo(orderLine.orderId)) -// .join(itemMaster, "im").on(orderLine.itemId, equalTo(itemMaster.itemId)) -// .applyWhere(d -> d.where(orderMaster.orderId, isEqualTo(2))) -// .build() -// .render(RenderingStrategies.MYBATIS3); -// -// String expectedStatment = "select om.order_id, om.order_date, ol.line_number, im.description, ol.quantity" -// + " from OrderMaster om join OrderLine ol on om.order_id = ol.order_id join ItemMaster im on ol.item_id = im.item_id" -// + " where om.order_id = #{parameters.p1,jdbcType=INTEGER}"; -// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); -// -// List rows = mapper.selectMany(selectStatement); -// -// assertThat(rows).hasSize(1); -// OrderMaster orderMaster = rows.get(0); -// assertThat(orderMaster.getId()).isEqualTo(2); -// assertThat(orderMaster.getDetails()).hasSize(2); -// OrderDetail orderDetail = orderMaster.getDetails().get(0); -// assertThat(orderDetail.getLineNumber()).isEqualTo(1); -// orderDetail = orderMaster.getDetails().get(1); -// assertThat(orderDetail.getLineNumber()).isEqualTo(2); -// } -// } -// -// @Test -// void testMultipleTableJoinWithComplexWhereClause() { -// try (SqlSession session = sqlSessionFactory.openSession()) { -// JoinMapper mapper = session.getMapper(JoinMapper.class); -// -// SelectStatementProvider selectStatement = select(orderMaster.orderId, orderMaster.orderDate, orderLine.lineNumber, itemMaster.description, orderLine.quantity) -// .from(orderMaster, "om") -// .join(orderLine, "ol").on(orderMaster.orderId, equalTo(orderLine.orderId)) -// .join(itemMaster, "im").on(orderLine.itemId, equalTo(itemMaster.itemId)) -// .where(orderMaster.orderId, isEqualTo(2), and(orderLine.lineNumber, isEqualTo(2))) -// .build() -// .render(RenderingStrategies.MYBATIS3); -// -// String expectedStatment = "select om.order_id, om.order_date, ol.line_number, im.description, ol.quantity" -// + " from OrderMaster om join OrderLine ol on om.order_id = ol.order_id join ItemMaster im on ol.item_id = im.item_id" -// + " where (om.order_id = #{parameters.p1,jdbcType=INTEGER} and ol.line_number = #{parameters.p2,jdbcType=INTEGER})"; -// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); -// -// List rows = mapper.selectMany(selectStatement); -// -// assertThat(rows).hasSize(1); -// OrderMaster orderMaster = rows.get(0); -// assertThat(orderMaster.getId()).isEqualTo(2); -// assertThat(orderMaster.getDetails()).hasSize(1); -// OrderDetail orderDetail = orderMaster.getDetails().get(0); -// assertThat(orderDetail.getLineNumber()).isEqualTo(2); -// } -// } -// -// @Test -// void testMultipleTableJoinWithOrderBy() { -// try (SqlSession session = sqlSessionFactory.openSession()) { -// JoinMapper mapper = session.getMapper(JoinMapper.class); -// -// SelectStatementProvider selectStatement = select(orderMaster.orderId, orderMaster.orderDate, orderLine.lineNumber, itemMaster.description, orderLine.quantity) -// .from(orderMaster, "om") -// .join(orderLine, "ol").on(orderMaster.orderId, equalTo(orderLine.orderId)) -// .join(itemMaster, "im").on(orderLine.itemId, equalTo(itemMaster.itemId)) -// .orderBy(orderMaster.orderId) -// .build() -// .render(RenderingStrategies.MYBATIS3); -// -// String expectedStatment = "select om.order_id, om.order_date, ol.line_number, im.description, ol.quantity" -// + " from OrderMaster om join OrderLine ol on om.order_id = ol.order_id join ItemMaster im on ol.item_id = im.item_id" -// + " order by order_id"; -// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); -// -// List rows = mapper.selectMany(selectStatement); -// -// assertThat(rows).hasSize(2); -// OrderMaster orderMaster = rows.get(0); -// assertThat(orderMaster.getId()).isEqualTo(1); -// assertThat(orderMaster.getDetails()).hasSize(1); -// OrderDetail orderDetail = orderMaster.getDetails().get(0); -// assertThat(orderDetail.getLineNumber()).isEqualTo(1); -// -// orderMaster = rows.get(1); -// assertThat(orderMaster.getId()).isEqualTo(2); -// assertThat(orderMaster.getDetails()).hasSize(2); -// orderDetail = orderMaster.getDetails().get(0); -// assertThat(orderDetail.getLineNumber()).isEqualTo(1); -// orderDetail = orderMaster.getDetails().get(1); -// assertThat(orderDetail.getLineNumber()).isEqualTo(2); -// } -// } -// -// @Test -// void testMultibleTableJoinNoAliasWithOrderBy() { -// try (SqlSession session = sqlSessionFactory.openSession()) { -// JoinMapper mapper = session.getMapper(JoinMapper.class); -// -// SelectStatementProvider selectStatement = select(orderMaster.orderId, orderMaster.orderDate, orderLine.lineNumber, itemMaster.description, orderLine.quantity) -// .from(orderMaster) -// .join(orderLine).on(orderMaster.orderId, equalTo(orderLine.orderId)) -// .join(itemMaster).on(orderLine.itemId, equalTo(itemMaster.itemId)) -// .where(orderMaster.orderId, isEqualTo(2)) -// .orderBy(orderMaster.orderId) -// .build() -// .render(RenderingStrategies.MYBATIS3); -// -// String expectedStatment = "select OrderMaster.order_id, OrderMaster.order_date, OrderLine.line_number, ItemMaster.description, OrderLine.quantity" -// + " from OrderMaster join OrderLine on OrderMaster.order_id = OrderLine.order_id join ItemMaster on OrderLine.item_id = ItemMaster.item_id" -// + " where OrderMaster.order_id = #{parameters.p1,jdbcType=INTEGER}" -// + " order by order_id"; -// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); -// -// List rows = mapper.selectMany(selectStatement); -// -// assertThat(rows).hasSize(1); -// OrderMaster orderMaster = rows.get(0); -// assertThat(orderMaster.getId()).isEqualTo(2); -// assertThat(orderMaster.getDetails()).hasSize(2); -// OrderDetail orderDetail = orderMaster.getDetails().get(0); -// assertThat(orderDetail.getLineNumber()).isEqualTo(1); -// orderDetail = orderMaster.getDetails().get(1); -// assertThat(orderDetail.getLineNumber()).isEqualTo(2); -// } -// } -// + @Test + void testMultipleTableJoinWithWhereClause() { + try (SqlSession session = sqlSessionFactory.openSession()) { + JoinMapper mapper = session.getMapper(JoinMapper.class); + + SelectStatementProvider selectStatement = select(orderMaster.orderId, orderMaster.orderDate, + orderLine.lineNumber, itemMaster.description, orderLine.quantity) + .from(orderMaster, "om") + .join(select(orderLine.orderId, orderLine.itemId, orderLine.quantity, orderLine.lineNumber) + .from(orderLine), + "ol") + .on(orderMaster.orderId, equalTo(orderLine.orderId.qualifiedWith("ol"))) + .join(select(itemMaster.itemId, itemMaster.description) + .from(itemMaster), + "im") + .on(orderLine.itemId.qualifiedWith("ol"), equalTo(itemMaster.itemId.qualifiedWith("im"))) + .where(orderMaster.orderId, isEqualTo(2)) + .build() + .render(RenderingStrategies.MYBATIS3); + + String expectedStatement = "select om.order_id, om.order_date, line_number, description, quantity" + + " from OrderMaster om join " + + "(select order_id, item_id, quantity, line_number from OrderLine) ol on om.order_id = ol.order_id " + + "join (select item_id, description from ItemMaster) im on ol.item_id = im.item_id" + + " where om.order_id = #{parameters.p1,jdbcType=INTEGER}"; + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); + + List rows = mapper.selectMany(selectStatement); + + assertThat(rows).hasSize(1); + OrderMaster orderMaster = rows.get(0); + assertThat(orderMaster.getId()).isEqualTo(2); + assertThat(orderMaster.getDetails()).hasSize(2); + OrderDetail orderDetail = orderMaster.getDetails().get(0); + assertThat(orderDetail.getLineNumber()).isEqualTo(1); + orderDetail = orderMaster.getDetails().get(1); + assertThat(orderDetail.getLineNumber()).isEqualTo(2); + } + } + + @Test + void testMultipleTableJoinWithSelectStar() { + try (SqlSession session = sqlSessionFactory.openSession()) { + JoinMapper mapper = session.getMapper(JoinMapper.class); + + SelectStatementProvider selectStatement = select(orderMaster.orderId, orderMaster.orderDate, orderLine.lineNumber, itemMaster.description, orderLine.quantity) + .from(orderMaster, "om") + .join(select(orderLine.allColumns()).from(orderLine), "ol") + .on(orderMaster.orderId, equalTo(orderLine.orderId.qualifiedWith("ol"))) + .join(select(itemMaster.allColumns()).from(itemMaster), "im") + .on(orderLine.itemId.qualifiedWith("ol"), equalTo(itemMaster.itemId.qualifiedWith("im"))) + .where(orderMaster.orderId, isEqualTo(2)) + .orderBy(orderMaster.orderId) + .build() + .render(RenderingStrategies.MYBATIS3); + + String expectedStatement = "select om.order_id, om.order_date, line_number, description, quantity" + + " from OrderMaster om join (select * from OrderLine) ol on om.order_id = ol.order_id" + + " join (select * from ItemMaster) im on ol.item_id = im.item_id" + + " where om.order_id = #{parameters.p1,jdbcType=INTEGER}" + + " order by order_id"; + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); + + List rows = mapper.selectMany(selectStatement); + + assertThat(rows).hasSize(1); + OrderMaster orderMaster = rows.get(0); + assertThat(orderMaster.getId()).isEqualTo(2); + assertThat(orderMaster.getDetails()).hasSize(2); + + OrderDetail orderDetail = orderMaster.getDetails().get(0); + assertThat(orderDetail.getLineNumber()).isEqualTo(1); + + orderDetail = orderMaster.getDetails().get(1); + assertThat(orderDetail.getLineNumber()).isEqualTo(2); + } + } + // @Test // void testRightJoin() { // try (SqlSession session = sqlSessionFactory.openSession()) { @@ -285,10 +202,10 @@ void testSingleTableJoin1() { // .build() // .render(RenderingStrategies.MYBATIS3); // -// String expectedStatment = "select ol.order_id, ol.quantity, im.item_id, im.description" +// String expectedStatement = "select ol.order_id, ol.quantity, im.item_id, im.description" // + " from OrderLine ol right join ItemMaster im on ol.item_id = im.item_id" // + " order by item_id"; -// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); +// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); // // List> rows = mapper.selectManyMappedRows(selectStatement); // @@ -320,11 +237,11 @@ void testSingleTableJoin1() { // .build() // .render(RenderingStrategies.MYBATIS3); // -// String expectedStatment = "select ol.order_id, ol.quantity, im.item_id, im.description" +// String expectedStatement = "select ol.order_id, ol.quantity, im.item_id, im.description" // + " from OrderMaster om join OrderLine ol on om.order_id = ol.order_id" // + " right join ItemMaster im on ol.item_id = im.item_id" // + " order by order_id, item_id"; -// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); +// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); // // List> rows = mapper.selectManyMappedRows(selectStatement); // @@ -356,11 +273,11 @@ void testSingleTableJoin1() { // .build() // .render(RenderingStrategies.MYBATIS3); // -// String expectedStatment = "select ol.order_id, ol.quantity, im.item_id, im.description" +// String expectedStatement = "select ol.order_id, ol.quantity, im.item_id, im.description" // + " from OrderMaster om join OrderLine ol on om.order_id = ol.order_id" // + " right join ItemMaster im on ol.item_id = im.item_id" // + " order by order_id, item_id"; -// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); +// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); // // List> rows = mapper.selectManyMappedRows(selectStatement); // @@ -392,11 +309,11 @@ void testSingleTableJoin1() { // .build() // .render(RenderingStrategies.MYBATIS3); // -// String expectedStatment = "select OrderLine.order_id, OrderLine.quantity, ItemMaster.item_id, ItemMaster.description" +// String expectedStatement = "select OrderLine.order_id, OrderLine.quantity, ItemMaster.item_id, ItemMaster.description" // + " from OrderMaster join OrderLine on OrderMaster.order_id = OrderLine.order_id" // + " right join ItemMaster on OrderLine.item_id = ItemMaster.item_id" // + " order by order_id, item_id"; -// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); +// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); // // List> rows = mapper.selectManyMappedRows(selectStatement); // @@ -427,10 +344,10 @@ void testSingleTableJoin1() { // .build() // .render(RenderingStrategies.MYBATIS3); // -// String expectedStatment = "select ol.order_id, ol.quantity, im.item_id, im.description" +// String expectedStatement = "select ol.order_id, ol.quantity, im.item_id, im.description" // + " from ItemMaster im left join OrderLine ol on ol.item_id = im.item_id" // + " order by item_id"; -// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); +// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); // // List> rows = mapper.selectManyMappedRows(selectStatement); // @@ -462,11 +379,11 @@ void testSingleTableJoin1() { // .build() // .render(RenderingStrategies.MYBATIS3); // -// String expectedStatment = "select ol.order_id, ol.quantity, im.item_id, im.description" +// String expectedStatement = "select ol.order_id, ol.quantity, im.item_id, im.description" // + " from OrderMaster om join OrderLine ol on om.order_id = ol.order_id" // + " left join ItemMaster im on ol.item_id = im.item_id" // + " order by order_id, item_id"; -// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); +// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); // // List> rows = mapper.selectManyMappedRows(selectStatement); // @@ -498,11 +415,11 @@ void testSingleTableJoin1() { // .build() // .render(RenderingStrategies.MYBATIS3); // -// String expectedStatment = "select ol.order_id, ol.quantity, im.item_id, im.description" +// String expectedStatement = "select ol.order_id, ol.quantity, im.item_id, im.description" // + " from OrderMaster om join OrderLine ol on om.order_id = ol.order_id" // + " left join ItemMaster im on ol.item_id = im.item_id" // + " order by order_id, item_id"; -// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); +// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); // // List> rows = mapper.selectManyMappedRows(selectStatement); // @@ -534,11 +451,11 @@ void testSingleTableJoin1() { // .build() // .render(RenderingStrategies.MYBATIS3); // -// String expectedStatment = "select OrderLine.order_id, OrderLine.quantity, ItemMaster.item_id, ItemMaster.description" +// String expectedStatement = "select OrderLine.order_id, OrderLine.quantity, ItemMaster.item_id, ItemMaster.description" // + " from OrderMaster join OrderLine on OrderMaster.order_id = OrderLine.order_id" // + " left join ItemMaster on OrderLine.item_id = ItemMaster.item_id" // + " order by order_id, item_id"; -// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); +// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); // // List> rows = mapper.selectManyMappedRows(selectStatement); // @@ -569,10 +486,10 @@ void testSingleTableJoin1() { // .build() // .render(RenderingStrategies.MYBATIS3); // -// String expectedStatment = "select ol.order_id, ol.quantity, ol.item_id as ol_itemid, im.item_id as im_itemid, im.description" +// String expectedStatement = "select ol.order_id, ol.quantity, ol.item_id as ol_itemid, im.item_id as im_itemid, im.description" // + " from ItemMaster im full join OrderLine ol on im.item_id = ol.item_id" // + " order by im_itemid"; -// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); +// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); // // List> rows = mapper.selectManyMappedRows(selectStatement); // @@ -611,11 +528,11 @@ void testSingleTableJoin1() { // .build() // .render(RenderingStrategies.MYBATIS3); // -// String expectedStatment = "select ol.order_id, ol.quantity, im.item_id, im.description" +// String expectedStatement = "select ol.order_id, ol.quantity, im.item_id, im.description" // + " from OrderMaster om join OrderLine ol on om.order_id = ol.order_id" // + " full join ItemMaster im on ol.item_id = im.item_id" // + " order by order_id, item_id"; -// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); +// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); // // List> rows = mapper.selectManyMappedRows(selectStatement); // @@ -653,11 +570,11 @@ void testSingleTableJoin1() { // .build() // .render(RenderingStrategies.MYBATIS3); // -// String expectedStatment = "select ol.order_id, ol.quantity, im.item_id, im.description" +// String expectedStatement = "select ol.order_id, ol.quantity, im.item_id, im.description" // + " from OrderMaster om join OrderLine ol on om.order_id = ol.order_id" // + " full join ItemMaster im on ol.item_id = im.item_id" // + " order by order_id, item_id"; -// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); +// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); // // List> rows = mapper.selectManyMappedRows(selectStatement); // @@ -773,11 +690,11 @@ void testSingleTableJoin1() { // .build() // .render(RenderingStrategies.MYBATIS3); // -// String expectedStatment = "select OrderLine.order_id, OrderLine.quantity, ItemMaster.item_id, ItemMaster.description" +// String expectedStatement = "select OrderLine.order_id, OrderLine.quantity, ItemMaster.item_id, ItemMaster.description" // + " from OrderMaster join OrderLine on OrderMaster.order_id = OrderLine.order_id" // + " full join ItemMaster on OrderLine.item_id = ItemMaster.item_id" // + " order by order_id, item_id"; -// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); +// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); // // List> rows = mapper.selectManyMappedRows(selectStatement); // @@ -818,10 +735,10 @@ void testSingleTableJoin1() { // .build() // .render(RenderingStrategies.MYBATIS3); // -// String expectedStatment = "select u1.user_id, u1.user_name, u1.parent_id" +// String expectedStatement = "select u1.user_id, u1.user_name, u1.parent_id" // + " from User u1 join User u2 on u1.user_id = u2.parent_id" // + " where u2.user_id = #{parameters.p1,jdbcType=INTEGER}"; -// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); +// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); // // List rows = mapper.selectUsers(selectStatement); // @@ -846,10 +763,10 @@ void testSingleTableJoin1() { // .build() // .render(RenderingStrategies.MYBATIS3); // -// String expectedStatment = "select ol.order_id, ol.quantity, im.item_id, im.description" +// String expectedStatement = "select ol.order_id, ol.quantity, im.item_id, im.description" // + " from ItemMaster im left join OrderLine ol on ol.item_id = im.item_id" // + " limit #{parameters.p1} offset #{parameters.p2}"; -// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); +// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); // // List> rows = mapper.selectManyMappedRows(selectStatement); // @@ -880,10 +797,10 @@ void testSingleTableJoin1() { // .build() // .render(RenderingStrategies.MYBATIS3); // -// String expectedStatment = "select ol.order_id, ol.quantity, im.item_id, im.description" +// String expectedStatement = "select ol.order_id, ol.quantity, im.item_id, im.description" // + " from ItemMaster im left join OrderLine ol on ol.item_id = im.item_id" // + " limit #{parameters.p1}"; -// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); +// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); // // List> rows = mapper.selectManyMappedRows(selectStatement); // @@ -914,10 +831,10 @@ void testSingleTableJoin1() { // .build() // .render(RenderingStrategies.MYBATIS3); // -// String expectedStatment = "select ol.order_id, ol.quantity, im.item_id, im.description" +// String expectedStatement = "select ol.order_id, ol.quantity, im.item_id, im.description" // + " from ItemMaster im left join OrderLine ol on ol.item_id = im.item_id" // + " offset #{parameters.p1} rows"; -// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); +// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); // // List> rows = mapper.selectManyMappedRows(selectStatement); // @@ -949,10 +866,10 @@ void testSingleTableJoin1() { // .build() // .render(RenderingStrategies.MYBATIS3); // -// String expectedStatment = "select ol.order_id, ol.quantity, im.item_id, im.description" +// String expectedStatement = "select ol.order_id, ol.quantity, im.item_id, im.description" // + " from ItemMaster im left join OrderLine ol on ol.item_id = im.item_id" // + " offset #{parameters.p1} rows fetch first #{parameters.p2} rows only"; -// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); +// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); // // List> rows = mapper.selectManyMappedRows(selectStatement); // @@ -983,10 +900,10 @@ void testSingleTableJoin1() { // .build() // .render(RenderingStrategies.MYBATIS3); // -// String expectedStatment = "select ol.order_id, ol.quantity, im.item_id, im.description" +// String expectedStatement = "select ol.order_id, ol.quantity, im.item_id, im.description" // + " from ItemMaster im left join OrderLine ol on ol.item_id = im.item_id" // + " fetch first #{parameters.p1} rows only"; -// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatment); +// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); // // List> rows = mapper.selectManyMappedRows(selectStatement); // From 44e99579c73db24cb154cbccf7a2550cde1b5633 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Tue, 10 Nov 2020 17:23:41 -0500 Subject: [PATCH 04/12] Coverage --- .../sql/select/QueryExpressionModel.java | 3 +- .../dynamic/sql/select/join/JoinModel.java | 4 +- .../java/examples/joins/JoinSubQueryTest.java | 462 +++++++++--------- 3 files changed, 242 insertions(+), 227 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionModel.java b/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionModel.java index f72e97dce..4e0b14ba7 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionModel.java @@ -54,7 +54,8 @@ private QueryExpressionModel(Builder builder) { groupByModel = builder.groupByModel; } - private TableAliasCalculator determineJoinTableAliasCalculator(JoinModel joinModel, Map tableAliases) { + private TableAliasCalculator determineJoinTableAliasCalculator(JoinModel joinModel, Map tableAliases) { if (joinModel.containsSubQueries()) { // if there are subQueries, then force explicit qualifiers return TableAliasCalculator.of(tableAliases); diff --git a/src/main/java/org/mybatis/dynamic/sql/select/join/JoinModel.java b/src/main/java/org/mybatis/dynamic/sql/select/join/JoinModel.java index 79c86d7e7..dc5174e22 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/join/JoinModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/join/JoinModel.java @@ -15,13 +15,13 @@ */ package org.mybatis.dynamic.sql.select.join; -import org.mybatis.dynamic.sql.TableExpression; - import java.util.ArrayList; import java.util.List; import java.util.function.Function; import java.util.stream.Stream; +import org.mybatis.dynamic.sql.TableExpression; + public class JoinModel { private final List joinSpecifications = new ArrayList<>(); diff --git a/src/test/java/examples/joins/JoinSubQueryTest.java b/src/test/java/examples/joins/JoinSubQueryTest.java index 6b8c12a41..aa8af557c 100644 --- a/src/test/java/examples/joins/JoinSubQueryTest.java +++ b/src/test/java/examples/joins/JoinSubQueryTest.java @@ -190,76 +190,80 @@ void testMultipleTableJoinWithSelectStar() { } } -// @Test -// void testRightJoin() { -// try (SqlSession session = sqlSessionFactory.openSession()) { -// CommonSelectMapper mapper = session.getMapper(CommonSelectMapper.class); -// -// SelectStatementProvider selectStatement = select(orderLine.orderId, orderLine.quantity, itemMaster.itemId, itemMaster.description) -// .from(orderLine, "ol") -// .rightJoin(itemMaster, "im").on(orderLine.itemId, equalTo(itemMaster.itemId)) -// .orderBy(itemMaster.itemId) -// .build() -// .render(RenderingStrategies.MYBATIS3); -// -// String expectedStatement = "select ol.order_id, ol.quantity, im.item_id, im.description" -// + " from OrderLine ol right join ItemMaster im on ol.item_id = im.item_id" -// + " order by item_id"; -// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); -// -// List> rows = mapper.selectManyMappedRows(selectStatement); -// -// assertThat(rows).hasSize(5); -// Map row = rows.get(2); -// assertThat(row).containsEntry("ORDER_ID", 1); -// assertThat(row).containsEntry("QUANTITY", 1); -// assertThat(row).containsEntry("DESCRIPTION", "First Base Glove"); -// assertThat(row).containsEntry("ITEM_ID", 33); -// -// row = rows.get(4); -// assertThat(row).doesNotContainKey("ORDER_ID"); -// assertThat(row).doesNotContainKey("QUANTITY"); -// assertThat(row).containsEntry("DESCRIPTION", "Catcher Glove"); -// assertThat(row).containsEntry("ITEM_ID", 55); -// } -// } -// -// @Test -// void testRightJoin2() { -// try (SqlSession session = sqlSessionFactory.openSession()) { -// CommonSelectMapper mapper = session.getMapper(CommonSelectMapper.class); -// -// SelectStatementProvider selectStatement = select(orderLine.orderId, orderLine.quantity, itemMaster.itemId, itemMaster.description) -// .from(orderMaster, "om") -// .join(orderLine, "ol").on(orderMaster.orderId, equalTo(orderLine.orderId)) -// .rightJoin(itemMaster, "im").on(orderLine.itemId, equalTo(itemMaster.itemId)) -// .orderBy(orderLine.orderId, itemMaster.itemId) -// .build() -// .render(RenderingStrategies.MYBATIS3); -// -// String expectedStatement = "select ol.order_id, ol.quantity, im.item_id, im.description" -// + " from OrderMaster om join OrderLine ol on om.order_id = ol.order_id" -// + " right join ItemMaster im on ol.item_id = im.item_id" -// + " order by order_id, item_id"; -// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); -// -// List> rows = mapper.selectManyMappedRows(selectStatement); -// -// assertThat(rows).hasSize(5); -// Map row = rows.get(0); -// assertThat(row).doesNotContainKey("ORDER_ID"); -// assertThat(row).doesNotContainKey("QUANTITY"); -// assertThat(row).containsEntry("DESCRIPTION", "Catcher Glove"); -// assertThat(row).containsEntry("ITEM_ID", 55); -// -// row = rows.get(4); -// assertThat(row).containsEntry("ORDER_ID", 2); -// assertThat(row).containsEntry("QUANTITY", 1); -// assertThat(row).containsEntry("DESCRIPTION", "Outfield Glove"); -// assertThat(row).containsEntry("ITEM_ID", 44); -// } -// } -// + @Test + void testRightJoin() { + try (SqlSession session = sqlSessionFactory.openSession()) { + CommonSelectMapper mapper = session.getMapper(CommonSelectMapper.class); + + SelectStatementProvider selectStatement = select(orderLine.orderId, orderLine.quantity, + itemMaster.itemId.qualifiedWith("im"), itemMaster.description) + .from(orderLine, "ol") + .rightJoin(select(itemMaster.allColumns()).from(itemMaster), "im") + .on(orderLine.itemId, equalTo(itemMaster.itemId.qualifiedWith("im"))) + .orderBy(itemMaster.itemId) + .build() + .render(RenderingStrategies.MYBATIS3); + + String expectedStatement = "select ol.order_id, ol.quantity, im.item_id, description" + + " from OrderLine ol right join (select * from ItemMaster) im on ol.item_id = im.item_id" + + " order by item_id"; + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); + + List> rows = mapper.selectManyMappedRows(selectStatement); + + assertThat(rows).hasSize(5); + Map row = rows.get(2); + assertThat(row).containsEntry("ORDER_ID", 1); + assertThat(row).containsEntry("QUANTITY", 1); + assertThat(row).containsEntry("DESCRIPTION", "First Base Glove"); + assertThat(row).containsEntry("ITEM_ID", 33); + + row = rows.get(4); + assertThat(row).doesNotContainKey("ORDER_ID"); + assertThat(row).doesNotContainKey("QUANTITY"); + assertThat(row).containsEntry("DESCRIPTION", "Catcher Glove"); + assertThat(row).containsEntry("ITEM_ID", 55); + } + } + + @Test + void testRightJoin2() { + try (SqlSession session = sqlSessionFactory.openSession()) { + CommonSelectMapper mapper = session.getMapper(CommonSelectMapper.class); + + SelectStatementProvider selectStatement = select(orderLine.orderId, orderLine.quantity, + itemMaster.itemId.qualifiedWith(("im")), itemMaster.description) + .from(orderMaster, "om") + .join(orderLine, "ol").on(orderMaster.orderId, equalTo(orderLine.orderId)) + .rightJoin(select(itemMaster.allColumns()).from(itemMaster), "im") + .on(orderLine.itemId, equalTo(itemMaster.itemId.qualifiedWith("im"))) + .orderBy(orderLine.orderId, itemMaster.itemId) + .build() + .render(RenderingStrategies.MYBATIS3); + + String expectedStatement = "select ol.order_id, ol.quantity, im.item_id, description" + + " from OrderMaster om join OrderLine ol on om.order_id = ol.order_id" + + " right join (select * from ItemMaster) im on ol.item_id = im.item_id" + + " order by order_id, item_id"; + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); + + List> rows = mapper.selectManyMappedRows(selectStatement); + + assertThat(rows).hasSize(5); + Map row = rows.get(0); + assertThat(row).doesNotContainKey("ORDER_ID"); + assertThat(row).doesNotContainKey("QUANTITY"); + assertThat(row).containsEntry("DESCRIPTION", "Catcher Glove"); + assertThat(row).containsEntry("ITEM_ID", 55); + + row = rows.get(4); + assertThat(row).containsEntry("ORDER_ID", 2); + assertThat(row).containsEntry("QUANTITY", 1); + assertThat(row).containsEntry("DESCRIPTION", "Outfield Glove"); + assertThat(row).containsEntry("ITEM_ID", 44); + } + } + // @Test // void testRightJoin3() { // try (SqlSession session = sqlSessionFactory.openSession()) { @@ -332,76 +336,81 @@ void testMultipleTableJoinWithSelectStar() { // } // } // -// @Test -// void testLeftJoin() { -// 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") -// .leftJoin(orderLine, "ol").on(orderLine.itemId, equalTo(itemMaster.itemId)) -// .orderBy(itemMaster.itemId) -// .build() -// .render(RenderingStrategies.MYBATIS3); -// -// String expectedStatement = "select ol.order_id, ol.quantity, im.item_id, im.description" -// + " from ItemMaster im left join OrderLine ol on ol.item_id = im.item_id" -// + " order by item_id"; -// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); -// -// List> rows = mapper.selectManyMappedRows(selectStatement); -// -// assertThat(rows).hasSize(5); -// Map row = rows.get(2); -// assertThat(row).containsEntry("ORDER_ID", 1); -// assertThat(row).containsEntry("QUANTITY", 1); -// assertThat(row).containsEntry("DESCRIPTION", "First Base Glove"); -// assertThat(row).containsEntry("ITEM_ID", 33); -// -// row = rows.get(4); -// assertThat(row).doesNotContainKey("ORDER_ID"); -// assertThat(row).doesNotContainKey("QUANTITY"); -// assertThat(row).containsEntry("DESCRIPTION", "Catcher Glove"); -// assertThat(row).containsEntry("ITEM_ID", 55); -// } -// } -// -// @Test -// void testLeftJoin2() { -// try (SqlSession session = sqlSessionFactory.openSession()) { -// CommonSelectMapper mapper = session.getMapper(CommonSelectMapper.class); -// -// SelectStatementProvider selectStatement = select(orderLine.orderId, orderLine.quantity, itemMaster.itemId, itemMaster.description) -// .from(orderMaster, "om") -// .join(orderLine, "ol").on(orderMaster.orderId, equalTo(orderLine.orderId)) -// .leftJoin(itemMaster, "im").on(orderLine.itemId, equalTo(itemMaster.itemId)) -// .orderBy(orderLine.orderId, itemMaster.itemId) -// .build() -// .render(RenderingStrategies.MYBATIS3); -// -// String expectedStatement = "select ol.order_id, ol.quantity, im.item_id, im.description" -// + " from OrderMaster om join OrderLine ol on om.order_id = ol.order_id" -// + " left join ItemMaster im on ol.item_id = im.item_id" -// + " order by order_id, item_id"; -// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); -// -// List> rows = mapper.selectManyMappedRows(selectStatement); -// -// assertThat(rows).hasSize(5); -// Map row = rows.get(2); -// assertThat(row).containsEntry("ORDER_ID", 2); -// assertThat(row).containsEntry("QUANTITY", 6); -// assertThat(row).doesNotContainKey("DESCRIPTION"); -// assertThat(row).doesNotContainKey("ITEM_ID"); -// -// row = rows.get(4); -// assertThat(row).containsEntry("ORDER_ID", 2); -// assertThat(row).containsEntry("QUANTITY", 1); -// assertThat(row).containsEntry("DESCRIPTION", "Outfield Glove"); -// assertThat(row).containsEntry("ITEM_ID", 44); -// } -// } -// + @Test + void testLeftJoin() { + try (SqlSession session = sqlSessionFactory.openSession()) { + CommonSelectMapper mapper = session.getMapper(CommonSelectMapper.class); + + SelectStatementProvider selectStatement = select(orderLine.orderId, orderLine.quantity, + itemMaster.itemId.qualifiedWith("im"), itemMaster.description) + .from(itemMaster, "im") + .leftJoin(select(orderLine.allColumns()).from(orderLine), "ol") + .on(orderLine.itemId.qualifiedWith("ol"), equalTo(itemMaster.itemId)) + .orderBy(itemMaster.itemId) + .build() + .render(RenderingStrategies.MYBATIS3); + + String expectedStatement = "select order_id, quantity, im.item_id, im.description" + + " from ItemMaster im" + + " left join (select * from OrderLine) ol on ol.item_id = im.item_id" + + " order by item_id"; + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); + + List> rows = mapper.selectManyMappedRows(selectStatement); + + assertThat(rows).hasSize(5); + Map row = rows.get(2); + assertThat(row).containsEntry("ORDER_ID", 1); + assertThat(row).containsEntry("QUANTITY", 1); + assertThat(row).containsEntry("DESCRIPTION", "First Base Glove"); + assertThat(row).containsEntry("ITEM_ID", 33); + + row = rows.get(4); + assertThat(row).doesNotContainKey("ORDER_ID"); + assertThat(row).doesNotContainKey("QUANTITY"); + assertThat(row).containsEntry("DESCRIPTION", "Catcher Glove"); + assertThat(row).containsEntry("ITEM_ID", 55); + } + } + + @Test + void testLeftJoin2() { + try (SqlSession session = sqlSessionFactory.openSession()) { + CommonSelectMapper mapper = session.getMapper(CommonSelectMapper.class); + + SelectStatementProvider selectStatement = select(orderLine.orderId, orderLine.quantity, + itemMaster.itemId.qualifiedWith("im"), itemMaster.description) + .from(orderMaster, "om") + .join(orderLine, "ol").on(orderMaster.orderId, equalTo(orderLine.orderId)) + .leftJoin(select(itemMaster.allColumns()).from(itemMaster), "im") + .on(orderLine.itemId, equalTo(itemMaster.itemId.qualifiedWith("im"))) + .orderBy(orderLine.orderId, itemMaster.itemId) + .build() + .render(RenderingStrategies.MYBATIS3); + + String expectedStatement = "select ol.order_id, ol.quantity, im.item_id, description" + + " from OrderMaster om join OrderLine ol on om.order_id = ol.order_id" + + " left join (select * from ItemMaster) im on ol.item_id = im.item_id" + + " order by order_id, item_id"; + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); + + List> rows = mapper.selectManyMappedRows(selectStatement); + + assertThat(rows).hasSize(5); + Map row = rows.get(2); + assertThat(row).containsEntry("ORDER_ID", 2); + assertThat(row).containsEntry("QUANTITY", 6); + assertThat(row).doesNotContainKey("DESCRIPTION"); + assertThat(row).doesNotContainKey("ITEM_ID"); + + row = rows.get(4); + assertThat(row).containsEntry("ORDER_ID", 2); + assertThat(row).containsEntry("QUANTITY", 1); + assertThat(row).containsEntry("DESCRIPTION", "Outfield Glove"); + assertThat(row).containsEntry("ITEM_ID", 44); + } + } + // @Test // void testLeftJoin3() { // try (SqlSession session = sqlSessionFactory.openSession()) { @@ -473,90 +482,95 @@ void testMultipleTableJoinWithSelectStar() { // assertThat(row).containsEntry("ITEM_ID", 44); // } // } -// -// @Test -// void testFullJoin() { -// try (SqlSession session = sqlSessionFactory.openSession()) { -// CommonSelectMapper mapper = session.getMapper(CommonSelectMapper.class); -// -// SelectStatementProvider selectStatement = select(orderLine.orderId, orderLine.quantity, orderLine.itemId.as("ol_itemid"), itemMaster.itemId.as("im_itemid"), itemMaster.description) -// .from(itemMaster, "im") -// .fullJoin(orderLine, "ol").on(itemMaster.itemId, equalTo(orderLine.itemId)) -// .orderBy(sortColumn("im_itemid")) -// .build() -// .render(RenderingStrategies.MYBATIS3); -// -// String expectedStatement = "select ol.order_id, ol.quantity, ol.item_id as ol_itemid, im.item_id as im_itemid, im.description" -// + " from ItemMaster im full join OrderLine ol on im.item_id = ol.item_id" -// + " order by im_itemid"; -// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); -// -// List> rows = mapper.selectManyMappedRows(selectStatement); -// -// assertThat(rows).hasSize(6); -// Map row = rows.get(0); -// assertThat(row).containsEntry("ORDER_ID", 2); -// assertThat(row).containsEntry("QUANTITY", 6); -// assertThat(row).containsEntry("OL_ITEMID", 66); -// assertThat(row).doesNotContainKey("DESCRIPTION"); -// assertThat(row).doesNotContainKey("IM_ITEMID"); -// -// row = rows.get(3); -// assertThat(row).containsEntry("ORDER_ID", 1); -// assertThat(row).containsEntry("QUANTITY", 1); -// assertThat(row).containsEntry("DESCRIPTION", "First Base Glove"); -// assertThat(row).containsEntry("IM_ITEMID", 33); -// -// row = rows.get(5); -// assertThat(row).doesNotContainKey("ORDER_ID"); -// assertThat(row).doesNotContainKey("QUANTITY"); -// assertThat(row).containsEntry("DESCRIPTION", "Catcher Glove"); -// assertThat(row).containsEntry("IM_ITEMID", 55); -// } -// } -// -// @Test -// void testFullJoin2() { -// try (SqlSession session = sqlSessionFactory.openSession()) { -// CommonSelectMapper mapper = session.getMapper(CommonSelectMapper.class); -// -// SelectStatementProvider selectStatement = select(orderLine.orderId, orderLine.quantity, itemMaster.itemId, itemMaster.description) -// .from(orderMaster, "om") -// .join(orderLine, "ol").on(orderMaster.orderId, equalTo(orderLine.orderId)) -// .fullJoin(itemMaster, "im").on(orderLine.itemId, equalTo(itemMaster.itemId)) -// .orderBy(orderLine.orderId, itemMaster.itemId) -// .build() -// .render(RenderingStrategies.MYBATIS3); -// -// String expectedStatement = "select ol.order_id, ol.quantity, im.item_id, im.description" -// + " from OrderMaster om join OrderLine ol on om.order_id = ol.order_id" -// + " full join ItemMaster im on ol.item_id = im.item_id" -// + " order by order_id, item_id"; -// assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); -// -// List> rows = mapper.selectManyMappedRows(selectStatement); -// -// assertThat(rows).hasSize(6); -// Map row = rows.get(0); -// assertThat(row).doesNotContainKey("ORDER_ID"); -// assertThat(row).doesNotContainKey("QUANTITY"); -// assertThat(row).containsEntry("DESCRIPTION", "Catcher Glove"); -// assertThat(row).containsEntry("ITEM_ID", 55); -// -// row = rows.get(3); -// assertThat(row).containsEntry("ORDER_ID", 2); -// assertThat(row).containsEntry("QUANTITY", 6); -// assertThat(row).doesNotContainKey("DESCRIPTION"); -// assertThat(row).doesNotContainKey("ITEM_ID"); -// -// row = rows.get(5); -// assertThat(row).containsEntry("ORDER_ID", 2); -// assertThat(row).containsEntry("QUANTITY", 1); -// assertThat(row).containsEntry("DESCRIPTION", "Outfield Glove"); -// assertThat(row).containsEntry("ITEM_ID", 44); -// } -// } -// + + @Test + void testFullJoin() { + try (SqlSession session = sqlSessionFactory.openSession()) { + CommonSelectMapper mapper = session.getMapper(CommonSelectMapper.class); + + SelectStatementProvider selectStatement = select(orderLine.orderId, orderLine.quantity, + orderLine.itemId.as("ol_itemid").qualifiedWith("ol"), itemMaster.itemId.as("im_itemid"), itemMaster.description) + .from(itemMaster, "im") + .fullJoin(select(orderLine.allColumns()).from(orderLine), "ol") + .on(itemMaster.itemId, equalTo(orderLine.itemId.qualifiedWith("ol"))) + .orderBy(sortColumn("im_itemid")) + .build() + .render(RenderingStrategies.MYBATIS3); + + String expectedStatement = "select order_id, quantity, ol.item_id as ol_itemid, im.item_id as im_itemid, im.description" + + " from ItemMaster im" + + " full join (select * from OrderLine) ol on im.item_id = ol.item_id" + + " order by im_itemid"; + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); + + List> rows = mapper.selectManyMappedRows(selectStatement); + + assertThat(rows).hasSize(6); + Map row = rows.get(0); + assertThat(row).containsEntry("ORDER_ID", 2); + assertThat(row).containsEntry("QUANTITY", 6); + assertThat(row).containsEntry("OL_ITEMID", 66); + assertThat(row).doesNotContainKey("DESCRIPTION"); + assertThat(row).doesNotContainKey("IM_ITEMID"); + + row = rows.get(3); + assertThat(row).containsEntry("ORDER_ID", 1); + assertThat(row).containsEntry("QUANTITY", 1); + assertThat(row).containsEntry("DESCRIPTION", "First Base Glove"); + assertThat(row).containsEntry("IM_ITEMID", 33); + + row = rows.get(5); + assertThat(row).doesNotContainKey("ORDER_ID"); + assertThat(row).doesNotContainKey("QUANTITY"); + assertThat(row).containsEntry("DESCRIPTION", "Catcher Glove"); + assertThat(row).containsEntry("IM_ITEMID", 55); + } + } + + @Test + void testFullJoin2() { + try (SqlSession session = sqlSessionFactory.openSession()) { + CommonSelectMapper mapper = session.getMapper(CommonSelectMapper.class); + + SelectStatementProvider selectStatement = select(orderLine.orderId, orderLine.quantity, + itemMaster.itemId.qualifiedWith("im"), itemMaster.description) + .from(orderMaster, "om") + .join(orderLine, "ol").on(orderMaster.orderId, equalTo(orderLine.orderId)) + .fullJoin(select(itemMaster.allColumns()).from(itemMaster), "im") + .on(orderLine.itemId, equalTo(itemMaster.itemId.qualifiedWith("im"))) + .orderBy(orderLine.orderId, itemMaster.itemId) + .build() + .render(RenderingStrategies.MYBATIS3); + + String expectedStatement = "select ol.order_id, ol.quantity, im.item_id, description" + + " from OrderMaster om join OrderLine ol on om.order_id = ol.order_id" + + " full join (select * from ItemMaster) im on ol.item_id = im.item_id" + + " order by order_id, item_id"; + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); + + List> rows = mapper.selectManyMappedRows(selectStatement); + + assertThat(rows).hasSize(6); + Map row = rows.get(0); + assertThat(row).doesNotContainKey("ORDER_ID"); + assertThat(row).doesNotContainKey("QUANTITY"); + assertThat(row).containsEntry("DESCRIPTION", "Catcher Glove"); + assertThat(row).containsEntry("ITEM_ID", 55); + + row = rows.get(3); + assertThat(row).containsEntry("ORDER_ID", 2); + assertThat(row).containsEntry("QUANTITY", 6); + assertThat(row).doesNotContainKey("DESCRIPTION"); + assertThat(row).doesNotContainKey("ITEM_ID"); + + row = rows.get(5); + assertThat(row).containsEntry("ORDER_ID", 2); + assertThat(row).containsEntry("QUANTITY", 1); + assertThat(row).containsEntry("DESCRIPTION", "Outfield Glove"); + assertThat(row).containsEntry("ITEM_ID", 44); + } + } + // @Test // void testFullJoin3() { // try (SqlSession session = sqlSessionFactory.openSession()) { From cb2496078669239b331d72226f8943e5616bf503 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Tue, 10 Nov 2020 21:12:32 -0500 Subject: [PATCH 05/12] Start Kotlin DSL for join subQueries --- .../select/AbstractQueryExpressionDSL.java | 16 +++- .../AbstractQueryExpressionDSLExtensions.kt | 12 +++ .../sql/util/kotlin/KotlinBaseBuilders.kt | 12 +++ .../kotlin/mybatis3/joins/JoinMapperTest.kt | 80 +++++++++++++++++++ 4 files changed, 119 insertions(+), 1 deletion(-) 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 c0faebd63..6a885676a 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/AbstractQueryExpressionDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/AbstractQueryExpressionDSL.java @@ -71,6 +71,13 @@ public T join(SqlTable joinTable, String tableAlias, JoinCriterion onJoinCriteri return join(joinTable, onJoinCriterion, 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) { addJoinSpecificationBuilder(joinTable, onJoinCriterion, JoinType.LEFT, Arrays.asList(andJoinCriteria)); @@ -143,7 +150,14 @@ public T fullJoin(SqlTable joinTable, String tableAlias, JoinCriterion onJoinCri return fullJoin(joinTable, onJoinCriterion, andJoinCriteria); } - private void addJoinSpecificationBuilder(SqlTable joinTable, JoinCriterion onJoinCriterion, JoinType joinType, + 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) { joinSpecificationBuilders.add(new JoinSpecification.Builder() .withJoinTable(joinTable) diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/AbstractQueryExpressionDSLExtensions.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/AbstractQueryExpressionDSLExtensions.kt index 608b112a4..edadd5718 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/AbstractQueryExpressionDSLExtensions.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/AbstractQueryExpressionDSLExtensions.kt @@ -31,6 +31,12 @@ fun > AbstractQueryExpressionDSL< return join(table, alias, onJoinCriterion, andJoinCriteria) } +fun > AbstractQueryExpressionDSL + .join(subQuery: KotlinQualifiedSubQueryBuilder, joinCriteria: JoinReceiver): T = + with(joinCriteria(JoinCollector())) { + return join(subQuery.selectBuilder, subQuery.correlationName, onJoinCriterion, andJoinCriteria) + } + fun > AbstractQueryExpressionDSL .fullJoin(table: SqlTable, collect: JoinReceiver): T = with(collect(JoinCollector())) { @@ -43,6 +49,12 @@ fun > AbstractQueryExpressionDSL< return fullJoin(table, alias, onJoinCriterion, andJoinCriteria) } +fun > AbstractQueryExpressionDSL + .fullJoin(builder: KotlinQualifiedSubQueryBuilder, collect: JoinReceiver): T = + with(collect(JoinCollector())) { + return fullJoin(builder.selectBuilder, builder.correlationName, onJoinCriterion, andJoinCriteria) + } + fun > AbstractQueryExpressionDSL .leftJoin(table: SqlTable, collect: JoinReceiver): T = with(collect(JoinCollector())) { diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinBaseBuilders.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinBaseBuilders.kt index 926288857..2acdad328 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinBaseBuilders.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinBaseBuilders.kt @@ -87,6 +87,12 @@ abstract class KotlinBaseJoiningBuilder KotlinQualifiedSubQueryBuilder, joinCriteria: JoinReceiver): B = + applySelf { + val builder = subQuery(KotlinQualifiedSubQueryBuilder()) + getDsl().join(builder, joinCriteria) + } + fun fullJoin(table: SqlTable, receiver: JoinReceiver): B = applySelf { getDsl().fullJoin(table, receiver) @@ -97,6 +103,12 @@ abstract class KotlinBaseJoiningBuilder KotlinQualifiedSubQueryBuilder, receiver: JoinReceiver): B = + applySelf { + val builder = subQuery(KotlinQualifiedSubQueryBuilder()) + getDsl().fullJoin(builder, receiver) + } + fun leftJoin(table: SqlTable, receiver: JoinReceiver): B = applySelf { getDsl().leftJoin(table, receiver) diff --git a/src/test/kotlin/examples/kotlin/mybatis3/joins/JoinMapperTest.kt b/src/test/kotlin/examples/kotlin/mybatis3/joins/JoinMapperTest.kt index e43125c98..18f6ad75f 100644 --- a/src/test/kotlin/examples/kotlin/mybatis3/joins/JoinMapperTest.kt +++ b/src/test/kotlin/examples/kotlin/mybatis3/joins/JoinMapperTest.kt @@ -222,6 +222,86 @@ class JoinMapperTest { } } + @Test + fun testFullJoinWithSubQuery() { + newSession().use { session -> + val mapper = session.getMapper(JoinMapper::class.java) + + val selectStatement = select(OrderLine.orderId.qualifiedWith("ol"), + OrderLine.quantity, ItemMaster.itemId.qualifiedWith("im"), + ItemMaster.description) { + from { + select(OrderMaster.allColumns()) { + from(OrderMaster) + } + +"om" + } + join(subQuery = { + select(OrderLine.allColumns()) { + from(OrderLine) + } + + "ol" + }, joinCriteria = { + on( + OrderMaster.orderId.qualifiedWith("om"), + equalTo(OrderLine.orderId.qualifiedWith("ol")) + ) + }) + fullJoin({ + select(ItemMaster.allColumns()) { + from(ItemMaster) + } + + "im" + }) { + on(OrderLine.itemId.qualifiedWith("ol"), + equalTo(ItemMaster.itemId.qualifiedWith("im"))) + } + orderBy(OrderLine.orderId, ItemMaster.itemId) + } + + val expectedStatement = "select ol.order_id, quantity, im.item_id, description" + + " from (select * from OrderMaster) om join (select * from OrderLine) ol on om.order_id = ol.order_id" + + " full join (select * from ItemMaster) im on ol.item_id = im.item_id" + + " order by order_id, item_id" + + assertThat(selectStatement.selectStatement).isEqualTo(expectedStatement) + + data class OrderDetail(val itemId: Int?, val orderId: Int?, val quantity: Int?, val description: String?) + + val rows = mapper.selectMany(selectStatement) { + OrderDetail( + it["ITEM_ID"] as Int?, + it["ORDER_ID"] as Int?, + it["QUANTITY"] as Int?, + it["DESCRIPTION"] as String? + ) + } + + assertThat(rows).hasSize(6) + + with(rows[0]) { + assertThat(itemId).isEqualTo(55) + assertThat(orderId).isNull() + assertThat(quantity).isNull() + assertThat(description).isEqualTo("Catcher Glove") + } + + with(rows[3]) { + assertThat(itemId).isNull() + assertThat(orderId).isEqualTo(2) + assertThat(quantity).isEqualTo(6) + assertThat(description).isNull() + } + + with(rows[5]) { + assertThat(itemId).isEqualTo(44) + assertThat(orderId).isEqualTo(2) + assertThat(quantity).isEqualTo(1) + assertThat(description).isEqualTo("Outfield Glove") + } + } + } + @Test fun testFullJoinWithoutAliases() { newSession().use { session -> From 24bab5ca16ce9eb99543f6fd6c8563c7505bddef Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 16 Nov 2020 18:27:03 -0500 Subject: [PATCH 06/12] Finish joins with subquery support --- .../select/AbstractQueryExpressionDSL.java | 18 +++- .../sql/util/kotlin/KotlinBaseBuilders.kt | 37 +++++++ .../kotlin/KotlinModelBuilderFunctions.kt | 1 + .../kotlin/mybatis3/joins/JoinMapperTest.kt | 98 ++++++++++++++++++- 4 files changed, 151 insertions(+), 3 deletions(-) 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 6a885676a..5b63e6fa2 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/AbstractQueryExpressionDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/AbstractQueryExpressionDSL.java @@ -102,6 +102,13 @@ public T leftJoin(SqlTable joinTable, String tableAlias, JoinCriterion onJoinCri return leftJoin(joinTable, onJoinCriterion, 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) { addJoinSpecificationBuilder(joinTable, onJoinCriterion, JoinType.RIGHT, Arrays.asList(andJoinCriteria)); @@ -126,6 +133,13 @@ public T rightJoin(SqlTable joinTable, String tableAlias, JoinCriterion onJoinCr return rightJoin(joinTable, onJoinCriterion, 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) { addJoinSpecificationBuilder(joinTable, onJoinCriterion, JoinType.FULL, Arrays.asList(andJoinCriteria)); @@ -157,8 +171,8 @@ public T fullJoin(Buildable subQuery, String tableAlias, JoinCriter 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/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinBaseBuilders.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinBaseBuilders.kt index 4e808b608..d63b1338d 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinBaseBuilders.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinBaseBuilders.kt @@ -76,6 +76,7 @@ abstract class KotlinBaseBuilder, B : KotlinBaseBuilder< protected abstract fun getWhere(): W } +@Suppress("TooManyFunctions") abstract class KotlinBaseJoiningBuilder, W : AbstractWhereDSL, B : KotlinBaseJoiningBuilder> : KotlinBaseBuilder() { @@ -89,6 +90,15 @@ abstract class KotlinBaseJoiningBuilder KotlinQualifiedSubQueryBuilder, + joinCriteria: JoinReceiver + ) = + applyJoin(joinCriteria) { + val builder = subQuery(KotlinQualifiedSubQueryBuilder()) + getDsl().join(builder.selectBuilder, builder.correlationName, it.onJoinCriterion, it.andJoinCriteria) + } + fun fullJoin(table: SqlTable, joinCriteria: JoinReceiver) = applyJoin(joinCriteria) { getDsl().fullJoin(table, it.onJoinCriterion, it.andJoinCriteria) @@ -99,6 +109,15 @@ abstract class KotlinBaseJoiningBuilder KotlinQualifiedSubQueryBuilder, + joinCriteria: JoinReceiver + ) = + applyJoin(joinCriteria) { + val builder = subQuery(KotlinQualifiedSubQueryBuilder()) + getDsl().fullJoin(builder.selectBuilder, builder.correlationName, it.onJoinCriterion, it.andJoinCriteria) + } + fun leftJoin(table: SqlTable, joinCriteria: JoinReceiver) = applyJoin(joinCriteria) { getDsl().leftJoin(table, it.onJoinCriterion, it.andJoinCriteria) @@ -109,6 +128,15 @@ abstract class KotlinBaseJoiningBuilder KotlinQualifiedSubQueryBuilder, + joinCriteria: JoinReceiver + ) = + applyJoin(joinCriteria) { + val builder = subQuery(KotlinQualifiedSubQueryBuilder()) + getDsl().leftJoin(builder.selectBuilder, builder.correlationName, it.onJoinCriterion, it.andJoinCriteria) + } + fun rightJoin(table: SqlTable, joinCriteria: JoinReceiver) = applyJoin(joinCriteria) { getDsl().rightJoin(table, it.onJoinCriterion, it.andJoinCriteria) @@ -119,6 +147,15 @@ abstract class KotlinBaseJoiningBuilder KotlinQualifiedSubQueryBuilder, + joinCriteria: JoinReceiver + ) = + applyJoin(joinCriteria) { + val builder = subQuery(KotlinQualifiedSubQueryBuilder()) + getDsl().rightJoin(builder.selectBuilder, builder.correlationName, it.onJoinCriterion, it.andJoinCriteria) + } + private fun applyJoin(joinCriteria: JoinReceiver, block: (JoinCollector) -> Unit) = applySelf { joinCriteria(JoinCollector()).also(block) diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinModelBuilderFunctions.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinModelBuilderFunctions.kt index 528ad6210..13439b845 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinModelBuilderFunctions.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinModelBuilderFunctions.kt @@ -29,6 +29,7 @@ import org.mybatis.dynamic.sql.insert.MultiRowInsertDSL * with the similar functions that build providers for the different rendering * strategies. */ +@Suppress("TooManyFunctions") object KotlinModelBuilderFunctions { fun count(column: BasicColumn, completer: CountCompleter) = completer(KotlinCountBuilder(SqlBuilder.countColumn(column))).build() diff --git a/src/test/kotlin/examples/kotlin/mybatis3/joins/JoinMapperTest.kt b/src/test/kotlin/examples/kotlin/mybatis3/joins/JoinMapperTest.kt index 18f6ad75f..dd4f80a70 100644 --- a/src/test/kotlin/examples/kotlin/mybatis3/joins/JoinMapperTest.kt +++ b/src/test/kotlin/examples/kotlin/mybatis3/joins/JoinMapperTest.kt @@ -260,7 +260,8 @@ class JoinMapperTest { } val expectedStatement = "select ol.order_id, quantity, im.item_id, description" + - " from (select * from OrderMaster) om join (select * from OrderLine) ol on om.order_id = ol.order_id" + + " from (select * from OrderMaster) om" + + " join (select * from OrderLine) ol on om.order_id = ol.order_id" + " full join (select * from ItemMaster) im on ol.item_id = im.item_id" + " order by order_id, item_id" @@ -391,6 +392,54 @@ class JoinMapperTest { } } + @Test + fun testLeftJoinWithSubQuery() { + newSession().use { session -> + val mapper = session.getMapper(JoinMapper::class.java) + + val selectStatement = select(OrderLine.orderId, OrderLine.quantity, + ItemMaster.itemId.qualifiedWith("im"), + ItemMaster.description) { + from(OrderMaster, "om") + join(OrderLine, "ol") { + on(OrderMaster.orderId, equalTo(OrderLine.orderId)) + } + leftJoin({ + select(ItemMaster.allColumns()) { + from(ItemMaster) + } + + "im" + }) { + on(OrderLine.itemId, equalTo(ItemMaster.itemId.qualifiedWith("im"))) + } + orderBy(OrderLine.orderId, ItemMaster.itemId) + } + + val expectedStatement = "select ol.order_id, ol.quantity, im.item_id, description" + + " from OrderMaster om join OrderLine ol on om.order_id = ol.order_id" + + " left join (select * from ItemMaster) im on ol.item_id = im.item_id" + + " order by order_id, item_id" + + assertThat(selectStatement.selectStatement).isEqualTo(expectedStatement) + + val rows = mapper.selectManyMappedRows(selectStatement) + + assertThat(rows).hasSize(5) + + assertThat(rows[2]).containsExactly( + entry("ORDER_ID", 2), + entry("QUANTITY", 6) + ) + + assertThat(rows[4]).containsExactly( + entry("ORDER_ID", 2), + entry("QUANTITY", 1), + entry("DESCRIPTION", "Outfield Glove"), + entry("ITEM_ID", 44) + ) + } + } + @Test fun testLeftJoinWithoutAliases() { newSession().use { session -> @@ -475,6 +524,53 @@ class JoinMapperTest { } } + @Test + fun testRightJoinWithSubQuery() { + newSession().use { session -> + val mapper = session.getMapper(JoinMapper::class.java) + + val selectStatement = select(OrderLine.orderId, OrderLine.quantity, + ItemMaster.itemId.qualifiedWith("im"), ItemMaster.description) { + from(OrderMaster, "om") + join(OrderLine, "ol") { + on(OrderMaster.orderId, equalTo(OrderLine.orderId)) + } + rightJoin ({ + select(ItemMaster.allColumns()) { + from(ItemMaster) + } + +"im" + }) { + on(OrderLine.itemId, equalTo(ItemMaster.itemId.qualifiedWith("im"))) + } + orderBy(OrderLine.orderId, ItemMaster.itemId) + } + + val expectedStatement = "select ol.order_id, ol.quantity, im.item_id, description" + + " from OrderMaster om join OrderLine ol on om.order_id = ol.order_id" + + " right join (select * from ItemMaster) im on ol.item_id = im.item_id" + + " order by order_id, item_id" + + assertThat(selectStatement.selectStatement).isEqualTo(expectedStatement) + + val rows = mapper.selectManyMappedRows(selectStatement) + + assertThat(rows).hasSize(5) + + assertThat(rows[0]).containsExactly( + entry("DESCRIPTION", "Catcher Glove"), + entry("ITEM_ID", 55) + ) + + assertThat(rows[4]).containsExactly( + entry("ORDER_ID", 2), + entry("QUANTITY", 1), + entry("DESCRIPTION", "Outfield Glove"), + entry("ITEM_ID", 44) + ) + } + } + @Test fun testRightJoinWithoutAliases() { newSession().use { session -> From d1226e2def66816543ec2d8fd9bec5c044264ae9 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Tue, 17 Nov 2020 14:55:54 -0500 Subject: [PATCH 07/12] Kotlin SubQuery builders can implement Buildable --- .../sql/util/kotlin/KotlinBaseBuilders.kt | 8 ++++---- .../dynamic/sql/util/kotlin/KotlinConditions.kt | 16 ++++++++-------- .../util/kotlin/KotlinModelBuilderFunctions.kt | 2 +- .../sql/util/kotlin/KotlinSelectBuilder.kt | 2 +- .../sql/util/kotlin/KotlinSubQueryBuilders.kt | 8 ++++++-- .../sql/util/kotlin/KotlinUpdateBuilder.kt | 2 +- 6 files changed, 21 insertions(+), 17 deletions(-) diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinBaseBuilders.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinBaseBuilders.kt index d63b1338d..7cf396ec1 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinBaseBuilders.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinBaseBuilders.kt @@ -96,7 +96,7 @@ abstract class KotlinBaseJoiningBuilder Unit) = diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinConditions.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinConditions.kt index 012dab612..8ca1b72ea 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinConditions.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinConditions.kt @@ -25,25 +25,25 @@ import org.mybatis.dynamic.sql.where.condition.IsNotEqualToWithSubselect import org.mybatis.dynamic.sql.where.condition.IsNotInWithSubselect fun isEqualTo(subQuery: KotlinSubQueryBuilder.() -> KotlinSubQueryBuilder) = - IsEqualToWithSubselect.of(subQuery(KotlinSubQueryBuilder()).selectBuilder) + IsEqualToWithSubselect.of(subQuery(KotlinSubQueryBuilder())) fun isNotEqualTo(subQuery: KotlinSubQueryBuilder.() -> KotlinSubQueryBuilder) = - IsNotEqualToWithSubselect.of(subQuery(KotlinSubQueryBuilder()).selectBuilder) + IsNotEqualToWithSubselect.of(subQuery(KotlinSubQueryBuilder())) fun isIn(subQuery: KotlinSubQueryBuilder.() -> KotlinSubQueryBuilder) = - IsInWithSubselect.of(subQuery(KotlinSubQueryBuilder()).selectBuilder) + IsInWithSubselect.of(subQuery(KotlinSubQueryBuilder())) fun isNotIn(subQuery: KotlinSubQueryBuilder.() -> KotlinSubQueryBuilder) = - IsNotInWithSubselect.of(subQuery(KotlinSubQueryBuilder()).selectBuilder) + IsNotInWithSubselect.of(subQuery(KotlinSubQueryBuilder())) fun isGreaterThan(subQuery: KotlinSubQueryBuilder.() -> KotlinSubQueryBuilder) = - IsGreaterThanWithSubselect.of(subQuery(KotlinSubQueryBuilder()).selectBuilder) + IsGreaterThanWithSubselect.of(subQuery(KotlinSubQueryBuilder())) fun isGreaterThanOrEqualTo(subQuery: KotlinSubQueryBuilder.() -> KotlinSubQueryBuilder) = - IsGreaterThanOrEqualToWithSubselect.of(subQuery(KotlinSubQueryBuilder()).selectBuilder) + IsGreaterThanOrEqualToWithSubselect.of(subQuery(KotlinSubQueryBuilder())) fun isLessThan(subQuery: KotlinSubQueryBuilder.() -> KotlinSubQueryBuilder) = - IsLessThanWithSubselect.of(subQuery(KotlinSubQueryBuilder()).selectBuilder) + IsLessThanWithSubselect.of(subQuery(KotlinSubQueryBuilder())) fun isLessThanOrEqualTo(subQuery: KotlinSubQueryBuilder.() -> KotlinSubQueryBuilder) = - IsLessThanOrEqualToWithSubselect.of(subQuery(KotlinSubQueryBuilder()).selectBuilder) + IsLessThanOrEqualToWithSubselect.of(subQuery(KotlinSubQueryBuilder())) diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinModelBuilderFunctions.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinModelBuilderFunctions.kt index 13439b845..5b040c0ad 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinModelBuilderFunctions.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinModelBuilderFunctions.kt @@ -52,7 +52,7 @@ object KotlinModelBuilderFunctions { with(completer(KotlinInsertSelectSubQueryBuilder())) { SqlBuilder.insertInto(table) .withColumnList(columnList) - .withSelectStatement(selectBuilder) + .withSelectStatement(this) .build() } diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinSelectBuilder.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinSelectBuilder.kt index 3b5eecdde..d3794de6c 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinSelectBuilder.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinSelectBuilder.kt @@ -45,7 +45,7 @@ class KotlinSelectBuilder(private val fromGatherer: QueryExpressionDSL.FromGathe fun from(subQuery: KotlinQualifiedSubQueryBuilder.() -> KotlinQualifiedSubQueryBuilder) = apply { val builder = subQuery(KotlinQualifiedSubQueryBuilder()) - dsl = fromGatherer.from(builder.selectBuilder, builder.correlationName) + dsl = fromGatherer.from(builder, builder.correlationName) } fun groupBy(vararg columns: BasicColumn) = diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinSubQueryBuilders.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinSubQueryBuilders.kt index 2c0d76de1..8627054b6 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinSubQueryBuilders.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinSubQueryBuilders.kt @@ -18,10 +18,12 @@ package org.mybatis.dynamic.sql.util.kotlin import org.mybatis.dynamic.sql.BasicColumn import org.mybatis.dynamic.sql.SqlBuilder import org.mybatis.dynamic.sql.SqlColumn +import org.mybatis.dynamic.sql.select.SelectModel +import org.mybatis.dynamic.sql.util.Buildable @MyBatisDslMarker -sealed class KotlinBaseSubQueryBuilder > { - lateinit var selectBuilder: KotlinSelectBuilder +sealed class KotlinBaseSubQueryBuilder> : Buildable { + private lateinit var selectBuilder: KotlinSelectBuilder fun select(vararg selectList: BasicColumn, completer: SelectCompleter) = select(selectList.toList(), completer) @@ -39,6 +41,8 @@ sealed class KotlinBaseSubQueryBuilder > { selectBuilder = completer(KotlinSelectBuilder(SqlBuilder.selectDistinct(selectList))) } + override fun build() = selectBuilder.build() + private fun applySelf(block: T.() -> Unit): T = self().apply { block() } diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinUpdateBuilder.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinUpdateBuilder.kt index 55895ec23..7ac404098 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinUpdateBuilder.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinUpdateBuilder.kt @@ -68,7 +68,7 @@ class KotlinUpdateBuilder(private val dsl: UpdateDSL) : fun equalToQueryResult(subQuery: KotlinSubQueryBuilder.() -> KotlinSubQueryBuilder) = applyToDsl { - set(column).equalTo(subQuery(KotlinSubQueryBuilder()).selectBuilder) + set(column).equalTo(subQuery(KotlinSubQueryBuilder())) } fun equalToWhenPresent(value: () -> T?) = From cbffbd66f199e55fab0dea38910a214da69e4b50 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Tue, 17 Nov 2020 18:46:21 -0500 Subject: [PATCH 08/12] Better pattern for partials in Kotlin --- .../PersonWithAddressMapperExtensions.kt | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/src/test/kotlin/examples/kotlin/mybatis3/canonical/PersonWithAddressMapperExtensions.kt b/src/test/kotlin/examples/kotlin/mybatis3/canonical/PersonWithAddressMapperExtensions.kt index afc007f1d..fac87a795 100644 --- a/src/test/kotlin/examples/kotlin/mybatis3/canonical/PersonWithAddressMapperExtensions.kt +++ b/src/test/kotlin/examples/kotlin/mybatis3/canonical/PersonWithAddressMapperExtensions.kt @@ -31,33 +31,36 @@ import org.mybatis.dynamic.sql.util.kotlin.mybatis3.selectList fun PersonWithAddressMapper.selectOne(completer: SelectCompleter): PersonWithAddress? { val start = KotlinSelectBuilder(select(id.`as`("A_ID"), firstName, lastName, birthDate, - employed, occupation, Address.id, Address.streetAddress, Address.city, Address.state)) - .from(Person) - .fullJoin(Address) { - on(Person.addressId, equalTo(Address.id)) - } + employed, occupation, Address.id, Address.streetAddress, Address.city, Address.state)).apply { + from(Person) + fullJoin(Address) { + on(Person.addressId, equalTo(Address.id)) + } + } return selectOne(this::selectOne, start, completer) } fun PersonWithAddressMapper.select(completer: SelectCompleter): List { val start = KotlinSelectBuilder(select(id.`as`("A_ID"), firstName, lastName, birthDate, - employed, occupation, Address.id, Address.streetAddress, Address.city, Address.state)) - .from(Person, "p") - .fullJoin(Address) { - on(Person.addressId, equalTo(Address.id)) - } + employed, occupation, Address.id, Address.streetAddress, Address.city, Address.state)).apply { + from(Person, "p") + fullJoin(Address) { + on(Person.addressId, equalTo(Address.id)) + } + } return selectList(this::selectMany, start, completer) } fun PersonWithAddressMapper.selectDistinct(completer: SelectCompleter): List { val start = KotlinSelectBuilder(selectDistinct(id.`as`("A_ID"), firstName, lastName, - birthDate, employed, occupation, Address.id, Address.streetAddress, Address.city, Address.state)) - .from(Person, "p") - .fullJoin(Address) { - on(Person.addressId, equalTo(Address.id)) - } + birthDate, employed, occupation, Address.id, Address.streetAddress, Address.city, Address.state)).apply { + from(Person, "p") + fullJoin(Address) { + on(Person.addressId, equalTo(Address.id)) + } + } return selectList(this::selectMany, start, completer) } From a8b513a3218df7b6109718e6ec373eddbbb297ec Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Wed, 18 Nov 2020 11:12:30 -0500 Subject: [PATCH 09/12] Make the receivers more typical for Kotlin --- .../sql/util/kotlin/CriteriaCollector.kt | 10 +++--- .../dynamic/sql/util/kotlin/JoinCollector.kt | 2 +- .../sql/util/kotlin/KotlinBaseBuilders.kt | 24 +++++++------- .../sql/util/kotlin/KotlinConditions.kt | 32 +++++++++--------- .../sql/util/kotlin/KotlinCountBuilder.kt | 2 +- .../sql/util/kotlin/KotlinDeleteBuilder.kt | 2 +- .../sql/util/kotlin/KotlinInsertHelpers.kt | 16 +++------ .../kotlin/KotlinModelBuilderFunctions.kt | 33 ++++++++++--------- .../sql/util/kotlin/KotlinSelectBuilder.kt | 6 ++-- .../sql/util/kotlin/KotlinSubQueryBuilders.kt | 4 +-- .../sql/util/kotlin/KotlinUpdateBuilder.kt | 6 ++-- .../mybatis3/ProviderBuilderFunctions.kt | 2 +- 12 files changed, 67 insertions(+), 72 deletions(-) diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/CriteriaCollector.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/CriteriaCollector.kt index e75b51a95..294d49266 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/CriteriaCollector.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/CriteriaCollector.kt @@ -19,7 +19,7 @@ import org.mybatis.dynamic.sql.BindableColumn import org.mybatis.dynamic.sql.SqlCriterion import org.mybatis.dynamic.sql.VisitableCondition -typealias CriteriaReceiver = CriteriaCollector.() -> CriteriaCollector +typealias CriteriaReceiver = CriteriaCollector.() -> Unit @MyBatisDslMarker class CriteriaCollector { @@ -38,13 +38,13 @@ class CriteriaCollector { fun and( column: BindableColumn, condition: VisitableCondition, - collect: CriteriaReceiver + criteriaReceiver: CriteriaReceiver ) = apply { criteria.add( SqlCriterion.withColumn(column) .withCondition(condition) - .withSubCriteria(collect(CriteriaCollector()).criteria) + .withSubCriteria(CriteriaCollector().apply(criteriaReceiver).criteria) .withConnector("and") .build() ) @@ -63,13 +63,13 @@ class CriteriaCollector { fun or( column: BindableColumn, condition: VisitableCondition, - collect: CriteriaReceiver + criteriaReceiver: CriteriaReceiver ) = apply { criteria.add( SqlCriterion.withColumn(column) .withCondition(condition) - .withSubCriteria(collect(CriteriaCollector()).criteria) + .withSubCriteria(CriteriaCollector().apply(criteriaReceiver).criteria) .withConnector("or") .build() ) 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 7d3bcb875..a12e87702 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 @@ -19,7 +19,7 @@ import org.mybatis.dynamic.sql.BasicColumn import org.mybatis.dynamic.sql.select.join.JoinCondition import org.mybatis.dynamic.sql.select.join.JoinCriterion -typealias JoinReceiver = JoinCollector.() -> JoinCollector +typealias JoinReceiver = JoinCollector.() -> Unit @MyBatisDslMarker class JoinCollector { diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinBaseBuilders.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinBaseBuilders.kt index 7cf396ec1..4aa9859c3 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinBaseBuilders.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinBaseBuilders.kt @@ -38,7 +38,7 @@ abstract class KotlinBaseBuilder, B : KotlinBaseBuilder< fun where(column: BindableColumn, condition: VisitableCondition, subCriteria: CriteriaReceiver): B = applySelf { - getWhere().where(column, condition, subCriteria(CriteriaCollector()).criteria) + getWhere().where(column, condition, CriteriaCollector().apply(subCriteria).criteria) } fun applyWhere(whereApplier: WhereApplier): B = @@ -53,7 +53,7 @@ abstract class KotlinBaseBuilder, B : KotlinBaseBuilder< fun and(column: BindableColumn, condition: VisitableCondition, subCriteria: CriteriaReceiver): B = applySelf { - getWhere().and(column, condition, subCriteria(CriteriaCollector()).criteria) + getWhere().and(column, condition, CriteriaCollector().apply(subCriteria).criteria) } fun or(column: BindableColumn, condition: VisitableCondition): B = @@ -63,7 +63,7 @@ abstract class KotlinBaseBuilder, B : KotlinBaseBuilder< fun or(column: BindableColumn, condition: VisitableCondition, subCriteria: CriteriaReceiver): B = applySelf { - getWhere().or(column, condition, subCriteria(CriteriaCollector()).criteria) + getWhere().or(column, condition, CriteriaCollector().apply(subCriteria).criteria) } fun allRows() = self() @@ -91,11 +91,11 @@ abstract class KotlinBaseJoiningBuilder KotlinQualifiedSubQueryBuilder, + subQuery: KotlinQualifiedSubQueryBuilder.() -> Unit, joinCriteria: JoinReceiver ) = applyJoin(joinCriteria) { - val builder = subQuery(KotlinQualifiedSubQueryBuilder()) + val builder = KotlinQualifiedSubQueryBuilder().apply(subQuery) getDsl().join(builder, builder.correlationName, it.onJoinCriterion, it.andJoinCriteria) } @@ -110,11 +110,11 @@ abstract class KotlinBaseJoiningBuilder KotlinQualifiedSubQueryBuilder, + subQuery: KotlinQualifiedSubQueryBuilder.() -> Unit, joinCriteria: JoinReceiver ) = applyJoin(joinCriteria) { - val builder = subQuery(KotlinQualifiedSubQueryBuilder()) + val builder = KotlinQualifiedSubQueryBuilder().apply(subQuery) getDsl().fullJoin(builder, builder.correlationName, it.onJoinCriterion, it.andJoinCriteria) } @@ -129,11 +129,11 @@ abstract class KotlinBaseJoiningBuilder KotlinQualifiedSubQueryBuilder, + subQuery: KotlinQualifiedSubQueryBuilder.() -> Unit, joinCriteria: JoinReceiver ) = applyJoin(joinCriteria) { - val builder = subQuery(KotlinQualifiedSubQueryBuilder()) + val builder = KotlinQualifiedSubQueryBuilder().apply(subQuery) getDsl().leftJoin(builder, builder.correlationName, it.onJoinCriterion, it.andJoinCriteria) } @@ -148,17 +148,17 @@ abstract class KotlinBaseJoiningBuilder KotlinQualifiedSubQueryBuilder, + subQuery: KotlinQualifiedSubQueryBuilder.() -> Unit, joinCriteria: JoinReceiver ) = applyJoin(joinCriteria) { - val builder = subQuery(KotlinQualifiedSubQueryBuilder()) + val builder = KotlinQualifiedSubQueryBuilder().apply(subQuery) getDsl().rightJoin(builder, builder.correlationName, it.onJoinCriterion, it.andJoinCriteria) } private fun applyJoin(joinCriteria: JoinReceiver, block: (JoinCollector) -> Unit) = applySelf { - joinCriteria(JoinCollector()).also(block) + JoinCollector().apply(joinCriteria).apply(block) } protected abstract fun getDsl(): AbstractQueryExpressionDSL diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinConditions.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinConditions.kt index 8ca1b72ea..a44b8efb8 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinConditions.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinConditions.kt @@ -24,26 +24,26 @@ import org.mybatis.dynamic.sql.where.condition.IsLessThanWithSubselect import org.mybatis.dynamic.sql.where.condition.IsNotEqualToWithSubselect import org.mybatis.dynamic.sql.where.condition.IsNotInWithSubselect -fun isEqualTo(subQuery: KotlinSubQueryBuilder.() -> KotlinSubQueryBuilder) = - IsEqualToWithSubselect.of(subQuery(KotlinSubQueryBuilder())) +fun isEqualTo(subQuery: KotlinSubQueryBuilder.() -> Unit) = + IsEqualToWithSubselect.of(KotlinSubQueryBuilder().apply(subQuery)) -fun isNotEqualTo(subQuery: KotlinSubQueryBuilder.() -> KotlinSubQueryBuilder) = - IsNotEqualToWithSubselect.of(subQuery(KotlinSubQueryBuilder())) +fun isNotEqualTo(subQuery: KotlinSubQueryBuilder.() -> Unit) = + IsNotEqualToWithSubselect.of(KotlinSubQueryBuilder().apply(subQuery)) -fun isIn(subQuery: KotlinSubQueryBuilder.() -> KotlinSubQueryBuilder) = - IsInWithSubselect.of(subQuery(KotlinSubQueryBuilder())) +fun isIn(subQuery: KotlinSubQueryBuilder.() -> Unit) = + IsInWithSubselect.of(KotlinSubQueryBuilder().apply(subQuery)) -fun isNotIn(subQuery: KotlinSubQueryBuilder.() -> KotlinSubQueryBuilder) = - IsNotInWithSubselect.of(subQuery(KotlinSubQueryBuilder())) +fun isNotIn(subQuery: KotlinSubQueryBuilder.() -> Unit) = + IsNotInWithSubselect.of(KotlinSubQueryBuilder().apply(subQuery)) -fun isGreaterThan(subQuery: KotlinSubQueryBuilder.() -> KotlinSubQueryBuilder) = - IsGreaterThanWithSubselect.of(subQuery(KotlinSubQueryBuilder())) +fun isGreaterThan(subQuery: KotlinSubQueryBuilder.() -> Unit) = + IsGreaterThanWithSubselect.of(KotlinSubQueryBuilder().apply(subQuery)) -fun isGreaterThanOrEqualTo(subQuery: KotlinSubQueryBuilder.() -> KotlinSubQueryBuilder) = - IsGreaterThanOrEqualToWithSubselect.of(subQuery(KotlinSubQueryBuilder())) +fun isGreaterThanOrEqualTo(subQuery: KotlinSubQueryBuilder.() -> Unit) = + IsGreaterThanOrEqualToWithSubselect.of(KotlinSubQueryBuilder().apply(subQuery)) -fun isLessThan(subQuery: KotlinSubQueryBuilder.() -> KotlinSubQueryBuilder) = - IsLessThanWithSubselect.of(subQuery(KotlinSubQueryBuilder())) +fun isLessThan(subQuery: KotlinSubQueryBuilder.() -> Unit) = + IsLessThanWithSubselect.of(KotlinSubQueryBuilder().apply(subQuery)) -fun isLessThanOrEqualTo(subQuery: KotlinSubQueryBuilder.() -> KotlinSubQueryBuilder) = - IsLessThanOrEqualToWithSubselect.of(subQuery(KotlinSubQueryBuilder())) +fun isLessThanOrEqualTo(subQuery: KotlinSubQueryBuilder.() -> Unit) = + IsLessThanOrEqualToWithSubselect.of(KotlinSubQueryBuilder().apply(subQuery)) diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinCountBuilder.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinCountBuilder.kt index ca4de6310..7fe80ca6f 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinCountBuilder.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinCountBuilder.kt @@ -20,7 +20,7 @@ import org.mybatis.dynamic.sql.select.CountDSL import org.mybatis.dynamic.sql.select.SelectModel import org.mybatis.dynamic.sql.util.Buildable -typealias CountCompleter = KotlinCountBuilder.() -> KotlinCountBuilder +typealias CountCompleter = KotlinCountBuilder.() -> Unit class KotlinCountBuilder(private val fromGatherer: CountDSL.FromGatherer) : KotlinBaseJoiningBuilder, diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinDeleteBuilder.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinDeleteBuilder.kt index fdb9e3d52..ae78c7d24 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinDeleteBuilder.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinDeleteBuilder.kt @@ -19,7 +19,7 @@ import org.mybatis.dynamic.sql.delete.DeleteDSL import org.mybatis.dynamic.sql.delete.DeleteModel import org.mybatis.dynamic.sql.util.Buildable -typealias DeleteCompleter = KotlinDeleteBuilder.() -> KotlinDeleteBuilder +typealias DeleteCompleter = KotlinDeleteBuilder.() -> Unit class KotlinDeleteBuilder(private val dsl: DeleteDSL) : KotlinBaseBuilder.DeleteWhereBuilder, KotlinDeleteBuilder>(), Buildable { diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinInsertHelpers.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinInsertHelpers.kt index 4b53cb945..232b7d25d 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinInsertHelpers.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinInsertHelpers.kt @@ -16,22 +16,16 @@ package org.mybatis.dynamic.sql.util.kotlin import org.mybatis.dynamic.sql.insert.BatchInsertDSL -import org.mybatis.dynamic.sql.insert.BatchInsertModel import org.mybatis.dynamic.sql.insert.GeneralInsertDSL -import org.mybatis.dynamic.sql.insert.GeneralInsertModel import org.mybatis.dynamic.sql.insert.InsertDSL -import org.mybatis.dynamic.sql.insert.InsertModel import org.mybatis.dynamic.sql.insert.MultiRowInsertDSL -import org.mybatis.dynamic.sql.insert.MultiRowInsertModel -import org.mybatis.dynamic.sql.util.Buildable -typealias GeneralInsertCompleter = @MyBatisDslMarker GeneralInsertDSL.() -> Buildable +typealias GeneralInsertCompleter = @MyBatisDslMarker GeneralInsertDSL.() -> Unit -typealias InsertCompleter = @MyBatisDslMarker InsertDSL.() -> Buildable> +typealias InsertCompleter = @MyBatisDslMarker InsertDSL.() -> Unit -typealias MultiRowInsertCompleter = @MyBatisDslMarker MultiRowInsertDSL.() -> Buildable> +typealias MultiRowInsertCompleter = @MyBatisDslMarker MultiRowInsertDSL.() -> Unit -typealias BatchInsertCompleter = @MyBatisDslMarker BatchInsertDSL.() -> Buildable> +typealias BatchInsertCompleter = @MyBatisDslMarker BatchInsertDSL.() -> Unit -typealias InsertSelectCompleter = - @MyBatisDslMarker KotlinInsertSelectSubQueryBuilder.() -> KotlinInsertSelectSubQueryBuilder +typealias InsertSelectCompleter = @MyBatisDslMarker KotlinInsertSelectSubQueryBuilder.() -> Unit diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinModelBuilderFunctions.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinModelBuilderFunctions.kt index 5b040c0ad..ceea48f3b 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinModelBuilderFunctions.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinModelBuilderFunctions.kt @@ -21,6 +21,7 @@ import org.mybatis.dynamic.sql.SqlTable import org.mybatis.dynamic.sql.insert.BatchInsertDSL import org.mybatis.dynamic.sql.insert.GeneralInsertDSL import org.mybatis.dynamic.sql.insert.InsertDSL +import org.mybatis.dynamic.sql.insert.InsertSelectModel import org.mybatis.dynamic.sql.insert.MultiRowInsertDSL /** @@ -32,51 +33,51 @@ import org.mybatis.dynamic.sql.insert.MultiRowInsertDSL @Suppress("TooManyFunctions") object KotlinModelBuilderFunctions { fun count(column: BasicColumn, completer: CountCompleter) = - completer(KotlinCountBuilder(SqlBuilder.countColumn(column))).build() + KotlinCountBuilder(SqlBuilder.countColumn(column)).apply(completer).build() fun countDistinct(column: BasicColumn, completer: CountCompleter) = - completer(KotlinCountBuilder(SqlBuilder.countDistinctColumn(column))).build() + KotlinCountBuilder(SqlBuilder.countDistinctColumn(column)).apply(completer).build() fun countFrom(table: SqlTable, completer: CountCompleter) = - with(KotlinCountBuilder(SqlBuilder.countColumn(SqlBuilder.constant("*")))) { - completer(from(table)).build() - } + KotlinCountBuilder(SqlBuilder.countColumn(SqlBuilder.constant("*"))) + .from(table).apply(completer).build() fun deleteFrom(table: SqlTable, completer: DeleteCompleter) = - completer(KotlinDeleteBuilder(SqlBuilder.deleteFrom(table))).build() + KotlinDeleteBuilder(SqlBuilder.deleteFrom(table)).apply(completer).build() fun insertInto(table: SqlTable, completer: GeneralInsertCompleter) = - completer(GeneralInsertDSL.insertInto(table)).build() + GeneralInsertDSL.insertInto(table).apply(completer).build() - fun insertSelect(table: SqlTable, completer: InsertSelectCompleter) = - with(completer(KotlinInsertSelectSubQueryBuilder())) { - SqlBuilder.insertInto(table) + fun insertSelect(table: SqlTable, completer: InsertSelectCompleter): InsertSelectModel { + with(KotlinInsertSelectSubQueryBuilder().apply(completer)) { + return SqlBuilder.insertInto(table) .withColumnList(columnList) .withSelectStatement(this) .build() } + } fun BatchInsertDSL.IntoGatherer.into(table: SqlTable, completer: BatchInsertCompleter) = - completer(into(table)).build() + into(table).also(completer).build() fun InsertDSL.IntoGatherer.into(table: SqlTable, completer: InsertCompleter) = - completer(into(table)).build() + into(table).apply(completer).build() fun MultiRowInsertDSL.IntoGatherer.into(table: SqlTable, completer: MultiRowInsertCompleter) = - completer(into(table)).build() + into(table).apply(completer).build() fun select(vararg columns: BasicColumn, completer: SelectCompleter) = select(columns.asList(), completer) fun select(columns: List, completer: SelectCompleter) = - completer(KotlinSelectBuilder(SqlBuilder.select(columns))).build() + KotlinSelectBuilder(SqlBuilder.select(columns)).apply(completer).build() fun selectDistinct(vararg columns: BasicColumn, completer: SelectCompleter) = selectDistinct(columns.asList(), completer) fun selectDistinct(columns: List, completer: SelectCompleter) = - completer(KotlinSelectBuilder(SqlBuilder.selectDistinct(columns))).build() + KotlinSelectBuilder(SqlBuilder.selectDistinct(columns)).apply(completer).build() fun update(table: SqlTable, completer: UpdateCompleter) = - completer(KotlinUpdateBuilder(SqlBuilder.update(table))).build() + KotlinUpdateBuilder(SqlBuilder.update(table)).apply(completer).build() } diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinSelectBuilder.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinSelectBuilder.kt index d3794de6c..af1ee5088 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinSelectBuilder.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinSelectBuilder.kt @@ -22,7 +22,7 @@ import org.mybatis.dynamic.sql.select.SelectModel import org.mybatis.dynamic.sql.util.Buildable import org.mybatis.dynamic.sql.select.QueryExpressionDSL -typealias SelectCompleter = KotlinSelectBuilder.() -> KotlinSelectBuilder +typealias SelectCompleter = KotlinSelectBuilder.() -> Unit @Suppress("TooManyFunctions") class KotlinSelectBuilder(private val fromGatherer: QueryExpressionDSL.FromGatherer) : @@ -42,9 +42,9 @@ class KotlinSelectBuilder(private val fromGatherer: QueryExpressionDSL.FromGathe dsl = fromGatherer.from(table, alias) } - fun from(subQuery: KotlinQualifiedSubQueryBuilder.() -> KotlinQualifiedSubQueryBuilder) = + fun from(subQuery: KotlinQualifiedSubQueryBuilder.() -> Unit) = apply { - val builder = subQuery(KotlinQualifiedSubQueryBuilder()) + val builder = KotlinQualifiedSubQueryBuilder().apply(subQuery) dsl = fromGatherer.from(builder, builder.correlationName) } diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinSubQueryBuilders.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinSubQueryBuilders.kt index 8627054b6..a5654a8fa 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinSubQueryBuilders.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinSubQueryBuilders.kt @@ -30,7 +30,7 @@ sealed class KotlinBaseSubQueryBuilder> : Build fun select(selectList: List, completer: SelectCompleter) = applySelf { - selectBuilder = completer(KotlinSelectBuilder(SqlBuilder.select(selectList))) + selectBuilder = KotlinSelectBuilder(SqlBuilder.select(selectList)).apply(completer) } fun selectDistinct(vararg selectList: BasicColumn, completer: SelectCompleter) = @@ -38,7 +38,7 @@ sealed class KotlinBaseSubQueryBuilder> : Build fun selectDistinct(selectList: List, completer: SelectCompleter) = applySelf { - selectBuilder = completer(KotlinSelectBuilder(SqlBuilder.selectDistinct(selectList))) + selectBuilder = KotlinSelectBuilder(SqlBuilder.selectDistinct(selectList)).apply(completer) } override fun build() = selectBuilder.build() diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinUpdateBuilder.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinUpdateBuilder.kt index 7ac404098..cf3b9dcdc 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinUpdateBuilder.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinUpdateBuilder.kt @@ -21,7 +21,7 @@ import org.mybatis.dynamic.sql.update.UpdateDSL import org.mybatis.dynamic.sql.update.UpdateModel import org.mybatis.dynamic.sql.util.Buildable -typealias UpdateCompleter = KotlinUpdateBuilder.() -> KotlinUpdateBuilder +typealias UpdateCompleter = KotlinUpdateBuilder.() -> Unit class KotlinUpdateBuilder(private val dsl: UpdateDSL) : KotlinBaseBuilder.UpdateWhereBuilder, KotlinUpdateBuilder>(), Buildable { @@ -66,9 +66,9 @@ class KotlinUpdateBuilder(private val dsl: UpdateDSL) : set(column).equalTo(rightColumn) } - fun equalToQueryResult(subQuery: KotlinSubQueryBuilder.() -> KotlinSubQueryBuilder) = + fun equalToQueryResult(subQuery: KotlinSubQueryBuilder.() -> Unit) = applyToDsl { - set(column).equalTo(subQuery(KotlinSubQueryBuilder())) + set(column).equalTo(KotlinSubQueryBuilder().apply(subQuery)) } fun equalToWhenPresent(value: () -> T?) = diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/mybatis3/ProviderBuilderFunctions.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/mybatis3/ProviderBuilderFunctions.kt index 7ef49997a..d2e517830 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/mybatis3/ProviderBuilderFunctions.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/mybatis3/ProviderBuilderFunctions.kt @@ -67,7 +67,7 @@ fun MultiRowInsertDSL.IntoGatherer.into(table: SqlTable, completer: Multi into(table, completer).render(RenderingStrategies.MYBATIS3) fun select(start: KotlinSelectBuilder, completer: SelectCompleter) = - completer(start).build().render(RenderingStrategies.MYBATIS3) + start.apply(completer).build().render(RenderingStrategies.MYBATIS3) fun select(vararg columns: BasicColumn, completer: SelectCompleter) = select(columns = columns, completer).render(RenderingStrategies.MYBATIS3) From e0f251965490cfa4062255d1ae4a5205a5f2d876 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Wed, 18 Nov 2020 11:37:21 -0500 Subject: [PATCH 10/12] Kotlin polishing --- .../dynamic/sql/util/kotlin/KotlinModelBuilderFunctions.kt | 6 ++---- .../mybatis/dynamic/sql/util/kotlin/KotlinUpdateBuilder.kt | 4 ++-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinModelBuilderFunctions.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinModelBuilderFunctions.kt index ceea48f3b..636d024d1 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinModelBuilderFunctions.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinModelBuilderFunctions.kt @@ -21,7 +21,6 @@ import org.mybatis.dynamic.sql.SqlTable import org.mybatis.dynamic.sql.insert.BatchInsertDSL import org.mybatis.dynamic.sql.insert.GeneralInsertDSL import org.mybatis.dynamic.sql.insert.InsertDSL -import org.mybatis.dynamic.sql.insert.InsertSelectModel import org.mybatis.dynamic.sql.insert.MultiRowInsertDSL /** @@ -48,14 +47,13 @@ object KotlinModelBuilderFunctions { fun insertInto(table: SqlTable, completer: GeneralInsertCompleter) = GeneralInsertDSL.insertInto(table).apply(completer).build() - fun insertSelect(table: SqlTable, completer: InsertSelectCompleter): InsertSelectModel { + fun insertSelect(table: SqlTable, completer: InsertSelectCompleter) = with(KotlinInsertSelectSubQueryBuilder().apply(completer)) { - return SqlBuilder.insertInto(table) + SqlBuilder.insertInto(table) .withColumnList(columnList) .withSelectStatement(this) .build() } - } fun BatchInsertDSL.IntoGatherer.into(table: SqlTable, completer: BatchInsertCompleter) = into(table).also(completer).build() diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinUpdateBuilder.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinUpdateBuilder.kt index cf3b9dcdc..881a28cfd 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinUpdateBuilder.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinUpdateBuilder.kt @@ -82,8 +82,8 @@ class KotlinUpdateBuilder(private val dsl: UpdateDSL) : } private fun applyToDsl(block: UpdateDSL.() -> Unit) = - this@KotlinUpdateBuilder.also { - it.dsl.apply(block) + this@KotlinUpdateBuilder.apply { + dsl.apply(block) } } } From a1cb48c7d774ff0e1d5f6777c3a306c69f371521 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Fri, 20 Nov 2020 10:32:03 -0500 Subject: [PATCH 11/12] Documentation --- CHANGELOG.md | 13 +- .../kotlin/KotlinModelBuilderFunctions.kt | 2 +- src/site/markdown/docs/subQueries.md | 273 +++++++++++------- 3 files changed, 183 insertions(+), 105 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e622653f..1dfa0befb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,10 +6,19 @@ This log will detail notable changes to MyBatis Dynamic SQL. Full details are av GitHub milestone: [https://github.com/mybatis/mybatis-dynamic-sql/issues?q=milestone%3A1.3.0+](https://github.com/mybatis/mybatis-dynamic-sql/issues?q=milestone%3A1.3.0+) +### Release Themes + +The major themes of this release include the following: + +1. Add support for subqueries in select statements - both in a from clause and a join clause +1. Continue to refine the Kotlin DSL. Most changes to the Kotlin DSL are internal and should be source code + compatible with existing code. There is one breaking change detailed below. +1. Remove deprecated code from prior releases + ### Breaking Change for Kotlin In this release the Kotlin support for `select` and `count` statements has been refactored. This will not impact code -created by MyBatis generator. It will have an impact on Spring users as well as MyBatis users that coded joins or +created by MyBatis generator. It will have an impact on Spring/Kotlin users as well as MyBatis users that coded joins or other queries directly in Kotlin. The difference is that the `from` clause has been moved inside the lambda for select and count statements. @@ -37,6 +46,8 @@ Kotlin DSL. - Added the capability to generate a camel cased alias for a column ([#272](https://github.com/mybatis/mybatis-dynamic-sql/issues/272)) - Added sub-query support for "from" clauses in a select statement ([#282](https://github.com/mybatis/mybatis-dynamic-sql/pull/282)) - Added Kotlin DSL updates to support sub-queries in select statements, where clauses, and insert statements ([#282](https://github.com/mybatis/mybatis-dynamic-sql/pull/282)) +- Added sub-query support for "join" clauses in a select statement + ## Release 1.2.1 - September 29, 2020 diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinModelBuilderFunctions.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinModelBuilderFunctions.kt index 636d024d1..fb5de806d 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinModelBuilderFunctions.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinModelBuilderFunctions.kt @@ -56,7 +56,7 @@ object KotlinModelBuilderFunctions { } fun BatchInsertDSL.IntoGatherer.into(table: SqlTable, completer: BatchInsertCompleter) = - into(table).also(completer).build() + into(table).apply(completer).build() fun InsertDSL.IntoGatherer.into(table: SqlTable, completer: InsertCompleter) = into(table).apply(completer).build() diff --git a/src/site/markdown/docs/subQueries.md b/src/site/markdown/docs/subQueries.md index 16ab0019c..cd8398d35 100644 --- a/src/site/markdown/docs/subQueries.md +++ b/src/site/markdown/docs/subQueries.md @@ -5,6 +5,113 @@ The library currently supports subqueries in the following areas: 1. In certain insert statements 1. In update statements 1. In the "from" clause of a select statement +1. In join clauses of a select statement + +Before we show examples of subqueries, it is important to understand how the library generates and applies +table qualifiers in select statements. We'll cover that first. + +## Table Qualifiers in Select Statements + +The library attempts to automatically calculate table qualifiers. If a table qualifier is specified, +the library will automatically render the table qualifier on all columns associated with the +table. For example with the following query: + +```java +SelectStatementProvider selectStatement = + select(id, animalName) + .from(animalData, "ad") + .build() + .render(RenderingStrategies.MYBATIS3); +``` + +The library will render SQL as: + +```sql +select ad.id, ad.animal_name +from AnimalData ad +``` + +Notice that the table qualifier `ad` is automatically applied to columns in the select list. + +In the case of join queries the table qualifier specified, or if not specified the table name +itself, will be used as the table qualifier. However, this function is disabled for joins on subqueries. + +With subqueries, it is important to understand the limits of automatic table qualifiers. The rules are +as follows: + +1. The scope of automatic table qualifiers is limited to a single select statement. For subqueries, the outer + query has a different scope than the subquery. +1. A qualifier can be applied to a subquery, but that qualifier is not automatically applied to + any column + +As an example, consider the following query: + +```java +DerivedColumn rowNum = DerivedColumn.of("rownum()"); + +SelectStatementProvider selectStatement = + select(animalName, rowNum) + .from( + select(id, animalName) + .from(animalData, "a") + .where(id, isLessThan(22)) + .orderBy(animalName.descending()), + "b" + ) + .where(rowNum, isLessThan(5)) + .and(animalName, isLike("%a%")) + .build() + .render(RenderingStrategies.MYBATIS3); +``` + +The rendered SQL will be as follows: + +```sql +select animal_name, rownum() +from (select a.id, a.animal_name + from AnimalDate a + where id < #{parameters.p1} + order by animal_name desc) b +where rownum() < #{parameters.p2} + and animal_name like #{parameters.p3} +``` + +Notice that the qualifier `a` is automatically applied to columns in the subquery and that the +qualifier `b` is not applied anywhere. + +If your query requires the subquery qualifier to be applied to columns in the outer select list, +you can manually apply the qualifier to columns as follows: + +```java +DerivedColumn rowNum = DerivedColumn.of("rownum()"); + +SelectStatementProvider selectStatement = + select(animalName.qualifiedWith("b"), rowNum) + .from( + select(id, animalName) + .from(animalData, "a") + .where(id, isLessThan(22)) + .orderBy(animalName.descending()), + "b" + ) + .where(rowNum, isLessThan(5)) + .and(animalName.qualifiedWith("b"), isLike("%a%")) + .build() + .render(RenderingStrategies.MYBATIS3); +``` + +In this case, we have manually applied the qualifier `b` to columns in the outer query. The +rendered SQL looks like this: + +```sql +select b.animal_name, rownum() +from (select a.id, a.animal_name + from AnimalDate a + where id < #{parameters.p1} + order by animal_name desc) b +where rownum() < #{parameters.p2} + and b.animal_name like #{parameters.p3} +``` ## Subqueries in Where Conditions The library support subqueries in the following where conditions: @@ -136,109 +243,6 @@ SelectStatementProvider selectStatement = Notice the use of a `DerivedColumn` to easily specify a function like `rownum()` that can be used both in the select list and in a where condition. -### Table Qualifiers with Subqueries - -The library attempts to automatically calculate table qualifiers. If a table qualifier is specified, -the library will automatically render the table qualifier on all columns associated with the -table. For example with the following query: - -```java -SelectStatementProvider selectStatement = - select(id, animalName) - .from(animalData, "ad") - .build() - .render(RenderingStrategies.MYBATIS3); -``` - -The library will render SQL as: - -```sql -select ad.id, ad.animal_name -from AnimalData ad -``` - -Notice that the table qualifier `ad` is automatically applied to columns in the select list. - -In the case of join queries the table qualifier specified, or if not specified the table name -itself, will be used as the table qualifier. - -With subqueries, it is important to understand the limits of automatic table qualifiers. The rules are -as follows: - -1. The scope of automatic table qualifiers is limited to a single select statement. For subqueries, the outer - query has a different scope than the subquery. -1. A qualifier can be applied to a subquery as a whole, but that qualifier is not automatically applied to - any column - -As an example, consider the following query: - -```java -DerivedColumn rowNum = DerivedColumn.of("rownum()"); - -SelectStatementProvider selectStatement = - select(animalName, rowNum) - .from( - select(id, animalName) - .from(animalData, "a") - .where(id, isLessThan(22)) - .orderBy(animalName.descending()), - "b" - ) - .where(rowNum, isLessThan(5)) - .and(animalName, isLike("%a%")) - .build() - .render(RenderingStrategies.MYBATIS3); -``` - -The rendered SQL will be as follows: - -```sql -select animal_name, rownum() -from (select a.id, a.animal_name - from AnimalDate a - where id < #{parameters.p1} - order by animal_name desc) b -where rownum() < #{parameters.p2} - and animal_name like #{parameters.p3} -``` - -Notice that the qualifier `a` is automatically applied to columns in the subquery and that the -qualifier `b` is not applied anywhere. - -If your query requires the subquery qualifier to be applied to columns in the outer select list, -you can manually apply the qualifier to columns as follows: - -```java -DerivedColumn rowNum = DerivedColumn.of("rownum()"); - -SelectStatementProvider selectStatement = - select(animalName.qualifiedWith("b"), rowNum) - .from( - select(id, animalName) - .from(animalData, "a") - .where(id, isLessThan(22)) - .orderBy(animalName.descending()), - "b" - ) - .where(rowNum, isLessThan(5)) - .and(animalName.qualifiedWith("b"), isLike("%a%")) - .build() - .render(RenderingStrategies.MYBATIS3); -``` - -In this case, we have manually applied the qualifier `b` to columns in the outer query. The -rendered SQL looks like this: - -```sql -select b.animal_name, rownum() -from (select a.id, a.animal_name - from AnimalDate a - where id < #{parameters.p1} - order by animal_name desc) b -where rownum() < #{parameters.p2} - and b.animal_name like #{parameters.p3} -``` - ### Kotlin Support The library includes a Kotlin builder for subqueries that integrates with the select DSL. You @@ -280,3 +284,66 @@ val selectStatement = In this case the `a` qualifier is used in the context of the inner select statement and the `b` qualifier is applied to the subquery as a whole. + +## Subqueries in Join Clauses +The library supports subqueries in "join" clauses similarly to subqueries in "from" clauses. For example: + +```java +SelectStatementProvider selectStatement = select(orderMaster.orderId, orderMaster.orderDate, + orderDetail.lineNumber, orderDetail.description, orderDetail.quantity) + .from(orderMaster, "om") + .join( + select(orderDetail.orderId, orderDetail.lineNumber, orderDetail.description, orderDetail.quantity) + .from(orderDetail), + "od") + .on(orderMaster.orderId, equalTo(orderDetail.orderId.qualifiedWith("od"))) + .build() + .render(RenderingStrategies.MYBATIS3); +``` + +This is rendered as: + +```sql +select om.order_id, om.order_date, line_number, description, quantity +from OrderMaster om +join (select order_id, line_number, description, quantity from OrderDetail) od +on om.order_id = od.order_id +``` + +Notice that the subquery is aliased with "od", but that alias is not automatically applied so it must +be specified when required. If in doubt, specify the alias with the `qualifiedBy` method. + +### Kotlin Support +The Kotlin select build supports subqueries in joins as follows: + +```kotlin +val selectStatement = select(OrderLine.orderId, OrderLine.quantity, + ItemMaster.itemId.qualifiedWith("im"), ItemMaster.description) { + from(OrderMaster, "om") + join(OrderLine, "ol") { + on(OrderMaster.orderId, equalTo(OrderLine.orderId)) + } + leftJoin({ + select(ItemMaster.allColumns()) { + from(ItemMaster) + } + + "im" + }) { + on(OrderLine.itemId, equalTo(ItemMaster.itemId.qualifiedWith("im"))) + } + orderBy(OrderLine.orderId, ItemMaster.itemId) +} +``` + +This is rendered as: + +```sql +select ol.order_id, ol.quantity, im.item_id, description +from OrderMaster om join OrderLine ol on om.order_id = ol.order_id +left join (select * from ItemMaster) im on ol.item_id = im.item_id +order by order_id, item_id +``` + +Notice again that subquery qualifiers must be specified when needed. Also note that the Kotlin join methods accept +two lambda functions - one for the subquery and one for the join specification. Only the join specification can +be outside the parenthesis of the join methods. From a86e399d8d903b57389b25c56f8bbebb8599f165 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Fri, 20 Nov 2020 10:53:27 -0500 Subject: [PATCH 12/12] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1dfa0befb..0d2df732a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,7 +46,7 @@ Kotlin DSL. - Added the capability to generate a camel cased alias for a column ([#272](https://github.com/mybatis/mybatis-dynamic-sql/issues/272)) - Added sub-query support for "from" clauses in a select statement ([#282](https://github.com/mybatis/mybatis-dynamic-sql/pull/282)) - Added Kotlin DSL updates to support sub-queries in select statements, where clauses, and insert statements ([#282](https://github.com/mybatis/mybatis-dynamic-sql/pull/282)) -- Added sub-query support for "join" clauses in a select statement +- Added sub-query support for "join" clauses in a select statement ([#293](https://github.com/mybatis/mybatis-dynamic-sql/pull/293)) ## Release 1.2.1 - September 29, 2020