From c7eaf1dfcda8c3520958c3becbb2cdd930669032 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Tue, 30 Apr 2024 16:33:33 -0400 Subject: [PATCH 001/289] Update Build for Java 11 --- pom.xml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index c5b04639a..c59ca2ac4 100644 --- a/pom.xml +++ b/pom.xml @@ -57,7 +57,7 @@ 17 - 8 + 11 5.10.2 5.1.1 @@ -68,7 +68,8 @@ org.mybatis.dynamic.sql 1.9.23 - 1.8 + 11 + 1.6 pom.xml,src/main/java,src/main/kotlin src/test/java,src/test/kotlin @@ -84,7 +85,7 @@ org.jetbrains.kotlin - kotlin-stdlib-jdk8 + kotlin-stdlib ${kotlin.version} provided true From eaf951c6e6f7a4f8d9006d2d8d72678520c07c09 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Tue, 30 Apr 2024 16:40:49 -0400 Subject: [PATCH 002/289] Better Use of Optional --- .../dynamic/sql/insert/render/GeneralInsertRenderer.java | 3 +-- .../org/mybatis/dynamic/sql/insert/render/InsertRenderer.java | 3 +-- .../org/mybatis/dynamic/sql/update/render/UpdateRenderer.java | 3 +-- .../mybatis/dynamic/sql/where/render/CriterionRenderer.java | 3 +-- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/render/GeneralInsertRenderer.java b/src/main/java/org/mybatis/dynamic/sql/insert/render/GeneralInsertRenderer.java index afc1d4b98..c5378b493 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/render/GeneralInsertRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/render/GeneralInsertRenderer.java @@ -40,8 +40,7 @@ private GeneralInsertRenderer(Builder builder) { public GeneralInsertStatementProvider render() { FieldAndValueCollector collector = model.columnMappings() .map(m -> m.accept(visitor)) - .filter(Optional::isPresent) - .map(Optional::get) + .flatMap(Optional::stream) .collect(FieldAndValueCollector.collect()); Validator.assertFalse(collector.isEmpty(), "ERROR.9"); //$NON-NLS-1$ diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/render/InsertRenderer.java b/src/main/java/org/mybatis/dynamic/sql/insert/render/InsertRenderer.java index 431b3df8f..443695c50 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/render/InsertRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/render/InsertRenderer.java @@ -35,8 +35,7 @@ private InsertRenderer(Builder builder) { public InsertStatementProvider render() { FieldAndValueCollector collector = model.columnMappings() .map(m -> m.accept(visitor)) - .filter(Optional::isPresent) - .map(Optional::get) + .flatMap(Optional::stream) .collect(FieldAndValueCollector.collect()); Validator.assertFalse(collector.isEmpty(), "ERROR.10"); //$NON-NLS-1$ diff --git a/src/main/java/org/mybatis/dynamic/sql/update/render/UpdateRenderer.java b/src/main/java/org/mybatis/dynamic/sql/update/render/UpdateRenderer.java index 50397ee7f..c25a29ff9 100644 --- a/src/main/java/org/mybatis/dynamic/sql/update/render/UpdateRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/update/render/UpdateRenderer.java @@ -85,8 +85,7 @@ private FragmentAndParameters calculateSetPhrase() { "ERROR.18"); //$NON-NLS-1$ FragmentCollector fragmentCollector = fragmentsAndParameters.stream() - .filter(Optional::isPresent) - .map(Optional::get) + .flatMap(Optional::stream) .collect(FragmentCollector.collect()); return toSetPhrase(fragmentCollector); diff --git a/src/main/java/org/mybatis/dynamic/sql/where/render/CriterionRenderer.java b/src/main/java/org/mybatis/dynamic/sql/where/render/CriterionRenderer.java index 6e3e13254..232b68c11 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/render/CriterionRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/render/CriterionRenderer.java @@ -135,8 +135,7 @@ private FragmentAndParameters renderExists(ExistsCriterion criterion) { private List renderSubCriteria(List subCriteria) { return subCriteria.stream().map(this::renderAndOrCriteriaGroup) - .filter(Optional::isPresent) - .map(Optional::get) + .flatMap(Optional::stream) .collect(Collectors.toList()); } From cb05e7cc127e07156076e5014a7bd366da5b6189 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Tue, 30 Apr 2024 17:05:50 -0400 Subject: [PATCH 003/289] Use List builder when possible --- .../examples/emptywhere/EmptyWhereTest.java | 7 +-- .../examples/simple/MyBatisMapToRowTest.java | 10 +-- .../examples/simple/PersonMapperTest.java | 3 +- .../examples/spring/SpringMapToRowTest.java | 10 +-- .../issues/gh430/NoInitialConditionTest.java | 63 +++++++++---------- .../mybatis/dynamic/sql/InvalidSQLTest.java | 6 +- .../dynamic/sql/insert/MapToRowTest.java | 53 ++++++---------- .../sql/select/SelectStatementTest.java | 4 +- 8 files changed, 60 insertions(+), 96 deletions(-) diff --git a/src/test/java/examples/emptywhere/EmptyWhereTest.java b/src/test/java/examples/emptywhere/EmptyWhereTest.java index 3f6d4a86e..8b3fdc546 100644 --- a/src/test/java/examples/emptywhere/EmptyWhereTest.java +++ b/src/test/java/examples/emptywhere/EmptyWhereTest.java @@ -56,12 +56,7 @@ static List baseVariations() { Variation v4 = new Variation(null, null, ""); - List answer = new ArrayList<>(); - answer.add(v1); - answer.add(v2); - answer.add(v3); - answer.add(v4); - return answer; + return List.of(v1, v2, v3, v4); } static Stream whereVariations() { diff --git a/src/test/java/examples/simple/MyBatisMapToRowTest.java b/src/test/java/examples/simple/MyBatisMapToRowTest.java index f17bca807..2b6f714b2 100644 --- a/src/test/java/examples/simple/MyBatisMapToRowTest.java +++ b/src/test/java/examples/simple/MyBatisMapToRowTest.java @@ -109,10 +109,7 @@ void testInsertMultiple() { try (SqlSession session = sqlSessionFactory.openSession()) { CompoundKeyMapper mapper = session.getMapper(CompoundKeyMapper.class); - List integers = new ArrayList<>(); - integers.add(1); - integers.add(2); - integers.add(3); + List integers = List.of(1, 2, 3); MultiRowInsertStatementProvider insertStatement = insertMultiple(integers) .into(compoundKey) @@ -142,10 +139,7 @@ void testInsertBatch() { try (SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH)) { CompoundKeyMapper mapper = session.getMapper(CompoundKeyMapper.class); - List integers = new ArrayList<>(); - integers.add(1); - integers.add(2); - integers.add(3); + List integers = List.of(1, 2, 3); BatchInsert insertStatement = insertBatch(integers) .into(compoundKey) diff --git a/src/test/java/examples/simple/PersonMapperTest.java b/src/test/java/examples/simple/PersonMapperTest.java index 3a8ee5b85..89f3a90f1 100644 --- a/src/test/java/examples/simple/PersonMapperTest.java +++ b/src/test/java/examples/simple/PersonMapperTest.java @@ -253,8 +253,7 @@ void testFirstNameIn() { @Test void testOrderByCollection() { - Collection orderByColumns = new ArrayList<>(); - orderByColumns.add(firstName); + Collection orderByColumns = List.of(firstName); try (SqlSession session = sqlSessionFactory.openSession()) { PersonMapper mapper = session.getMapper(PersonMapper.class); diff --git a/src/test/java/examples/spring/SpringMapToRowTest.java b/src/test/java/examples/spring/SpringMapToRowTest.java index 91271b39f..c3b1077c9 100644 --- a/src/test/java/examples/spring/SpringMapToRowTest.java +++ b/src/test/java/examples/spring/SpringMapToRowTest.java @@ -74,10 +74,7 @@ void testInsertOne() { @Test void testInsertMultiple() { - List integers = new ArrayList<>(); - integers.add(1); - integers.add(2); - integers.add(3); + List integers = List.of(1, 2, 3); MultiRowInsertStatementProvider insertStatement = insertMultiple(integers) .into(compoundKey) @@ -102,10 +99,7 @@ void testInsertMultiple() { @Test void testInsertBatch() { - List integers = new ArrayList<>(); - integers.add(1); - integers.add(2); - integers.add(3); + List integers = List.of(1, 2, 3); BatchInsert insertStatement = insertBatch(integers) .into(compoundKey) diff --git a/src/test/java/issues/gh430/NoInitialConditionTest.java b/src/test/java/issues/gh430/NoInitialConditionTest.java index b9104d43e..22f5c954c 100644 --- a/src/test/java/issues/gh430/NoInitialConditionTest.java +++ b/src/test/java/issues/gh430/NoInitialConditionTest.java @@ -19,7 +19,7 @@ import static org.mybatis.dynamic.sql.SqlBuilder.*; import static org.mybatis.dynamic.sql.subselect.FooDynamicSqlSupport.*; -import java.util.ArrayList; +import java.util.Collections; import java.util.Date; import java.util.List; @@ -32,7 +32,7 @@ class NoInitialConditionTest { @Test void testNoInitialConditionEmptyList() { - List criteria = new ArrayList<>(); + List criteria = Collections.emptyList(); SelectStatementProvider selectStatement = buildSelectStatement(criteria); @@ -43,8 +43,7 @@ void testNoInitialConditionEmptyList() { @Test void testNoInitialConditionSingleSub() { - List criteria = new ArrayList<>(); - criteria.add(or(column2, isEqualTo(3))); + List criteria = List.of(or(column2, isEqualTo(3))); SelectStatementProvider selectStatement = buildSelectStatement(criteria); @@ -56,10 +55,10 @@ void testNoInitialConditionSingleSub() { @Test void testNoInitialConditionMultipleSubs() { - List criteria = new ArrayList<>(); - criteria.add(or(column2, isEqualTo(3))); - criteria.add(or(column2, isEqualTo(4))); - criteria.add(or(column2, isEqualTo(5))); + List criteria = List.of( + or(column2, isEqualTo(3)), + or(column2, isEqualTo(4)), + or(column2, isEqualTo(5))); SelectStatementProvider selectStatement = buildSelectStatement(criteria); @@ -71,10 +70,10 @@ void testNoInitialConditionMultipleSubs() { @Test void testNoInitialConditionWhereMultipleSubs() { - List criteria = new ArrayList<>(); - criteria.add(or(column2, isEqualTo(3))); - criteria.add(or(column2, isEqualTo(4))); - criteria.add(or(column2, isEqualTo(5))); + List criteria = List.of( + or(column2, isEqualTo(3)), + or(column2, isEqualTo(4)), + or(column2, isEqualTo(5))); SelectStatementProvider selectStatement = select(column1, column2) .from(foo) @@ -90,10 +89,10 @@ void testNoInitialConditionWhereMultipleSubs() { @Test void testNoInitialConditionWhereNotMultipleSubs() { - List criteria = new ArrayList<>(); - criteria.add(or(column2, isEqualTo(3))); - criteria.add(or(column2, isEqualTo(4))); - criteria.add(or(column2, isEqualTo(5))); + List criteria = List.of( + or(column2, isEqualTo(3)), + or(column2, isEqualTo(4)), + or(column2, isEqualTo(5))); SelectStatementProvider selectStatement = select(column1, column2) .from(foo) @@ -110,10 +109,10 @@ void testNoInitialConditionWhereNotMultipleSubs() { @Test void testNoInitialConditionWhereGroupMultipleSubs() { - List criteria = new ArrayList<>(); - criteria.add(or(column2, isEqualTo(3))); - criteria.add(or(column2, isEqualTo(4))); - criteria.add(or(column2, isEqualTo(5))); + List criteria = List.of( + or(column2, isEqualTo(3)), + or(column2, isEqualTo(4)), + or(column2, isEqualTo(5))); SelectStatementProvider selectStatement = select(column1, column2) .from(foo) @@ -130,10 +129,10 @@ void testNoInitialConditionWhereGroupMultipleSubs() { @Test void testNoInitialConditionWhereCCAndMultipleSubs() { - List criteria = new ArrayList<>(); - criteria.add(or(column2, isEqualTo(3))); - criteria.add(or(column2, isEqualTo(4))); - criteria.add(or(column2, isEqualTo(5))); + List criteria = List.of( + or(column2, isEqualTo(3)), + or(column2, isEqualTo(4)), + or(column2, isEqualTo(5))); SelectStatementProvider selectStatement = select(column1, column2) .from(foo) @@ -149,10 +148,10 @@ void testNoInitialConditionWhereCCAndMultipleSubs() { @Test void testNoInitialConditionWhereCCOrMultipleSubs() { - List criteria = new ArrayList<>(); - criteria.add(or(column2, isEqualTo(3))); - criteria.add(or(column2, isEqualTo(4))); - criteria.add(or(column2, isEqualTo(5))); + List criteria = List.of( + or(column2, isEqualTo(3)), + or(column2, isEqualTo(4)), + or(column2, isEqualTo(5))); SelectStatementProvider selectStatement = select(column1, column2) .from(foo) @@ -168,10 +167,10 @@ void testNoInitialConditionWhereCCOrMultipleSubs() { @Test void testNoInitialConditionWhereOrMultipleSubs() { - List criteria = new ArrayList<>(); - criteria.add(or(column2, isEqualTo(3))); - criteria.add(or(column2, isEqualTo(4))); - criteria.add(or(column2, isEqualTo(5))); + List criteria = List.of( + or(column2, isEqualTo(3)), + or(column2, isEqualTo(4)), + or(column2, isEqualTo(5))); SelectStatementProvider selectStatement = select(column1, column2) .from(foo) diff --git a/src/test/java/org/mybatis/dynamic/sql/InvalidSQLTest.java b/src/test/java/org/mybatis/dynamic/sql/InvalidSQLTest.java index acaff0b4f..bd8df6c7a 100644 --- a/src/test/java/org/mybatis/dynamic/sql/InvalidSQLTest.java +++ b/src/test/java/org/mybatis/dynamic/sql/InvalidSQLTest.java @@ -115,8 +115,7 @@ void testInvalidMultipleInsertStatementNoRecords() { @Test void testInvalidMultipleInsertStatementNoMappings() { - List records = new ArrayList<>(); - records.add(new TestRow()); + List records = List.of(new TestRow()); MultiRowInsertModel.Builder builder = new MultiRowInsertModel.Builder() .withRecords(records) @@ -137,8 +136,7 @@ void testInvalidBatchInsertStatementNoRecords() { @Test void testInvalidBatchInsertStatementNoMappings() { - List records = new ArrayList<>(); - records.add(new TestRow()); + List records = List.of(new TestRow()); BatchInsertModel.Builder builder = new BatchInsertModel.Builder() .withRecords(records) diff --git a/src/test/java/org/mybatis/dynamic/sql/insert/MapToRowTest.java b/src/test/java/org/mybatis/dynamic/sql/insert/MapToRowTest.java index cd4871f14..fc8c17ad5 100644 --- a/src/test/java/org/mybatis/dynamic/sql/insert/MapToRowTest.java +++ b/src/test/java/org/mybatis/dynamic/sql/insert/MapToRowTest.java @@ -20,7 +20,6 @@ import static org.mybatis.dynamic.sql.SqlBuilder.insertMultiple; import java.sql.JDBCType; -import java.util.ArrayList; import java.util.List; import org.junit.jupiter.api.Test; @@ -37,10 +36,10 @@ class MapToRowTest { @Test void testBasicInsertMultipleWithMyBatis() { - List records = new ArrayList<>(); - records.add(new Record(33, 1)); - records.add(new Record(33, 2)); - records.add(new Record(33, 3)); + List records = List.of( + new Record(33, 1), + new Record(33, 2), + new Record(33, 3)); MultiRowInsertStatementProvider insertStatement = insertMultiple(records) .into(foo) @@ -55,10 +54,10 @@ void testBasicInsertMultipleWithMyBatis() { @Test void testBasicInsertMultipleWithSpring() { - List records = new ArrayList<>(); - records.add(new Record(33, 1)); - records.add(new Record(33, 2)); - records.add(new Record(33, 3)); + List records = List.of( + new Record(33, 1), + new Record(33, 2), + new Record(33, 3)); MultiRowInsertStatementProvider insertStatement = insertMultiple(records) .into(foo) @@ -73,10 +72,7 @@ void testBasicInsertMultipleWithSpring() { @Test void testBasicInsertMultipleRowMappingWithMyBatis() { - List integers = new ArrayList<>(); - integers.add(1); - integers.add(2); - integers.add(3); + List integers = List.of(1, 2, 3); MultiRowInsertStatementProvider insertStatement = insertMultiple(integers) .into(foo) @@ -91,10 +87,7 @@ void testBasicInsertMultipleRowMappingWithMyBatis() { @Test void testBasicInsertMultipleRowMappingWithSpring() { - List integers = new ArrayList<>(); - integers.add(1); - integers.add(2); - integers.add(3); + List integers = List.of(1, 2, 3); MultiRowInsertStatementProvider insertStatement = insertMultiple(integers) .into(foo) @@ -109,10 +102,10 @@ void testBasicInsertMultipleRowMappingWithSpring() { @Test void testBatchInsertWithMyBatis() { - List records = new ArrayList<>(); - records.add(new Record(33, 1)); - records.add(new Record(33, 2)); - records.add(new Record(33, 3)); + List records = List.of( + new Record(33, 1), + new Record(33, 2), + new Record(33, 3)); BatchInsert batchInsert = insertBatch(records) .into(foo) @@ -127,10 +120,10 @@ void testBatchInsertWithMyBatis() { @Test void testBatchInsertWithSpring() { - List records = new ArrayList<>(); - records.add(new Record(33, 1)); - records.add(new Record(33, 2)); - records.add(new Record(33, 3)); + List records = List.of( + new Record(33, 1), + new Record(33, 2), + new Record(33, 3)); BatchInsert batchInsert = insertBatch(records) .into(foo) @@ -145,10 +138,7 @@ void testBatchInsertWithSpring() { @Test void testBatchInsertRowMappingWithMyBatis() { - List integers = new ArrayList<>(); - integers.add(1); - integers.add(2); - integers.add(3); + List integers = List.of(1, 2, 3); BatchInsert batchInsert = insertBatch(integers) .into(foo) @@ -163,10 +153,7 @@ void testBatchInsertRowMappingWithMyBatis() { @Test void testBatchInsertRowMappingWithSpring() { - List integers = new ArrayList<>(); - integers.add(1); - integers.add(2); - integers.add(3); + List integers = List.of(1, 2, 3); BatchInsert batchInsert = insertBatch(integers) .into(foo) diff --git a/src/test/java/org/mybatis/dynamic/sql/select/SelectStatementTest.java b/src/test/java/org/mybatis/dynamic/sql/select/SelectStatementTest.java index 9fd066a42..a243fec17 100644 --- a/src/test/java/org/mybatis/dynamic/sql/select/SelectStatementTest.java +++ b/src/test/java/org/mybatis/dynamic/sql/select/SelectStatementTest.java @@ -180,9 +180,7 @@ void testOrderByMultipleColumns() { @Test void testOrderByMultipleColumnsWithCollection() { - Collection orderByColumns = new ArrayList<>(); - orderByColumns.add(column2.descending()); - orderByColumns.add(column1); + Collection orderByColumns = List.of(column2.descending(), column1); SelectStatementProvider selectStatement = select(column1.as("A_COLUMN1"), column2) .from(table, "a") From c3ec1241a48f354f52a55a17559f1ab38881f6e0 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Wed, 1 May 2024 10:43:39 -0400 Subject: [PATCH 004/289] Restore new version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ce548f554..c59ca2ac4 100644 --- a/pom.xml +++ b/pom.xml @@ -26,7 +26,7 @@ org.mybatis.dynamic-sql mybatis-dynamic-sql - 1.5.2-SNAPSHOT + 1.6.0-SNAPSHOT MyBatis Dynamic SQL MyBatis framework for generating dynamic SQL From 3fb12f7a4523e734f0e823f027f215c915ceb74f Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 3 Jun 2024 17:15:35 -0400 Subject: [PATCH 005/289] [maven-release-plugin] prepare for next development iteration --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 284c3ff83..8dc86be10 100644 --- a/pom.xml +++ b/pom.xml @@ -26,7 +26,7 @@ org.mybatis.dynamic-sql mybatis-dynamic-sql - 1.5.2 + 1.6.0-SNAPSHOT MyBatis Dynamic SQL MyBatis framework for generating dynamic SQL @@ -36,7 +36,7 @@ scm:git:ssh://git@github.com/mybatis/mybatis-dynamic-sql.git scm:git:ssh://git@github.com/mybatis/mybatis-dynamic-sql.git - mybatis-dynamic-sql-1.5.2 + HEAD https://github.com/mybatis/mybatis-dynamic-sql/ @@ -78,7 +78,7 @@ org.mybatis.dynamic.sql.*;version=${project.version};-noimport:=true - 1717449261 + 1717449335 From 2856f6c96218e31ec8dc8968119501a9f4b6e0ca Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 3 Jun 2024 17:35:30 -0400 Subject: [PATCH 006/289] Update Kotlin API Version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1a186bbe3..6effacd82 100644 --- a/pom.xml +++ b/pom.xml @@ -69,7 +69,7 @@ 2.0.0 11 - 1.6 + 1.7 pom.xml,src/main/java,src/main/kotlin src/test/java,src/test/kotlin From a2e024f9ff64f2cb26cb94843cf0d7bdcbeee377 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 3 Jun 2024 17:47:29 -0400 Subject: [PATCH 007/289] Restore changes lost in merge --- pom.xml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pom.xml b/pom.xml index 6effacd82..3205bf22d 100644 --- a/pom.xml +++ b/pom.xml @@ -207,6 +207,15 @@ + + org.jacoco + jacoco-maven-plugin + + + org/jetbrains/kotlin/**/* + + + org.apache.maven.plugins maven-site-plugin From f887c344ff05b3c72ff2ea7ea7a92b93335473a7 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Fri, 7 Jun 2024 10:37:33 -0400 Subject: [PATCH 008/289] Target Java 17 --- pom.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 3205bf22d..b846ad845 100644 --- a/pom.xml +++ b/pom.xml @@ -57,7 +57,7 @@ 17 - 11 + 17 5.10.2 5.1.2 @@ -68,7 +68,6 @@ org.mybatis.dynamic.sql 2.0.0 - 11 1.7 pom.xml,src/main/java,src/main/kotlin From 22e75b123979a0e8e9ab0846c415874d087753c8 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Fri, 7 Jun 2024 10:44:35 -0400 Subject: [PATCH 009/289] Use Predicate.not for readability --- src/site/markdown/docs/conditions.md | 4 ++-- src/test/java/examples/animal/data/MyInCondition.java | 4 +++- .../data/OptionalConditionsWithPredicatesAnimalDataTest.java | 3 ++- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/site/markdown/docs/conditions.md b/src/site/markdown/docs/conditions.md index d5683f206..55a2e6617 100644 --- a/src/site/markdown/docs/conditions.md +++ b/src/site/markdown/docs/conditions.md @@ -267,7 +267,7 @@ any null or blank string, and you want to trim all strings. This can be accompli .where(animalName, isIn(" Mouse", " ", null, "", "Musk shrew ") .filter(Objects::nonNull) .map(String::trim) - .filter(st -> !st.isEmpty())) + .filter(not(String::isEmpty))) .orderBy(id) .build() .render(RenderingStrategies.MYBATIS3); @@ -284,7 +284,7 @@ public class MyInCondition { return SqlBuilder.isIn(values) .filter(Objects::nonNull) .map(String::trim) - .filter(st -> !st.isEmpty()); + .filter(not(String::isEmpty)); } } ``` diff --git a/src/test/java/examples/animal/data/MyInCondition.java b/src/test/java/examples/animal/data/MyInCondition.java index 86035a838..65453997f 100644 --- a/src/test/java/examples/animal/data/MyInCondition.java +++ b/src/test/java/examples/animal/data/MyInCondition.java @@ -15,6 +15,8 @@ */ package examples.animal.data; +import static java.util.function.Predicate.not; + import java.util.Objects; import org.mybatis.dynamic.sql.SqlBuilder; @@ -25,6 +27,6 @@ public static IsIn isIn(String...values) { return SqlBuilder.isIn(values) .filter(Objects::nonNull) .map((String::trim)) - .filter(st -> !st.isEmpty()); + .filter(not(String::isEmpty)); } } diff --git a/src/test/java/examples/animal/data/OptionalConditionsWithPredicatesAnimalDataTest.java b/src/test/java/examples/animal/data/OptionalConditionsWithPredicatesAnimalDataTest.java index 7dd1e131e..cff21a348 100644 --- a/src/test/java/examples/animal/data/OptionalConditionsWithPredicatesAnimalDataTest.java +++ b/src/test/java/examples/animal/data/OptionalConditionsWithPredicatesAnimalDataTest.java @@ -20,6 +20,7 @@ import static examples.animal.data.AnimalDataDynamicSqlSupport.bodyWeight; import static examples.animal.data.AnimalDataDynamicSqlSupport.brainWeight; import static examples.animal.data.AnimalDataDynamicSqlSupport.id; +import static java.util.function.Predicate.not; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertAll; import static org.mybatis.dynamic.sql.SqlBuilder.*; @@ -484,7 +485,7 @@ void testValueStreamTransformer() { .where(animalName, isIn(" Mouse", " ", null, "", "Musk shrew ") .filter(Objects::nonNull) .map(String::trim) - .filter(st -> !st.isEmpty())) + .filter(not(String::isEmpty))) .orderBy(id) .build() .render(RenderingStrategies.MYBATIS3); From 24fef48d28f3935e20099907d525820969234c0e Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Fri, 7 Jun 2024 11:00:39 -0400 Subject: [PATCH 010/289] Remove Deprecated Java code --- .../org/mybatis/dynamic/sql/BasicColumn.java | 23 +-- .../org/mybatis/dynamic/sql/SqlTable.java | 71 -------- .../DefaultInsertStatementProvider.java | 13 -- .../render/InsertStatementProvider.java | 10 -- .../schema_supplier/SchemaSupplier.java | 26 --- .../schema_supplier/SchemaSupplierTest.java | 146 ----------------- .../java/examples/schema_supplier/User.java | 37 ----- .../UserDynamicSqlSupport.java | 36 ----- .../examples/schema_supplier/UserMapper.java | 56 ------- .../mybatis/dynamic/sql/InvalidSQLTest.java | 59 ------- .../org/mybatis/dynamic/sql/SqlTableTest.java | 153 ------------------ .../sql/insert/InsertStatementTest.java | 18 --- 12 files changed, 1 insertion(+), 647 deletions(-) delete mode 100644 src/test/java/examples/schema_supplier/SchemaSupplier.java delete mode 100644 src/test/java/examples/schema_supplier/SchemaSupplierTest.java delete mode 100644 src/test/java/examples/schema_supplier/User.java delete mode 100644 src/test/java/examples/schema_supplier/UserDynamicSqlSupport.java delete mode 100644 src/test/java/examples/schema_supplier/UserMapper.java diff --git a/src/main/java/org/mybatis/dynamic/sql/BasicColumn.java b/src/main/java/org/mybatis/dynamic/sql/BasicColumn.java index aaee827b1..b73757a71 100644 --- a/src/main/java/org/mybatis/dynamic/sql/BasicColumn.java +++ b/src/main/java/org/mybatis/dynamic/sql/BasicColumn.java @@ -17,11 +17,8 @@ import java.util.Optional; -import org.mybatis.dynamic.sql.exception.DynamicSqlException; import org.mybatis.dynamic.sql.render.RenderingContext; -import org.mybatis.dynamic.sql.render.TableAliasCalculator; import org.mybatis.dynamic.sql.util.FragmentAndParameters; -import org.mybatis.dynamic.sql.util.Messages; /** * Describes attributes of columns that are necessary for rendering if the column is not expected to @@ -59,25 +56,7 @@ public interface BasicColumn { * @return a rendered SQL fragment and, optionally, parameters associated with the fragment * @since 1.5.1 */ - default FragmentAndParameters render(RenderingContext renderingContext) { - // the default implementation ensures compatibility with prior releases. When the - // deprecated renderWithTableAlias method is removed, this function can become purely abstract. - // Also remove the method tableAliasCalculator() from RenderingContext. - return FragmentAndParameters.fromFragment(renderWithTableAlias(renderingContext.tableAliasCalculator())); - } - - /** - * Returns the name of the item aliased with a table name if appropriate. - * For example, "a.foo". This is appropriate for where clauses and order by clauses. - * - * @param tableAliasCalculator the table alias calculator for the current renderer - * @return the item name with the table alias applied - * @deprecated Please replace this method by overriding the more general "render" method - */ - @Deprecated - default String renderWithTableAlias(TableAliasCalculator tableAliasCalculator) { - throw new DynamicSqlException(Messages.getString("ERROR.36")); //$NON-NLS-1$ - } + FragmentAndParameters render(RenderingContext renderingContext); /** * Utility method to make it easier to build column lists for methods that require an diff --git a/src/main/java/org/mybatis/dynamic/sql/SqlTable.java b/src/main/java/org/mybatis/dynamic/sql/SqlTable.java index d3b34eff0..1322d958f 100644 --- a/src/main/java/org/mybatis/dynamic/sql/SqlTable.java +++ b/src/main/java/org/mybatis/dynamic/sql/SqlTable.java @@ -32,77 +32,6 @@ protected SqlTable(String tableName) { this.nameSupplier = () -> tableName; } - /** - * Creates an SqlTable whose name can be changed at runtime. - * - * @param tableNameSupplier table name supplier - * @deprecated please use {@link AliasableSqlTable} if you need to change the table name at runtime - */ - @Deprecated - protected SqlTable(Supplier tableNameSupplier) { - Objects.requireNonNull(tableNameSupplier); - - this.nameSupplier = tableNameSupplier; - } - - /** - * Creates an SqlTable whose name can be changed at runtime. - * - * @param schemaSupplier schema supplier - * @param tableName table name - * @deprecated please use {@link AliasableSqlTable} if you need to change the table name at runtime - */ - @Deprecated - protected SqlTable(Supplier> schemaSupplier, String tableName) { - this(Optional::empty, schemaSupplier, tableName); - } - - /** - * Creates an SqlTable whose name can be changed at runtime. - * - * @param catalogSupplier catalog supplier - * @param schemaSupplier schema supplier - * @param tableName table name - * @deprecated please use {@link AliasableSqlTable} if you need to change the table name at runtime - */ - @Deprecated - protected SqlTable(Supplier> catalogSupplier, Supplier> schemaSupplier, - String tableName) { - Objects.requireNonNull(catalogSupplier); - Objects.requireNonNull(schemaSupplier); - Objects.requireNonNull(tableName); - - this.nameSupplier = () -> compose(catalogSupplier, schemaSupplier, tableName); - } - - private String compose(Supplier> catalogSupplier, Supplier> schemaSupplier, - String tableName) { - return catalogSupplier.get().map(c -> compose(c, schemaSupplier, tableName)) - .orElseGet(() -> compose(schemaSupplier, tableName)); - } - - private String compose(String catalog, Supplier> schemaSupplier, String tableName) { - return schemaSupplier.get().map(s -> composeCatalogSchemaAndTable(catalog, s, tableName)) - .orElseGet(() -> composeCatalogAndTable(catalog, tableName)); - } - - private String compose(Supplier> schemaSupplier, String tableName) { - return schemaSupplier.get().map(s -> composeSchemaAndTable(s, tableName)) - .orElse(tableName); - } - - private String composeCatalogAndTable(String catalog, String tableName) { - return catalog + ".." + tableName; //$NON-NLS-1$ - } - - private String composeSchemaAndTable(String schema, String tableName) { - return schema + "." + tableName; //$NON-NLS-1$ - } - - private String composeCatalogSchemaAndTable(String catalog, String schema, String tableName) { - return catalog + "." + schema + "." + tableName; //$NON-NLS-1$ //$NON-NLS-2$ - } - public String tableNameAtRuntime() { return nameSupplier.get(); } diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/render/DefaultInsertStatementProvider.java b/src/main/java/org/mybatis/dynamic/sql/insert/render/DefaultInsertStatementProvider.java index aae15c34e..d75e90e27 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/render/DefaultInsertStatementProvider.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/render/DefaultInsertStatementProvider.java @@ -21,24 +21,11 @@ public class DefaultInsertStatementProvider implements InsertStatementProvider { private final String insertStatement; - // need to keep both row and record for now so we don't break - // old code. The MyBatis reflection utilities don't handle - // the case where the attribute name is different from the getter. - // - // MyBatis Generator version 1.4.1 (March 8, 2022) changed to use "row" instead of "record". - // Target March 2023 for removing "record" from MyBatis Dynamic SQL. - private final T record; private final T row; private DefaultInsertStatementProvider(Builder builder) { insertStatement = Objects.requireNonNull(builder.insertStatement); row = Objects.requireNonNull(builder.row); - record = row; - } - - @Override - public T getRecord() { - return record; } @Override diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/render/InsertStatementProvider.java b/src/main/java/org/mybatis/dynamic/sql/insert/render/InsertStatementProvider.java index 6658320f9..ea0d0db18 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/render/InsertStatementProvider.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/render/InsertStatementProvider.java @@ -18,16 +18,6 @@ import org.jetbrains.annotations.NotNull; public interface InsertStatementProvider { - /** - * Return the row associated with this insert statement. - * - * @return the row associated with this insert statement. - * - * @deprecated in favor of {@link InsertStatementProvider#getRow()} - */ - @Deprecated - T getRecord(); - /** * Return the row associated with this insert statement. * diff --git a/src/test/java/examples/schema_supplier/SchemaSupplier.java b/src/test/java/examples/schema_supplier/SchemaSupplier.java deleted file mode 100644 index b5a3e8fbe..000000000 --- a/src/test/java/examples/schema_supplier/SchemaSupplier.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2016-2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package examples.schema_supplier; - -import java.util.Optional; - -public class SchemaSupplier { - public static final String schema_property = "schemaToUse"; - - public static Optional schemaPropertyReader() { - return Optional.ofNullable(System.getProperty(schema_property)); - } -} diff --git a/src/test/java/examples/schema_supplier/SchemaSupplierTest.java b/src/test/java/examples/schema_supplier/SchemaSupplierTest.java deleted file mode 100644 index 7cc70fc7c..000000000 --- a/src/test/java/examples/schema_supplier/SchemaSupplierTest.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright 2016-2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package examples.schema_supplier; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertThrows; - -import java.io.InputStream; -import java.io.InputStreamReader; -import java.sql.Connection; -import java.sql.DriverManager; -import java.util.List; - -import org.apache.ibatis.datasource.unpooled.UnpooledDataSource; -import org.apache.ibatis.exceptions.PersistenceException; -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.select.SelectDSLCompleter; - -class SchemaSupplierTest { - - 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/schema_supplier/CreateDB.sql"); - assert is != null; - 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(UserMapper.class); - sqlSessionFactory = new SqlSessionFactoryBuilder().build(config); - } - - @Test - void testUnsetSchemaProperty() { - System.clearProperty(SchemaSupplier.schema_property); - - try (SqlSession session = sqlSessionFactory.openSession()) { - UserMapper mapper = session.getMapper(UserMapper.class); - - User user = new User(); - user.setId(1); - user.setName("Fred"); - - assertThrows(PersistenceException.class, () -> mapper.insert(user)); - } - } - - @Test - void testSchemaProperty() { - System.setProperty(SchemaSupplier.schema_property, "schema1"); - - try (SqlSession session = sqlSessionFactory.openSession()) { - UserMapper mapper = session.getMapper(UserMapper.class); - - insertFlintstones(mapper); - - List records = mapper.select(SelectDSLCompleter.allRows()); - assertThat(records).hasSize(2); - } - } - - @Test - void testSchemaSwitchingProperty() { - try (SqlSession session = sqlSessionFactory.openSession()) { - UserMapper mapper = session.getMapper(UserMapper.class); - - System.setProperty(SchemaSupplier.schema_property, "schema1"); - insertFlintstones(mapper); - - List records = mapper.select(SelectDSLCompleter.allRows()); - assertThat(records).hasSize(2); - - System.setProperty(SchemaSupplier.schema_property, "schema2"); - insertRubbles(mapper); - - records = mapper.select(SelectDSLCompleter.allRows()); - assertThat(records).hasSize(3); - } - } - - private void insertFlintstones(UserMapper mapper) { - User user = new User(); - user.setId(1); - user.setName("Fred"); - int rows = mapper.insert(user); - assertThat(rows).isEqualTo(1); - - user = new User(); - user.setId(2); - user.setName("Wilma"); - rows = mapper.insert(user); - assertThat(rows).isEqualTo(1); - } - - private void insertRubbles(UserMapper mapper) { - User user = new User(); - user.setId(1); - user.setName("Barney"); - int rows = mapper.insert(user); - assertThat(rows).isEqualTo(1); - - user = new User(); - user.setId(2); - user.setName("Betty"); - rows = mapper.insert(user); - assertThat(rows).isEqualTo(1); - - user = new User(); - user.setId(3); - user.setName("Bamm Bamm"); - rows = mapper.insert(user); - assertThat(rows).isEqualTo(1); - } -} diff --git a/src/test/java/examples/schema_supplier/User.java b/src/test/java/examples/schema_supplier/User.java deleted file mode 100644 index 02acc9c53..000000000 --- a/src/test/java/examples/schema_supplier/User.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2016-2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package examples.schema_supplier; - -public class User { - private int id; - private String name; - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } -} diff --git a/src/test/java/examples/schema_supplier/UserDynamicSqlSupport.java b/src/test/java/examples/schema_supplier/UserDynamicSqlSupport.java deleted file mode 100644 index fdb38f0ea..000000000 --- a/src/test/java/examples/schema_supplier/UserDynamicSqlSupport.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2016-2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package examples.schema_supplier; - -import java.sql.JDBCType; - -import org.mybatis.dynamic.sql.SqlColumn; -import org.mybatis.dynamic.sql.SqlTable; - -public class UserDynamicSqlSupport { - public static final User user = new User(); - public static final SqlColumn id = user.id; - public static final SqlColumn name = user.name; - - public static final class User extends SqlTable { - public final SqlColumn id = column("user_id", JDBCType.INTEGER); - public final SqlColumn name = column("user_name", JDBCType.VARCHAR); - - public User() { - super(SchemaSupplier::schemaPropertyReader, "User"); - } - } -} diff --git a/src/test/java/examples/schema_supplier/UserMapper.java b/src/test/java/examples/schema_supplier/UserMapper.java deleted file mode 100644 index 602ed49a3..000000000 --- a/src/test/java/examples/schema_supplier/UserMapper.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2016-2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package examples.schema_supplier; - -import static examples.schema_supplier.UserDynamicSqlSupport.*; - -import java.util.List; - -import org.apache.ibatis.annotations.Result; -import org.apache.ibatis.annotations.Results; -import org.apache.ibatis.annotations.SelectProvider; -import org.apache.ibatis.type.JdbcType; -import org.mybatis.dynamic.sql.BasicColumn; -import org.mybatis.dynamic.sql.SqlBuilder; -import org.mybatis.dynamic.sql.render.RenderingStrategies; -import org.mybatis.dynamic.sql.select.SelectDSLCompleter; -import org.mybatis.dynamic.sql.select.render.SelectStatementProvider; -import org.mybatis.dynamic.sql.util.SqlProviderAdapter; -import org.mybatis.dynamic.sql.util.mybatis3.CommonInsertMapper; -import org.mybatis.dynamic.sql.util.mybatis3.MyBatis3Utils; - -public interface UserMapper extends CommonInsertMapper { - - @SelectProvider(type=SqlProviderAdapter.class, method="select") - @Results(id="UserResult", value= { - @Result(column="USER_ID", property="id", jdbcType=JdbcType.INTEGER, id=true), - @Result(column="USER_NAME", property="name", jdbcType=JdbcType.VARCHAR) - }) - List selectMany(SelectStatementProvider selectStatement); - - default List select(SelectDSLCompleter completer) { - return MyBatis3Utils.selectList(this::selectMany, BasicColumn.columnList(id, name), user, completer); - } - - default int insert(User row) { - return insert(SqlBuilder.insert(row) - .into(user) - .map(id).toProperty("id") - .map(name).toProperty("name") - .build() - .render(RenderingStrategies.MYBATIS3)); - } -} diff --git a/src/test/java/org/mybatis/dynamic/sql/InvalidSQLTest.java b/src/test/java/org/mybatis/dynamic/sql/InvalidSQLTest.java index 4c7afc0b0..6665dd48f 100644 --- a/src/test/java/org/mybatis/dynamic/sql/InvalidSQLTest.java +++ b/src/test/java/org/mybatis/dynamic/sql/InvalidSQLTest.java @@ -19,7 +19,6 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.mybatis.dynamic.sql.SqlBuilder.insert; import static org.mybatis.dynamic.sql.SqlBuilder.insertInto; -import static org.mybatis.dynamic.sql.SqlBuilder.select; import static org.mybatis.dynamic.sql.SqlBuilder.update; import static org.mybatis.dynamic.sql.SqlBuilder.value; @@ -32,7 +31,6 @@ import org.junit.jupiter.api.Test; import org.mybatis.dynamic.sql.common.OrderByModel; import org.mybatis.dynamic.sql.configuration.StatementConfiguration; -import org.mybatis.dynamic.sql.exception.DynamicSqlException; import org.mybatis.dynamic.sql.exception.InvalidSqlException; import org.mybatis.dynamic.sql.insert.BatchInsertModel; import org.mybatis.dynamic.sql.insert.GeneralInsertModel; @@ -41,7 +39,6 @@ import org.mybatis.dynamic.sql.insert.MultiRowInsertModel; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.render.RenderingStrategies; -import org.mybatis.dynamic.sql.render.TableAliasCalculator; import org.mybatis.dynamic.sql.select.GroupByModel; import org.mybatis.dynamic.sql.select.PagingModel; import org.mybatis.dynamic.sql.select.QueryExpressionModel; @@ -50,7 +47,6 @@ import org.mybatis.dynamic.sql.select.join.JoinSpecification; import org.mybatis.dynamic.sql.select.join.JoinType; import org.mybatis.dynamic.sql.select.render.FetchFirstPagingModelRenderer; -import org.mybatis.dynamic.sql.select.render.SelectStatementProvider; import org.mybatis.dynamic.sql.update.UpdateModel; import org.mybatis.dynamic.sql.util.InternalError; import org.mybatis.dynamic.sql.util.Messages; @@ -267,23 +263,6 @@ void testInvalidValueAlias() { .withMessage(Messages.getString("ERROR.38")); } - @Test - void testBadColumn() { - SelectModel selectModel = select(new BadCount<>()).from(person).build(); - assertThatExceptionOfType(DynamicSqlException.class) - .isThrownBy(() -> selectModel.render(RenderingStrategies.MYBATIS3)) - .withMessage(Messages.getString("ERROR.36")); - } - - @Test - void testDeprecatedColumn() { - SelectStatementProvider selectStatement = select(new DeprecatedCount<>()) - .from(person) - .build() - .render(RenderingStrategies.MYBATIS3); - assertThat(selectStatement.getSelectStatement()).isEqualTo("select count(*) from person"); - } - static class TestRow { private Integer id; @@ -295,42 +274,4 @@ public void setId(Integer id) { this.id = id; } } - - static class BadCount implements BindableColumn { - private String alias; - - @Override - public Optional alias() { - return Optional.ofNullable(alias); - } - - @Override - public BindableColumn as(String alias) { - BadCount newCount = new BadCount<>(); - newCount.alias = alias; - return newCount; - } - } - - static class DeprecatedCount implements BindableColumn { - private String alias; - - @Override - @Deprecated - public String renderWithTableAlias(TableAliasCalculator tableAliasCalculator) { - return "count(*)"; - } - - @Override - public Optional alias() { - return Optional.ofNullable(alias); - } - - @Override - public BindableColumn as(String alias) { - DeprecatedCount newCount = new DeprecatedCount<>(); - newCount.alias = alias; - return newCount; - } - } } diff --git a/src/test/java/org/mybatis/dynamic/sql/SqlTableTest.java b/src/test/java/org/mybatis/dynamic/sql/SqlTableTest.java index 32d336572..473258dcb 100644 --- a/src/test/java/org/mybatis/dynamic/sql/SqlTableTest.java +++ b/src/test/java/org/mybatis/dynamic/sql/SqlTableTest.java @@ -17,166 +17,13 @@ import static org.assertj.core.api.Assertions.assertThat; -import java.util.Optional; -import java.util.function.Supplier; - import org.junit.jupiter.api.Test; class SqlTableTest { - private static final String NAME_PROPERTY = "nameProperty"; - @Test void testFullName() { SqlTable table = new SqlTable("my_table"); assertThat(table.tableNameAtRuntime()).isEqualTo("my_table"); } - - @Test - void testFullNameSupplier() { - - System.setProperty(NAME_PROPERTY, "my_table"); - SqlTable table = new SqlTable(SqlTableTest::namePropertyReader); - assertThat(table.tableNameAtRuntime()).isEqualTo("my_table"); - System.clearProperty(NAME_PROPERTY); - } - - @Test - void testSchemaSupplierEmpty() { - SqlTable table = new SqlTable(Optional::empty, "my_table"); - assertThat(table.tableNameAtRuntime()).isEqualTo("my_table"); - } - - @Test - void testSchemaSupplierWithValue() { - SqlTable table = new SqlTable(() -> Optional.of("my_schema"), "my_table"); - assertThat(table.tableNameAtRuntime()).isEqualTo("my_schema.my_table"); - } - - @Test - void testSingletonSchemaSupplier() { - SqlTable table = new SqlTable(MySchemaSupplier.instance(), "my_table"); - assertThat(table.tableNameAtRuntime()).isEqualTo("first_schema.my_table"); - } - - @Test - void testThatSchemaSupplierDoesDelay() { - MySchemaSupplier schemaSupplier = new MySchemaSupplier(); - SqlTable table = new SqlTable(schemaSupplier, "my_table"); - assertThat(table.tableNameAtRuntime()).isEqualTo("first_schema.my_table"); - - schemaSupplier.setFirst(false); - assertThat(table.tableNameAtRuntime()).isEqualTo("second_schema.my_table"); - } - - @Test - void testCatalogAndSchemaSupplierEmpty() { - SqlTable table = new SqlTable(Optional::empty, Optional::empty, "my_table"); - assertThat(table.tableNameAtRuntime()).isEqualTo("my_table"); - } - - @Test - void testCatalogSupplierWithValue() { - SqlTable table = new SqlTable(() -> Optional.of("my_catalog"), Optional::empty, "my_table"); - assertThat(table.tableNameAtRuntime()).isEqualTo("my_catalog..my_table"); - } - - @Test - void testThatCatalogSupplierDoesDelay() { - MyCatalogSupplier catalogSupplier = new MyCatalogSupplier(); - SqlTable table = new SqlTable(catalogSupplier, Optional::empty, "my_table"); - assertThat(table.tableNameAtRuntime()).isEqualTo("first_catalog..my_table"); - - catalogSupplier.setFirst(false); - assertThat(table.tableNameAtRuntime()).isEqualTo("second_catalog..my_table"); - } - - @Test - void testThatCatalogSupplierAndSchemaSupplierBothDelay() { - MyCatalogSupplier catalogSupplier = new MyCatalogSupplier(); - MySchemaSupplier schemaSupplier = new MySchemaSupplier(); - SqlTable table = new SqlTable(catalogSupplier, schemaSupplier, "my_table"); - assertThat(table.tableNameAtRuntime()).isEqualTo("first_catalog.first_schema.my_table"); - - catalogSupplier.setFirst(false); - assertThat(table.tableNameAtRuntime()).isEqualTo("second_catalog.first_schema.my_table"); - - catalogSupplier.setFirst(true); - schemaSupplier.setFirst(false); - assertThat(table.tableNameAtRuntime()).isEqualTo("first_catalog.second_schema.my_table"); - - catalogSupplier.setFirst(false); - assertThat(table.tableNameAtRuntime()).isEqualTo("second_catalog.second_schema.my_table"); - - catalogSupplier.setEmpty(true); - assertThat(table.tableNameAtRuntime()).isEqualTo("second_schema.my_table"); - - schemaSupplier.setEmpty(true); - assertThat(table.tableNameAtRuntime()).isEqualTo("my_table"); - - catalogSupplier.setEmpty(false); - assertThat(table.tableNameAtRuntime()).isEqualTo("second_catalog..my_table"); - } - - private static String namePropertyReader() { - return System.getProperty(NAME_PROPERTY); - } - - static class MySchemaSupplier implements Supplier> { - private static final MySchemaSupplier instance = new MySchemaSupplier(); - - static MySchemaSupplier instance() { - return instance; - } - - private boolean first = true; - private boolean empty; - - void setFirst(boolean first) { - this.first = first; - } - - void setEmpty(boolean empty) { - this.empty = empty; - } - - @Override - public Optional get() { - if (empty) { - return Optional.empty(); - } - - if (first) { - return Optional.of("first_schema"); - } else { - return Optional.of("second_schema"); - } - } - } - - static class MyCatalogSupplier implements Supplier> { - private boolean first = true; - private boolean empty; - - void setFirst(boolean first) { - this.first = first; - } - - void setEmpty(boolean empty) { - this.empty = empty; - } - - @Override - public Optional get() { - if (empty) { - return Optional.empty(); - } - - if (first) { - return Optional.of("first_catalog"); - } else { - return Optional.of("second_catalog"); - } - } - } } diff --git a/src/test/java/org/mybatis/dynamic/sql/insert/InsertStatementTest.java b/src/test/java/org/mybatis/dynamic/sql/insert/InsertStatementTest.java index 350532cb2..e0ebe5d19 100644 --- a/src/test/java/org/mybatis/dynamic/sql/insert/InsertStatementTest.java +++ b/src/test/java/org/mybatis/dynamic/sql/insert/InsertStatementTest.java @@ -115,24 +115,6 @@ void testSelectiveInsertStatementBuilder() { assertThat(insertStatement.getInsertStatement()).isEqualTo(expected); } - @Test - void testDeprecatedMethod() { - TestRecord row = new TestRecord(); - row.setLastName("jones"); - row.setOccupation("dino driver"); - - InsertStatementProvider insertStatement = insert(row) - .into(foo) - .map(id).toPropertyWhenPresent("id", row::getId) - .map(firstName).toPropertyWhenPresent("firstName", row::getFirstName) - .map(lastName).toPropertyWhenPresent("lastName", row::getLastName) - .map(occupation).toPropertyWhenPresent("occupation", row::getOccupation) - .build() - .render(RenderingStrategies.MYBATIS3); - - assertThat(insertStatement.getRow()).isEqualTo(insertStatement.getRecord()); - } - static class TestRecord { private Integer id; private String firstName; From 8582ae1194212977c27bef2e15df113023cae3e2 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Fri, 7 Jun 2024 11:23:09 -0400 Subject: [PATCH 011/289] Remove Deprecated Kotlin code --- .../sql/util/kotlin/KotlinBaseBuilders.kt | 34 ---------------- .../mybatis3/canonical/ReusableWhereTest.kt | 40 ------------------- .../kotlin/gh430/KNoInitialConditionsTest.kt | 12 ++++-- 3 files changed, 8 insertions(+), 78 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 2f6bc175b..4207905c6 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 @@ -25,15 +25,6 @@ import org.mybatis.dynamic.sql.where.AbstractWhereStarter @DslMarker annotation class MyBatisDslMarker -@Deprecated("Please use GroupingCriteriaCollector.where") -typealias WhereApplier = KotlinBaseBuilder<*>.() -> Unit - -@Deprecated("Please use GroupingCriteriaCollector.where") -fun WhereApplier.andThen(after: WhereApplier): WhereApplier = { - invoke(this) - after(this) -} - @MyBatisDslMarker @Suppress("TooManyFunctions") abstract class KotlinBaseBuilder> { @@ -51,31 +42,6 @@ abstract class KotlinBaseBuilder> { getDsl().where(criteria) } - @Deprecated("Please move the \"and\" function into the where lambda. If the where lambda has more than one condition, you may need to surround the existing conditions with \"group\" first.") - fun and(criteria: GroupingCriteriaReceiver): Unit = - GroupingCriteriaCollector().apply(criteria).let { - getDsl().where().and(it.initialCriterion, it.subCriteria) - } - - @Deprecated("Please move the \"and\" function into the where lambda. If the where lambda has more than one condition, you may need to surround the existing conditions with \"group\" first.") - fun and(criteria: List) { - getDsl().where().and(criteria) - } - - @Deprecated("Please move the \"or\" function into the where lambda. If the where lambda has more than one condition, you may need to surround the existing conditions with \"group\" first.") - fun or(criteria: GroupingCriteriaReceiver): Unit = - GroupingCriteriaCollector().apply(criteria).let { - getDsl().where().or(it.initialCriterion, it.subCriteria) - } - - @Deprecated("Please move the \"or\" function into the where lambda. If the where lambda has more than one condition, you may need to surround the existing conditions with \"group\" first.") - fun or(criteria: List) { - getDsl().where().or(criteria) - } - - @Deprecated("Please use GroupingCriteriaCollector.where, then pass it to the \"where\" method") - fun applyWhere(whereApplier: WhereApplier) = whereApplier.invoke(this) - /** * This function does nothing, but it can be used to make some code snippets more understandable. * diff --git a/src/test/kotlin/examples/kotlin/mybatis3/canonical/ReusableWhereTest.kt b/src/test/kotlin/examples/kotlin/mybatis3/canonical/ReusableWhereTest.kt index 7feca7e63..db54364e7 100644 --- a/src/test/kotlin/examples/kotlin/mybatis3/canonical/ReusableWhereTest.kt +++ b/src/test/kotlin/examples/kotlin/mybatis3/canonical/ReusableWhereTest.kt @@ -27,7 +27,6 @@ import org.junit.jupiter.api.BeforeAll import org.junit.jupiter.api.Test import org.junit.jupiter.api.TestInstance import org.mybatis.dynamic.sql.util.kotlin.GroupingCriteriaCollector.Companion.where -import org.mybatis.dynamic.sql.util.kotlin.WhereApplier import org.mybatis.dynamic.sql.util.kotlin.andThen import org.mybatis.dynamic.sql.util.kotlin.mybatis3.select @@ -44,19 +43,6 @@ class ReusableWhereTest { } } - @Test - fun testCountWithDeprecatedClause() { - sqlSessionFactory.openSession().use { session -> - val mapper = session.getMapper(PersonMapper::class.java) - - val rows = mapper.count { - applyWhere(commonWhere) - } - - assertThat(rows).isEqualTo(3) - } - } - @Test fun testDelete() { sqlSessionFactory.openSession().use { session -> @@ -98,27 +84,6 @@ class ReusableWhereTest { } } - @Test - fun testDeprecatedComposition() { - val composedWhereClause = commonWhere.andThen { - and { birthDate.isNotNull() } - }.andThen { - or { addressId isLessThan 3 } - } - - val selectStatement = select(person.allColumns()) { - from(person) - applyWhere(composedWhereClause) - } - - assertThat(selectStatement.selectStatement).isEqualTo( - "select * from Person " + - "where id = #{parameters.p1,jdbcType=INTEGER} or occupation is null " + - "and birth_date is not null " + - "or address_id < #{parameters.p2,jdbcType=INTEGER}" - ) - } - @Test fun testComposition() { val composedWhereClause = commonWhereClause.andThen { @@ -140,11 +105,6 @@ class ReusableWhereTest { ) } - private val commonWhere: WhereApplier = { - where { id isEqualTo 1 } - or { occupation.isNull() } - } - private val commonWhereClause = where { id isEqualTo 1 or { occupation.isNull() } diff --git a/src/test/kotlin/issues/kotlin/gh430/KNoInitialConditionsTest.kt b/src/test/kotlin/issues/kotlin/gh430/KNoInitialConditionsTest.kt index 0f78c6d13..b11b4f3aa 100644 --- a/src/test/kotlin/issues/kotlin/gh430/KNoInitialConditionsTest.kt +++ b/src/test/kotlin/issues/kotlin/gh430/KNoInitialConditionsTest.kt @@ -175,8 +175,10 @@ class KNoInitialConditionsTest { val selectStatement = select(column1, column2) { from(foo) - where { column1 isLessThan Date() } - or(criteria) + where { + column1 isLessThan Date() + or(criteria) + } } val expected = "select column1, column2 from foo where column1 < :p1 " + @@ -187,7 +189,9 @@ class KNoInitialConditionsTest { private fun buildSelectStatement(criteria: List) = select(column1, column2) { from(foo) - where { column1 isLessThan Date() } - and(criteria) + where { + column1 isLessThan Date() + and(criteria) + } } } From bc27cfb062dc8296c9e8deac63f6edf8f6b25bf5 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Fri, 7 Jun 2024 11:25:33 -0400 Subject: [PATCH 012/289] Remove Deprecated Kotlin code --- .../examples/kotlin/mybatis3/canonical/PersonMapperTest.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/kotlin/examples/kotlin/mybatis3/canonical/PersonMapperTest.kt b/src/test/kotlin/examples/kotlin/mybatis3/canonical/PersonMapperTest.kt index 8276ebe9c..5dc24ede2 100644 --- a/src/test/kotlin/examples/kotlin/mybatis3/canonical/PersonMapperTest.kt +++ b/src/test/kotlin/examples/kotlin/mybatis3/canonical/PersonMapperTest.kt @@ -242,7 +242,7 @@ class PersonMapperTest { } @Test - fun testInsertSelect() { + fun testInsertSelectExtensionFunction() { sqlSessionFactory.openSession().use { session -> val mapper = session.getMapper(PersonMapper::class.java) @@ -259,7 +259,7 @@ class PersonMapperTest { } @Test - fun testDeprecatedInsertSelect() { + fun testInsertSelect() { sqlSessionFactory.openSession().use { session -> val mapper = session.getMapper(PersonMapper::class.java) From 414f98de650392689f927632b4013fb8698bce61 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Fri, 7 Jun 2024 11:46:36 -0400 Subject: [PATCH 013/289] Remove Unused Method --- .../org/mybatis/dynamic/sql/render/RenderingContext.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/render/RenderingContext.java b/src/main/java/org/mybatis/dynamic/sql/render/RenderingContext.java index a23c8d07a..8a5d1cf5e 100644 --- a/src/main/java/org/mybatis/dynamic/sql/render/RenderingContext.java +++ b/src/main/java/org/mybatis/dynamic/sql/render/RenderingContext.java @@ -53,11 +53,6 @@ private RenderingContext(Builder builder) { : builder.parameterName + "." + RenderingStrategy.DEFAULT_PARAMETER_PREFIX; //$NON-NLS-1$ } - public TableAliasCalculator tableAliasCalculator() { - // this method can be removed when the renderWithTableAlias method is removed from BasicColumn - return tableAliasCalculator; - } - private String nextMapKey() { return renderingStrategy.formatParameterMapKey(sequence); } From 8deb494b48463117ec428237e6a72c8951f1c491 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Fri, 7 Jun 2024 13:54:38 -0400 Subject: [PATCH 014/289] Simplify SqlTable --- .../java/org/mybatis/dynamic/sql/AliasableSqlTable.java | 4 ++-- src/main/java/org/mybatis/dynamic/sql/SqlTable.java | 9 +++------ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/AliasableSqlTable.java b/src/main/java/org/mybatis/dynamic/sql/AliasableSqlTable.java index 4e6c32386..7474b00ba 100644 --- a/src/main/java/org/mybatis/dynamic/sql/AliasableSqlTable.java +++ b/src/main/java/org/mybatis/dynamic/sql/AliasableSqlTable.java @@ -32,7 +32,7 @@ protected AliasableSqlTable(String tableName, Supplier constructor) { public T withAlias(String alias) { T newTable = constructor.get(); ((AliasableSqlTable) newTable).tableAlias = alias; - newTable.nameSupplier = nameSupplier; + newTable.tableName = tableName; return newTable; } @@ -48,7 +48,7 @@ public T withName(String name) { Objects.requireNonNull(name); T newTable = constructor.get(); ((AliasableSqlTable) newTable).tableAlias = tableAlias; - newTable.nameSupplier = () -> name; + newTable.tableName = name; return newTable; } diff --git a/src/main/java/org/mybatis/dynamic/sql/SqlTable.java b/src/main/java/org/mybatis/dynamic/sql/SqlTable.java index 1322d958f..c482458d9 100644 --- a/src/main/java/org/mybatis/dynamic/sql/SqlTable.java +++ b/src/main/java/org/mybatis/dynamic/sql/SqlTable.java @@ -18,22 +18,19 @@ import java.sql.JDBCType; import java.util.Objects; import java.util.Optional; -import java.util.function.Supplier; import org.jetbrains.annotations.NotNull; public class SqlTable implements TableExpression { - protected Supplier nameSupplier; + protected String tableName; protected SqlTable(String tableName) { - Objects.requireNonNull(tableName); - - this.nameSupplier = () -> tableName; + this.tableName = Objects.requireNonNull(tableName); } public String tableNameAtRuntime() { - return nameSupplier.get(); + return tableName; } public BasicColumn allColumns() { From 471ca84f06bbdd9837d11b5f8868d7e96d31415a Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Fri, 7 Jun 2024 13:58:50 -0400 Subject: [PATCH 015/289] Obsolete Message --- .../resources/org/mybatis/dynamic/sql/util/messages.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/org/mybatis/dynamic/sql/util/messages.properties b/src/main/resources/org/mybatis/dynamic/sql/util/messages.properties index 9927dbeec..c25eb02c5 100644 --- a/src/main/resources/org/mybatis/dynamic/sql/util/messages.properties +++ b/src/main/resources/org/mybatis/dynamic/sql/util/messages.properties @@ -52,7 +52,7 @@ ERROR.33=Calling "select" or "selectDistinct" more than once is not allowed. Add union or unionAll expression ERROR.34=You must specify "select" or "selectDistinct" before any other clauses in a multi-select statement ERROR.35=Multi-select statements must have at least one "union" or "union all" expression -ERROR.36=You must either implement the "render" or "renderWithTableAlias" method in a column or function +ERROR.36=Obsolete Message - Not Used ERROR.37=The "{0}" function does not support conditions that fail to render ERROR.38=Bound values cannot be aliased ERROR.39=When clauses in case expressions must render From 2ab30ded4f5b0e4210a40e5d820453a5694e0e15 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 13 Jun 2024 14:10:33 +0000 Subject: [PATCH 016/289] Update dependency org.springframework:spring-jdbc to v6.1.9 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8dc86be10..a37a79ec8 100644 --- a/pom.xml +++ b/pom.xml @@ -92,7 +92,7 @@ org.springframework spring-jdbc - 6.1.8 + 6.1.9 provided true From f6361ec73c0739fc0abb2a2b8d6da66110cd59a5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 17 Jun 2024 10:37:18 +0000 Subject: [PATCH 017/289] Update dependency maven to v3.9.8 --- .mvn/wrapper/maven-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties index 34d543889..bceca511d 100644 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -15,5 +15,5 @@ # specific language governing permissions and limitations # under the License. wrapperVersion=3.3.1 -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.7/apache-maven-3.9.7-bin.zip +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.8/apache-maven-3.9.8-bin.zip wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.1/maven-wrapper-3.3.1.jar From b90a1ff24d6998085fe3a0fa92f00bb34df1bf6f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 19 Jun 2024 18:28:41 +0000 Subject: [PATCH 018/289] Update dependency org.springframework:spring-jdbc to v6.1.10 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a37a79ec8..6aedfc031 100644 --- a/pom.xml +++ b/pom.xml @@ -92,7 +92,7 @@ org.springframework spring-jdbc - 6.1.9 + 6.1.10 provided true From ced7fcd228d7264a17d485717455bf1743a94d29 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Thu, 20 Jun 2024 09:25:46 -0400 Subject: [PATCH 019/289] Remove Obsolete Test --- .../org/mybatis/dynamic/sql/SqlTableTest.java | 29 ------------------- 1 file changed, 29 deletions(-) delete mode 100644 src/test/java/org/mybatis/dynamic/sql/SqlTableTest.java diff --git a/src/test/java/org/mybatis/dynamic/sql/SqlTableTest.java b/src/test/java/org/mybatis/dynamic/sql/SqlTableTest.java deleted file mode 100644 index 473258dcb..000000000 --- a/src/test/java/org/mybatis/dynamic/sql/SqlTableTest.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2016-2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.mybatis.dynamic.sql; - -import static org.assertj.core.api.Assertions.assertThat; - -import org.junit.jupiter.api.Test; - -class SqlTableTest { - - @Test - void testFullName() { - SqlTable table = new SqlTable("my_table"); - assertThat(table.tableNameAtRuntime()).isEqualTo("my_table"); - } -} From 8e18992327610bb4caaf8b17260a77b649aae97f Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Thu, 20 Jun 2024 09:34:58 -0400 Subject: [PATCH 020/289] Better method name --- src/main/java/org/mybatis/dynamic/sql/SqlTable.java | 2 +- .../dynamic/sql/exception/DuplicateTableAliasException.java | 2 +- .../dynamic/sql/insert/render/InsertRenderingUtilities.java | 2 +- .../dynamic/sql/render/GuaranteedTableAliasCalculator.java | 2 +- .../java/org/mybatis/dynamic/sql/render/RenderingContext.java | 4 ++-- src/test/java/examples/joins/JoinMapperTest.java | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/SqlTable.java b/src/main/java/org/mybatis/dynamic/sql/SqlTable.java index c482458d9..40b6ccf17 100644 --- a/src/main/java/org/mybatis/dynamic/sql/SqlTable.java +++ b/src/main/java/org/mybatis/dynamic/sql/SqlTable.java @@ -29,7 +29,7 @@ protected SqlTable(String tableName) { this.tableName = Objects.requireNonNull(tableName); } - public String tableNameAtRuntime() { + public String tableName() { return tableName; } diff --git a/src/main/java/org/mybatis/dynamic/sql/exception/DuplicateTableAliasException.java b/src/main/java/org/mybatis/dynamic/sql/exception/DuplicateTableAliasException.java index d32e66e5e..ee8c1e2d1 100644 --- a/src/main/java/org/mybatis/dynamic/sql/exception/DuplicateTableAliasException.java +++ b/src/main/java/org/mybatis/dynamic/sql/exception/DuplicateTableAliasException.java @@ -43,6 +43,6 @@ public DuplicateTableAliasException(SqlTable table, String newAlias, String exis } private static String generateMessage(SqlTable table, String newAlias, String existingAlias) { - return Messages.getString("ERROR.1", table.tableNameAtRuntime(), newAlias, existingAlias); //$NON-NLS-1$ + return Messages.getString("ERROR.1", table.tableName(), newAlias, existingAlias); //$NON-NLS-1$ } } diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/render/InsertRenderingUtilities.java b/src/main/java/org/mybatis/dynamic/sql/insert/render/InsertRenderingUtilities.java index 31bbf02ed..e22143109 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/render/InsertRenderingUtilities.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/render/InsertRenderingUtilities.java @@ -31,6 +31,6 @@ public static String calculateInsertStatement(SqlTable table, FieldAndValueColle } public static String calculateInsertStatementStart(SqlTable table) { - return "insert into " + table.tableNameAtRuntime(); //$NON-NLS-1$ + return "insert into " + table.tableName(); //$NON-NLS-1$ } } diff --git a/src/main/java/org/mybatis/dynamic/sql/render/GuaranteedTableAliasCalculator.java b/src/main/java/org/mybatis/dynamic/sql/render/GuaranteedTableAliasCalculator.java index 59948b03f..4d4a3b883 100644 --- a/src/main/java/org/mybatis/dynamic/sql/render/GuaranteedTableAliasCalculator.java +++ b/src/main/java/org/mybatis/dynamic/sql/render/GuaranteedTableAliasCalculator.java @@ -38,7 +38,7 @@ public Optional aliasForColumn(SqlTable table) { if (alias.isPresent()) { return alias; } else { - return Optional.of(table.tableNameAtRuntime()); + return Optional.of(table.tableName()); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/render/RenderingContext.java b/src/main/java/org/mybatis/dynamic/sql/render/RenderingContext.java index 8a5d1cf5e..bc953f847 100644 --- a/src/main/java/org/mybatis/dynamic/sql/render/RenderingContext.java +++ b/src/main/java/org/mybatis/dynamic/sql/render/RenderingContext.java @@ -88,8 +88,8 @@ public String aliasedColumnName(SqlColumn column, String explicitAlias) { public String aliasedTableName(SqlTable table) { return tableAliasCalculator.aliasForTable(table) - .map(a -> table.tableNameAtRuntime() + spaceBefore(a)) - .orElseGet(table::tableNameAtRuntime); + .map(a -> table.tableName() + spaceBefore(a)) + .orElseGet(table::tableName); } public boolean isNonRenderingClauseAllowed() { diff --git a/src/test/java/examples/joins/JoinMapperTest.java b/src/test/java/examples/joins/JoinMapperTest.java index e84571231..50c8e30f5 100644 --- a/src/test/java/examples/joins/JoinMapperTest.java +++ b/src/test/java/examples/joins/JoinMapperTest.java @@ -957,7 +957,7 @@ void testSelfWithDuplicateAlias() { .from(user, "u1"); assertThatExceptionOfType(DuplicateTableAliasException.class).isThrownBy(() -> dsl.join(user, "u2")) - .withMessage(Messages.getString("ERROR.1", user.tableNameAtRuntime(), "u2", "u1")); + .withMessage(Messages.getString("ERROR.1", user.tableName(), "u2", "u1")); } @Test From 51311e07ecbf3c2b56419a473b4c8c194e574293 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 24 Jun 2024 11:18:22 -0400 Subject: [PATCH 021/289] Update error locations for K2 compiler --- .../kotlin/nullability/test/ComparisonTest.kt | 24 +++++++++---------- .../nullability/test/EqualNotEqualTest.kt | 8 +++---- src/test/kotlin/nullability/test/InTest.kt | 2 +- src/test/kotlin/nullability/test/NotInTest.kt | 2 +- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/test/kotlin/nullability/test/ComparisonTest.kt b/src/test/kotlin/nullability/test/ComparisonTest.kt index ebd25607f..0df088eb2 100644 --- a/src/test/kotlin/nullability/test/ComparisonTest.kt +++ b/src/test/kotlin/nullability/test/ComparisonTest.kt @@ -38,7 +38,7 @@ class ComparisonTest { val compilerMessageCollector = compile(source) assertThat(compilerMessageCollector.errorLocations()) .hasSize(1) -// TODO .contains(ErrorLocation(9, 30)) + .contains(ErrorLocation(9, 20)) } @Test @@ -81,7 +81,7 @@ class ComparisonTest { val compilerMessageCollector = compile(source) assertThat(compilerMessageCollector.errorLocations()) .hasSize(1) -// TODO .contains(ErrorLocation(10, 31)) + .contains(ErrorLocation(10, 21)) } @Test @@ -124,7 +124,7 @@ class ComparisonTest { val compilerMessageCollector = compile(source) assertThat(compilerMessageCollector.errorLocations()) .hasSize(1) -// TODO .contains(ErrorLocation(9, 33)) + .contains(ErrorLocation(9, 20)) } @Test @@ -167,7 +167,7 @@ class ComparisonTest { val compilerMessageCollector = compile(source) assertThat(compilerMessageCollector.errorLocations()) .hasSize(1) -// TODO .contains(ErrorLocation(10, 34)) + .contains(ErrorLocation(10, 21)) } @Test @@ -210,7 +210,7 @@ class ComparisonTest { val compilerMessageCollector = compile(source) assertThat(compilerMessageCollector.errorLocations()) .hasSize(1) -// TODO .contains(ErrorLocation(9, 34)) + .contains(ErrorLocation(9, 20)) } @Test @@ -253,7 +253,7 @@ class ComparisonTest { val compilerMessageCollector = compile(source) assertThat(compilerMessageCollector.errorLocations()) .hasSize(1) -// TODO .contains(ErrorLocation(10, 35)) + .contains(ErrorLocation(10, 21)) } @Test @@ -296,7 +296,7 @@ class ComparisonTest { val compilerMessageCollector = compile(source) assertThat(compilerMessageCollector.errorLocations()) .hasSize(1) -// TODO .contains(ErrorLocation(9, 43)) + .contains(ErrorLocation(9, 20)) } @Test @@ -339,7 +339,7 @@ class ComparisonTest { val compilerMessageCollector = compile(source) assertThat(compilerMessageCollector.errorLocations()) .hasSize(1) -// TODO .contains(ErrorLocation(10, 44)) + .contains(ErrorLocation(10, 21)) } @Test @@ -382,7 +382,7 @@ class ComparisonTest { val compilerMessageCollector = compile(source) assertThat(compilerMessageCollector.errorLocations()) .hasSize(1) -// TODO .contains(ErrorLocation(9, 31)) + .contains(ErrorLocation(9, 20)) } @Test @@ -425,7 +425,7 @@ class ComparisonTest { val compilerMessageCollector = compile(source) assertThat(compilerMessageCollector.errorLocations()) .hasSize(1) -// TODO .contains(ErrorLocation(10, 32)) + .contains(ErrorLocation(10, 21)) } @Test @@ -468,7 +468,7 @@ class ComparisonTest { val compilerMessageCollector = compile(source) assertThat(compilerMessageCollector.errorLocations()) .hasSize(1) -// TODO .contains(ErrorLocation(9, 40)) + .contains(ErrorLocation(9, 20)) } @Test @@ -511,7 +511,7 @@ class ComparisonTest { val compilerMessageCollector = compile(source) assertThat(compilerMessageCollector.errorLocations()) .hasSize(1) -// TODO .contains(ErrorLocation(10, 41)) + .contains(ErrorLocation(10, 21)) } @Test diff --git a/src/test/kotlin/nullability/test/EqualNotEqualTest.kt b/src/test/kotlin/nullability/test/EqualNotEqualTest.kt index d1f475d69..70fd7c242 100644 --- a/src/test/kotlin/nullability/test/EqualNotEqualTest.kt +++ b/src/test/kotlin/nullability/test/EqualNotEqualTest.kt @@ -38,7 +38,7 @@ class EqualNotEqualTest { val compilerMessageCollector = compile(source) assertThat(compilerMessageCollector.errorLocations()) .hasSize(1) -// TODO .contains(ErrorLocation(9, 37)) + .contains(ErrorLocation(9, 27)) } @Test @@ -81,7 +81,7 @@ class EqualNotEqualTest { val compilerMessageCollector = compile(source) assertThat(compilerMessageCollector.errorLocations()) .hasSize(1) -// TODO .contains(ErrorLocation(10, 40)) + .contains(ErrorLocation(10, 27)) } @Test @@ -124,7 +124,7 @@ class EqualNotEqualTest { val compilerMessageCollector = compile(source) assertThat(compilerMessageCollector.errorLocations()) .hasSize(1) -// TODO .contains(ErrorLocation(10, 38)) + .contains(ErrorLocation(10, 28)) } @Test @@ -169,7 +169,7 @@ class EqualNotEqualTest { val compilerMessageCollector = compile(source) assertThat(compilerMessageCollector.errorLocations()) .hasSize(1) -// TODO .contains(ErrorLocation(11, 41)) + .contains(ErrorLocation(11, 28)) } @Test diff --git a/src/test/kotlin/nullability/test/InTest.kt b/src/test/kotlin/nullability/test/InTest.kt index 23fa9e784..4ea242830 100644 --- a/src/test/kotlin/nullability/test/InTest.kt +++ b/src/test/kotlin/nullability/test/InTest.kt @@ -108,6 +108,6 @@ class InTest { val compilerMessageCollector = compile(source) assertThat(compilerMessageCollector.errorLocations()) .hasSize(1) -// TODO .contains(ErrorLocation(11, 26)) + .contains(ErrorLocation(11, 21)) } } diff --git a/src/test/kotlin/nullability/test/NotInTest.kt b/src/test/kotlin/nullability/test/NotInTest.kt index f88356c26..adbcf21bf 100644 --- a/src/test/kotlin/nullability/test/NotInTest.kt +++ b/src/test/kotlin/nullability/test/NotInTest.kt @@ -108,6 +108,6 @@ class NotInTest { val compilerMessageCollector = compile(source) assertThat(compilerMessageCollector.errorLocations()) .hasSize(1) -// TODO .contains(ErrorLocation(11, 29)) + .contains(ErrorLocation(11, 21)) } } From 5b03ef0ec32cc68c4133383d55326c44f76e9593 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 27 Jun 2024 15:55:05 +0000 Subject: [PATCH 022/289] Update junit5 monorepo to v5.10.3 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6aedfc031..d16979e76 100644 --- a/pom.xml +++ b/pom.xml @@ -58,7 +58,7 @@ 17 8 - 5.10.2 + 5.10.3 5.1.2 checkstyle-override.xml From 869c584ea5ff5909f28181037b26188dadc60e32 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 5 Jul 2024 16:41:27 +0000 Subject: [PATCH 023/289] Update JamesIves/github-pages-deploy-action action to v4.6.3 --- .github/workflows/site.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/site.yaml b/.github/workflows/site.yaml index 746afc0ec..11eb6ac73 100644 --- a/.github/workflows/site.yaml +++ b/.github/workflows/site.yaml @@ -25,7 +25,7 @@ jobs: CI_DEPLOY_USERNAME: ${{ secrets.CI_DEPLOY_USERNAME }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Deploy Site to gh-pages - uses: JamesIves/github-pages-deploy-action@v4.6.1 + uses: JamesIves/github-pages-deploy-action@v4.6.3 with: ssh-key: true branch: gh-pages From 48ff191897e53cc4d502767f4ba5b377cb808cb3 Mon Sep 17 00:00:00 2001 From: Jeremy Landis Date: Sat, 6 Jul 2024 13:22:26 -0400 Subject: [PATCH 024/289] [mvn] Update maven wrapper --- .mvn/wrapper/MavenWrapperDownloader.java | 2 +- .mvn/wrapper/maven-wrapper.properties | 5 +++-- mvnw | 6 +++--- mvnw.cmd | 6 +++--- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/.mvn/wrapper/MavenWrapperDownloader.java b/.mvn/wrapper/MavenWrapperDownloader.java index f6cb0fa0b..bdf0ddfa6 100644 --- a/.mvn/wrapper/MavenWrapperDownloader.java +++ b/.mvn/wrapper/MavenWrapperDownloader.java @@ -30,7 +30,7 @@ import java.util.concurrent.ThreadLocalRandom; public final class MavenWrapperDownloader { - private static final String WRAPPER_VERSION = "3.3.1"; + private static final String WRAPPER_VERSION = "3.3.2"; private static final boolean VERBOSE = Boolean.parseBoolean(System.getenv("MVNW_VERBOSE")); diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties index bceca511d..fd5166374 100644 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -14,6 +14,7 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -wrapperVersion=3.3.1 +wrapperVersion=3.3.2 +distributionType=source distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.8/apache-maven-3.9.8-bin.zip -wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.1/maven-wrapper-3.3.1.jar +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar diff --git a/mvnw b/mvnw index b21a698ee..668388825 100755 --- a/mvnw +++ b/mvnw @@ -19,7 +19,7 @@ # ---------------------------------------------------------------------------- # ---------------------------------------------------------------------------- -# Apache Maven Wrapper startup batch script, version 3.3.1 +# Apache Maven Wrapper startup batch script, version 3.3.2 # # Required ENV vars: # ------------------ @@ -212,9 +212,9 @@ else log "Couldn't find $wrapperJarPath, downloading it ..." if [ -n "$MVNW_REPOURL" ]; then - wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.3.1/maven-wrapper-3.3.1.jar" + wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar" else - wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.1/maven-wrapper-3.3.1.jar" + wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar" fi while IFS="=" read -r key value; do # Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' ) diff --git a/mvnw.cmd b/mvnw.cmd index f93f29a8e..da4fe4dd9 100644 --- a/mvnw.cmd +++ b/mvnw.cmd @@ -18,7 +18,7 @@ @REM ---------------------------------------------------------------------------- @REM ---------------------------------------------------------------------------- -@REM Apache Maven Wrapper startup batch script, version 3.3.1 +@REM Apache Maven Wrapper startup batch script, version 3.3.2 @REM @REM Required ENV vars: @REM JAVA_HOME - location of a JDK home dir @@ -119,7 +119,7 @@ SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain -set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.1/maven-wrapper-3.3.1.jar" +set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar" FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B @@ -133,7 +133,7 @@ if exist %WRAPPER_JAR% ( ) ) else ( if not "%MVNW_REPOURL%" == "" ( - SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.3.1/maven-wrapper-3.3.1.jar" + SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar" ) if "%MVNW_VERBOSE%" == "true" ( echo Couldn't find %WRAPPER_JAR%, downloading it ... From 14c8f6f6dc9a43d09b016f8004230c015598edff Mon Sep 17 00:00:00 2001 From: Jeremy Landis Date: Sat, 6 Jul 2024 13:24:08 -0400 Subject: [PATCH 025/289] [GHA] Update github actions --- .github/workflows/ci.yaml | 8 +++++--- .github/workflows/coveralls.yaml | 3 ++- .github/workflows/site.yaml | 15 ++++++--------- .github/workflows/sonar.yaml | 5 +++-- .github/workflows/sonatype.yaml | 3 ++- 5 files changed, 18 insertions(+), 16 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 43119e8b4..d5a23da97 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -7,9 +7,10 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-latest] - java: [17, 21, 22-ea] - distribution: ['temurin'] + cache: [maven] + distribution: [temurin] + java: [17, 21, 22, 23-ea] + os: [ubuntu-latest, macos-latest, windows-latest] fail-fast: false max-parallel: 4 name: Test JDK ${{ matrix.java }}, ${{ matrix.os }} @@ -21,5 +22,6 @@ jobs: with: java-version: ${{ matrix.java }} distribution: ${{ matrix.distribution }} + cache: ${{ matrix.cache }} - name: Test with Maven run: ./mvnw test -B -V --no-transfer-progress -D"license.skip=true" diff --git a/.github/workflows/coveralls.yaml b/.github/workflows/coveralls.yaml index a898e3793..270a6c85b 100644 --- a/.github/workflows/coveralls.yaml +++ b/.github/workflows/coveralls.yaml @@ -11,8 +11,9 @@ jobs: - name: Set up JDK uses: actions/setup-java@v4 with: + cache: maven + distribution: temurin java-version: 21 - distribution: zulu - name: Report Coverage to Coveralls for Pull Requests if: github.event_name == 'pull_request' run: ./mvnw -B -V test jacoco:report coveralls:report -q -Dlicense.skip=true -DrepoToken=$GITHUB_TOKEN -DserviceName=github -DpullRequest=$PR_NUMBER --no-transfer-progress diff --git a/.github/workflows/site.yaml b/.github/workflows/site.yaml index 11eb6ac73..5d6998019 100644 --- a/.github/workflows/site.yaml +++ b/.github/workflows/site.yaml @@ -14,21 +14,18 @@ jobs: - name: Set up JDK uses: actions/setup-java@v4 with: + cache: maven + distribution: temurin java-version: 21 - distribution: zulu - - uses: webfactory/ssh-agent@master - with: - ssh-private-key: ${{ secrets.DEPLOY_KEY }} - name: Build site - run: ./mvnw site site:stage -DskipTests -B -V --no-transfer-progress -Dlicense.skip=true + run: ./mvnw site site:stage -DskipTests -Dlicense.skip=true -B -V --no-transfer-progress --settings ./.mvn/settings.xml env: CI_DEPLOY_USERNAME: ${{ secrets.CI_DEPLOY_USERNAME }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NVD_API_KEY: ${{ secrets.NVD_API_KEY }} - name: Deploy Site to gh-pages - uses: JamesIves/github-pages-deploy-action@v4.6.3 + uses: JamesIves/github-pages-deploy-action@v4 with: - ssh-key: true branch: gh-pages folder: target/staging - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + ssh-key: ${{ secrets.DEPLOY_KEY }} diff --git a/.github/workflows/sonar.yaml b/.github/workflows/sonar.yaml index e4bf41ac8..293c0e4ad 100644 --- a/.github/workflows/sonar.yaml +++ b/.github/workflows/sonar.yaml @@ -17,10 +17,11 @@ jobs: - name: Set up JDK uses: actions/setup-java@v4 with: + cache: maven + distribution: temurin java-version: 21 - distribution: zulu - name: Analyze with SonarCloud - run: ./mvnw verify jacoco:report sonar:sonar -B -Dsonar.projectKey=mybatis_mybatis-dynamic-sql -Dsonar.organization=mybatis -Dsonar.host.url=https://sonarcloud.io -Dsonar.token=$SONAR_TOKEN -Dlicense.skip=true --no-transfer-progress + run: ./mvnw verify jacoco:report sonar:sonar -B -V -Dsonar.projectKey=mybatis_mybatis-dynamic-sql -Dsonar.organization=mybatis -Dsonar.host.url=https://sonarcloud.io -Dsonar.token=$SONAR_TOKEN -Dlicense.skip=true --no-transfer-progress env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} diff --git a/.github/workflows/sonatype.yaml b/.github/workflows/sonatype.yaml index 72086bc1d..494bb2f4c 100644 --- a/.github/workflows/sonatype.yaml +++ b/.github/workflows/sonatype.yaml @@ -14,8 +14,9 @@ jobs: - name: Set up JDK uses: actions/setup-java@v4 with: + cache: maven + distribution: temurin java-version: 21 - distribution: zulu - name: Deploy to Sonatype run: ./mvnw deploy -DskipTests -B -V --no-transfer-progress --settings ./.mvn/settings.xml -Dlicense.skip=true env: From 5669e5d075281b4f0d4ff71bd392fb67bfdac2ed Mon Sep 17 00:00:00 2001 From: Jeremy Landis Date: Sat, 6 Jul 2024 13:28:41 -0400 Subject: [PATCH 026/289] [GHA] Run on ubuntu only again --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index d5a23da97..5a6947c02 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -10,7 +10,7 @@ jobs: cache: [maven] distribution: [temurin] java: [17, 21, 22, 23-ea] - os: [ubuntu-latest, macos-latest, windows-latest] + os: [ubuntu-latest] fail-fast: false max-parallel: 4 name: Test JDK ${{ matrix.java }}, ${{ matrix.os }} From 325a9e58e46ee46c17d65a78a7fabd405dfe840f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 9 Jul 2024 18:24:21 +0000 Subject: [PATCH 027/289] Update dependency org.assertj:assertj-core to v3.26.3 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d16979e76..2e52b8ca9 100644 --- a/pom.xml +++ b/pom.xml @@ -125,7 +125,7 @@ org.assertj assertj-core - 3.26.0 + 3.26.3 test From 1bbe16a79df8f08c7967f87b13c4ba3f972301e4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 11 Jul 2024 10:29:33 +0000 Subject: [PATCH 028/289] Update dependency org.springframework:spring-jdbc to v6.1.11 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2e52b8ca9..34c3d1ef8 100644 --- a/pom.xml +++ b/pom.xml @@ -92,7 +92,7 @@ org.springframework spring-jdbc - 6.1.10 + 6.1.11 provided true From 5652077273bcea7e7b51cb08f24bf5b2989f560e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 17 Jul 2024 15:40:07 +0000 Subject: [PATCH 029/289] Update dependency org.mariadb.jdbc:mariadb-java-client to v3.4.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 34c3d1ef8..8205dbbe7 100644 --- a/pom.xml +++ b/pom.xml @@ -199,7 +199,7 @@ org.mariadb.jdbc mariadb-java-client - 3.4.0 + 3.4.1 test From 62992bad171c4334eed4145144f6882538686375 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 17 Jul 2024 15:40:12 +0000 Subject: [PATCH 030/289] Update dependency org.testcontainers:mariadb to v1.20.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 34c3d1ef8..1eab6c049 100644 --- a/pom.xml +++ b/pom.xml @@ -74,7 +74,7 @@ src/test/java,src/test/kotlin official - 1.19.8 + 1.20.0 org.mybatis.dynamic.sql.*;version=${project.version};-noimport:=true From 0e54dace33c05cbe2eb8a0d0e504e75bcfb8a970 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 31 Jul 2024 19:14:03 +0000 Subject: [PATCH 031/289] Update testcontainers-java monorepo to v1.20.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 332f928f0..b72e92fd4 100644 --- a/pom.xml +++ b/pom.xml @@ -74,7 +74,7 @@ src/test/java,src/test/kotlin official - 1.20.0 + 1.20.1 org.mybatis.dynamic.sql.*;version=${project.version};-noimport:=true From aa8d486355d14813545988976e720e7b5b713a99 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 1 Aug 2024 12:56:15 +0000 Subject: [PATCH 032/289] Update dependency org.hamcrest:hamcrest to v3 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b72e92fd4..24b549daa 100644 --- a/pom.xml +++ b/pom.xml @@ -168,7 +168,7 @@ org.hamcrest hamcrest - 2.2 + 3.0 test From cd452ac502d55d082c267f5ea511628a929937ca Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Thu, 1 Aug 2024 11:04:22 -0400 Subject: [PATCH 033/289] Shim in a more general render method for sort specification --- .../dynamic/sql/SortSpecification.java | 29 +++++++++++++++++-- .../org/mybatis/dynamic/sql/SqlColumn.java | 23 ++++++--------- .../dynamic/sql/common/OrderByRenderer.java | 24 +++++++-------- .../sql/delete/render/DeleteRenderer.java | 2 +- .../sql/select/ColumnSortSpecification.java | 21 ++++++-------- .../sql/select/SimpleSortSpecification.java | 21 ++++++-------- .../select/render/MultiSelectRenderer.java | 2 +- .../sql/select/render/SelectRenderer.java | 2 +- .../sql/update/render/UpdateRenderer.java | 2 +- .../dynamic/sql/util/messages.properties | 4 ++- 10 files changed, 73 insertions(+), 57 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/SortSpecification.java b/src/main/java/org/mybatis/dynamic/sql/SortSpecification.java index a17557017..85f9f5288 100644 --- a/src/main/java/org/mybatis/dynamic/sql/SortSpecification.java +++ b/src/main/java/org/mybatis/dynamic/sql/SortSpecification.java @@ -15,6 +15,11 @@ */ package org.mybatis.dynamic.sql; +import org.mybatis.dynamic.sql.exception.DynamicSqlException; +import org.mybatis.dynamic.sql.render.RenderingContext; +import org.mybatis.dynamic.sql.util.FragmentAndParameters; +import org.mybatis.dynamic.sql.util.Messages; + /** * Defines attributes of columns that are necessary for rendering an order by expression. * @@ -34,13 +39,33 @@ public interface SortSpecification { * NOT include the "DESC" word for descending sort specifications. * * @return the order by phrase + * @deprecated Please replace this method by overriding the more general "renderForOrderBy" method. Target for + * removal in release 2.1 */ - String orderByName(); + @Deprecated + default String orderByName() { + throw new DynamicSqlException(Messages.getString("ERROR.44")); //$NON-NLS-1$ + } /** * Return true if the sort order is descending. * * @return true if the SortSpecification should render as descending + * @deprecated Please replace this method by overriding the more general "renderForOrderBy" method. Target for + * removal in release 2.1 */ - boolean isDescending(); + @Deprecated + default boolean isDescending() { + throw new DynamicSqlException(Messages.getString("ERROR.44")); //$NON-NLS-1$ + } + + // the default implementation ensures compatibility with prior releases. When the + // deprecated methods are removed, this function can become purely abstract. + default FragmentAndParameters renderForOrderBy(RenderingContext renderingContext) { + String phrase = orderByName(); + if (isDescending()) { + phrase = phrase + " DESC"; //$NON-NLS-1$ + } + return FragmentAndParameters.fromFragment(phrase); + } } diff --git a/src/main/java/org/mybatis/dynamic/sql/SqlColumn.java b/src/main/java/org/mybatis/dynamic/sql/SqlColumn.java index 76f40e15c..0c8475d33 100644 --- a/src/main/java/org/mybatis/dynamic/sql/SqlColumn.java +++ b/src/main/java/org/mybatis/dynamic/sql/SqlColumn.java @@ -30,7 +30,7 @@ public class SqlColumn implements BindableColumn, SortSpecification { protected final String name; protected final SqlTable table; protected final JDBCType jdbcType; - protected final boolean isDescending; + protected final String descendingPhrase; protected final String alias; protected final String typeHandler; protected final RenderingStrategy renderingStrategy; @@ -42,7 +42,7 @@ private SqlColumn(Builder builder) { name = Objects.requireNonNull(builder.name); table = Objects.requireNonNull(builder.table); jdbcType = builder.jdbcType; - isDescending = builder.isDescending; + descendingPhrase = builder.descendingPhrase; alias = builder.alias; typeHandler = builder.typeHandler; renderingStrategy = builder.renderingStrategy; @@ -87,7 +87,7 @@ public Object convertParameterType(T value) { @Override public SortSpecification descending() { Builder b = copy(); - return b.withDescending(true).build(); + return b.withDescendingPhrase(" DESC").build(); //$NON-NLS-1$ } @Override @@ -126,13 +126,8 @@ public SqlColumn asCamelCase() { } @Override - public boolean isDescending() { - return isDescending; - } - - @Override - public String orderByName() { - return alias().orElse(name); + public FragmentAndParameters renderForOrderBy(RenderingContext renderingContext) { + return FragmentAndParameters.fromFragment(alias().orElse(name) + descendingPhrase); } @Override @@ -188,7 +183,7 @@ private Builder copy() { .withName(this.name) .withTable(this.table) .withJdbcType(this.jdbcType) - .withDescending(this.isDescending) + .withDescendingPhrase(this.descendingPhrase) .withAlias(this.alias) .withTypeHandler(this.typeHandler) .withRenderingStrategy(this.renderingStrategy) @@ -214,7 +209,7 @@ public static class Builder { protected String name; protected SqlTable table; protected JDBCType jdbcType; - protected boolean isDescending = false; + protected String descendingPhrase = ""; //$NON-NLS-1$ protected String alias; protected String typeHandler; protected RenderingStrategy renderingStrategy; @@ -237,8 +232,8 @@ public Builder withJdbcType(JDBCType jdbcType) { return this; } - public Builder withDescending(boolean isDescending) { - this.isDescending = isDescending; + public Builder withDescendingPhrase(String descendingPhrase) { + this.descendingPhrase = descendingPhrase; return this; } diff --git a/src/main/java/org/mybatis/dynamic/sql/common/OrderByRenderer.java b/src/main/java/org/mybatis/dynamic/sql/common/OrderByRenderer.java index f1a28ed4e..206c1a297 100644 --- a/src/main/java/org/mybatis/dynamic/sql/common/OrderByRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/common/OrderByRenderer.java @@ -15,24 +15,24 @@ */ package org.mybatis.dynamic.sql.common; +import java.util.Objects; import java.util.stream.Collectors; -import org.mybatis.dynamic.sql.SortSpecification; +import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.util.FragmentAndParameters; +import org.mybatis.dynamic.sql.util.FragmentCollector; public class OrderByRenderer { - public FragmentAndParameters render(OrderByModel orderByModel) { - String phrase = orderByModel.columns() - .map(this::calculateOrderByPhrase) - .collect(Collectors.joining(", ", "order by ", "")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - return FragmentAndParameters.fromFragment(phrase); + private final RenderingContext renderingContext; + + public OrderByRenderer(RenderingContext renderingContext) { + this.renderingContext = Objects.requireNonNull(renderingContext); } - private String calculateOrderByPhrase(SortSpecification column) { - String phrase = column.orderByName(); - if (column.isDescending()) { - phrase = phrase + " DESC"; //$NON-NLS-1$ - } - return phrase; + public FragmentAndParameters render(OrderByModel orderByModel) { + return orderByModel.columns().map(c -> c.renderForOrderBy(renderingContext)) + .collect(FragmentCollector.collect()) + .toFragmentAndParameters( + Collectors.joining(", ", "order by ", "")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } } diff --git a/src/main/java/org/mybatis/dynamic/sql/delete/render/DeleteRenderer.java b/src/main/java/org/mybatis/dynamic/sql/delete/render/DeleteRenderer.java index ce46c4c10..8a9c945d4 100644 --- a/src/main/java/org/mybatis/dynamic/sql/delete/render/DeleteRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/delete/render/DeleteRenderer.java @@ -96,7 +96,7 @@ private Optional calculateOrderByClause() { } private FragmentAndParameters renderOrderByClause(OrderByModel orderByModel) { - return new OrderByRenderer().render(orderByModel); + return new OrderByRenderer(renderingContext).render(orderByModel); } public static Builder withDeleteModel(DeleteModel deleteModel) { diff --git a/src/main/java/org/mybatis/dynamic/sql/select/ColumnSortSpecification.java b/src/main/java/org/mybatis/dynamic/sql/select/ColumnSortSpecification.java index b8503a971..4420affc9 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/ColumnSortSpecification.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/ColumnSortSpecification.java @@ -19,34 +19,31 @@ import org.mybatis.dynamic.sql.SortSpecification; import org.mybatis.dynamic.sql.SqlColumn; +import org.mybatis.dynamic.sql.render.RenderingContext; +import org.mybatis.dynamic.sql.util.FragmentAndParameters; public class ColumnSortSpecification implements SortSpecification { private final String tableAlias; private final SqlColumn column; - private final boolean isDescending; + private final String descendingPhrase; public ColumnSortSpecification(String tableAlias, SqlColumn column) { - this(tableAlias, column, false); + this(tableAlias, column, ""); //$NON-NLS-1$ } - private ColumnSortSpecification(String tableAlias, SqlColumn column, boolean isDescending) { + private ColumnSortSpecification(String tableAlias, SqlColumn column, String descendingPhrase) { this.tableAlias = Objects.requireNonNull(tableAlias); this.column = Objects.requireNonNull(column); - this.isDescending = isDescending; + this.descendingPhrase = descendingPhrase; } @Override public SortSpecification descending() { - return new ColumnSortSpecification(tableAlias, column, true); + return new ColumnSortSpecification(tableAlias, column, " DESC"); //$NON-NLS-1$ } @Override - public String orderByName() { - return tableAlias + "." + column.name(); //$NON-NLS-1$ - } - - @Override - public boolean isDescending() { - return isDescending; + public FragmentAndParameters renderForOrderBy(RenderingContext renderingContext) { + return FragmentAndParameters.fromFragment(tableAlias + "." + column.name() + descendingPhrase); //$NON-NLS-1$ } } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/SimpleSortSpecification.java b/src/main/java/org/mybatis/dynamic/sql/select/SimpleSortSpecification.java index 9620020e2..2c363ccc4 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/SimpleSortSpecification.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/SimpleSortSpecification.java @@ -18,6 +18,8 @@ import java.util.Objects; import org.mybatis.dynamic.sql.SortSpecification; +import org.mybatis.dynamic.sql.render.RenderingContext; +import org.mybatis.dynamic.sql.util.FragmentAndParameters; /** * This class is used for an order by phrase where there is no suitable column name @@ -28,30 +30,25 @@ public class SimpleSortSpecification implements SortSpecification { private final String name; - private final boolean isDescending; + private final String descendingPhrase; private SimpleSortSpecification(String name) { - this(name, false); + this(name, ""); //$NON-NLS-1$ } - private SimpleSortSpecification(String name, boolean isDescending) { + private SimpleSortSpecification(String name, String descendingPhrase) { this.name = Objects.requireNonNull(name); - this.isDescending = isDescending; + this.descendingPhrase = descendingPhrase; } @Override public SortSpecification descending() { - return new SimpleSortSpecification(name, true); + return new SimpleSortSpecification(name, " DESC"); //$NON-NLS-1$ } @Override - public String orderByName() { - return name; - } - - @Override - public boolean isDescending() { - return isDescending; + public FragmentAndParameters renderForOrderBy(RenderingContext renderingContext) { + return FragmentAndParameters.fromFragment(name + descendingPhrase); } public static SimpleSortSpecification of(String name) { diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/MultiSelectRenderer.java b/src/main/java/org/mybatis/dynamic/sql/select/render/MultiSelectRenderer.java index 59e926f67..c063e7866 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/render/MultiSelectRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/render/MultiSelectRenderer.java @@ -87,7 +87,7 @@ private Optional renderOrderBy() { } private FragmentAndParameters renderOrderBy(OrderByModel orderByModel) { - return new OrderByRenderer().render(orderByModel); + return new OrderByRenderer(renderingContext).render(orderByModel); } private Optional renderPagingModel() { diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/SelectRenderer.java b/src/main/java/org/mybatis/dynamic/sql/select/render/SelectRenderer.java index 3f65a51e4..128ab3e8e 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/render/SelectRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/render/SelectRenderer.java @@ -68,7 +68,7 @@ private Optional renderOrderBy() { } private FragmentAndParameters renderOrderBy(OrderByModel orderByModel) { - return new OrderByRenderer().render(orderByModel); + return new OrderByRenderer(renderingContext).render(orderByModel); } private Optional renderPagingModel() { diff --git a/src/main/java/org/mybatis/dynamic/sql/update/render/UpdateRenderer.java b/src/main/java/org/mybatis/dynamic/sql/update/render/UpdateRenderer.java index 50397ee7f..3edfed684 100644 --- a/src/main/java/org/mybatis/dynamic/sql/update/render/UpdateRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/update/render/UpdateRenderer.java @@ -122,7 +122,7 @@ private Optional calculateOrderByClause() { } private FragmentAndParameters renderOrderByClause(OrderByModel orderByModel) { - return new OrderByRenderer().render(orderByModel); + return new OrderByRenderer(renderingContext).render(orderByModel); } public static Builder withUpdateModel(UpdateModel updateModel) { diff --git a/src/main/resources/org/mybatis/dynamic/sql/util/messages.properties b/src/main/resources/org/mybatis/dynamic/sql/util/messages.properties index 9927dbeec..35d0a810c 100644 --- a/src/main/resources/org/mybatis/dynamic/sql/util/messages.properties +++ b/src/main/resources/org/mybatis/dynamic/sql/util/messages.properties @@ -52,7 +52,7 @@ ERROR.33=Calling "select" or "selectDistinct" more than once is not allowed. Add union or unionAll expression ERROR.34=You must specify "select" or "selectDistinct" before any other clauses in a multi-select statement ERROR.35=Multi-select statements must have at least one "union" or "union all" expression -ERROR.36=You must either implement the "render" or "renderWithTableAlias" method in a column or function +ERROR.36=You must either implement the "render" or "renderWithTableAlias" method in a column or function ERROR.37=The "{0}" function does not support conditions that fail to render ERROR.38=Bound values cannot be aliased ERROR.39=When clauses in case expressions must render @@ -60,4 +60,6 @@ ERROR.40=Case expressions must have at least one "when" clause ERROR.41=You cannot call "then" in a Kotlin case expression more than once ERROR.42=You cannot call `else` in a Kotlin case expression more than once ERROR.43=A Kotlin cast expression must have one, and only one, `as` element +ERROR.44=You must either implement the "renderForOrderBy" method or both "orderByName" and "isDescending" methods in a \ + sort specification INTERNAL.ERROR=Internal Error {0} From f4702861162c54e92bcf4a9af5520d6278b56a97 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 4 Aug 2024 22:45:43 +0000 Subject: [PATCH 034/289] Update dependency org.mybatis:mybatis-parent to v45 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 24b549daa..80746c98f 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ org.mybatis mybatis-parent - 44 + 45 org.mybatis.dynamic-sql From 2d85bb46a33b02f36a376e60e475bbe0ec6735dc Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 5 Aug 2024 10:53:15 -0400 Subject: [PATCH 035/289] Allow case statements in order by phrases --- .../caseexpression/SearchedCaseDSL.java | 4 +- .../caseexpression/SearchedCaseModel.java | 26 +- .../select/caseexpression/SimpleCaseDSL.java | 4 +- .../caseexpression/SimpleCaseModel.java | 28 +- .../sql/select/render/SimpleCaseRenderer.java | 4 +- .../render/ColumnAndConditionRenderer.java | 4 +- .../mariadb/NumbersDynamicSQLSupport.java | 36 ++ .../examples/mariadb/OrderByCaseTest.java | 358 ++++++++++++++++++ .../canonical/SpringKotlinSubQueryTest.kt | 4 +- .../resources/examples/mariadb/CreateDB.sql | 12 + 10 files changed, 470 insertions(+), 10 deletions(-) create mode 100644 src/test/java/examples/mariadb/NumbersDynamicSQLSupport.java create mode 100644 src/test/java/examples/mariadb/OrderByCaseTest.java diff --git a/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/SearchedCaseDSL.java b/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/SearchedCaseDSL.java index 674012d3c..360fc344d 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/SearchedCaseDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/SearchedCaseDSL.java @@ -71,7 +71,7 @@ public SearchedCaseEnder else_(BasicColumn column) { return new SearchedCaseEnder(); } - public BasicColumn end() { + public SearchedCaseModel end() { return new SearchedCaseModel.Builder() .withElseValue(elseValue) .withWhenConditions(whenConditions) @@ -100,7 +100,7 @@ protected WhenDSL getThis() { } public class SearchedCaseEnder { - public BasicColumn end() { + public SearchedCaseModel end() { return SearchedCaseDSL.this.end(); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/SearchedCaseModel.java b/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/SearchedCaseModel.java index 65d3f949f..15fd864f8 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/SearchedCaseModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/SearchedCaseModel.java @@ -21,20 +21,23 @@ import java.util.stream.Stream; import org.mybatis.dynamic.sql.BasicColumn; +import org.mybatis.dynamic.sql.SortSpecification; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.select.render.SearchedCaseRenderer; import org.mybatis.dynamic.sql.util.FragmentAndParameters; import org.mybatis.dynamic.sql.util.Validator; -public class SearchedCaseModel implements BasicColumn { +public class SearchedCaseModel implements BasicColumn, SortSpecification { private final List whenConditions; private final BasicColumn elseValue; private final String alias; + private final String descendingPhrase; private SearchedCaseModel(Builder builder) { whenConditions = builder.whenConditions; alias = builder.alias; elseValue = builder.elseValue; + descendingPhrase = builder.descendingPhrase; Validator.assertNotEmpty(whenConditions, "ERROR.40"); //$NON-NLS-1$ } @@ -56,9 +59,24 @@ public SearchedCaseModel as(String alias) { return new Builder().withWhenConditions(whenConditions) .withElseValue(elseValue) .withAlias(alias) + .withDescendingPhrase(descendingPhrase) .build(); } + @Override + public SearchedCaseModel descending() { + return new Builder().withWhenConditions(whenConditions) + .withElseValue(elseValue) + .withAlias(alias) + .withDescendingPhrase(" DESC") //$NON-NLS-1$ + .build(); + } + + @Override + public FragmentAndParameters renderForOrderBy(RenderingContext renderingContext) { + return render(renderingContext).mapFragment(f -> f + descendingPhrase); + } + @Override public FragmentAndParameters render(RenderingContext renderingContext) { return new SearchedCaseRenderer(this, renderingContext).render(); @@ -68,6 +86,7 @@ public static class Builder { private final List whenConditions = new ArrayList<>(); private BasicColumn elseValue; private String alias; + private String descendingPhrase = ""; //$NON-NLS-1$ public Builder withWhenConditions(List whenConditions) { this.whenConditions.addAll(whenConditions); @@ -84,6 +103,11 @@ public Builder withAlias(String alias) { return this; } + public Builder withDescendingPhrase(String descendingPhrase) { + this.descendingPhrase = descendingPhrase; + return this; + } + public SearchedCaseModel build() { return new SearchedCaseModel(this); } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/SimpleCaseDSL.java b/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/SimpleCaseDSL.java index 83e46473a..6b3f41338 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/SimpleCaseDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/SimpleCaseDSL.java @@ -60,7 +60,7 @@ public SimpleCaseEnder else_(BasicColumn column) { return new SimpleCaseEnder(); } - public BasicColumn end() { + public SimpleCaseModel end() { return new SimpleCaseModel.Builder() .withColumn(column) .withWhenConditions(whenConditions) @@ -100,7 +100,7 @@ public SimpleCaseDSL then(BasicColumn column) { } public class SimpleCaseEnder { - public BasicColumn end() { + public SimpleCaseModel end() { return SimpleCaseDSL.this.end(); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/SimpleCaseModel.java b/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/SimpleCaseModel.java index 4b71407ae..3c649c3da 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/SimpleCaseModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/SimpleCaseModel.java @@ -23,22 +23,25 @@ import org.mybatis.dynamic.sql.BasicColumn; import org.mybatis.dynamic.sql.BindableColumn; +import org.mybatis.dynamic.sql.SortSpecification; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.select.render.SimpleCaseRenderer; import org.mybatis.dynamic.sql.util.FragmentAndParameters; import org.mybatis.dynamic.sql.util.Validator; -public class SimpleCaseModel implements BasicColumn { +public class SimpleCaseModel implements BasicColumn, SortSpecification { private final BindableColumn column; private final List> whenConditions; private final BasicColumn elseValue; private final String alias; + private final String descendingPhrase; private SimpleCaseModel(Builder builder) { column = Objects.requireNonNull(builder.column); whenConditions = builder.whenConditions; elseValue = builder.elseValue; alias = builder.alias; + descendingPhrase = builder.descendingPhrase; Validator.assertNotEmpty(whenConditions, "ERROR.40"); //$NON-NLS-1$ } @@ -66,9 +69,26 @@ public SimpleCaseModel as(String alias) { .withWhenConditions(whenConditions) .withElseValue(elseValue) .withAlias(alias) + .withDescendingPhrase(descendingPhrase) .build(); } + @Override + public SimpleCaseModel descending() { + return new Builder() + .withColumn(column) + .withWhenConditions(whenConditions) + .withElseValue(elseValue) + .withAlias(alias) + .withDescendingPhrase(" DESC") //$NON-NLS-1$ + .build(); + } + + @Override + public FragmentAndParameters renderForOrderBy(RenderingContext renderingContext) { + return render(renderingContext).mapFragment(f -> f + descendingPhrase); + } + @Override public FragmentAndParameters render(RenderingContext renderingContext) { return new SimpleCaseRenderer<>(this, renderingContext).render(); @@ -79,6 +99,7 @@ public static class Builder { private final List> whenConditions = new ArrayList<>(); private BasicColumn elseValue; private String alias; + private String descendingPhrase = ""; //$NON-NLS-1$ public Builder withColumn(BindableColumn column) { this.column = column; @@ -100,6 +121,11 @@ public Builder withAlias(String alias) { return this; } + public Builder withDescendingPhrase(String descendingPhrase) { + this.descendingPhrase = descendingPhrase; + return this; + } + public SimpleCaseModel build() { return new SimpleCaseModel<>(this); } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/SimpleCaseRenderer.java b/src/main/java/org/mybatis/dynamic/sql/select/render/SimpleCaseRenderer.java index 2639d0b53..94cd071f1 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/render/SimpleCaseRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/render/SimpleCaseRenderer.java @@ -48,7 +48,9 @@ public FragmentAndParameters render() { } private FragmentAndParameters renderCase() { - return simpleCaseModel.column().render(renderingContext) + return simpleCaseModel.column().alias() + .map(FragmentAndParameters::fromFragment) + .orElseGet(() -> simpleCaseModel.column().render(renderingContext)) .mapFragment(f -> "case " + f); //$NON-NLS-1$ } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/render/ColumnAndConditionRenderer.java b/src/main/java/org/mybatis/dynamic/sql/where/render/ColumnAndConditionRenderer.java index 2a78ccbf8..da1050ed8 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/render/ColumnAndConditionRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/render/ColumnAndConditionRenderer.java @@ -36,7 +36,9 @@ private ColumnAndConditionRenderer(Builder builder) { } public FragmentAndParameters render() { - FragmentAndParameters renderedLeftColumn = column.render(renderingContext); + FragmentAndParameters renderedLeftColumn = column.alias() + .map(FragmentAndParameters::fromFragment) + .orElseGet(() -> column.render(renderingContext)); DefaultConditionVisitor visitor = DefaultConditionVisitor.withColumn(column) .withRenderingContext(renderingContext) diff --git a/src/test/java/examples/mariadb/NumbersDynamicSQLSupport.java b/src/test/java/examples/mariadb/NumbersDynamicSQLSupport.java new file mode 100644 index 000000000..f707b91fe --- /dev/null +++ b/src/test/java/examples/mariadb/NumbersDynamicSQLSupport.java @@ -0,0 +1,36 @@ +/* + * Copyright 2016-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package examples.mariadb; + +import org.mybatis.dynamic.sql.SqlColumn; +import org.mybatis.dynamic.sql.SqlTable; + +import java.sql.JDBCType; + +public final class NumbersDynamicSQLSupport { + public static final Numbers numbers = new Numbers(); + public static final SqlColumn id = numbers.id; + public static final SqlColumn description = numbers.description; + + public static final class Numbers extends SqlTable { + public final SqlColumn id = column("id", JDBCType.INTEGER); + public final SqlColumn description = column("description", JDBCType.VARCHAR); + + public Numbers() { + super("numbers"); + } + } +} diff --git a/src/test/java/examples/mariadb/OrderByCaseTest.java b/src/test/java/examples/mariadb/OrderByCaseTest.java new file mode 100644 index 000000000..0e0daf251 --- /dev/null +++ b/src/test/java/examples/mariadb/OrderByCaseTest.java @@ -0,0 +1,358 @@ +/* + * Copyright 2016-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package examples.mariadb; + +import static examples.mariadb.NumbersDynamicSQLSupport.description; +import static examples.mariadb.NumbersDynamicSQLSupport.id; +import static examples.mariadb.NumbersDynamicSQLSupport.numbers; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mybatis.dynamic.sql.SqlBuilder.case_; +import static org.mybatis.dynamic.sql.SqlBuilder.isEqualTo; +import static org.mybatis.dynamic.sql.SqlBuilder.select; + +import java.util.List; +import java.util.Map; + +import config.TestContainersConfiguration; +import org.apache.ibatis.datasource.unpooled.UnpooledDataSource; +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.BeforeAll; +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 org.testcontainers.containers.MariaDBContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +@Testcontainers +class OrderByCaseTest { + + @SuppressWarnings("resource") + @Container + private static final MariaDBContainer mariadb = + new MariaDBContainer<>(TestContainersConfiguration.MARIADB_LATEST) + .withInitScript("examples/mariadb/CreateDB.sql"); + + private static SqlSessionFactory sqlSessionFactory; + + @BeforeAll + static void setup() { + UnpooledDataSource ds = new UnpooledDataSource(mariadb.getDriverClassName(), mariadb.getJdbcUrl(), + mariadb.getUsername(), mariadb.getPassword()); + Environment environment = new Environment("test", new JdbcTransactionFactory(), ds); + Configuration config = new Configuration(environment); + config.addMapper(CommonSelectMapper.class); + sqlSessionFactory = new SqlSessionFactoryBuilder().build(config); + } + + @Test + void testOrderBySimpleCase() { + try (SqlSession session = sqlSessionFactory.openSession()) { + CommonSelectMapper mapper = session.getMapper(CommonSelectMapper.class); + + SelectStatementProvider selectStatement = select(id, description).from(numbers) + .orderBy(case_(description) + .when("One").then(3) + .when("Two").then(5) + .when("Three").then(4) + .when("Four").then(2) + .when("Five").then(1) + .else_(99) + .end()) + .build() + .render(RenderingStrategies.MYBATIS3); + + String expected = "select id, description from numbers order by case description " + + "when #{parameters.p1,jdbcType=VARCHAR} then 3 " + + "when #{parameters.p2,jdbcType=VARCHAR} then 5 " + + "when #{parameters.p3,jdbcType=VARCHAR} then 4 " + + "when #{parameters.p4,jdbcType=VARCHAR} then 2 " + + "when #{parameters.p5,jdbcType=VARCHAR} then 1 else 99 end"; + + assertThat(selectStatement.getSelectStatement()).isEqualTo( expected); + + List> rows = mapper.selectManyMappedRows(selectStatement); + assertThat(rows).hasSize(5); + assertThat(rows.get(0)).extracting("id", "description").containsExactly(5, "Five"); + assertThat(rows.get(1)).extracting("id", "description").containsExactly(4, "Four"); + assertThat(rows.get(2)).extracting("id", "description").containsExactly(1, "One"); + assertThat(rows.get(3)).extracting("id", "description").containsExactly(3, "Three"); + assertThat(rows.get(4)).extracting("id", "description").containsExactly(2, "Two"); + } + } + + @Test + void testOrderBySimpleCaseWithTableAlias() { + // ignore table aliases in order by phrases + try (SqlSession session = sqlSessionFactory.openSession()) { + CommonSelectMapper mapper = session.getMapper(CommonSelectMapper.class); + + SelectStatementProvider selectStatement = select(id, description).from(numbers, "n") + .orderBy(case_(description) + .when("One").then(3) + .when("Two").then(5) + .when("Three").then(4) + .when("Four").then(2) + .when("Five").then(1) + .else_(99) + .end()) + .build() + .render(RenderingStrategies.MYBATIS3); + + String expected = "select n.id, n.description from numbers n order by case description " + + "when #{parameters.p1,jdbcType=VARCHAR} then 3 " + + "when #{parameters.p2,jdbcType=VARCHAR} then 5 " + + "when #{parameters.p3,jdbcType=VARCHAR} then 4 " + + "when #{parameters.p4,jdbcType=VARCHAR} then 2 " + + "when #{parameters.p5,jdbcType=VARCHAR} then 1 else 99 end"; + + assertThat(selectStatement.getSelectStatement()).isEqualTo( expected); + + List> rows = mapper.selectManyMappedRows(selectStatement); + assertThat(rows).hasSize(5); + assertThat(rows.get(0)).extracting("id", "description").containsExactly(5, "Five"); + assertThat(rows.get(1)).extracting("id", "description").containsExactly(4, "Four"); + assertThat(rows.get(2)).extracting("id", "description").containsExactly(1, "One"); + assertThat(rows.get(3)).extracting("id", "description").containsExactly(3, "Three"); + assertThat(rows.get(4)).extracting("id", "description").containsExactly(2, "Two"); + } + } + + @Test + void testOrderBySimpleCaseWithColumnAlias() { + // ignore table aliases in order by phrases + try (SqlSession session = sqlSessionFactory.openSession()) { + CommonSelectMapper mapper = session.getMapper(CommonSelectMapper.class); + + SelectStatementProvider selectStatement = select(id, description.as("descr")).from(numbers) + .orderBy(case_(description.as("descr")) + .when("One").then(3) + .when("Two").then(5) + .when("Three").then(4) + .when("Four").then(2) + .when("Five").then(1) + .else_(99) + .end()) + .build() + .render(RenderingStrategies.MYBATIS3); + + String expected = "select id, description as descr from numbers order by case descr " + + "when #{parameters.p1,jdbcType=VARCHAR} then 3 " + + "when #{parameters.p2,jdbcType=VARCHAR} then 5 " + + "when #{parameters.p3,jdbcType=VARCHAR} then 4 " + + "when #{parameters.p4,jdbcType=VARCHAR} then 2 " + + "when #{parameters.p5,jdbcType=VARCHAR} then 1 else 99 end"; + + assertThat(selectStatement.getSelectStatement()).isEqualTo( expected); + + List> rows = mapper.selectManyMappedRows(selectStatement); + assertThat(rows).hasSize(5); + assertThat(rows.get(0)).extracting("id", "descr").containsExactly(5, "Five"); + assertThat(rows.get(1)).extracting("id", "descr").containsExactly(4, "Four"); + assertThat(rows.get(2)).extracting("id", "descr").containsExactly(1, "One"); + assertThat(rows.get(3)).extracting("id", "descr").containsExactly(3, "Three"); + assertThat(rows.get(4)).extracting("id", "descr").containsExactly(2, "Two"); + } + } + + @Test + void testOrderBySimpleCaseDescending() { + try (SqlSession session = sqlSessionFactory.openSession()) { + CommonSelectMapper mapper = session.getMapper(CommonSelectMapper.class); + + SelectStatementProvider selectStatement = select(id, description).from(numbers) + .orderBy(case_(description) + .when("One").then(3) + .when("Two").then(5) + .when("Three").then(4) + .when("Four").then(2) + .when("Five").then(1) + .else_(99) + .end().descending()) + .build() + .render(RenderingStrategies.MYBATIS3); + + String expected = "select id, description from numbers order by case description " + + "when #{parameters.p1,jdbcType=VARCHAR} then 3 " + + "when #{parameters.p2,jdbcType=VARCHAR} then 5 " + + "when #{parameters.p3,jdbcType=VARCHAR} then 4 " + + "when #{parameters.p4,jdbcType=VARCHAR} then 2 " + + "when #{parameters.p5,jdbcType=VARCHAR} then 1 else 99 end DESC"; + + assertThat(selectStatement.getSelectStatement()).isEqualTo( expected); + + List> rows = mapper.selectManyMappedRows(selectStatement); + assertThat(rows).hasSize(5); + assertThat(rows.get(4)).extracting("id", "description").containsExactly(5, "Five"); + assertThat(rows.get(3)).extracting("id", "description").containsExactly(4, "Four"); + assertThat(rows.get(2)).extracting("id", "description").containsExactly(1, "One"); + assertThat(rows.get(1)).extracting("id", "description").containsExactly(3, "Three"); + assertThat(rows.get(0)).extracting("id", "description").containsExactly(2, "Two"); + } + } + + @Test + void testOrderBySearchedCase() { + try (SqlSession session = sqlSessionFactory.openSession()) { + CommonSelectMapper mapper = session.getMapper(CommonSelectMapper.class); + + SelectStatementProvider selectStatement = select(id, description).from(numbers) + .orderBy(case_() + .when(description, isEqualTo("One")).then(3) + .when(description, isEqualTo("Two")).then(5) + .when(description, isEqualTo("Three")).then(4) + .when(description, isEqualTo("Four")).then(2) + .when(description, isEqualTo("Five")).then(1) + .else_(99) + .end()) + .build() + .render(RenderingStrategies.MYBATIS3); + + String expected = "select id, description from numbers order by case " + + "when description = #{parameters.p1,jdbcType=VARCHAR} then 3 " + + "when description = #{parameters.p2,jdbcType=VARCHAR} then 5 " + + "when description = #{parameters.p3,jdbcType=VARCHAR} then 4 " + + "when description = #{parameters.p4,jdbcType=VARCHAR} then 2 " + + "when description = #{parameters.p5,jdbcType=VARCHAR} then 1 else 99 end"; + + assertThat(selectStatement.getSelectStatement()).isEqualTo( expected); + + List> rows = mapper.selectManyMappedRows(selectStatement); + assertThat(rows).hasSize(5); + assertThat(rows.get(0)).extracting("id", "description").containsExactly(5, "Five"); + assertThat(rows.get(1)).extracting("id", "description").containsExactly(4, "Four"); + assertThat(rows.get(2)).extracting("id", "description").containsExactly(1, "One"); + assertThat(rows.get(3)).extracting("id", "description").containsExactly(3, "Three"); + assertThat(rows.get(4)).extracting("id", "description").containsExactly(2, "Two"); + } + } + + @Test + void testOrderBySearchedCaseWithTableAlias() { + // ignore table aliases in order by phrases + try (SqlSession session = sqlSessionFactory.openSession()) { + CommonSelectMapper mapper = session.getMapper(CommonSelectMapper.class); + + SelectStatementProvider selectStatement = select(id, description).from(numbers, "n") + .orderBy(case_() + .when(description, isEqualTo("One")).then(3) + .when(description, isEqualTo("Two")).then(5) + .when(description, isEqualTo("Three")).then(4) + .when(description, isEqualTo("Four")).then(2) + .when(description, isEqualTo("Five")).then(1) + .else_(99) + .end()) + .build() + .render(RenderingStrategies.MYBATIS3); + + String expected = "select n.id, n.description from numbers n order by case " + + "when description = #{parameters.p1,jdbcType=VARCHAR} then 3 " + + "when description = #{parameters.p2,jdbcType=VARCHAR} then 5 " + + "when description = #{parameters.p3,jdbcType=VARCHAR} then 4 " + + "when description = #{parameters.p4,jdbcType=VARCHAR} then 2 " + + "when description = #{parameters.p5,jdbcType=VARCHAR} then 1 else 99 end"; + + assertThat(selectStatement.getSelectStatement()).isEqualTo( expected); + + List> rows = mapper.selectManyMappedRows(selectStatement); + assertThat(rows).hasSize(5); + assertThat(rows.get(0)).extracting("id", "description").containsExactly(5, "Five"); + assertThat(rows.get(1)).extracting("id", "description").containsExactly(4, "Four"); + assertThat(rows.get(2)).extracting("id", "description").containsExactly(1, "One"); + assertThat(rows.get(3)).extracting("id", "description").containsExactly(3, "Three"); + assertThat(rows.get(4)).extracting("id", "description").containsExactly(2, "Two"); + } + } + + @Test + void testOrderBySearchedCaseWithColumnAlias() { + // ignore table aliases in order by phrases + try (SqlSession session = sqlSessionFactory.openSession()) { + CommonSelectMapper mapper = session.getMapper(CommonSelectMapper.class); + + SelectStatementProvider selectStatement = select(id, description.as("descr")).from(numbers) + .orderBy(case_() + .when(description.as("descr"), isEqualTo("One")).then(3) + .when(description.as("descr"), isEqualTo("Two")).then(5) + .when(description.as("descr"), isEqualTo("Three")).then(4) + .when(description.as("descr"), isEqualTo("Four")).then(2) + .when(description.as("descr"), isEqualTo("Five")).then(1) + .else_(99) + .end()) + .build() + .render(RenderingStrategies.MYBATIS3); + + String expected = "select id, description as descr from numbers order by case " + + "when descr = #{parameters.p1,jdbcType=VARCHAR} then 3 " + + "when descr = #{parameters.p2,jdbcType=VARCHAR} then 5 " + + "when descr = #{parameters.p3,jdbcType=VARCHAR} then 4 " + + "when descr = #{parameters.p4,jdbcType=VARCHAR} then 2 " + + "when descr = #{parameters.p5,jdbcType=VARCHAR} then 1 else 99 end"; + + assertThat(selectStatement.getSelectStatement()).isEqualTo( expected); + + List> rows = mapper.selectManyMappedRows(selectStatement); + assertThat(rows).hasSize(5); + assertThat(rows.get(0)).extracting("id", "descr").containsExactly(5, "Five"); + assertThat(rows.get(1)).extracting("id", "descr").containsExactly(4, "Four"); + assertThat(rows.get(2)).extracting("id", "descr").containsExactly(1, "One"); + assertThat(rows.get(3)).extracting("id", "descr").containsExactly(3, "Three"); + assertThat(rows.get(4)).extracting("id", "descr").containsExactly(2, "Two"); + } + } + + @Test + void testOrderBySearchedCaseDescending() { + try (SqlSession session = sqlSessionFactory.openSession()) { + CommonSelectMapper mapper = session.getMapper(CommonSelectMapper.class); + + SelectStatementProvider selectStatement = select(id, description).from(numbers) + .orderBy(case_() + .when(description, isEqualTo("One")).then(3) + .when(description, isEqualTo("Two")).then(5) + .when(description, isEqualTo("Three")).then(4) + .when(description, isEqualTo("Four")).then(2) + .when(description, isEqualTo("Five")).then(1) + .else_(99) + .end().descending()) + .build() + .render(RenderingStrategies.MYBATIS3); + + String expected = "select id, description from numbers order by case " + + "when description = #{parameters.p1,jdbcType=VARCHAR} then 3 " + + "when description = #{parameters.p2,jdbcType=VARCHAR} then 5 " + + "when description = #{parameters.p3,jdbcType=VARCHAR} then 4 " + + "when description = #{parameters.p4,jdbcType=VARCHAR} then 2 " + + "when description = #{parameters.p5,jdbcType=VARCHAR} then 1 else 99 end DESC"; + + assertThat(selectStatement.getSelectStatement()).isEqualTo( expected); + + List> rows = mapper.selectManyMappedRows(selectStatement); + assertThat(rows).hasSize(5); + assertThat(rows.get(4)).extracting("id", "description").containsExactly(5, "Five"); + assertThat(rows.get(3)).extracting("id", "description").containsExactly(4, "Four"); + assertThat(rows.get(2)).extracting("id", "description").containsExactly(1, "One"); + assertThat(rows.get(1)).extracting("id", "description").containsExactly(3, "Three"); + assertThat(rows.get(0)).extracting("id", "description").containsExactly(2, "Two"); + } + } +} diff --git a/src/test/kotlin/examples/kotlin/spring/canonical/SpringKotlinSubQueryTest.kt b/src/test/kotlin/examples/kotlin/spring/canonical/SpringKotlinSubQueryTest.kt index eb97249a6..d4ff965b9 100644 --- a/src/test/kotlin/examples/kotlin/spring/canonical/SpringKotlinSubQueryTest.kt +++ b/src/test/kotlin/examples/kotlin/spring/canonical/SpringKotlinSubQueryTest.kt @@ -113,12 +113,12 @@ open class SpringKotlinSubQueryTest { @Test fun testBasicSubQueryWithAliases() { - val rowNum = DerivedColumn.of("rownum()") `as` "myRows" + val rowNum = DerivedColumn.of("rownum()") val outerFirstName = "b"(firstName) val personId = DerivedColumn.of("personId", "b") val selectStatement = - select(outerFirstName.asCamelCase(), personId, rowNum) { + select(outerFirstName.asCamelCase(), personId, rowNum `as` "myRows") { from { select(id `as` "personId", firstName) { from(person, "a") diff --git a/src/test/resources/examples/mariadb/CreateDB.sql b/src/test/resources/examples/mariadb/CreateDB.sql index 3e16f6a73..3c90c396d 100644 --- a/src/test/resources/examples/mariadb/CreateDB.sql +++ b/src/test/resources/examples/mariadb/CreateDB.sql @@ -41,3 +41,15 @@ insert into items values (17, 'Item 17', 117); insert into items values (18, 'Item 18', 118); insert into items values (19, 'Item 19', 119); insert into items values (20, 'Item 20', 120); + +create table numbers ( + id int not null, + description varchar(50) not null, + primary key (id) +); + +insert into numbers values (1, 'One'); +insert into numbers values (2, 'Two'); +insert into numbers values (3, 'Three'); +insert into numbers values (4, 'Four'); +insert into numbers values (5, 'Five'); From a959711d16f0275abe49c7dbb719865076d1e29e Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 5 Aug 2024 11:08:38 -0400 Subject: [PATCH 036/289] Update version to 2.0.0! --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 03b765595..0da827e3b 100644 --- a/pom.xml +++ b/pom.xml @@ -26,7 +26,7 @@ org.mybatis.dynamic-sql mybatis-dynamic-sql - 1.6.0-SNAPSHOT + 2.0.0-SNAPSHOT MyBatis Dynamic SQL MyBatis framework for generating dynamic SQL From 523c7497e87700b1d1641f767a15676f98dd7b6f Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 5 Aug 2024 11:08:49 -0400 Subject: [PATCH 037/289] Docs --- CHANGELOG.md | 4 ++++ README.md | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d80d14ee3..de304acca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ This log will detail notable changes to MyBatis Dynamic SQL. Full details are available on the GitHub milestone pages. +## Release 2.0.0 - Unreleased + +The library now requires Java 17. + ## Release 1.5.2 - June 3, 2024 This is a small maintenance release with the following changes: diff --git a/README.md b/README.md index 12dac83b3..a9172a1b3 100644 --- a/README.md +++ b/README.md @@ -80,4 +80,4 @@ The library test cases provide several complete examples of using the library in ## Requirements -The library has no dependencies. Java 8 or higher is required. +The library has no dependencies. Version 2.x requires Java 17. Version 1.8 requires Java 8. From 491e9b4af33246acf800a051fbbcf4f136057dbf Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 5 Aug 2024 12:00:17 -0400 Subject: [PATCH 038/289] Kick Github --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a9172a1b3..33f212278 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,6 @@ The library test cases provide several complete examples of using the library in | Kotlin | Spring JDBC | Example using Kotlin utility classes for Spring JDBC Template | [../examples/kotlin/spring/canonical](src/test/kotlin/examples/kotlin/spring/canonical) | -## Requirements +## Requirements The library has no dependencies. Version 2.x requires Java 17. Version 1.8 requires Java 8. From 73f5e8f726fd8fe305d41b3e77e79c2083d14a50 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 5 Aug 2024 12:00:25 -0400 Subject: [PATCH 039/289] Kick Github --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 33f212278..a9172a1b3 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,6 @@ The library test cases provide several complete examples of using the library in | Kotlin | Spring JDBC | Example using Kotlin utility classes for Spring JDBC Template | [../examples/kotlin/spring/canonical](src/test/kotlin/examples/kotlin/spring/canonical) | -## Requirements +## Requirements The library has no dependencies. Version 2.x requires Java 17. Version 1.8 requires Java 8. From bc1506cd71197a064f277834369f7acd62896687 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 5 Aug 2024 16:46:33 +0000 Subject: [PATCH 040/289] Update junit5 monorepo to v5.10.3 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0da827e3b..5d5447a8f 100644 --- a/pom.xml +++ b/pom.xml @@ -58,7 +58,7 @@ 17 17 - 5.10.2 + 5.10.3 5.1.2 checkstyle-override.xml From 7e06a2a6080bf4aba479f00e946cabffe4f024f0 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 5 Aug 2024 12:48:15 -0400 Subject: [PATCH 041/289] Small typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a9172a1b3..812dc3b9d 100644 --- a/README.md +++ b/README.md @@ -80,4 +80,4 @@ The library test cases provide several complete examples of using the library in ## Requirements -The library has no dependencies. Version 2.x requires Java 17. Version 1.8 requires Java 8. +The library has no dependencies. Version 2.x requires Java 17. Version 1.x requires Java 8. From a6022069af41a7132b19b01303b6002b38004880 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 5 Aug 2024 12:51:44 -0400 Subject: [PATCH 042/289] Docs --- CHANGELOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index de304acca..31e9fa8b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,10 @@ This log will detail notable changes to MyBatis Dynamic SQL. Full details are av ## Release 2.0.0 - Unreleased -The library now requires Java 17. +Significant changes: + +- The library now requires Java 17 +- Deprecated code from prior releases is removed ## Release 1.5.2 - June 3, 2024 From 6f483d823a5970d589840e0843dc0dd5b91558c5 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 5 Aug 2024 17:04:34 -0400 Subject: [PATCH 043/289] Coverage for deprecated methods --- .../sql/DeprecatedSortMethodsTest.java | 142 ++++++++++++++++++ .../mybatis/dynamic/sql/InvalidSQLTest.java | 1 - 2 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 src/test/java/org/mybatis/dynamic/sql/DeprecatedSortMethodsTest.java diff --git a/src/test/java/org/mybatis/dynamic/sql/DeprecatedSortMethodsTest.java b/src/test/java/org/mybatis/dynamic/sql/DeprecatedSortMethodsTest.java new file mode 100644 index 000000000..678d997d2 --- /dev/null +++ b/src/test/java/org/mybatis/dynamic/sql/DeprecatedSortMethodsTest.java @@ -0,0 +1,142 @@ +/* + * Copyright 2016-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mybatis.dynamic.sql; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; + +import java.util.List; + +import org.junit.jupiter.api.Test; +import org.mybatis.dynamic.sql.common.OrderByModel; +import org.mybatis.dynamic.sql.common.OrderByRenderer; +import org.mybatis.dynamic.sql.configuration.StatementConfiguration; +import org.mybatis.dynamic.sql.exception.DynamicSqlException; +import org.mybatis.dynamic.sql.render.RenderingContext; +import org.mybatis.dynamic.sql.render.RenderingStrategies; +import org.mybatis.dynamic.sql.render.TableAliasCalculator; +import org.mybatis.dynamic.sql.util.FragmentAndParameters; +import org.mybatis.dynamic.sql.util.Messages; + +class DeprecatedSortMethodsTest { + + @Test + void bothMethodsExist() { + SortSpecification ss = new SortSpecification() { + @Override + public SortSpecification descending() { + return this; + } + + @Override + public String orderByName() { + return "id"; + } + + @Override + public boolean isDescending() { + return true; + } + }; + + OrderByModel model = OrderByModel.of(List.of(ss)); + + RenderingContext renderingContext = RenderingContext + .withRenderingStrategy(RenderingStrategies.MYBATIS3) + .withTableAliasCalculator(TableAliasCalculator.empty()) + .withStatementConfiguration(new StatementConfiguration()) + .build(); + OrderByRenderer renderer = new OrderByRenderer(renderingContext); + FragmentAndParameters fp = renderer.render(model); + assertThat(fp.fragment()).isEqualTo("order by id DESC"); + } + + @Test + void orderByNameMethodMissing() { + SortSpecification ss = new SortSpecification() { + @Override + public SortSpecification descending() { + return this; + } + + @Override + public boolean isDescending() { + return true; + } + }; + + OrderByModel model = OrderByModel.of(List.of(ss)); + + RenderingContext renderingContext = RenderingContext + .withRenderingStrategy(RenderingStrategies.MYBATIS3) + .withTableAliasCalculator(TableAliasCalculator.empty()) + .withStatementConfiguration(new StatementConfiguration()) + .build(); + OrderByRenderer renderer = new OrderByRenderer(renderingContext); + assertThatExceptionOfType(DynamicSqlException.class) + .isThrownBy(() -> renderer.render(model)) + .withMessage(Messages.getString("ERROR.44")); + } + + @Test + void isDescendingMethodMissing() { + SortSpecification ss = new SortSpecification() { + @Override + public SortSpecification descending() { + return this; + } + + @Override + public String orderByName() { + return "id"; + } + }; + + OrderByModel model = OrderByModel.of(List.of(ss)); + + RenderingContext renderingContext = RenderingContext + .withRenderingStrategy(RenderingStrategies.MYBATIS3) + .withTableAliasCalculator(TableAliasCalculator.empty()) + .withStatementConfiguration(new StatementConfiguration()) + .build(); + OrderByRenderer renderer = new OrderByRenderer(renderingContext); + assertThatExceptionOfType(DynamicSqlException.class) + .isThrownBy(() -> renderer.render(model)) + .withMessage(Messages.getString("ERROR.44")); + } + + @Test + void bothMethodsMissing() { + SortSpecification ss = new SortSpecification() { + @Override + public SortSpecification descending() { + return this; + } + }; + + OrderByModel model = OrderByModel.of(List.of(ss)); + + RenderingContext renderingContext = RenderingContext + .withRenderingStrategy(RenderingStrategies.MYBATIS3) + .withTableAliasCalculator(TableAliasCalculator.empty()) + .withStatementConfiguration(new StatementConfiguration()) + .build(); + OrderByRenderer renderer = new OrderByRenderer(renderingContext); + assertThatExceptionOfType(DynamicSqlException.class) + .isThrownBy(() -> renderer.render(model)) + .withMessage(Messages.getString("ERROR.44")); + } +} diff --git a/src/test/java/org/mybatis/dynamic/sql/InvalidSQLTest.java b/src/test/java/org/mybatis/dynamic/sql/InvalidSQLTest.java index bfec86e73..cc5f16193 100644 --- a/src/test/java/org/mybatis/dynamic/sql/InvalidSQLTest.java +++ b/src/test/java/org/mybatis/dynamic/sql/InvalidSQLTest.java @@ -22,7 +22,6 @@ import static org.mybatis.dynamic.sql.SqlBuilder.update; import static org.mybatis.dynamic.sql.SqlBuilder.value; -import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.MissingResourceException; From 1da8ab4f9190b0575e4a1929ba7f40a6c91cc16b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 6 Aug 2024 10:20:50 +0000 Subject: [PATCH 044/289] Update kotlin monorepo to v2.0.10 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5d5447a8f..aa2ee3a0d 100644 --- a/pom.xml +++ b/pom.xml @@ -67,7 +67,7 @@ org.mybatis.dynamic.sql - 2.0.0 + 2.0.10 1.8 pom.xml,src/main/java,src/main/kotlin From d69b968dbea48b25978592de12a8bf26fc5abdb5 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Tue, 6 Aug 2024 11:01:23 -0400 Subject: [PATCH 045/289] Sonar suggestions --- .../org/mybatis/dynamic/sql/AbstractListValueCondition.java | 2 +- src/main/java/org/mybatis/dynamic/sql/SortSpecification.java | 4 ++-- .../org/mybatis/dynamic/sql/insert/render/BatchInsert.java | 3 +-- .../dynamic/sql/select/AbstractQueryExpressionDSL.java | 3 +-- src/main/java/org/mybatis/dynamic/sql/select/SelectDSL.java | 3 +-- .../org/mybatis/dynamic/sql/update/render/UpdateRenderer.java | 4 ++-- .../java/org/mybatis/dynamic/sql/util/SqlProviderAdapter.java | 3 +-- .../mybatis/dynamic/sql/util/mybatis3/CommonSelectMapper.java | 3 +-- .../mybatis/dynamic/sql/util/spring/BatchInsertUtility.java | 3 +-- .../sql/where/condition/IsInCaseInsensitiveWhenPresent.java | 3 +-- .../mybatis/dynamic/sql/where/condition/IsInWhenPresent.java | 3 +-- .../where/condition/IsNotInCaseInsensitiveWhenPresent.java | 3 +-- .../dynamic/sql/where/condition/IsNotInWhenPresent.java | 3 +-- .../mybatis/dynamic/sql/where/render/CriterionRenderer.java | 2 +- 14 files changed, 16 insertions(+), 26 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/AbstractListValueCondition.java b/src/main/java/org/mybatis/dynamic/sql/AbstractListValueCondition.java index 104859de8..dc287e842 100644 --- a/src/main/java/org/mybatis/dynamic/sql/AbstractListValueCondition.java +++ b/src/main/java/org/mybatis/dynamic/sql/AbstractListValueCondition.java @@ -51,7 +51,7 @@ private Collection applyMapper(Function mapper) { private Collection applyFilter(Predicate predicate) { Objects.requireNonNull(predicate); - return values.stream().filter(predicate).collect(Collectors.toList()); + return values.stream().filter(predicate).toList(); } protected > S filterSupport(Predicate predicate, diff --git a/src/main/java/org/mybatis/dynamic/sql/SortSpecification.java b/src/main/java/org/mybatis/dynamic/sql/SortSpecification.java index 85f9f5288..87b986d27 100644 --- a/src/main/java/org/mybatis/dynamic/sql/SortSpecification.java +++ b/src/main/java/org/mybatis/dynamic/sql/SortSpecification.java @@ -42,7 +42,7 @@ public interface SortSpecification { * @deprecated Please replace this method by overriding the more general "renderForOrderBy" method. Target for * removal in release 2.1 */ - @Deprecated + @Deprecated(since = "2.0", forRemoval = true) default String orderByName() { throw new DynamicSqlException(Messages.getString("ERROR.44")); //$NON-NLS-1$ } @@ -54,7 +54,7 @@ default String orderByName() { * @deprecated Please replace this method by overriding the more general "renderForOrderBy" method. Target for * removal in release 2.1 */ - @Deprecated + @Deprecated(since = "2.0", forRemoval = true) default boolean isDescending() { throw new DynamicSqlException(Messages.getString("ERROR.44")); //$NON-NLS-1$ } diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/render/BatchInsert.java b/src/main/java/org/mybatis/dynamic/sql/insert/render/BatchInsert.java index 2759bb907..cde4ec626 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/render/BatchInsert.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/render/BatchInsert.java @@ -19,7 +19,6 @@ import java.util.Collections; import java.util.List; import java.util.Objects; -import java.util.stream.Collectors; public class BatchInsert { private final String insertStatement; @@ -38,7 +37,7 @@ private BatchInsert(Builder builder) { public List> insertStatements() { return records.stream() .map(this::toInsertStatement) - .collect(Collectors.toList()); + .toList(); } private InsertStatementProvider toInsertStatement(T row) { 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 d800a02ff..d82076a49 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/AbstractQueryExpressionDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/AbstractQueryExpressionDSL.java @@ -23,7 +23,6 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; -import java.util.stream.Collectors; import org.mybatis.dynamic.sql.SqlTable; import org.mybatis.dynamic.sql.TableExpression; @@ -196,7 +195,7 @@ protected Optional buildJoinModel() { return Optional.of(JoinModel.of(joinSpecificationBuilders.stream() .map(JoinSpecification.Builder::build) - .collect(Collectors.toList()))); + .toList())); } protected void addTableAlias(SqlTable table, String tableAlias) { diff --git a/src/main/java/org/mybatis/dynamic/sql/select/SelectDSL.java b/src/main/java/org/mybatis/dynamic/sql/select/SelectDSL.java index a509e974b..cb1fae92d 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/SelectDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/SelectDSL.java @@ -23,7 +23,6 @@ import java.util.Optional; import java.util.function.Consumer; import java.util.function.Function; -import java.util.stream.Collectors; import org.jetbrains.annotations.NotNull; import org.mybatis.dynamic.sql.BasicColumn; @@ -143,7 +142,7 @@ public R build() { private List buildModels() { return queryExpressions.stream() .map(QueryExpressionDSL::buildModel) - .collect(Collectors.toList()); + .toList(); } private Optional buildPagingModel() { diff --git a/src/main/java/org/mybatis/dynamic/sql/update/render/UpdateRenderer.java b/src/main/java/org/mybatis/dynamic/sql/update/render/UpdateRenderer.java index 0a3fae0d1..f11662c02 100644 --- a/src/main/java/org/mybatis/dynamic/sql/update/render/UpdateRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/update/render/UpdateRenderer.java @@ -78,8 +78,8 @@ private FragmentAndParameters calculateUpdateStatementStart() { private FragmentAndParameters calculateSetPhrase() { List> fragmentsAndParameters = updateModel.columnMappings() - .map(m -> m.accept(visitor)) - .collect(Collectors.toList()); + .map(m -> m.accept(visitor)) + .toList(); Validator.assertFalse(fragmentsAndParameters.stream().noneMatch(Optional::isPresent), "ERROR.18"); //$NON-NLS-1$ diff --git a/src/main/java/org/mybatis/dynamic/sql/util/SqlProviderAdapter.java b/src/main/java/org/mybatis/dynamic/sql/util/SqlProviderAdapter.java index fafcc6bda..2e129b611 100644 --- a/src/main/java/org/mybatis/dynamic/sql/util/SqlProviderAdapter.java +++ b/src/main/java/org/mybatis/dynamic/sql/util/SqlProviderAdapter.java @@ -17,7 +17,6 @@ import java.util.List; import java.util.Map; -import java.util.stream.Collectors; import org.mybatis.dynamic.sql.delete.render.DeleteStatementProvider; import org.mybatis.dynamic.sql.insert.render.GeneralInsertStatementProvider; @@ -76,7 +75,7 @@ public String insertMultipleWithGeneratedKeys(Map parameterMap) .map(Map.Entry::getValue) .filter(String.class::isInstance) .map(String.class::cast) - .collect(Collectors.toList()); + .toList(); if (entries.size() == 1) { return entries.get(0); diff --git a/src/main/java/org/mybatis/dynamic/sql/util/mybatis3/CommonSelectMapper.java b/src/main/java/org/mybatis/dynamic/sql/util/mybatis3/CommonSelectMapper.java index d7d67edc0..f0cfb72c0 100644 --- a/src/main/java/org/mybatis/dynamic/sql/util/mybatis3/CommonSelectMapper.java +++ b/src/main/java/org/mybatis/dynamic/sql/util/mybatis3/CommonSelectMapper.java @@ -20,7 +20,6 @@ import java.util.Map; import java.util.Optional; import java.util.function.Function; -import java.util.stream.Collectors; import org.apache.ibatis.annotations.SelectProvider; import org.mybatis.dynamic.sql.select.render.SelectStatementProvider; @@ -110,7 +109,7 @@ default List selectMany(SelectStatementProvider selectStatement, Function, R> rowMapper) { return selectManyMappedRows(selectStatement).stream() .map(rowMapper) - .collect(Collectors.toList()); + .toList(); } /** diff --git a/src/main/java/org/mybatis/dynamic/sql/util/spring/BatchInsertUtility.java b/src/main/java/org/mybatis/dynamic/sql/util/spring/BatchInsertUtility.java index 485868ba6..01b76b9a0 100644 --- a/src/main/java/org/mybatis/dynamic/sql/util/spring/BatchInsertUtility.java +++ b/src/main/java/org/mybatis/dynamic/sql/util/spring/BatchInsertUtility.java @@ -16,7 +16,6 @@ package org.mybatis.dynamic.sql.util.spring; import java.util.List; -import java.util.stream.Collectors; import org.springframework.jdbc.core.namedparam.SqlParameterSource; import org.springframework.jdbc.core.namedparam.SqlParameterSourceUtils; @@ -35,7 +34,7 @@ private BatchInsertUtility() {} public static SqlParameterSource[] createBatch(List rows) { List> tt = rows.stream() .map(RowHolder::new) - .collect(Collectors.toList()); + .toList(); return SqlParameterSourceUtils.createBatch(tt); } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java index b123d30c5..3fc3eca6f 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java @@ -21,7 +21,6 @@ import java.util.Objects; import java.util.function.Predicate; import java.util.function.UnaryOperator; -import java.util.stream.Collectors; import org.mybatis.dynamic.sql.AbstractListValueCondition; import org.mybatis.dynamic.sql.util.StringUtilities; @@ -35,7 +34,7 @@ public static IsInCaseInsensitiveWhenPresent empty() { } protected IsInCaseInsensitiveWhenPresent(Collection values) { - super(values.stream().filter(Objects::nonNull).collect(Collectors.toList())); + super(values.stream().filter(Objects::nonNull).toList()); } @Override diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInWhenPresent.java index fc2994ea7..6e12a0437 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInWhenPresent.java @@ -21,7 +21,6 @@ import java.util.Objects; import java.util.function.Function; import java.util.function.Predicate; -import java.util.stream.Collectors; import org.mybatis.dynamic.sql.AbstractListValueCondition; @@ -35,7 +34,7 @@ public static IsInWhenPresent empty() { } protected IsInWhenPresent(Collection values) { - super(values.stream().filter(Objects::nonNull).collect(Collectors.toList())); + super(values.stream().filter(Objects::nonNull).toList()); } @Override diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java index 58f0b347e..543ff7817 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java @@ -21,7 +21,6 @@ import java.util.Objects; import java.util.function.Predicate; import java.util.function.UnaryOperator; -import java.util.stream.Collectors; import org.mybatis.dynamic.sql.AbstractListValueCondition; import org.mybatis.dynamic.sql.util.StringUtilities; @@ -35,7 +34,7 @@ public static IsNotInCaseInsensitiveWhenPresent empty() { } protected IsNotInCaseInsensitiveWhenPresent(Collection values) { - super(values.stream().filter(Objects::nonNull).collect(Collectors.toList())); + super(values.stream().filter(Objects::nonNull).toList()); } @Override diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInWhenPresent.java index 8115413ef..6917128ab 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInWhenPresent.java @@ -21,7 +21,6 @@ import java.util.Objects; import java.util.function.Function; import java.util.function.Predicate; -import java.util.stream.Collectors; import org.mybatis.dynamic.sql.AbstractListValueCondition; @@ -35,7 +34,7 @@ public static IsNotInWhenPresent empty() { } protected IsNotInWhenPresent(Collection values) { - super(values.stream().filter(Objects::nonNull).collect(Collectors.toList())); + super(values.stream().filter(Objects::nonNull).toList()); } @Override diff --git a/src/main/java/org/mybatis/dynamic/sql/where/render/CriterionRenderer.java b/src/main/java/org/mybatis/dynamic/sql/where/render/CriterionRenderer.java index 232b68c11..0e4325179 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/render/CriterionRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/render/CriterionRenderer.java @@ -136,7 +136,7 @@ private FragmentAndParameters renderExists(ExistsCriterion criterion) { private List renderSubCriteria(List subCriteria) { return subCriteria.stream().map(this::renderAndOrCriteriaGroup) .flatMap(Optional::stream) - .collect(Collectors.toList()); + .toList(); } private Optional renderAndOrCriteriaGroup(AndOrCriteriaGroup criterion) { From e83b6f9d0550bff54f8bf2e96424857ddc9d48b6 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Tue, 6 Aug 2024 11:07:02 -0400 Subject: [PATCH 046/289] Coverage --- .../sql/insert/render/BatchInsert.java | 2 +- .../sql/DeprecatedSortMethodsTest.java | 33 ++++++++++++++++++- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/render/BatchInsert.java b/src/main/java/org/mybatis/dynamic/sql/insert/render/BatchInsert.java index cde4ec626..5a3c22893 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/render/BatchInsert.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/render/BatchInsert.java @@ -56,7 +56,7 @@ public String getInsertStatementSQL() { } public List getRecords() { - return Collections.unmodifiableList(records); + return records; } public static Builder withRecords(List records) { diff --git a/src/test/java/org/mybatis/dynamic/sql/DeprecatedSortMethodsTest.java b/src/test/java/org/mybatis/dynamic/sql/DeprecatedSortMethodsTest.java index 678d997d2..520783155 100644 --- a/src/test/java/org/mybatis/dynamic/sql/DeprecatedSortMethodsTest.java +++ b/src/test/java/org/mybatis/dynamic/sql/DeprecatedSortMethodsTest.java @@ -48,12 +48,43 @@ public String orderByName() { @Override public boolean isDescending() { - return true; + return false; } }; OrderByModel model = OrderByModel.of(List.of(ss)); + RenderingContext renderingContext = RenderingContext + .withRenderingStrategy(RenderingStrategies.MYBATIS3) + .withTableAliasCalculator(TableAliasCalculator.empty()) + .withStatementConfiguration(new StatementConfiguration()) + .build(); + OrderByRenderer renderer = new OrderByRenderer(renderingContext); + FragmentAndParameters fp = renderer.render(model); + assertThat(fp.fragment()).isEqualTo("order by id"); + } + + @Test + void bothMethodsExistDescending() { + SortSpecification ss = new SortSpecification() { + @Override + public SortSpecification descending() { + return this; + } + + @Override + public String orderByName() { + return "id"; + } + + @Override + public boolean isDescending() { + return true; + } + }; + + OrderByModel model = OrderByModel.of(List.of(ss)); + RenderingContext renderingContext = RenderingContext .withRenderingStrategy(RenderingStrategies.MYBATIS3) .withTableAliasCalculator(TableAliasCalculator.empty()) From 8b645112a8cc500573f1dc997efcbd2a4fdf2e66 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Tue, 6 Aug 2024 11:24:26 -0400 Subject: [PATCH 047/289] Checkstyle and PMD Updates --- .../java/org/mybatis/dynamic/sql/SortSpecification.java | 4 ++-- .../java/org/mybatis/dynamic/sql/insert/BatchInsertDSL.java | 2 +- .../org/mybatis/dynamic/sql/insert/MultiRowInsertDSL.java | 2 +- .../org/mybatis/dynamic/sql/util/FragmentAndParameters.java | 2 +- .../sql/where/condition/IsInCaseInsensitiveWhenPresent.java | 6 ++++-- .../where/condition/IsNotInCaseInsensitiveWhenPresent.java | 6 ++++-- 6 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/SortSpecification.java b/src/main/java/org/mybatis/dynamic/sql/SortSpecification.java index 87b986d27..48aee58c4 100644 --- a/src/main/java/org/mybatis/dynamic/sql/SortSpecification.java +++ b/src/main/java/org/mybatis/dynamic/sql/SortSpecification.java @@ -40,7 +40,7 @@ public interface SortSpecification { * * @return the order by phrase * @deprecated Please replace this method by overriding the more general "renderForOrderBy" method. Target for - * removal in release 2.1 + * removal in release 2.1 */ @Deprecated(since = "2.0", forRemoval = true) default String orderByName() { @@ -52,7 +52,7 @@ default String orderByName() { * * @return true if the SortSpecification should render as descending * @deprecated Please replace this method by overriding the more general "renderForOrderBy" method. Target for - * removal in release 2.1 + * removal in release 2.1 */ @Deprecated(since = "2.0", forRemoval = true) default boolean isDescending() { diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/BatchInsertDSL.java b/src/main/java/org/mybatis/dynamic/sql/insert/BatchInsertDSL.java index 9b5f69cec..104557a4c 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/BatchInsertDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/BatchInsertDSL.java @@ -59,7 +59,7 @@ public BatchInsertModel build() { @SafeVarargs public static IntoGatherer insert(T... records) { - return BatchInsertDSL.insert(Arrays.asList(records)); + return insert(Arrays.asList(records)); } public static IntoGatherer insert(Collection records) { diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/MultiRowInsertDSL.java b/src/main/java/org/mybatis/dynamic/sql/insert/MultiRowInsertDSL.java index 1b8feaca3..6976dabc9 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/MultiRowInsertDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/MultiRowInsertDSL.java @@ -58,7 +58,7 @@ public MultiRowInsertModel build() { @SafeVarargs public static IntoGatherer insert(T... records) { - return MultiRowInsertDSL.insert(Arrays.asList(records)); + return insert(Arrays.asList(records)); } public static IntoGatherer insert(Collection records) { diff --git a/src/main/java/org/mybatis/dynamic/sql/util/FragmentAndParameters.java b/src/main/java/org/mybatis/dynamic/sql/util/FragmentAndParameters.java index c6b65b3b0..4c240120c 100644 --- a/src/main/java/org/mybatis/dynamic/sql/util/FragmentAndParameters.java +++ b/src/main/java/org/mybatis/dynamic/sql/util/FragmentAndParameters.java @@ -46,7 +46,7 @@ public Map parameters() { * @return a new instance with the same parameters and a transformed fragment */ public FragmentAndParameters mapFragment(UnaryOperator mapper) { - return FragmentAndParameters.withFragment(mapper.apply(fragment)) + return withFragment(mapper.apply(fragment)) .withParameters(parameters) .build(); } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java index 3fc3eca6f..356fb034a 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java @@ -27,7 +27,8 @@ public class IsInCaseInsensitiveWhenPresent extends AbstractListValueCondition implements CaseInsensitiveVisitableCondition { - private static final IsInCaseInsensitiveWhenPresent EMPTY = new IsInCaseInsensitiveWhenPresent(Collections.emptyList()); + private static final IsInCaseInsensitiveWhenPresent EMPTY = + new IsInCaseInsensitiveWhenPresent(Collections.emptyList()); public static IsInCaseInsensitiveWhenPresent empty() { return EMPTY; @@ -44,7 +45,8 @@ public String operator() { @Override public IsInCaseInsensitiveWhenPresent filter(Predicate predicate) { - return filterSupport(predicate, IsInCaseInsensitiveWhenPresent::new, this, IsInCaseInsensitiveWhenPresent::empty); + return filterSupport(predicate, IsInCaseInsensitiveWhenPresent::new, this, + IsInCaseInsensitiveWhenPresent::empty); } /** diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java index 543ff7817..7f254eedd 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java @@ -27,7 +27,8 @@ public class IsNotInCaseInsensitiveWhenPresent extends AbstractListValueCondition implements CaseInsensitiveVisitableCondition { - private static final IsNotInCaseInsensitiveWhenPresent EMPTY = new IsNotInCaseInsensitiveWhenPresent(Collections.emptyList()); + private static final IsNotInCaseInsensitiveWhenPresent EMPTY = + new IsNotInCaseInsensitiveWhenPresent(Collections.emptyList()); public static IsNotInCaseInsensitiveWhenPresent empty() { return EMPTY; @@ -44,7 +45,8 @@ public String operator() { @Override public IsNotInCaseInsensitiveWhenPresent filter(Predicate predicate) { - return filterSupport(predicate, IsNotInCaseInsensitiveWhenPresent::new, this, IsNotInCaseInsensitiveWhenPresent::empty); + return filterSupport(predicate, IsNotInCaseInsensitiveWhenPresent::new, + this, IsNotInCaseInsensitiveWhenPresent::empty); } /** From 1d2dc669b0092896058efbf2a38c61b54f585aeb Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Tue, 6 Aug 2024 11:40:51 -0400 Subject: [PATCH 048/289] CPD Fixes --- .../java/org/mybatis/dynamic/sql/insert/BatchInsertDSL.java | 4 ++-- .../org/mybatis/dynamic/sql/insert/MultiRowInsertDSL.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/BatchInsertDSL.java b/src/main/java/org/mybatis/dynamic/sql/insert/BatchInsertDSL.java index 104557a4c..ba912e5a6 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/BatchInsertDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/BatchInsertDSL.java @@ -58,11 +58,11 @@ public BatchInsertModel build() { } @SafeVarargs - public static IntoGatherer insert(T... records) { + public static BatchInsertDSL.IntoGatherer insert(T... records) { return insert(Arrays.asList(records)); } - public static IntoGatherer insert(Collection records) { + public static BatchInsertDSL.IntoGatherer insert(Collection records) { return new IntoGatherer<>(records); } diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/MultiRowInsertDSL.java b/src/main/java/org/mybatis/dynamic/sql/insert/MultiRowInsertDSL.java index 6976dabc9..7c0530a2a 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/MultiRowInsertDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/MultiRowInsertDSL.java @@ -57,11 +57,11 @@ public MultiRowInsertModel build() { } @SafeVarargs - public static IntoGatherer insert(T... records) { + public static MultiRowInsertDSL.IntoGatherer insert(T... records) { return insert(Arrays.asList(records)); } - public static IntoGatherer insert(Collection records) { + public static MultiRowInsertDSL.IntoGatherer insert(Collection records) { return new IntoGatherer<>(records); } From 4b89c48e6e08636f866e531ed7ff517a2c901c65 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Tue, 6 Aug 2024 12:53:03 -0400 Subject: [PATCH 049/289] Don't need Hamcrest anymore --- pom.xml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/pom.xml b/pom.xml index 5d5447a8f..d2ce1ecdd 100644 --- a/pom.xml +++ b/pom.xml @@ -164,14 +164,6 @@ 1.5.6 test - - - org.hamcrest - hamcrest - 3.0 - test - - org.testcontainers postgresql From dca5d3dadc52b5d22d195a35dba3a1001f44e54d Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Tue, 6 Aug 2024 14:48:07 -0400 Subject: [PATCH 050/289] Docs --- CHANGELOG.md | 1 + src/site/markdown/docs/caseExpressions.md | 4 ++-- src/site/markdown/docs/kotlinCaseExpressions.md | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 31e9fa8b3..3323eafdb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ Significant changes: - The library now requires Java 17 - Deprecated code from prior releases is removed +- Allow CASE expressions in ORDER BY Clauses ## Release 1.5.2 - June 3, 2024 diff --git a/src/site/markdown/docs/caseExpressions.md b/src/site/markdown/docs/caseExpressions.md index 9b83d4f3e..3f711e626 100644 --- a/src/site/markdown/docs/caseExpressions.md +++ b/src/site/markdown/docs/caseExpressions.md @@ -3,9 +3,9 @@ Support for case expressions was added in version 1.5.1. For information about case expressions in the Kotlin DSL, see the [Kotlin Case Expressions](kotlinCaseExpressions.md) page. -## Case Statements in SQL +## Case Expressions in SQL The library supports different types of case expressions - a "simple" case expression, and a "searched" case -expressions. +expressions. Case expressions can be used in many places including select lists, order by phrases, etc. A simple case expression checks the values of a single column. It looks like this: diff --git a/src/site/markdown/docs/kotlinCaseExpressions.md b/src/site/markdown/docs/kotlinCaseExpressions.md index 5366db40b..d0fdb4b4d 100644 --- a/src/site/markdown/docs/kotlinCaseExpressions.md +++ b/src/site/markdown/docs/kotlinCaseExpressions.md @@ -3,9 +3,9 @@ Support for case expressions was added in version 1.5.1. For information about case expressions in the Java DSL, see the [Java Case Expressions](caseExpressions.md) page. -## Case Statements in SQL +## Case Expressions in SQL The library supports different types of case expressions - a "simple" case expression, and a "searched" case -expressions. +expressions. Case expressions can be used in many places including select lists, order by phrases, etc. A simple case expression checks the values of a single column. It looks like this: From b938d32d6838c8e8a45ce055ed21058d75d59d4d Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Tue, 6 Aug 2024 15:28:31 -0400 Subject: [PATCH 051/289] Update Kotlin compiler settings for JVM 17 --- pom.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 94348cd05..ff30de791 100644 --- a/pom.xml +++ b/pom.xml @@ -68,7 +68,9 @@ org.mybatis.dynamic.sql 2.0.10 - 1.8 + 17 + 2.0 + 2.0 pom.xml,src/main/java,src/main/kotlin src/test/java,src/test/kotlin From 42646b53469ec8adff0c5b71d7d15b0bbb83087c Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Tue, 6 Aug 2024 17:53:37 -0400 Subject: [PATCH 052/289] Refactor column hierarchy so we can build un-typed functions --- .../org/mybatis/dynamic/sql/BasicColumn.java | 14 +++++ .../mybatis/dynamic/sql/BindableColumn.java | 19 +------ .../org/mybatis/dynamic/sql/SqlBuilder.java | 4 ++ .../dynamic/sql/select/aggregate/Avg.java | 3 +- .../dynamic/sql/select/aggregate/Max.java | 3 +- .../dynamic/sql/select/aggregate/Min.java | 3 +- .../dynamic/sql/select/aggregate/Sum.java | 9 +++- .../AbstractTypeConvertingFunction.java | 5 +- .../function/AbstractUniTypeFunction.java | 4 +- .../dynamic/sql/select/function/Add.java | 2 +- .../dynamic/sql/select/function/Concat.java | 2 +- .../sql/select/function/Concatenate.java | 2 +- .../dynamic/sql/select/function/Divide.java | 2 +- .../dynamic/sql/select/function/Lower.java | 3 +- .../dynamic/sql/select/function/Multiply.java | 2 +- .../sql/select/function/OperatorFunction.java | 6 +-- .../sql/select/function/Substring.java | 3 +- .../dynamic/sql/select/function/Subtract.java | 2 +- .../dynamic/sql/select/function/Upper.java | 3 +- .../sql/util/kotlin/elements/SqlElements.kt | 2 + .../java/examples/animal/data/Length.java | 7 ++- .../examples/type_conversion/ToBase64.java | 3 +- .../mybatis3/canonical/PersonMapperTest.kt | 51 +++++++++++++++++++ 23 files changed, 110 insertions(+), 44 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/BasicColumn.java b/src/main/java/org/mybatis/dynamic/sql/BasicColumn.java index b73757a71..a583ba4ff 100644 --- a/src/main/java/org/mybatis/dynamic/sql/BasicColumn.java +++ b/src/main/java/org/mybatis/dynamic/sql/BasicColumn.java @@ -15,9 +15,11 @@ */ package org.mybatis.dynamic.sql; +import java.sql.JDBCType; import java.util.Optional; import org.mybatis.dynamic.sql.render.RenderingContext; +import org.mybatis.dynamic.sql.render.RenderingStrategy; import org.mybatis.dynamic.sql.util.FragmentAndParameters; /** @@ -58,6 +60,18 @@ public interface BasicColumn { */ FragmentAndParameters render(RenderingContext renderingContext); + default Optional jdbcType() { + return Optional.empty(); + } + + default Optional typeHandler() { + return Optional.empty(); + } + + default Optional renderingStrategy() { + return Optional.empty(); + } + /** * Utility method to make it easier to build column lists for methods that require an * array rather than the varargs method. diff --git a/src/main/java/org/mybatis/dynamic/sql/BindableColumn.java b/src/main/java/org/mybatis/dynamic/sql/BindableColumn.java index 274b52e25..77e6e5bc1 100644 --- a/src/main/java/org/mybatis/dynamic/sql/BindableColumn.java +++ b/src/main/java/org/mybatis/dynamic/sql/BindableColumn.java @@ -15,14 +15,11 @@ */ package org.mybatis.dynamic.sql; -import java.sql.JDBCType; import java.util.Optional; -import org.mybatis.dynamic.sql.render.RenderingStrategy; - /** - * Describes additional attributes of columns that are necessary for binding the column as a JDBC parameter. - * Columns in where clauses are typically bound. + * Describes a column with a known data type. The type is only used by the compiler to assure type safety + * when building clauses with conditions. * * @author Jeff Butler * @@ -37,18 +34,6 @@ public interface BindableColumn extends BasicColumn { @Override BindableColumn as(String alias); - default Optional jdbcType() { - return Optional.empty(); - } - - default Optional typeHandler() { - return Optional.empty(); - } - - default Optional renderingStrategy() { - return Optional.empty(); - } - default Object convertParameterType(T value) { return value; } diff --git a/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java b/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java index 6516696f6..df4292653 100644 --- a/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java +++ b/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java @@ -497,6 +497,10 @@ static Sum sum(BindableColumn column) { return Sum.of(column); } + static Sum sum(BasicColumn column) { + return Sum.of(column); + } + static Sum sum(BindableColumn column, VisitableCondition condition) { return Sum.of(column, condition); } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/aggregate/Avg.java b/src/main/java/org/mybatis/dynamic/sql/select/aggregate/Avg.java index 5130abf7c..6fcb1f3b5 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/aggregate/Avg.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/aggregate/Avg.java @@ -15,6 +15,7 @@ */ package org.mybatis.dynamic.sql.select.aggregate; +import org.mybatis.dynamic.sql.BasicColumn; import org.mybatis.dynamic.sql.BindableColumn; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.select.function.AbstractUniTypeFunction; @@ -22,7 +23,7 @@ public class Avg extends AbstractUniTypeFunction> { - private Avg(BindableColumn column) { + private Avg(BasicColumn column) { super(column); } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/aggregate/Max.java b/src/main/java/org/mybatis/dynamic/sql/select/aggregate/Max.java index f44225f12..2e3e0fec0 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/aggregate/Max.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/aggregate/Max.java @@ -15,6 +15,7 @@ */ package org.mybatis.dynamic.sql.select.aggregate; +import org.mybatis.dynamic.sql.BasicColumn; import org.mybatis.dynamic.sql.BindableColumn; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.select.function.AbstractUniTypeFunction; @@ -22,7 +23,7 @@ public class Max extends AbstractUniTypeFunction> { - private Max(BindableColumn column) { + private Max(BasicColumn column) { super(column); } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/aggregate/Min.java b/src/main/java/org/mybatis/dynamic/sql/select/aggregate/Min.java index 02830335c..b376d00a2 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/aggregate/Min.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/aggregate/Min.java @@ -15,6 +15,7 @@ */ package org.mybatis.dynamic.sql.select.aggregate; +import org.mybatis.dynamic.sql.BasicColumn; import org.mybatis.dynamic.sql.BindableColumn; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.select.function.AbstractUniTypeFunction; @@ -22,7 +23,7 @@ public class Min extends AbstractUniTypeFunction> { - private Min(BindableColumn column) { + private Min(BasicColumn column) { super(column); } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/aggregate/Sum.java b/src/main/java/org/mybatis/dynamic/sql/select/aggregate/Sum.java index 02c8c7a42..e86a0d5b4 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/aggregate/Sum.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/aggregate/Sum.java @@ -17,6 +17,7 @@ import java.util.function.Function; +import org.mybatis.dynamic.sql.BasicColumn; import org.mybatis.dynamic.sql.BindableColumn; import org.mybatis.dynamic.sql.VisitableCondition; import org.mybatis.dynamic.sql.render.RenderingContext; @@ -28,7 +29,7 @@ public class Sum extends AbstractUniTypeFunction> { private final Function renderer; - private Sum(BindableColumn column) { + private Sum(BasicColumn column) { super(column); renderer = rc -> column.render(rc).mapFragment(this::applyAggregate); } @@ -48,7 +49,7 @@ private Sum(BindableColumn column, VisitableCondition condition) { }; } - private Sum(BindableColumn column, Function renderer) { + private Sum(BasicColumn column, Function renderer) { super(column); this.renderer = renderer; } @@ -71,6 +72,10 @@ public static Sum of(BindableColumn column) { return new Sum<>(column); } + public static Sum of(BasicColumn column) { + return new Sum<>(column); + } + public static Sum of(BindableColumn column, VisitableCondition condition) { return new Sum<>(column, condition); } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/function/AbstractTypeConvertingFunction.java b/src/main/java/org/mybatis/dynamic/sql/select/function/AbstractTypeConvertingFunction.java index cab8aff39..98e019fa7 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/function/AbstractTypeConvertingFunction.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/function/AbstractTypeConvertingFunction.java @@ -18,6 +18,7 @@ import java.util.Objects; import java.util.Optional; +import org.mybatis.dynamic.sql.BasicColumn; import org.mybatis.dynamic.sql.BindableColumn; /** @@ -36,10 +37,10 @@ */ public abstract class AbstractTypeConvertingFunction> implements BindableColumn { - protected final BindableColumn column; + protected final BasicColumn column; protected String alias; - protected AbstractTypeConvertingFunction(BindableColumn column) { + protected AbstractTypeConvertingFunction(BasicColumn column) { this.column = Objects.requireNonNull(column); } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/function/AbstractUniTypeFunction.java b/src/main/java/org/mybatis/dynamic/sql/select/function/AbstractUniTypeFunction.java index 7a0690bae..6e59885cb 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/function/AbstractUniTypeFunction.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/function/AbstractUniTypeFunction.java @@ -18,7 +18,7 @@ import java.sql.JDBCType; import java.util.Optional; -import org.mybatis.dynamic.sql.BindableColumn; +import org.mybatis.dynamic.sql.BasicColumn; /** * Represents a function that does not change the underlying data type. @@ -33,7 +33,7 @@ public abstract class AbstractUniTypeFunction> extends AbstractTypeConvertingFunction { - protected AbstractUniTypeFunction(BindableColumn column) { + protected AbstractUniTypeFunction(BasicColumn column) { super(column); } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/function/Add.java b/src/main/java/org/mybatis/dynamic/sql/select/function/Add.java index fe0661bea..533f5cc15 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/function/Add.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/function/Add.java @@ -23,7 +23,7 @@ public class Add extends OperatorFunction { - private Add(BindableColumn firstColumn, BasicColumn secondColumn, + private Add(BasicColumn firstColumn, BasicColumn secondColumn, List subsequentColumns) { super("+", firstColumn, secondColumn, subsequentColumns); //$NON-NLS-1$ } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/function/Concat.java b/src/main/java/org/mybatis/dynamic/sql/select/function/Concat.java index e633b2953..ec1c7f93e 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/function/Concat.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/function/Concat.java @@ -29,7 +29,7 @@ public class Concat extends AbstractUniTypeFunction> { private final List allColumns = new ArrayList<>(); - protected Concat(BindableColumn firstColumn, List subsequentColumns) { + protected Concat(BasicColumn firstColumn, List subsequentColumns) { super(firstColumn); allColumns.add(firstColumn); this.allColumns.addAll(subsequentColumns); diff --git a/src/main/java/org/mybatis/dynamic/sql/select/function/Concatenate.java b/src/main/java/org/mybatis/dynamic/sql/select/function/Concatenate.java index 3179f2a1d..fa16f4a43 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/function/Concatenate.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/function/Concatenate.java @@ -23,7 +23,7 @@ public class Concatenate extends OperatorFunction { - protected Concatenate(BindableColumn firstColumn, BasicColumn secondColumn, + protected Concatenate(BasicColumn firstColumn, BasicColumn secondColumn, List subsequentColumns) { super("||", firstColumn, secondColumn, subsequentColumns); //$NON-NLS-1$ } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/function/Divide.java b/src/main/java/org/mybatis/dynamic/sql/select/function/Divide.java index 24d2832ca..76d804707 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/function/Divide.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/function/Divide.java @@ -23,7 +23,7 @@ public class Divide extends OperatorFunction { - private Divide(BindableColumn firstColumn, BasicColumn secondColumn, + private Divide(BasicColumn firstColumn, BasicColumn secondColumn, List subsequentColumns) { super("/", firstColumn, secondColumn, subsequentColumns); //$NON-NLS-1$ } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/function/Lower.java b/src/main/java/org/mybatis/dynamic/sql/select/function/Lower.java index e59d04712..6bed396c0 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/function/Lower.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/function/Lower.java @@ -15,13 +15,14 @@ */ package org.mybatis.dynamic.sql.select.function; +import org.mybatis.dynamic.sql.BasicColumn; import org.mybatis.dynamic.sql.BindableColumn; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.util.FragmentAndParameters; public class Lower extends AbstractUniTypeFunction> { - private Lower(BindableColumn column) { + private Lower(BasicColumn column) { super(column); } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/function/Multiply.java b/src/main/java/org/mybatis/dynamic/sql/select/function/Multiply.java index 50d38b966..de359e09c 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/function/Multiply.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/function/Multiply.java @@ -23,7 +23,7 @@ public class Multiply extends OperatorFunction { - private Multiply(BindableColumn firstColumn, BasicColumn secondColumn, + private Multiply(BasicColumn firstColumn, BasicColumn secondColumn, List subsequentColumns) { super("*", firstColumn, secondColumn, subsequentColumns); //$NON-NLS-1$ } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/function/OperatorFunction.java b/src/main/java/org/mybatis/dynamic/sql/select/function/OperatorFunction.java index 7ce5c5c25..7c9a89316 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/function/OperatorFunction.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/function/OperatorFunction.java @@ -35,7 +35,7 @@ public class OperatorFunction extends AbstractUniTypeFunction subsequentColumns = new ArrayList<>(); private final String operator; - protected OperatorFunction(String operator, BindableColumn firstColumn, BasicColumn secondColumn, + protected OperatorFunction(String operator, BasicColumn firstColumn, BasicColumn secondColumn, List subsequentColumns) { super(firstColumn); this.secondColumn = Objects.requireNonNull(secondColumn); @@ -52,9 +52,7 @@ protected OperatorFunction copy() { public FragmentAndParameters render(RenderingContext renderingContext) { String paddedOperator = " " + operator + " "; //$NON-NLS-1$ //$NON-NLS-2$ - // note - the cast below is added for type inference issues in some compilers - return Stream.of(Stream.of((BasicColumn) column), - Stream.of(secondColumn), subsequentColumns.stream()) + return Stream.of(Stream.of(column, secondColumn), subsequentColumns.stream()) .flatMap(Function.identity()) .map(column -> column.render(renderingContext)) .collect(FragmentCollector.collect()) diff --git a/src/main/java/org/mybatis/dynamic/sql/select/function/Substring.java b/src/main/java/org/mybatis/dynamic/sql/select/function/Substring.java index 81b95ea5c..d49263977 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/function/Substring.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/function/Substring.java @@ -15,6 +15,7 @@ */ package org.mybatis.dynamic.sql.select.function; +import org.mybatis.dynamic.sql.BasicColumn; import org.mybatis.dynamic.sql.BindableColumn; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.util.FragmentAndParameters; @@ -24,7 +25,7 @@ public class Substring extends AbstractUniTypeFunction> { private final int offset; private final int length; - private Substring(BindableColumn column, int offset, int length) { + private Substring(BasicColumn column, int offset, int length) { super(column); this.offset = offset; this.length = length; diff --git a/src/main/java/org/mybatis/dynamic/sql/select/function/Subtract.java b/src/main/java/org/mybatis/dynamic/sql/select/function/Subtract.java index 94e7e3c81..8f011e902 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/function/Subtract.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/function/Subtract.java @@ -23,7 +23,7 @@ public class Subtract extends OperatorFunction { - private Subtract(BindableColumn firstColumn, BasicColumn secondColumn, + private Subtract(BasicColumn firstColumn, BasicColumn secondColumn, List subsequentColumns) { super("-", firstColumn, secondColumn, subsequentColumns); //$NON-NLS-1$ } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/function/Upper.java b/src/main/java/org/mybatis/dynamic/sql/select/function/Upper.java index 2891032df..a62e5d655 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/function/Upper.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/function/Upper.java @@ -15,13 +15,14 @@ */ package org.mybatis.dynamic.sql.select.function; +import org.mybatis.dynamic.sql.BasicColumn; import org.mybatis.dynamic.sql.BindableColumn; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.util.FragmentAndParameters; public class Upper extends AbstractUniTypeFunction> { - private Upper(BindableColumn column) { + private Upper(BasicColumn column) { super(column); } diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/SqlElements.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/SqlElements.kt index 2d9f1e8a1..8a249279a 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/SqlElements.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/SqlElements.kt @@ -137,6 +137,8 @@ fun avg(column: BindableColumn): Avg = SqlBuilder.avg(column) fun sum(column: BindableColumn): Sum = SqlBuilder.sum(column) +fun sum(column: BasicColumn): Sum<*> = SqlBuilder.sum(column) + fun sum(column: BindableColumn, condition: VisitableCondition): Sum = SqlBuilder.sum(column, condition) // constants diff --git a/src/test/java/examples/animal/data/Length.java b/src/test/java/examples/animal/data/Length.java index cf779c15e..6fb90e40d 100644 --- a/src/test/java/examples/animal/data/Length.java +++ b/src/test/java/examples/animal/data/Length.java @@ -18,13 +18,14 @@ import java.sql.JDBCType; import java.util.Optional; +import org.mybatis.dynamic.sql.BasicColumn; import org.mybatis.dynamic.sql.BindableColumn; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.select.function.AbstractTypeConvertingFunction; import org.mybatis.dynamic.sql.util.FragmentAndParameters; public class Length extends AbstractTypeConvertingFunction { - private Length(BindableColumn column) { + private Length(BasicColumn column) { super(column); } @@ -48,8 +49,6 @@ protected Length copy() { } public static Length length(BindableColumn column) { - @SuppressWarnings("unchecked") - BindableColumn c = (BindableColumn) column; - return new Length(c); + return new Length(column); } } diff --git a/src/test/java/examples/type_conversion/ToBase64.java b/src/test/java/examples/type_conversion/ToBase64.java index 97d8ad097..ce5ab5891 100644 --- a/src/test/java/examples/type_conversion/ToBase64.java +++ b/src/test/java/examples/type_conversion/ToBase64.java @@ -18,6 +18,7 @@ import java.sql.JDBCType; import java.util.Optional; +import org.mybatis.dynamic.sql.BasicColumn; import org.mybatis.dynamic.sql.BindableColumn; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.select.function.AbstractTypeConvertingFunction; @@ -25,7 +26,7 @@ public class ToBase64 extends AbstractTypeConvertingFunction { - protected ToBase64(BindableColumn column) { + protected ToBase64(BasicColumn column) { super(column); } diff --git a/src/test/kotlin/examples/kotlin/mybatis3/canonical/PersonMapperTest.kt b/src/test/kotlin/examples/kotlin/mybatis3/canonical/PersonMapperTest.kt index 5dc24ede2..75a703c09 100644 --- a/src/test/kotlin/examples/kotlin/mybatis3/canonical/PersonMapperTest.kt +++ b/src/test/kotlin/examples/kotlin/mybatis3/canonical/PersonMapperTest.kt @@ -35,13 +35,18 @@ import org.junit.jupiter.api.TestInstance import org.junit.jupiter.api.TestInstance.Lifecycle import org.mybatis.dynamic.sql.exception.NonRenderingWhereClauseException import org.mybatis.dynamic.sql.util.kotlin.elements.add +import org.mybatis.dynamic.sql.util.kotlin.elements.case +import org.mybatis.dynamic.sql.util.kotlin.elements.concat import org.mybatis.dynamic.sql.util.kotlin.elements.constant import org.mybatis.dynamic.sql.util.kotlin.elements.isIn import org.mybatis.dynamic.sql.util.kotlin.elements.sortColumn +import org.mybatis.dynamic.sql.util.kotlin.elements.stringConstant +import org.mybatis.dynamic.sql.util.kotlin.elements.sum import org.mybatis.dynamic.sql.util.kotlin.mybatis3.insertInto import org.mybatis.dynamic.sql.util.kotlin.mybatis3.insertSelect import org.mybatis.dynamic.sql.util.kotlin.mybatis3.multiSelect import org.mybatis.dynamic.sql.util.kotlin.mybatis3.select +import org.mybatis.dynamic.sql.util.mybatis3.CommonSelectMapper import java.util.* @TestInstance(Lifecycle.PER_CLASS) @@ -55,6 +60,7 @@ class PersonMapperTest { withMapper(PersonMapper::class) withMapper(PersonWithAddressMapper::class) withMapper(AddressMapper::class) + withMapper(CommonSelectMapper::class) withTypeHandler(YesNoTypeHandler::class) } } @@ -917,4 +923,49 @@ class PersonMapperTest { "where id in ()" assertThat(selectStatement.selectStatement).isEqualTo(expected) } + + @Test + fun testSumWithCase() { + sqlSessionFactory.openSession().use { session -> + val mapper = session.getMapper(CommonSelectMapper::class.java) + + val selectStatement = select(id, sum(case { + `when` { + id isEqualTo 1 + then(101) + } + `else`(999) + }).`as`("fred")) { + from(person) + groupBy(id) + } + + val expected = + "select id, sum(case when id = #{parameters.p1,jdbcType=INTEGER} then 101 else 999 end) as fred from Person group by id" + assertThat(selectStatement.selectStatement).isEqualTo(expected) + + val rows = mapper.selectManyMappedRows(selectStatement) + assertThat(rows).hasSize(6) + } + } + + @Test + fun testConcat() { + sqlSessionFactory.openSession().use { session -> + val mapper = session.getMapper(CommonSelectMapper::class.java) + + val selectStatement = select(id, concat(firstName, stringConstant(" "), lastName).`as`("fullname")) { + from(person) + where { concat(firstName, stringConstant(" "), lastName) isEqualTo "Fred Flintstone" } + } + + val expected = + "select id, concat(first_name, ' ', last_name) as fullname from Person " + + "where concat(first_name, ' ', last_name) = #{parameters.p1,jdbcType=VARCHAR}" + assertThat(selectStatement.selectStatement).isEqualTo(expected) + + val rows = mapper.selectManyMappedRows(selectStatement) + assertThat(rows).hasSize(1) + } + } } From a7663060c6b180b9eab9b374ddee73e0caf6ef7c Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Wed, 7 Aug 2024 11:59:55 -0400 Subject: [PATCH 053/289] Docs --- CHANGELOG.md | 16 ++++++++++++++- src/site/markdown/docs/extending.md | 30 ++++++++++++++++++++--------- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3323eafdb..dddb1c222 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,21 @@ This log will detail notable changes to MyBatis Dynamic SQL. Full details are av ## Release 2.0.0 - Unreleased -Significant changes: +Release 2.0.0 is a significant milestone for the library. We have moved to Java 17 as the minimum version supported. If +you are unable to move to this version of Java then the releases in the 1.x line can be used with Java 8. + +In addition, we have taken the opportunity to make changes to the library that may break existing code. We have +worked to make these changes as minimal as possible. + +**Potentially Breaking Changes:** + +- If you have implemented any custom functions, you will likely need to make changes. The supplied base classes now + hold an instance of `BasicColumn` rather than `BindableColumn`. This change was made to make the functions more + useful in variety of circumstances. If you follow the patterns shown on the + [Extending the Library](https://mybatis.org/mybatis-dynamic-sql/docs/extending.html) page, the change should be as + minimal as changing the private constructor to accept `BasicColumn` rather than `BindableColumn`. + +Other important changes: - The library now requires Java 17 - Deprecated code from prior releases is removed diff --git a/src/site/markdown/docs/extending.md b/src/site/markdown/docs/extending.md index ae04f434a..a32dea137 100644 --- a/src/site/markdown/docs/extending.md +++ b/src/site/markdown/docs/extending.md @@ -11,10 +11,10 @@ The SELECT support is the most complex part of the library, and also the part of extended. There are two main interfaces involved with extending the SELECT support. Picking which interface to implement is dependent on how you want to use your extension. -| Interface | Purpose | -|------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------| -| `org.mybatis.dynamic.sql.BasicColumn` | Use this interface if you want to add capabilities to a SELECT list or a GROUP BY expression. For example, using a database function. | -| `org.mybatis.dynamic.sql.BindableColumn` | Use this interface if you want to add capabilities to a WHERE clause. For example, creating a custom condition. | +| Interface | Purpose | +|------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `org.mybatis.dynamic.sql.BasicColumn` | Use this interface if you want to add capabilities to a SELECT list, a GROUP BY, or an ORDER BY expression. For example, using a database function. | +| `org.mybatis.dynamic.sql.BindableColumn` | Use this interface if you want to add capabilities to a WHERE clause in addition to the capabilities of `BasicColumn`. For example, creating a custom condition. | Rendering is the process of generating an appropriate SQL fragment to implement the function or calculated column. The library will call a method `render(RenderingContext)` in your implementation. This method should return an @@ -101,6 +101,7 @@ the function changes the data type from `byte[]` to `String`. import java.sql.JDBCType; import java.util.Optional; +import org.mybatis.dynamic.sql.BasicColumn; import org.mybatis.dynamic.sql.BindableColumn; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.select.function.AbstractTypeConvertingFunction; @@ -108,7 +109,7 @@ import org.mybatis.dynamic.sql.util.FragmentAndParameters; public class ToBase64 extends AbstractTypeConvertingFunction { - protected ToBase64(BindableColumn column) { + private ToBase64(BasicColumn column) { super(column); } @@ -143,13 +144,15 @@ public class ToBase64 extends AbstractTypeConvertingFunction { - private Upper(BindableColumn column) { + private Upper(BasicColumn column) { super(column); } @@ -178,19 +181,21 @@ Note that `FragmentAndParameters` has a utility method that can simplify the imp add any new parameters to the resulting fragment. For example, the UPPER function can be simplified as follows: ```java +import org.mybatis.dynamic.sql.BasicColumn; +import org.mybatis.dynamic.sql.BindableColumn; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.select.function.AbstractUniTypeFunction; import org.mybatis.dynamic.sql.util.FragmentAndParameters; public class Upper extends AbstractUniTypeFunction { - private Upper(BindableColumn column) { + private Upper(BasicColumn column) { super(column); } @Override public FragmentAndParameters render(RenderingContext renderingContext) { - return = column.render(renderingContext).mapFragment(f -> "upper(" + f + ")"); //$NON-NLS-1$ //$NON-NLS-2$ + return column.render(renderingContext).mapFragment(f -> "upper(" + f + ")"); //$NON-NLS-1$ //$NON-NLS-2$ } @Override @@ -211,9 +216,16 @@ The following function implements the concatenate operator. Note that the operat arbitrary length: ```java +import java.util.Arrays; +import java.util.List; + +import org.mybatis.dynamic.sql.BasicColumn; +import org.mybatis.dynamic.sql.BindableColumn; +import org.mybatis.dynamic.sql.select.function.OperatorFunction; + public class Concatenate extends OperatorFunction { - protected Concatenate(BindableColumn firstColumn, BasicColumn secondColumn, + protected Concatenate(BasicColumn firstColumn, BasicColumn secondColumn, List subsequentColumns) { super("||", firstColumn, secondColumn, subsequentColumns); //$NON-NLS-1$ } From 406220c18530511337225813ef24abc83a5bb2f5 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Wed, 7 Aug 2024 15:07:35 -0400 Subject: [PATCH 054/289] Docs --- CHANGELOG.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dddb1c222..9f3da4db9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,14 +15,14 @@ worked to make these changes as minimal as possible. - If you have implemented any custom functions, you will likely need to make changes. The supplied base classes now hold an instance of `BasicColumn` rather than `BindableColumn`. This change was made to make the functions more useful in variety of circumstances. If you follow the patterns shown on the - [Extending the Library](https://mybatis.org/mybatis-dynamic-sql/docs/extending.html) page, the change should be as - minimal as changing the private constructor to accept `BasicColumn` rather than `BindableColumn`. + [Extending the Library](https://mybatis.org/mybatis-dynamic-sql/docs/extending.html) page, the change should be + limited to changing the private constructor to accept `BasicColumn` rather than `BindableColumn`. Other important changes: - The library now requires Java 17 - Deprecated code from prior releases is removed -- Allow CASE expressions in ORDER BY Clauses +- We now allow CASE expressions in ORDER BY Clauses ## Release 1.5.2 - June 3, 2024 From e5ba7c95f6f2ba1d9923328cab5db57f7e527e2a Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Wed, 7 Aug 2024 16:39:44 -0400 Subject: [PATCH 055/289] Remove Deprecated sortSpecification Methods These methods are likely not used outside the library itself, so the risk of a breaking change is low --- CHANGELOG.md | 3 + .../dynamic/sql/SortSpecification.java | 39 +--- .../dynamic/sql/util/messages.properties | 2 - .../sql/DeprecatedSortMethodsTest.java | 173 ------------------ 4 files changed, 9 insertions(+), 208 deletions(-) delete mode 100644 src/test/java/org/mybatis/dynamic/sql/DeprecatedSortMethodsTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f3da4db9..2e35e5e63 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,9 @@ worked to make these changes as minimal as possible. **Potentially Breaking Changes:** +- If you have implemented any custom implementations of `SortSpecification`, you will need to update those + implementations due to a new rendering strategy for ORDER BY phrases. The old methods `isDescending` and `orderByName` + are removed in favor of a new method `renderForOrderBy` - If you have implemented any custom functions, you will likely need to make changes. The supplied base classes now hold an instance of `BasicColumn` rather than `BindableColumn`. This change was made to make the functions more useful in variety of circumstances. If you follow the patterns shown on the diff --git a/src/main/java/org/mybatis/dynamic/sql/SortSpecification.java b/src/main/java/org/mybatis/dynamic/sql/SortSpecification.java index 48aee58c4..05ba42e30 100644 --- a/src/main/java/org/mybatis/dynamic/sql/SortSpecification.java +++ b/src/main/java/org/mybatis/dynamic/sql/SortSpecification.java @@ -15,10 +15,8 @@ */ package org.mybatis.dynamic.sql; -import org.mybatis.dynamic.sql.exception.DynamicSqlException; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.util.FragmentAndParameters; -import org.mybatis.dynamic.sql.util.Messages; /** * Defines attributes of columns that are necessary for rendering an order by expression. @@ -35,37 +33,12 @@ public interface SortSpecification { SortSpecification descending(); /** - * Return the phrase that should be written into a rendered order by clause. This should - * NOT include the "DESC" word for descending sort specifications. + * Return a fragment rendered for use in an ORDER BY clause. The fragment should include "DESC" if a + * descending order is desired. * - * @return the order by phrase - * @deprecated Please replace this method by overriding the more general "renderForOrderBy" method. Target for - * removal in release 2.1 + * @param renderingContext the current rendering context + * @return a rendered fragment and parameters is applicable + * @since 2.0.0 */ - @Deprecated(since = "2.0", forRemoval = true) - default String orderByName() { - throw new DynamicSqlException(Messages.getString("ERROR.44")); //$NON-NLS-1$ - } - - /** - * Return true if the sort order is descending. - * - * @return true if the SortSpecification should render as descending - * @deprecated Please replace this method by overriding the more general "renderForOrderBy" method. Target for - * removal in release 2.1 - */ - @Deprecated(since = "2.0", forRemoval = true) - default boolean isDescending() { - throw new DynamicSqlException(Messages.getString("ERROR.44")); //$NON-NLS-1$ - } - - // the default implementation ensures compatibility with prior releases. When the - // deprecated methods are removed, this function can become purely abstract. - default FragmentAndParameters renderForOrderBy(RenderingContext renderingContext) { - String phrase = orderByName(); - if (isDescending()) { - phrase = phrase + " DESC"; //$NON-NLS-1$ - } - return FragmentAndParameters.fromFragment(phrase); - } + FragmentAndParameters renderForOrderBy(RenderingContext renderingContext); } diff --git a/src/main/resources/org/mybatis/dynamic/sql/util/messages.properties b/src/main/resources/org/mybatis/dynamic/sql/util/messages.properties index c7e90f7e5..c25eb02c5 100644 --- a/src/main/resources/org/mybatis/dynamic/sql/util/messages.properties +++ b/src/main/resources/org/mybatis/dynamic/sql/util/messages.properties @@ -60,6 +60,4 @@ ERROR.40=Case expressions must have at least one "when" clause ERROR.41=You cannot call "then" in a Kotlin case expression more than once ERROR.42=You cannot call `else` in a Kotlin case expression more than once ERROR.43=A Kotlin cast expression must have one, and only one, `as` element -ERROR.44=You must either implement the "renderForOrderBy" method or both "orderByName" and "isDescending" methods in a \ - sort specification INTERNAL.ERROR=Internal Error {0} diff --git a/src/test/java/org/mybatis/dynamic/sql/DeprecatedSortMethodsTest.java b/src/test/java/org/mybatis/dynamic/sql/DeprecatedSortMethodsTest.java deleted file mode 100644 index 520783155..000000000 --- a/src/test/java/org/mybatis/dynamic/sql/DeprecatedSortMethodsTest.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright 2016-2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.mybatis.dynamic.sql; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; - -import java.util.List; - -import org.junit.jupiter.api.Test; -import org.mybatis.dynamic.sql.common.OrderByModel; -import org.mybatis.dynamic.sql.common.OrderByRenderer; -import org.mybatis.dynamic.sql.configuration.StatementConfiguration; -import org.mybatis.dynamic.sql.exception.DynamicSqlException; -import org.mybatis.dynamic.sql.render.RenderingContext; -import org.mybatis.dynamic.sql.render.RenderingStrategies; -import org.mybatis.dynamic.sql.render.TableAliasCalculator; -import org.mybatis.dynamic.sql.util.FragmentAndParameters; -import org.mybatis.dynamic.sql.util.Messages; - -class DeprecatedSortMethodsTest { - - @Test - void bothMethodsExist() { - SortSpecification ss = new SortSpecification() { - @Override - public SortSpecification descending() { - return this; - } - - @Override - public String orderByName() { - return "id"; - } - - @Override - public boolean isDescending() { - return false; - } - }; - - OrderByModel model = OrderByModel.of(List.of(ss)); - - RenderingContext renderingContext = RenderingContext - .withRenderingStrategy(RenderingStrategies.MYBATIS3) - .withTableAliasCalculator(TableAliasCalculator.empty()) - .withStatementConfiguration(new StatementConfiguration()) - .build(); - OrderByRenderer renderer = new OrderByRenderer(renderingContext); - FragmentAndParameters fp = renderer.render(model); - assertThat(fp.fragment()).isEqualTo("order by id"); - } - - @Test - void bothMethodsExistDescending() { - SortSpecification ss = new SortSpecification() { - @Override - public SortSpecification descending() { - return this; - } - - @Override - public String orderByName() { - return "id"; - } - - @Override - public boolean isDescending() { - return true; - } - }; - - OrderByModel model = OrderByModel.of(List.of(ss)); - - RenderingContext renderingContext = RenderingContext - .withRenderingStrategy(RenderingStrategies.MYBATIS3) - .withTableAliasCalculator(TableAliasCalculator.empty()) - .withStatementConfiguration(new StatementConfiguration()) - .build(); - OrderByRenderer renderer = new OrderByRenderer(renderingContext); - FragmentAndParameters fp = renderer.render(model); - assertThat(fp.fragment()).isEqualTo("order by id DESC"); - } - - @Test - void orderByNameMethodMissing() { - SortSpecification ss = new SortSpecification() { - @Override - public SortSpecification descending() { - return this; - } - - @Override - public boolean isDescending() { - return true; - } - }; - - OrderByModel model = OrderByModel.of(List.of(ss)); - - RenderingContext renderingContext = RenderingContext - .withRenderingStrategy(RenderingStrategies.MYBATIS3) - .withTableAliasCalculator(TableAliasCalculator.empty()) - .withStatementConfiguration(new StatementConfiguration()) - .build(); - OrderByRenderer renderer = new OrderByRenderer(renderingContext); - assertThatExceptionOfType(DynamicSqlException.class) - .isThrownBy(() -> renderer.render(model)) - .withMessage(Messages.getString("ERROR.44")); - } - - @Test - void isDescendingMethodMissing() { - SortSpecification ss = new SortSpecification() { - @Override - public SortSpecification descending() { - return this; - } - - @Override - public String orderByName() { - return "id"; - } - }; - - OrderByModel model = OrderByModel.of(List.of(ss)); - - RenderingContext renderingContext = RenderingContext - .withRenderingStrategy(RenderingStrategies.MYBATIS3) - .withTableAliasCalculator(TableAliasCalculator.empty()) - .withStatementConfiguration(new StatementConfiguration()) - .build(); - OrderByRenderer renderer = new OrderByRenderer(renderingContext); - assertThatExceptionOfType(DynamicSqlException.class) - .isThrownBy(() -> renderer.render(model)) - .withMessage(Messages.getString("ERROR.44")); - } - - @Test - void bothMethodsMissing() { - SortSpecification ss = new SortSpecification() { - @Override - public SortSpecification descending() { - return this; - } - }; - - OrderByModel model = OrderByModel.of(List.of(ss)); - - RenderingContext renderingContext = RenderingContext - .withRenderingStrategy(RenderingStrategies.MYBATIS3) - .withTableAliasCalculator(TableAliasCalculator.empty()) - .withStatementConfiguration(new StatementConfiguration()) - .build(); - OrderByRenderer renderer = new OrderByRenderer(renderingContext); - assertThatExceptionOfType(DynamicSqlException.class) - .isThrownBy(() -> renderer.render(model)) - .withMessage(Messages.getString("ERROR.44")); - } -} From f9209112bb855c7f00575db11ce7994f4849dc80 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Wed, 7 Aug 2024 16:43:32 -0400 Subject: [PATCH 056/289] Typo --- CHANGELOG.md | 2 +- src/main/java/org/mybatis/dynamic/sql/SortSpecification.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e35e5e63..1ef040d6c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,7 @@ worked to make these changes as minimal as possible. **Potentially Breaking Changes:** -- If you have implemented any custom implementations of `SortSpecification`, you will need to update those +- If you have created any custom implementations of `SortSpecification`, you will need to update those implementations due to a new rendering strategy for ORDER BY phrases. The old methods `isDescending` and `orderByName` are removed in favor of a new method `renderForOrderBy` - If you have implemented any custom functions, you will likely need to make changes. The supplied base classes now diff --git a/src/main/java/org/mybatis/dynamic/sql/SortSpecification.java b/src/main/java/org/mybatis/dynamic/sql/SortSpecification.java index 05ba42e30..0fd0da18f 100644 --- a/src/main/java/org/mybatis/dynamic/sql/SortSpecification.java +++ b/src/main/java/org/mybatis/dynamic/sql/SortSpecification.java @@ -37,7 +37,7 @@ public interface SortSpecification { * descending order is desired. * * @param renderingContext the current rendering context - * @return a rendered fragment and parameters is applicable + * @return a rendered fragment and parameters if applicable * @since 2.0.0 */ FragmentAndParameters renderForOrderBy(RenderingContext renderingContext); From 06a52b9a442929fcc1ab8845df5bba26827c0079 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Thu, 8 Aug 2024 12:26:53 -0400 Subject: [PATCH 057/289] Add @Serial annotation to exceptions --- .../dynamic/sql/exception/DuplicateTableAliasException.java | 2 ++ .../org/mybatis/dynamic/sql/exception/DynamicSqlException.java | 3 +++ .../org/mybatis/dynamic/sql/exception/InvalidSqlException.java | 3 +++ .../sql/exception/NonRenderingWhereClauseException.java | 3 +++ 4 files changed, 11 insertions(+) diff --git a/src/main/java/org/mybatis/dynamic/sql/exception/DuplicateTableAliasException.java b/src/main/java/org/mybatis/dynamic/sql/exception/DuplicateTableAliasException.java index ee8c1e2d1..89ad51fdb 100644 --- a/src/main/java/org/mybatis/dynamic/sql/exception/DuplicateTableAliasException.java +++ b/src/main/java/org/mybatis/dynamic/sql/exception/DuplicateTableAliasException.java @@ -15,6 +15,7 @@ */ package org.mybatis.dynamic.sql.exception; +import java.io.Serial; import java.util.Objects; import org.mybatis.dynamic.sql.SqlTable; @@ -34,6 +35,7 @@ */ public class DuplicateTableAliasException extends DynamicSqlException { + @Serial private static final long serialVersionUID = -2631664872557787391L; public DuplicateTableAliasException(SqlTable table, String newAlias, String existingAlias) { diff --git a/src/main/java/org/mybatis/dynamic/sql/exception/DynamicSqlException.java b/src/main/java/org/mybatis/dynamic/sql/exception/DynamicSqlException.java index 3a8bc5791..df7d61ce0 100644 --- a/src/main/java/org/mybatis/dynamic/sql/exception/DynamicSqlException.java +++ b/src/main/java/org/mybatis/dynamic/sql/exception/DynamicSqlException.java @@ -15,7 +15,10 @@ */ package org.mybatis.dynamic.sql.exception; +import java.io.Serial; + public class DynamicSqlException extends RuntimeException { + @Serial private static final long serialVersionUID = 349021672061361244L; public DynamicSqlException(String message) { diff --git a/src/main/java/org/mybatis/dynamic/sql/exception/InvalidSqlException.java b/src/main/java/org/mybatis/dynamic/sql/exception/InvalidSqlException.java index 51ce3f787..ee1a13a9d 100644 --- a/src/main/java/org/mybatis/dynamic/sql/exception/InvalidSqlException.java +++ b/src/main/java/org/mybatis/dynamic/sql/exception/InvalidSqlException.java @@ -15,7 +15,10 @@ */ package org.mybatis.dynamic.sql.exception; +import java.io.Serial; + public class InvalidSqlException extends DynamicSqlException { + @Serial private static final long serialVersionUID = 1666851020951347843L; public InvalidSqlException(String message) { diff --git a/src/main/java/org/mybatis/dynamic/sql/exception/NonRenderingWhereClauseException.java b/src/main/java/org/mybatis/dynamic/sql/exception/NonRenderingWhereClauseException.java index 3dfa0ed36..23210e5a4 100644 --- a/src/main/java/org/mybatis/dynamic/sql/exception/NonRenderingWhereClauseException.java +++ b/src/main/java/org/mybatis/dynamic/sql/exception/NonRenderingWhereClauseException.java @@ -19,6 +19,8 @@ import org.mybatis.dynamic.sql.configuration.StatementConfiguration; import org.mybatis.dynamic.sql.util.Messages; +import java.io.Serial; + /** * This exception is thrown when the where clause in a statement will not render. * This can happen if all the optional conditions in a where clause fail to @@ -40,6 +42,7 @@ * @author Jeff Butler */ public class NonRenderingWhereClauseException extends DynamicSqlException { + @Serial private static final long serialVersionUID = 6619119078542625135L; public NonRenderingWhereClauseException() { From f03663176d3eea6286bc5e6c6646c3b7d39936ed Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Thu, 8 Aug 2024 12:28:47 -0400 Subject: [PATCH 058/289] Throw InvalidSqlException during rendering if an In condition is empty This changes the prior behavior where the condition would render as invalid SQL and a runtime exception from the database was expected. --- CHANGELOG.md | 4 + .../mybatis/dynamic/sql/util/Validator.java | 18 +- .../dynamic/sql/where/condition/IsIn.java | 2 + .../where/condition/IsInCaseInsensitive.java | 2 + .../dynamic/sql/where/condition/IsNotIn.java | 2 + .../condition/IsNotInCaseInsensitive.java | 2 + .../dynamic/sql/util/messages.properties | 1 + src/site/markdown/docs/conditions.md | 14 +- .../data/VariousListConditionsTest.java | 178 ++++++------------ .../sql/select/SelectStatementTest.java | 24 --- .../mybatis3/canonical/PersonMapperTest.kt | 12 -- 11 files changed, 83 insertions(+), 176 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ef040d6c..010c421c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,10 @@ Other important changes: - The library now requires Java 17 - Deprecated code from prior releases is removed - We now allow CASE expressions in ORDER BY Clauses +- The "In" conditions will now throw `InvalidSqlException` during rendering if the list of values is empty. Previously + an empty In condition would render as invalid SQL and would usually cause a runtime exception from the database. + With this change, the exception thrown is more predictable and the error is caught before sending the SQL to the + database. ## Release 1.5.2 - June 3, 2024 diff --git a/src/main/java/org/mybatis/dynamic/sql/util/Validator.java b/src/main/java/org/mybatis/dynamic/sql/util/Validator.java index 1d4b3f7b8..47814c7a2 100644 --- a/src/main/java/org/mybatis/dynamic/sql/util/Validator.java +++ b/src/main/java/org/mybatis/dynamic/sql/util/Validator.java @@ -26,12 +26,20 @@ public static void assertNotEmpty(Collection collection, String messageNumber assertFalse(collection.isEmpty(), messageNumber); } + public static void assertNotEmpty(Collection collection, String messageNumber, String p1) { + assertFalse(collection.isEmpty(), messageNumber, p1); + } + public static void assertFalse(boolean condition, String messageNumber) { - internalAssertFalse(condition, Messages.getString(messageNumber)); + if (condition) { + throw new InvalidSqlException(Messages.getString(messageNumber)); + } } public static void assertFalse(boolean condition, String messageNumber, String p1) { - internalAssertFalse(condition, Messages.getString(messageNumber, p1)); + if (condition) { + throw new InvalidSqlException(Messages.getString(messageNumber, p1)); + } } public static void assertTrue(boolean condition, String messageNumber) { @@ -41,10 +49,4 @@ public static void assertTrue(boolean condition, String messageNumber) { public static void assertTrue(boolean condition, String messageNumber, String p1) { assertFalse(!condition, messageNumber, p1); } - - private static void internalAssertFalse(boolean condition, String message) { - if (condition) { - throw new InvalidSqlException(message); - } - } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsIn.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsIn.java index ce00047b5..ef6979b67 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsIn.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsIn.java @@ -23,6 +23,7 @@ import org.mybatis.dynamic.sql.AbstractListValueCondition; import org.mybatis.dynamic.sql.render.RenderingContext; +import org.mybatis.dynamic.sql.util.Validator; public class IsIn extends AbstractListValueCondition { private static final IsIn EMPTY = new IsIn<>(Collections.emptyList()); @@ -39,6 +40,7 @@ protected IsIn(Collection values) { @Override public boolean shouldRender(RenderingContext renderingContext) { + Validator.assertNotEmpty(values, "ERROR.44", "IsIn"); //$NON-NLS-1$ //$NON-NLS-2$ return true; } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java index 3fe30c1ef..274226158 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java @@ -24,6 +24,7 @@ import org.mybatis.dynamic.sql.AbstractListValueCondition; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.util.StringUtilities; +import org.mybatis.dynamic.sql.util.Validator; public class IsInCaseInsensitive extends AbstractListValueCondition implements CaseInsensitiveVisitableCondition { @@ -39,6 +40,7 @@ protected IsInCaseInsensitive(Collection values) { @Override public boolean shouldRender(RenderingContext renderingContext) { + Validator.assertNotEmpty(values, "ERROR.44", "IsInCaseInsensitive"); //$NON-NLS-1$ //$NON-NLS-2$ return true; } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotIn.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotIn.java index dc7358b2a..9c621f00b 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotIn.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotIn.java @@ -23,6 +23,7 @@ import org.mybatis.dynamic.sql.AbstractListValueCondition; import org.mybatis.dynamic.sql.render.RenderingContext; +import org.mybatis.dynamic.sql.util.Validator; public class IsNotIn extends AbstractListValueCondition { private static final IsNotIn EMPTY = new IsNotIn<>(Collections.emptyList()); @@ -39,6 +40,7 @@ protected IsNotIn(Collection values) { @Override public boolean shouldRender(RenderingContext renderingContext) { + Validator.assertNotEmpty(values, "ERROR.44", "IsNotIn"); //$NON-NLS-1$ //$NON-NLS-2$ return true; } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java index fa43af0b6..e91e893c6 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java @@ -24,6 +24,7 @@ import org.mybatis.dynamic.sql.AbstractListValueCondition; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.util.StringUtilities; +import org.mybatis.dynamic.sql.util.Validator; public class IsNotInCaseInsensitive extends AbstractListValueCondition implements CaseInsensitiveVisitableCondition { @@ -39,6 +40,7 @@ protected IsNotInCaseInsensitive(Collection values) { @Override public boolean shouldRender(RenderingContext renderingContext) { + Validator.assertNotEmpty(values, "ERROR.44", "IsNotInCaseInsensitive"); //$NON-NLS-1$ //$NON-NLS-2$ return true; } diff --git a/src/main/resources/org/mybatis/dynamic/sql/util/messages.properties b/src/main/resources/org/mybatis/dynamic/sql/util/messages.properties index c25eb02c5..ef092e651 100644 --- a/src/main/resources/org/mybatis/dynamic/sql/util/messages.properties +++ b/src/main/resources/org/mybatis/dynamic/sql/util/messages.properties @@ -60,4 +60,5 @@ ERROR.40=Case expressions must have at least one "when" clause ERROR.41=You cannot call "then" in a Kotlin case expression more than once ERROR.42=You cannot call `else` in a Kotlin case expression more than once ERROR.43=A Kotlin cast expression must have one, and only one, `as` element +ERROR.44={0} conditions must contain at least one value INTERNAL.ERROR=Internal Error {0} diff --git a/src/site/markdown/docs/conditions.md b/src/site/markdown/docs/conditions.md index 55a2e6617..2e266e22b 100644 --- a/src/site/markdown/docs/conditions.md +++ b/src/site/markdown/docs/conditions.md @@ -204,8 +204,8 @@ mapping if you so desire. Starting with version 1.5.2, we made a change to the rendering rules for the "in" conditions. This was done to limit the danger of conditions failing to render and thus affecting more rows than expected. For the base conditions ("isIn", -"isNotIn", etc.), if the list of values is empty, then the condition will still render, but the resulting SQL will -be invalid and will cause a runtime exception. We believe this is the safest outcome. For example, suppose +"isNotIn", etc.), if the list of values is empty, then the library will throw +`org.mybatis.dynamic.sql.exception.InvalidSqlException`. We believe this is the safest outcome. For example, suppose a DELETE statement was coded as follows: ```java @@ -214,12 +214,6 @@ a DELETE statement was coded as follows: .and(id, isIn(Collections.emptyList())); ``` -This statement will be rendered as follows: - -```sql - delete from foo where status = ? and id in () -``` - This will cause a runtime error due to invalid SQL, but it eliminates the possibility of deleting ALL rows with active status. If you want to allow the "in" condition to drop from the SQL if the list is empty, then use the "inWhenPresent" condition. @@ -229,8 +223,8 @@ and the case-insensitive versions of these conditions: | Input | Effect | |------------------------------------------|-----------------------------------------------------------------------------------| -| isIn(null) | NullPointerException | -| isIn(Collections.emptyList()) | Rendered as "in ()" (Invalid SQL) | +| isIn(null) | NullPointerException thrown | +| isIn(Collections.emptyList()) | InvalidSqlException thrown | | isIn(2, 3, null) | Rendered as "in (?, ?, ?)" (Parameter values are 2, 3, and null) | | isInWhenPresent(null) | Condition Not Rendered | | isInWhenPresent(Collections.emptyList()) | Condition Not Rendered | diff --git a/src/test/java/examples/animal/data/VariousListConditionsTest.java b/src/test/java/examples/animal/data/VariousListConditionsTest.java index 469b64718..4e71ef668 100644 --- a/src/test/java/examples/animal/data/VariousListConditionsTest.java +++ b/src/test/java/examples/animal/data/VariousListConditionsTest.java @@ -34,14 +34,12 @@ import java.io.InputStreamReader; import java.sql.Connection; import java.sql.DriverManager; -import java.sql.SQLSyntaxErrorException; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; import org.apache.ibatis.datasource.unpooled.UnpooledDataSource; -import org.apache.ibatis.exceptions.PersistenceException; import org.apache.ibatis.jdbc.ScriptRunner; import org.apache.ibatis.mapping.Environment; import org.apache.ibatis.session.Configuration; @@ -51,8 +49,10 @@ import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.mybatis.dynamic.sql.exception.InvalidSqlException; import org.mybatis.dynamic.sql.render.RenderingStrategies; import org.mybatis.dynamic.sql.select.render.SelectStatementProvider; +import org.mybatis.dynamic.sql.util.Messages; import org.mybatis.dynamic.sql.util.mybatis3.CommonSelectMapper; class VariousListConditionsTest { @@ -136,26 +136,15 @@ void testInWhenPresentWithNull() { @Test void testInWithEmptyList() { - try (SqlSession sqlSession = sqlSessionFactory.openSession()) { - CommonSelectMapper mapper = sqlSession.getMapper(CommonSelectMapper.class); - - SelectStatementProvider selectStatement = select(id, animalName) - .from(animalData) - .where(id, isIn(Collections.emptyList())) - .orderBy(id) - .build() - .render(RenderingStrategies.MYBATIS3); - - assertThat(selectStatement.getSelectStatement()).isEqualTo( - "select id, animal_name from AnimalData " + - "where id in () " + - "order by id" - ); - - assertThatExceptionOfType(PersistenceException.class).isThrownBy(() -> - mapper.selectManyMappedRows(selectStatement) - ).withCauseInstanceOf(SQLSyntaxErrorException.class); - } + var selectModel = select(id, animalName) + .from(animalData) + .where(id, isIn(Collections.emptyList())) + .orderBy(id) + .build(); + + assertThatExceptionOfType(InvalidSqlException.class) + .isThrownBy(() -> selectModel.render(RenderingStrategies.MYBATIS3)) + .withMessage(Messages.getString("ERROR.44", "IsIn")); } @Test @@ -319,121 +308,66 @@ void testNotInCaseInsensitiveWhenPresentMap() { @Test void testInEventuallyEmpty() { - try (SqlSession sqlSession = sqlSessionFactory.openSession()) { - CommonSelectMapper mapper = sqlSession.getMapper(CommonSelectMapper.class); - - SelectStatementProvider selectStatement = select(id, animalName) - .from(animalData) - .where(id, isIn(1, 2).filter(s -> false)) - .orderBy(id) - .build() - .render(RenderingStrategies.MYBATIS3); - - assertThat(selectStatement.getSelectStatement()).isEqualTo( - "select id, animal_name from AnimalData " + - "where id in () " + - "order by id" - ); - - assertThatExceptionOfType(PersistenceException.class).isThrownBy( - () -> mapper.selectManyMappedRows(selectStatement)) - .withCauseInstanceOf(SQLSyntaxErrorException.class); - } + var selectModel = select(id, animalName) + .from(animalData) + .where(id, isIn(1, 2).filter(s -> false)) + .orderBy(id) + .build(); + + assertThatExceptionOfType(InvalidSqlException.class) + .isThrownBy(() -> selectModel.render(RenderingStrategies.MYBATIS3)) + .withMessage(Messages.getString("ERROR.44", "IsIn")); } @Test void testInCaseInsensitiveEventuallyEmpty() { - try (SqlSession sqlSession = sqlSessionFactory.openSession()) { - CommonSelectMapper mapper = sqlSession.getMapper(CommonSelectMapper.class); - - SelectStatementProvider selectStatement = select(id, animalName) - .from(animalData) - .where(animalName, isInCaseInsensitive("Fred", "Betty").filter(s -> false)) - .orderBy(id) - .build() - .render(RenderingStrategies.MYBATIS3); - - assertThat(selectStatement.getSelectStatement()).isEqualTo( - "select id, animal_name from AnimalData " + - "where upper(animal_name) in () " + - "order by id" - ); - - assertThatExceptionOfType(PersistenceException.class).isThrownBy( - () -> mapper.selectManyMappedRows(selectStatement)) - .withCauseInstanceOf(SQLSyntaxErrorException.class); - } + var selectModel = select(id, animalName) + .from(animalData) + .where(animalName, isInCaseInsensitive("Fred", "Betty").filter(s -> false)) + .orderBy(id) + .build(); + + assertThatExceptionOfType(InvalidSqlException.class) + .isThrownBy(() -> selectModel.render(RenderingStrategies.MYBATIS3)) + .withMessage(Messages.getString("ERROR.44", "IsInCaseInsensitive")); } @Test void testNotInEventuallyEmpty() { - try (SqlSession sqlSession = sqlSessionFactory.openSession()) { - CommonSelectMapper mapper = sqlSession.getMapper(CommonSelectMapper.class); - - SelectStatementProvider selectStatement = select(id, animalName) - .from(animalData) - .where(id, isNotIn(1, 2).filter(s -> false)) - .orderBy(id) - .build() - .render(RenderingStrategies.MYBATIS3); - - assertThat(selectStatement.getSelectStatement()).isEqualTo( - "select id, animal_name from AnimalData " + - "where id not in () " + - "order by id" - ); - - assertThatExceptionOfType(PersistenceException.class).isThrownBy( - () -> mapper.selectManyMappedRows(selectStatement)) - .withCauseInstanceOf(SQLSyntaxErrorException.class); - } + var selectModel = select(id, animalName) + .from(animalData) + .where(id, isNotIn(1, 2).filter(s -> false)) + .orderBy(id) + .build(); + + assertThatExceptionOfType(InvalidSqlException.class) + .isThrownBy(() -> selectModel.render(RenderingStrategies.MYBATIS3)) + .withMessage(Messages.getString("ERROR.44", "IsNotIn")); } @Test void testNotInCaseInsensitiveEventuallyEmpty() { - try (SqlSession sqlSession = sqlSessionFactory.openSession()) { - CommonSelectMapper mapper = sqlSession.getMapper(CommonSelectMapper.class); - - SelectStatementProvider selectStatement = select(id, animalName) - .from(animalData) - .where(animalName, isNotInCaseInsensitive("Fred", "Betty").filter(s -> false)) - .orderBy(id) - .build() - .render(RenderingStrategies.MYBATIS3); - - assertThat(selectStatement.getSelectStatement()).isEqualTo( - "select id, animal_name from AnimalData " + - "where upper(animal_name) not in () " + - "order by id" - ); - - assertThatExceptionOfType(PersistenceException.class).isThrownBy( - () -> mapper.selectManyMappedRows(selectStatement)) - .withCauseInstanceOf(SQLSyntaxErrorException.class); - } + var selectModel = select(id, animalName) + .from(animalData) + .where(animalName, isNotInCaseInsensitive("Fred", "Betty").filter(s -> false)) + .orderBy(id) + .build(); + + assertThatExceptionOfType(InvalidSqlException.class) + .isThrownBy(() -> selectModel.render(RenderingStrategies.MYBATIS3)) + .withMessage(Messages.getString("ERROR.44", "IsNotInCaseInsensitive")); } @Test void testInEventuallyEmptyDoubleFilter() { - try (SqlSession sqlSession = sqlSessionFactory.openSession()) { - CommonSelectMapper mapper = sqlSession.getMapper(CommonSelectMapper.class); - - SelectStatementProvider selectStatement = select(id, animalName) - .from(animalData) - .where(id, isIn(1, 2).filter(s -> false).filter(s -> false)) - .orderBy(id) - .build() - .render(RenderingStrategies.MYBATIS3); - - assertThat(selectStatement.getSelectStatement()).isEqualTo( - "select id, animal_name from AnimalData " + - "where id in () " + - "order by id" - ); - - assertThatExceptionOfType(PersistenceException.class).isThrownBy( - () -> mapper.selectManyMappedRows(selectStatement)) - .withCauseInstanceOf(SQLSyntaxErrorException.class); - } + var selectModel = select(id, animalName) + .from(animalData) + .where(id, isIn(1, 2).filter(s -> false).filter(s -> false)) + .orderBy(id) + .build(); + + assertThatExceptionOfType(InvalidSqlException.class) + .isThrownBy(() -> selectModel.render(RenderingStrategies.MYBATIS3)) + .withMessage(Messages.getString("ERROR.44", "IsIn")); } } diff --git a/src/test/java/org/mybatis/dynamic/sql/select/SelectStatementTest.java b/src/test/java/org/mybatis/dynamic/sql/select/SelectStatementTest.java index f548a4d71..6311403d8 100644 --- a/src/test/java/org/mybatis/dynamic/sql/select/SelectStatementTest.java +++ b/src/test/java/org/mybatis/dynamic/sql/select/SelectStatementTest.java @@ -21,7 +21,6 @@ import static org.mybatis.dynamic.sql.SqlBuilder.*; import java.sql.JDBCType; -import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Date; @@ -283,18 +282,6 @@ void testGroupBySingleColumn() { ); } - @Test - void testInEmptyList() { - List emptyList = Collections.emptyList(); - SelectStatementProvider selectStatement = select(column1, column3) - .from(table, "a") - .where(column3, isIn(emptyList)) - .build() - .render(RenderingStrategies.MYBATIS3); - - assertThat(selectStatement.getSelectStatement()).isEqualTo("select a.column1, a.column3 from foo a where a.column3 in ()"); - } - @Test void testNotInEmptyList() { List emptyList = Collections.emptyList(); @@ -358,17 +345,6 @@ void testNotInWhenPresentEmptyList() { ); } - @Test - void testNotInCaseInsensitiveEmptyList() { - SelectStatementProvider selectStatement = select(column1, column3) - .from(table, "a") - .where(column3, isNotInCaseInsensitive(Collections.emptyList())) - .build() - .render(RenderingStrategies.MYBATIS3); - - assertThat(selectStatement.getSelectStatement()).isEqualTo("select a.column1, a.column3 from foo a where upper(a.column3) not in ()"); - } - @Test void testNotInCaseInsensitiveWhenPresentEmptyList() { SelectModel selectModel = select(column1, column3) diff --git a/src/test/kotlin/examples/kotlin/mybatis3/canonical/PersonMapperTest.kt b/src/test/kotlin/examples/kotlin/mybatis3/canonical/PersonMapperTest.kt index 75a703c09..6178e0326 100644 --- a/src/test/kotlin/examples/kotlin/mybatis3/canonical/PersonMapperTest.kt +++ b/src/test/kotlin/examples/kotlin/mybatis3/canonical/PersonMapperTest.kt @@ -912,18 +912,6 @@ class PersonMapperTest { assertThat(insertStatement.insertStatement).isEqualTo(expected) } - @Test - fun testRenderingEmptyList() { - val selectStatement = select(id, firstName, lastName, birthDate, employed, occupation, addressId) { - from(person) - where { id isIn emptyList() } - } - - val expected = "select id, first_name, last_name, birth_date, employed, occupation, address_id from Person " + - "where id in ()" - assertThat(selectStatement.selectStatement).isEqualTo(expected) - } - @Test fun testSumWithCase() { sqlSessionFactory.openSession().use { session -> From f4309703757232f7b8ea5512324a88054a2d1dd6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 12 Aug 2024 01:28:57 +0000 Subject: [PATCH 059/289] Update dependency org.mybatis:mybatis-spring to v3.0.4 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ff30de791..9495ec37d 100644 --- a/pom.xml +++ b/pom.xml @@ -133,7 +133,7 @@ org.mybatis mybatis-spring - 3.0.3 + 3.0.4 test From 40d28e43701acd7ec904f1ee34e761a750dd3502 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 12 Aug 2024 20:34:47 -0400 Subject: [PATCH 060/289] Support Full Boolean Expressions in Joins --- .../org/mybatis/dynamic/sql/SqlBuilder.java | 26 +- .../mybatis/dynamic/sql/delete/DeleteDSL.java | 4 +- .../select/AbstractQueryExpressionDSL.java | 134 +- .../sql/select/QueryExpressionDSL.java | 81 +- .../sql/select/join/JoinSpecification.java | 35 +- .../sql/select/render/JoinRenderer.java | 39 +- .../render/JoinSpecificationRenderer.java | 44 + .../mybatis/dynamic/sql/update/UpdateDSL.java | 4 +- .../sql/where/AbstractWhereStarter.java | 22 +- .../mybatis/dynamic/sql/where/WhereDSL.java | 2 +- .../dynamic/sql/util/kotlin/JoinCollector.kt | 25 +- .../joins/NewSyntaxJoinMapperTest.java | 1270 +++++++++++++++++ 12 files changed, 1480 insertions(+), 206 deletions(-) create mode 100644 src/main/java/org/mybatis/dynamic/sql/select/render/JoinSpecificationRenderer.java create mode 100644 src/test/java/examples/joins/NewSyntaxJoinMapperTest.java diff --git a/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java b/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java index df4292653..13f385e21 100644 --- a/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java +++ b/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java @@ -433,19 +433,9 @@ static AndOrCriteriaGroup and(List subCriteria) { } // join support - static JoinCriterion and(BindableColumn joinColumn, JoinCondition joinCondition) { - return new JoinCriterion.Builder() - .withConnector("and") //$NON-NLS-1$ - .withJoinColumn(joinColumn) - .withJoinCondition(joinCondition) - .build(); - } - - static JoinCriterion on(BindableColumn joinColumn, JoinCondition joinCondition) { - return new JoinCriterion.Builder() - .withConnector("on") //$NON-NLS-1$ - .withJoinColumn(joinColumn) - .withJoinCondition(joinCondition) + static ColumnAndConditionCriterion on(BindableColumn joinColumn, VisitableCondition joinCondition) { + return ColumnAndConditionCriterion.withColumn(joinColumn) + .withCondition(joinCondition) .build(); } @@ -460,12 +450,14 @@ static SearchedCaseDSL case_() { return SearchedCaseDSL.searchedCase(); } - static EqualTo equalTo(BindableColumn column) { - return new EqualTo<>(column); + // TODO - Deprecate? + static IsEqualToColumn equalTo(BindableColumn column) { + return IsEqualToColumn.of(column); } - static EqualToValue equalTo(T value) { - return new EqualToValue<>(value); + // TODO - Deprecate? + static IsEqualTo equalTo(T value) { + return IsEqualTo.of(value); } // aggregate support diff --git a/src/main/java/org/mybatis/dynamic/sql/delete/DeleteDSL.java b/src/main/java/org/mybatis/dynamic/sql/delete/DeleteDSL.java index e7c1ad184..0ee9a99c9 100644 --- a/src/main/java/org/mybatis/dynamic/sql/delete/DeleteDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/delete/DeleteDSL.java @@ -32,8 +32,8 @@ import org.mybatis.dynamic.sql.where.AbstractWhereStarter; import org.mybatis.dynamic.sql.where.EmbeddedWhereModel; -public class DeleteDSL extends AbstractWhereStarter.DeleteWhereBuilder, DeleteDSL> - implements Buildable { +public class DeleteDSL implements AbstractWhereStarter.DeleteWhereBuilder, DeleteDSL>, + Buildable { private final Function adapterFunction; private final SqlTable table; 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 d82076a49..a1a44d2ab 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/AbstractQueryExpressionDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/AbstractQueryExpressionDSL.java @@ -23,11 +23,13 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; +import java.util.function.Supplier; +import org.mybatis.dynamic.sql.AndOrCriteriaGroup; +import org.mybatis.dynamic.sql.SqlCriterion; import org.mybatis.dynamic.sql.SqlTable; import org.mybatis.dynamic.sql.TableExpression; import org.mybatis.dynamic.sql.exception.DuplicateTableAliasException; -import org.mybatis.dynamic.sql.select.join.JoinCriterion; import org.mybatis.dynamic.sql.select.join.JoinModel; import org.mybatis.dynamic.sql.select.join.JoinSpecification; import org.mybatis.dynamic.sql.select.join.JoinType; @@ -37,9 +39,9 @@ public abstract class AbstractQueryExpressionDSL, T extends AbstractQueryExpressionDSL> - extends AbstractWhereStarter { + implements AbstractWhereStarter { - private final List joinSpecificationBuilders = new ArrayList<>(); + private final List> joinSpecificationSuppliers = new ArrayList<>(); private final Map tableAliases = new HashMap<>(); private final TableExpression table; @@ -51,151 +53,151 @@ public TableExpression table() { return table; } - public T join(SqlTable joinTable, JoinCriterion onJoinCriterion, - JoinCriterion... andJoinCriteria) { - addJoinSpecificationBuilder(joinTable, onJoinCriterion, JoinType.INNER, Arrays.asList(andJoinCriteria)); + public T join(SqlTable joinTable, SqlCriterion onJoinCriterion, + AndOrCriteriaGroup... andJoinCriteria) { + addJoinSpecificationSupplier(joinTable, onJoinCriterion, JoinType.INNER, Arrays.asList(andJoinCriteria)); return getThis(); } - public T join(SqlTable joinTable, String tableAlias, JoinCriterion onJoinCriterion, - JoinCriterion... andJoinCriteria) { + public T join(SqlTable joinTable, String tableAlias, SqlCriterion onJoinCriterion, + AndOrCriteriaGroup... andJoinCriteria) { addTableAlias(joinTable, tableAlias); return join(joinTable, onJoinCriterion, andJoinCriteria); } - public T join(SqlTable joinTable, JoinCriterion onJoinCriterion, - List> andJoinCriteria) { - addJoinSpecificationBuilder(joinTable, onJoinCriterion, JoinType.INNER, andJoinCriteria); + public T join(SqlTable joinTable, SqlCriterion onJoinCriterion, + List andJoinCriteria) { + addJoinSpecificationSupplier(joinTable, onJoinCriterion, JoinType.INNER, andJoinCriteria); return getThis(); } - public T join(SqlTable joinTable, String tableAlias, JoinCriterion onJoinCriterion, - List> andJoinCriteria) { + public T join(SqlTable joinTable, String tableAlias, SqlCriterion onJoinCriterion, + List andJoinCriteria) { addTableAlias(joinTable, tableAlias); return join(joinTable, onJoinCriterion, andJoinCriteria); } - public T join(Buildable subQuery, String tableAlias, JoinCriterion onJoinCriterion, - List> andJoinCriteria) { - addJoinSpecificationBuilder(buildSubQuery(subQuery, tableAlias), onJoinCriterion, JoinType.INNER, + public T join(Buildable subQuery, String tableAlias, SqlCriterion onJoinCriterion, + List andJoinCriteria) { + addJoinSpecificationSupplier(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)); + public T leftJoin(SqlTable joinTable, SqlCriterion onJoinCriterion, + AndOrCriteriaGroup... andJoinCriteria) { + addJoinSpecificationSupplier(joinTable, onJoinCriterion, JoinType.LEFT, Arrays.asList(andJoinCriteria)); return getThis(); } - public T leftJoin(SqlTable joinTable, String tableAlias, JoinCriterion onJoinCriterion, - JoinCriterion... andJoinCriteria) { + public T leftJoin(SqlTable joinTable, String tableAlias, SqlCriterion onJoinCriterion, + AndOrCriteriaGroup... andJoinCriteria) { addTableAlias(joinTable, tableAlias); return leftJoin(joinTable, onJoinCriterion, andJoinCriteria); } - public T leftJoin(SqlTable joinTable, JoinCriterion onJoinCriterion, - List> andJoinCriteria) { - addJoinSpecificationBuilder(joinTable, onJoinCriterion, JoinType.LEFT, andJoinCriteria); + public T leftJoin(SqlTable joinTable, SqlCriterion onJoinCriterion, + List andJoinCriteria) { + addJoinSpecificationSupplier(joinTable, onJoinCriterion, JoinType.LEFT, andJoinCriteria); return getThis(); } - public T leftJoin(SqlTable joinTable, String tableAlias, JoinCriterion onJoinCriterion, - List> andJoinCriteria) { + public T leftJoin(SqlTable joinTable, String tableAlias, SqlCriterion onJoinCriterion, + List andJoinCriteria) { addTableAlias(joinTable, tableAlias); return leftJoin(joinTable, onJoinCriterion, andJoinCriteria); } - public T leftJoin(Buildable subQuery, String tableAlias, JoinCriterion onJoinCriterion, - List> andJoinCriteria) { - addJoinSpecificationBuilder(buildSubQuery(subQuery, tableAlias), onJoinCriterion, JoinType.LEFT, + public T leftJoin(Buildable subQuery, String tableAlias, SqlCriterion onJoinCriterion, + List andJoinCriteria) { + addJoinSpecificationSupplier(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)); + public T rightJoin(SqlTable joinTable, SqlCriterion onJoinCriterion, + AndOrCriteriaGroup... andJoinCriteria) { + addJoinSpecificationSupplier(joinTable, onJoinCriterion, JoinType.RIGHT, Arrays.asList(andJoinCriteria)); return getThis(); } - public T rightJoin(SqlTable joinTable, String tableAlias, JoinCriterion onJoinCriterion, - JoinCriterion... andJoinCriteria) { + public T rightJoin(SqlTable joinTable, String tableAlias, SqlCriterion onJoinCriterion, + AndOrCriteriaGroup... andJoinCriteria) { addTableAlias(joinTable, tableAlias); return rightJoin(joinTable, onJoinCriterion, andJoinCriteria); } - public T rightJoin(SqlTable joinTable, JoinCriterion onJoinCriterion, - List> andJoinCriteria) { - addJoinSpecificationBuilder(joinTable, onJoinCriterion, JoinType.RIGHT, andJoinCriteria); + public T rightJoin(SqlTable joinTable, SqlCriterion onJoinCriterion, + List andJoinCriteria) { + addJoinSpecificationSupplier(joinTable, onJoinCriterion, JoinType.RIGHT, andJoinCriteria); return getThis(); } - public T rightJoin(SqlTable joinTable, String tableAlias, JoinCriterion onJoinCriterion, - List> andJoinCriteria) { + public T rightJoin(SqlTable joinTable, String tableAlias, SqlCriterion onJoinCriterion, + List andJoinCriteria) { addTableAlias(joinTable, tableAlias); return rightJoin(joinTable, onJoinCriterion, andJoinCriteria); } - public T rightJoin(Buildable subQuery, String tableAlias, JoinCriterion onJoinCriterion, - List> andJoinCriteria) { - addJoinSpecificationBuilder(buildSubQuery(subQuery, tableAlias), onJoinCriterion, JoinType.RIGHT, + public T rightJoin(Buildable subQuery, String tableAlias, SqlCriterion onJoinCriterion, + List andJoinCriteria) { + addJoinSpecificationSupplier(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)); + public T fullJoin(SqlTable joinTable, SqlCriterion onJoinCriterion, + AndOrCriteriaGroup... andJoinCriteria) { + addJoinSpecificationSupplier(joinTable, onJoinCriterion, JoinType.FULL, Arrays.asList(andJoinCriteria)); return getThis(); } - public T fullJoin(SqlTable joinTable, String tableAlias, JoinCriterion onJoinCriterion, - JoinCriterion... andJoinCriteria) { + public T fullJoin(SqlTable joinTable, String tableAlias, SqlCriterion onJoinCriterion, + AndOrCriteriaGroup... andJoinCriteria) { addTableAlias(joinTable, tableAlias); return fullJoin(joinTable, onJoinCriterion, andJoinCriteria); } - public T fullJoin(SqlTable joinTable, JoinCriterion onJoinCriterion, - List> andJoinCriteria) { - addJoinSpecificationBuilder(joinTable, onJoinCriterion, JoinType.FULL, andJoinCriteria); + public T fullJoin(SqlTable joinTable, SqlCriterion onJoinCriterion, + List andJoinCriteria) { + addJoinSpecificationSupplier(joinTable, onJoinCriterion, JoinType.FULL, andJoinCriteria); return getThis(); } - public T fullJoin(SqlTable joinTable, String tableAlias, JoinCriterion onJoinCriterion, - List> andJoinCriteria) { + public T fullJoin(SqlTable joinTable, String tableAlias, SqlCriterion onJoinCriterion, + List andJoinCriteria) { addTableAlias(joinTable, tableAlias); return fullJoin(joinTable, onJoinCriterion, andJoinCriteria); } - public T fullJoin(Buildable subQuery, String tableAlias, JoinCriterion onJoinCriterion, - List> andJoinCriteria) { - addJoinSpecificationBuilder(buildSubQuery(subQuery, tableAlias), onJoinCriterion, JoinType.FULL, + public T fullJoin(Buildable subQuery, String tableAlias, SqlCriterion onJoinCriterion, + List andJoinCriteria) { + addJoinSpecificationSupplier(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() + private void addJoinSpecificationSupplier(TableExpression joinTable, SqlCriterion onJoinCriterion, + JoinType joinType, List andJoinCriteria) { + joinSpecificationSuppliers.add(() -> new JoinSpecification.Builder() .withJoinTable(joinTable) .withJoinType(joinType) - .withJoinCriterion(onJoinCriterion) - .withJoinCriteria(andJoinCriteria)); + .withInitialCriterion(onJoinCriterion) + .withSubCriteria(andJoinCriteria).build()); } - protected void addJoinSpecificationBuilder(JoinSpecification.Builder builder) { - joinSpecificationBuilders.add(builder); + protected void addJoinSpecificationSupplier(Supplier joinSpecificationSupplier) { + joinSpecificationSuppliers.add(joinSpecificationSupplier); } protected Optional buildJoinModel() { - if (joinSpecificationBuilders.isEmpty()) { + if (joinSpecificationSuppliers.isEmpty()) { return Optional.empty(); } - return Optional.of(JoinModel.of(joinSpecificationBuilders.stream() - .map(JoinSpecification.Builder::build) - .toList())); + return Optional.of(JoinModel.of(joinSpecificationSuppliers.stream() + .map(Supplier::get) + .toList())); } protected void addTableAlias(SqlTable table, String tableAlias) { 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 593252979..4c025b660 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionDSL.java @@ -23,15 +23,17 @@ import java.util.function.Consumer; import org.jetbrains.annotations.NotNull; +import org.mybatis.dynamic.sql.AndOrCriteriaGroup; import org.mybatis.dynamic.sql.BasicColumn; import org.mybatis.dynamic.sql.BindableColumn; +import org.mybatis.dynamic.sql.ColumnAndConditionCriterion; import org.mybatis.dynamic.sql.CriteriaGroup; import org.mybatis.dynamic.sql.SortSpecification; import org.mybatis.dynamic.sql.SqlTable; import org.mybatis.dynamic.sql.TableExpression; +import org.mybatis.dynamic.sql.VisitableCondition; +import org.mybatis.dynamic.sql.common.AbstractBooleanExpressionDSL; import org.mybatis.dynamic.sql.configuration.StatementConfiguration; -import org.mybatis.dynamic.sql.select.join.JoinCondition; -import org.mybatis.dynamic.sql.select.join.JoinCriterion; import org.mybatis.dynamic.sql.select.join.JoinSpecification; import org.mybatis.dynamic.sql.select.join.JoinType; import org.mybatis.dynamic.sql.util.Buildable; @@ -339,50 +341,54 @@ public JoinSpecificationStarter(TableExpression joinTable, JoinType joinType) { this.joinType = joinType; } - public JoinSpecificationFinisher on(BindableColumn joinColumn, JoinCondition joinCondition) { + public JoinSpecificationFinisher on(BindableColumn joinColumn, VisitableCondition joinCondition) { return new JoinSpecificationFinisher(joinTable, joinColumn, joinCondition, joinType); } - public JoinSpecificationFinisher on(BindableColumn joinColumn, JoinCondition onJoinCondition, - JoinCriterion... andJoinCriteria) { - return new JoinSpecificationFinisher(joinTable, joinColumn, onJoinCondition, joinType, andJoinCriteria); + public JoinSpecificationFinisher on(BindableColumn joinColumn, VisitableCondition onJoinCondition, + AndOrCriteriaGroup... subCriteria) { + return new JoinSpecificationFinisher(joinTable, joinColumn, onJoinCondition, joinType, subCriteria); } } - public class JoinSpecificationFinisher - extends AbstractWhereStarter - implements Buildable { - private final JoinSpecification.Builder joinSpecificationBuilder; + public class JoinSpecificationFinisher extends AbstractBooleanExpressionDSL + implements AbstractWhereStarter, Buildable { + private final TableExpression table; + private final JoinType joinType; public JoinSpecificationFinisher(TableExpression table, BindableColumn joinColumn, - JoinCondition joinCondition, JoinType joinType) { - JoinCriterion joinCriterion = new JoinCriterion.Builder() - .withConnector("on") //$NON-NLS-1$ - .withJoinColumn(joinColumn) - .withJoinCondition(joinCondition) - .build(); + VisitableCondition joinCondition, JoinType joinType) { + this.table = table; + this.joinType = joinType; + addJoinSpecificationSupplier(this::buildJoinSpecification); - joinSpecificationBuilder = JoinSpecification.withJoinTable(table) - .withJoinType(joinType) - .withJoinCriterion(joinCriterion); + ColumnAndConditionCriterion c = ColumnAndConditionCriterion.withColumn(joinColumn) + .withCondition(joinCondition) + .build(); - addJoinSpecificationBuilder(joinSpecificationBuilder); + setInitialCriterion(c); } public JoinSpecificationFinisher(TableExpression table, BindableColumn joinColumn, - JoinCondition joinCondition, JoinType joinType, JoinCriterion... andJoinCriteria) { - JoinCriterion onJoinCriterion = new JoinCriterion.Builder() - .withConnector("on") //$NON-NLS-1$ - .withJoinColumn(joinColumn) - .withJoinCondition(joinCondition) + VisitableCondition joinCondition, JoinType joinType, AndOrCriteriaGroup... subCriteria) { + this.table = table; + this.joinType = joinType; + addJoinSpecificationSupplier(this::buildJoinSpecification); + + ColumnAndConditionCriterion c = ColumnAndConditionCriterion.withColumn(joinColumn) + .withCondition(joinCondition) + .withSubCriteria(Arrays.asList(subCriteria)) .build(); - joinSpecificationBuilder = JoinSpecification.withJoinTable(table) - .withJoinType(joinType) - .withJoinCriterion(onJoinCriterion) - .withJoinCriteria(Arrays.asList(andJoinCriteria)); + setInitialCriterion(c); + } - addJoinSpecificationBuilder(joinSpecificationBuilder); + private JoinSpecification buildJoinSpecification() { + return JoinSpecification.withJoinTable(table) + .withJoinType(joinType) + .withInitialCriterion(getInitialCriterion()) + .withSubCriteria(subCriteria) + .build(); } @NotNull @@ -402,16 +408,6 @@ public QueryExpressionWhereBuilder where() { return QueryExpressionDSL.this.where(); } - public JoinSpecificationFinisher and(BindableColumn joinColumn, JoinCondition joinCondition) { - JoinCriterion joinCriterion = new JoinCriterion.Builder() - .withConnector("and") //$NON-NLS-1$ - .withJoinColumn(joinColumn) - .withJoinCondition(joinCondition) - .build(); - joinSpecificationBuilder.withJoinCriterion(joinCriterion); - return this; - } - public JoinSpecificationStarter join(SqlTable joinTable) { return QueryExpressionDSL.this.join(joinTable); } @@ -495,6 +491,11 @@ public SelectDSL.OffsetFirstFinisher offset(long offset) { public SelectDSL.FetchFirstFinisher fetchFirst(long fetchFirstRows) { return QueryExpressionDSL.this.fetchFirst(fetchFirstRows); } + + @Override + protected JoinSpecificationFinisher getThis() { + return this; + } } public class GroupByFinisher extends AbstractHavingStarter implements Buildable { diff --git a/src/main/java/org/mybatis/dynamic/sql/select/join/JoinSpecification.java b/src/main/java/org/mybatis/dynamic/sql/select/join/JoinSpecification.java index ab95dcf5e..9db5243d2 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/join/JoinSpecification.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/join/JoinSpecification.java @@ -15,36 +15,29 @@ */ package org.mybatis.dynamic.sql.select.join; -import java.util.ArrayList; -import java.util.List; import java.util.Objects; -import java.util.stream.Stream; import org.mybatis.dynamic.sql.TableExpression; +import org.mybatis.dynamic.sql.common.AbstractBooleanExpressionModel; import org.mybatis.dynamic.sql.util.Validator; -public class JoinSpecification { +public class JoinSpecification extends AbstractBooleanExpressionModel { private final TableExpression table; - private final List> joinCriteria; private final JoinType joinType; private JoinSpecification(Builder builder) { + super(builder); table = Objects.requireNonNull(builder.table); - joinCriteria = Objects.requireNonNull(builder.joinCriteria); joinType = Objects.requireNonNull(builder.joinType); - Validator.assertNotEmpty(joinCriteria, "ERROR.16"); //$NON-NLS-1$ + Validator.assertFalse(initialCriterion().isEmpty() && subCriteria().isEmpty(), + "ERROR.16"); //$NON-NLS-1$ } public TableExpression table() { return table; } - @SuppressWarnings("java:S1452") - public Stream> joinCriteria() { - return joinCriteria.stream(); - } - public JoinType joinType() { return joinType; } @@ -53,9 +46,8 @@ public static Builder withJoinTable(TableExpression table) { return new Builder().withJoinTable(table); } - public static class Builder { + public static class Builder extends AbstractBuilder { private TableExpression table; - private final List> joinCriteria = new ArrayList<>(); private JoinType joinType; public Builder withJoinTable(TableExpression table) { @@ -63,16 +55,6 @@ public Builder withJoinTable(TableExpression table) { return this; } - public Builder withJoinCriterion(JoinCriterion joinCriterion) { - this.joinCriteria.add(joinCriterion); - return this; - } - - public Builder withJoinCriteria(List> joinCriteria) { - this.joinCriteria.addAll(joinCriteria); - return this; - } - public Builder withJoinType(JoinType joinType) { this.joinType = joinType; return this; @@ -81,5 +63,10 @@ public Builder withJoinType(JoinType joinType) { public JoinSpecification build() { return new JoinSpecification(this); } + + @Override + protected Builder getThis() { + return this; + } } } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/JoinRenderer.java b/src/main/java/org/mybatis/dynamic/sql/select/render/JoinRenderer.java index 667b4e299..0da029f59 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/render/JoinRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/render/JoinRenderer.java @@ -20,8 +20,8 @@ import java.util.Objects; import java.util.stream.Collectors; +import org.mybatis.dynamic.sql.exception.InvalidSqlException; import org.mybatis.dynamic.sql.render.RenderingContext; -import org.mybatis.dynamic.sql.select.join.JoinCriterion; import org.mybatis.dynamic.sql.select.join.JoinModel; import org.mybatis.dynamic.sql.select.join.JoinSpecification; import org.mybatis.dynamic.sql.util.FragmentAndParameters; @@ -47,41 +47,20 @@ public FragmentAndParameters render() { private FragmentAndParameters renderJoinSpecification(JoinSpecification joinSpecification) { FragmentAndParameters renderedTable = joinSpecification.table().accept(tableExpressionRenderer); - FragmentAndParameters renderedJoin = renderConditions(joinSpecification); + FragmentAndParameters renderedJoinSpecification = JoinSpecificationRenderer + .withJoinSpecification(joinSpecification) + .withRenderingContext(renderingContext) + .build() + .render() + .orElseThrow(() -> new InvalidSqlException("Join Specifications Must Render")); // TODO String fragment = joinSpecification.joinType().type() + spaceBefore(renderedTable.fragment()) - + spaceBefore(renderedJoin.fragment()); + + spaceBefore(renderedJoinSpecification.fragment()); return FragmentAndParameters.withFragment(fragment) .withParameters(renderedTable.parameters()) - .withParameters(renderedJoin.parameters()) - .build(); - } - - private FragmentAndParameters renderConditions(JoinSpecification joinSpecification) { - return joinSpecification.joinCriteria() - .map(this::renderCriterion) - .collect(FragmentCollector.collect()) - .toFragmentAndParameters(Collectors.joining(" ")); //$NON-NLS-1$ - } - - private FragmentAndParameters renderCriterion(JoinCriterion joinCriterion) { - FragmentAndParameters renderedColumn = joinCriterion.leftColumn().render(renderingContext); - - String prefix = joinCriterion.connector() - + spaceBefore(renderedColumn.fragment()); - - JoinConditionRenderer joinConditionRenderer = new JoinConditionRenderer.Builder() - .withRenderingContext(renderingContext) - .withLeftColumn(joinCriterion.leftColumn()) - .build(); - - FragmentAndParameters suffix = joinCriterion.joinCondition().accept(joinConditionRenderer); - - return FragmentAndParameters.withFragment(prefix + spaceBefore(suffix.fragment())) - .withParameters(suffix.parameters()) - .withParameters(renderedColumn.parameters()) + .withParameters(renderedJoinSpecification.parameters()) .build(); } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/JoinSpecificationRenderer.java b/src/main/java/org/mybatis/dynamic/sql/select/render/JoinSpecificationRenderer.java new file mode 100644 index 000000000..300e416d8 --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/select/render/JoinSpecificationRenderer.java @@ -0,0 +1,44 @@ +/* + * Copyright 2016-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mybatis.dynamic.sql.select.render; + +import org.mybatis.dynamic.sql.common.AbstractBooleanExpressionRenderer; +import org.mybatis.dynamic.sql.select.join.JoinSpecification; + +public class JoinSpecificationRenderer extends AbstractBooleanExpressionRenderer { + private JoinSpecificationRenderer(Builder builder) { + super("on", builder); //$NON-NLS-1$ + } + + public static JoinSpecificationRenderer.Builder withJoinSpecification(JoinSpecification joinSpecification) { + return new Builder(joinSpecification); + } + + public static class Builder extends AbstractBuilder { + public Builder(JoinSpecification joinSpecification) { + super(joinSpecification); + } + + public JoinSpecificationRenderer build() { + return new JoinSpecificationRenderer(this); + } + + @Override + protected Builder getThis() { + return this; + } + } +} diff --git a/src/main/java/org/mybatis/dynamic/sql/update/UpdateDSL.java b/src/main/java/org/mybatis/dynamic/sql/update/UpdateDSL.java index 8cf7259a3..4daa99ccc 100644 --- a/src/main/java/org/mybatis/dynamic/sql/update/UpdateDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/update/UpdateDSL.java @@ -47,8 +47,8 @@ import org.mybatis.dynamic.sql.where.AbstractWhereStarter; import org.mybatis.dynamic.sql.where.EmbeddedWhereModel; -public class UpdateDSL extends AbstractWhereStarter.UpdateWhereBuilder, UpdateDSL> - implements Buildable { +public class UpdateDSL implements AbstractWhereStarter.UpdateWhereBuilder, UpdateDSL>, + Buildable { private final Function adapterFunction; private final List columnMappings = new ArrayList<>(); diff --git a/src/main/java/org/mybatis/dynamic/sql/where/AbstractWhereStarter.java b/src/main/java/org/mybatis/dynamic/sql/where/AbstractWhereStarter.java index 03da51bd8..e94f0a8a1 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/AbstractWhereStarter.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/AbstractWhereStarter.java @@ -35,14 +35,14 @@ * * @param the implementation of the Where DSL customized for a particular SQL statement. */ -public abstract class AbstractWhereStarter, D extends AbstractWhereStarter> - implements ConfigurableStatement { +public interface AbstractWhereStarter, D extends AbstractWhereStarter> + extends ConfigurableStatement { - public F where(BindableColumn column, VisitableCondition condition, AndOrCriteriaGroup... subCriteria) { + default F where(BindableColumn column, VisitableCondition condition, AndOrCriteriaGroup... subCriteria) { return where(column, condition, Arrays.asList(subCriteria)); } - public F where(BindableColumn column, VisitableCondition condition, + default F where(BindableColumn column, VisitableCondition condition, List subCriteria) { SqlCriterion sqlCriterion = ColumnAndConditionCriterion.withColumn(column) .withCondition(condition) @@ -52,11 +52,11 @@ public F where(BindableColumn column, VisitableCondition condition, return initialize(sqlCriterion); } - public F where(ExistsPredicate existsPredicate, AndOrCriteriaGroup... subCriteria) { + default F where(ExistsPredicate existsPredicate, AndOrCriteriaGroup... subCriteria) { return where(existsPredicate, Arrays.asList(subCriteria)); } - public F where(ExistsPredicate existsPredicate, List subCriteria) { + default F where(ExistsPredicate existsPredicate, List subCriteria) { ExistsCriterion sqlCriterion = new ExistsCriterion.Builder() .withExistsPredicate(existsPredicate) .withSubCriteria(subCriteria) @@ -65,11 +65,11 @@ public F where(ExistsPredicate existsPredicate, List subCrit return initialize(sqlCriterion); } - public F where(SqlCriterion initialCriterion, AndOrCriteriaGroup... subCriteria) { + default F where(SqlCriterion initialCriterion, AndOrCriteriaGroup... subCriteria) { return where(initialCriterion, Arrays.asList(subCriteria)); } - public F where(SqlCriterion initialCriterion, List subCriteria) { + default F where(SqlCriterion initialCriterion, List subCriteria) { SqlCriterion sqlCriterion = new CriteriaGroup.Builder() .withInitialCriterion(initialCriterion) .withSubCriteria(subCriteria) @@ -78,7 +78,7 @@ public F where(SqlCriterion initialCriterion, List subCriter return initialize(sqlCriterion); } - public F where(List subCriteria) { + default F where(List subCriteria) { SqlCriterion sqlCriterion = new CriteriaGroup.Builder() .withSubCriteria(subCriteria) .build(); @@ -86,9 +86,9 @@ public F where(List subCriteria) { return initialize(sqlCriterion); } - public abstract F where(); + F where(); - public F applyWhere(WhereApplier whereApplier) { + default F applyWhere(WhereApplier whereApplier) { F finisher = where(); whereApplier.accept(finisher); return finisher; diff --git a/src/main/java/org/mybatis/dynamic/sql/where/WhereDSL.java b/src/main/java/org/mybatis/dynamic/sql/where/WhereDSL.java index 0eb23f638..a4adc2967 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/WhereDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/WhereDSL.java @@ -26,7 +26,7 @@ * *

This can also be used to create reusable where clauses for different statements. */ -public class WhereDSL extends AbstractWhereStarter { +public class WhereDSL implements AbstractWhereStarter { private final StatementConfiguration statementConfiguration = new StatementConfiguration(); private final StandaloneWhereFinisher whereBuilder = new StandaloneWhereFinisher(); 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 3ba5c2acb..6212167c1 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/JoinCollector.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/JoinCollector.kt @@ -15,40 +15,39 @@ */ package org.mybatis.dynamic.sql.util.kotlin +import org.mybatis.dynamic.sql.AndOrCriteriaGroup import org.mybatis.dynamic.sql.BindableColumn +import org.mybatis.dynamic.sql.ColumnAndConditionCriterion import org.mybatis.dynamic.sql.SqlBuilder -import org.mybatis.dynamic.sql.select.join.JoinCondition -import org.mybatis.dynamic.sql.select.join.JoinCriterion +import org.mybatis.dynamic.sql.SqlCriterion +import org.mybatis.dynamic.sql.VisitableCondition typealias JoinReceiver = JoinCollector.() -> Unit @MyBatisDslMarker class JoinCollector { - private var onJoinCriterion: JoinCriterion<*>? = null - internal val andJoinCriteria = mutableListOf>() + private var onJoinCriterion: SqlCriterion? = null + internal val andJoinCriteria = mutableListOf() - internal fun onJoinCriterion() : JoinCriterion<*> = invalidIfNull(onJoinCriterion, "ERROR.22") //$NON-NLS-1$ + internal fun onJoinCriterion() : SqlCriterion = invalidIfNull(onJoinCriterion, "ERROR.22") //$NON-NLS-1$ fun on(leftColumn: BindableColumn): RightColumnCollector = RightColumnCollector { - onJoinCriterion = JoinCriterion.Builder() - .withConnector("on") //$NON-NLS-1$ - .withJoinColumn(leftColumn) - .withJoinCondition(it) + onJoinCriterion = ColumnAndConditionCriterion.withColumn(leftColumn) + .withCondition(it) .build() } fun and(leftColumn: BindableColumn): RightColumnCollector = RightColumnCollector { andJoinCriteria.add( - JoinCriterion.Builder() + AndOrCriteriaGroup.Builder() .withConnector("and") //$NON-NLS-1$ - .withJoinColumn(leftColumn) - .withJoinCondition(it) + .withInitialCriterion(ColumnAndConditionCriterion.withColumn(leftColumn).withCondition(it).build()) .build() ) } } -class RightColumnCollector(private val joinConditionConsumer: (JoinCondition) -> Unit) { +class RightColumnCollector(private val joinConditionConsumer: (VisitableCondition) -> Unit) { infix fun equalTo(rightColumn: BindableColumn) = joinConditionConsumer.invoke(SqlBuilder.equalTo(rightColumn)) infix fun equalTo(value: T) = joinConditionConsumer.invoke(SqlBuilder.equalTo(value)) diff --git a/src/test/java/examples/joins/NewSyntaxJoinMapperTest.java b/src/test/java/examples/joins/NewSyntaxJoinMapperTest.java new file mode 100644 index 000000000..ae8f5d0f0 --- /dev/null +++ b/src/test/java/examples/joins/NewSyntaxJoinMapperTest.java @@ -0,0 +1,1270 @@ +/* + * Copyright 2016-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package 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.exception.DuplicateTableAliasException; +import org.mybatis.dynamic.sql.render.RenderingStrategies; +import org.mybatis.dynamic.sql.select.QueryExpressionDSL; +import org.mybatis.dynamic.sql.select.SelectModel; +import org.mybatis.dynamic.sql.select.render.SelectStatementProvider; +import org.mybatis.dynamic.sql.util.Messages; +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.orderDate; +import static examples.joins.OrderMasterDynamicSQLSupport.orderMaster; +import static examples.joins.UserDynamicSQLSupport.user; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.mybatis.dynamic.sql.SqlBuilder.and; +import static org.mybatis.dynamic.sql.SqlBuilder.constant; +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; +import static org.mybatis.dynamic.sql.SqlBuilder.where; + +class NewSyntaxJoinMapperTest { + + 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"); + assert is != null; + 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, orderDate, orderDetail.lineNumber, orderDetail.description, orderDetail.quantity) + .from(orderMaster, "om") + .join(orderDetail, "od").on(orderMaster.orderId, isEqualTo(orderDetail.orderId)) + .build() + .render(RenderingStrategies.MYBATIS3); + + 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(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 testSingleTableJoin2() { + try (SqlSession session = sqlSessionFactory.openSession()) { + JoinMapper mapper = session.getMapper(JoinMapper.class); + + SelectStatementProvider selectStatement = select(orderMaster.orderId, orderDate, orderDetail.lineNumber, orderDetail.description, orderDetail.quantity) + .from(orderMaster, "om") + .join(orderDetail, "od", on(orderMaster.orderId, isEqualTo(orderDetail.orderId))) + .build() + .render(RenderingStrategies.MYBATIS3); + + 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(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 testCompoundJoin1() { + // this is a nonsensical join, but it does test the "and" capability + SelectStatementProvider selectStatement = select(orderMaster.orderId, orderDate, orderDetail.lineNumber, orderDetail.description, orderDetail.quantity) + .from(orderMaster, "om") + .join(orderDetail, "od").on(orderMaster.orderId, isEqualTo(orderDetail.orderId), and(orderMaster.orderId, isEqualTo(orderDetail.orderId))) + .build() + .render(RenderingStrategies.MYBATIS3); + + 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(expectedStatement); + } + + @Test + void testCompoundJoin2() { + // this is a nonsensical join, but it does test the "and" capability + SelectStatementProvider selectStatement = select(orderMaster.orderId, orderDate, orderDetail.lineNumber, orderDetail.description, orderDetail.quantity) + .from(orderMaster, "om") + .join(orderDetail, "od").on(orderMaster.orderId, isEqualTo(orderDetail.orderId)) + .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) + .and(orderMaster.orderId, isEqualTo(orderDetail.orderId)) + .build() + .render(RenderingStrategies.MYBATIS3); + + 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(expectedStatement); + } + + @Test + void testCompoundJoin3() { + // this is a nonsensical join, but it does test the "and" capability + SelectStatementProvider selectStatement = select(orderMaster.orderId, orderDate, orderDetail.lineNumber, orderDetail.description, orderDetail.quantity) + .from(orderMaster, "om") + .join(orderDetail, "od", on(orderMaster.orderId, isEqualTo(orderDetail.orderId)), and(orderMaster.orderId, isEqualTo(orderDetail.orderId))) + .build() + .render(RenderingStrategies.MYBATIS3); + + 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(expectedStatement); + } + + @Test + void testCompoundJoin4() { + // this is a nonsensical join, but it does test the "and" capability + SelectStatementProvider selectStatement = select(orderMaster.orderId, orderDate, orderDetail.lineNumber, orderDetail.description, orderDetail.quantity) + .from(orderMaster, "om") + .leftJoin(orderDetail, "od", on(orderMaster.orderId, isEqualTo(orderDetail.orderId)), and(orderMaster.orderId, isEqualTo(orderDetail.orderId))) + .build() + .render(RenderingStrategies.MYBATIS3); + + 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(expectedStatement); + } + + @Test + void testCompoundJoin5() { + // this is a nonsensical join, but it does test the "and" capability + SelectStatementProvider selectStatement = select(orderMaster.orderId, orderDate, orderDetail.lineNumber, orderDetail.description, orderDetail.quantity) + .from(orderMaster, "om") + .rightJoin(orderDetail, "od", on(orderMaster.orderId, isEqualTo(orderDetail.orderId)), and(orderMaster.orderId, isEqualTo(orderDetail.orderId))) + .build() + .render(RenderingStrategies.MYBATIS3); + + 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(expectedStatement); + } + + @Test + void testCompoundJoin6() { + // this is a nonsensical join, but it does test the "and" capability + SelectStatementProvider selectStatement = select(orderMaster.orderId, orderDate, orderDetail.lineNumber, orderDetail.description, orderDetail.quantity) + .from(orderMaster, "om") + .fullJoin(orderDetail, "od", on(orderMaster.orderId, isEqualTo(orderDetail.orderId)), and(orderMaster.orderId, isEqualTo(orderDetail.orderId))) + .build() + .render(RenderingStrategies.MYBATIS3); + + 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(expectedStatement); + } + + @Test + void testMultipleTableJoinWithWhereClause() { + try (SqlSession session = sqlSessionFactory.openSession()) { + JoinMapper mapper = session.getMapper(JoinMapper.class); + + SelectStatementProvider selectStatement = select(orderMaster.orderId, orderDate, orderLine.lineNumber, itemMaster.description, orderLine.quantity) + .from(orderMaster, "om") + .join(orderLine, "ol").on(orderMaster.orderId, isEqualTo(orderLine.orderId)) + .join(itemMaster, "im").on(orderLine.itemId, isEqualTo(itemMaster.itemId)) + .where(orderMaster.orderId, isEqualTo(2)) + .build() + .render(RenderingStrategies.MYBATIS3); + + 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(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 testMultipleTableJoinWithApplyWhere() { + try (SqlSession session = sqlSessionFactory.openSession()) { + JoinMapper mapper = session.getMapper(JoinMapper.class); + + SelectStatementProvider selectStatement = select(orderMaster.orderId, orderDate, orderLine.lineNumber, itemMaster.description, orderLine.quantity) + .from(orderMaster, "om") + .join(orderLine, "ol").on(orderMaster.orderId, isEqualTo(orderLine.orderId)) + .join(itemMaster, "im").on(orderLine.itemId, isEqualTo(itemMaster.itemId)) + .applyWhere(where(orderMaster.orderId, isEqualTo(2)).toWhereApplier()) + .build() + .render(RenderingStrategies.MYBATIS3); + + 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(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 testMultipleTableJoinWithComplexWhereClause() { + try (SqlSession session = sqlSessionFactory.openSession()) { + JoinMapper mapper = session.getMapper(JoinMapper.class); + + SelectStatementProvider selectStatement = select(orderMaster.orderId, orderDate, orderLine.lineNumber, itemMaster.description, orderLine.quantity) + .from(orderMaster, "om") + .join(orderLine, "ol").on(orderMaster.orderId, isEqualTo(orderLine.orderId)) + .join(itemMaster, "im").on(orderLine.itemId, isEqualTo(itemMaster.itemId)) + .where(orderMaster.orderId, isEqualTo(2), and(orderLine.lineNumber, isEqualTo(2))) + .build() + .render(RenderingStrategies.MYBATIS3); + + 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(expectedStatement); + + 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, orderDate, orderLine.lineNumber, itemMaster.description, orderLine.quantity) + .from(orderMaster, "om") + .join(orderLine, "ol").on(orderMaster.orderId, isEqualTo(orderLine.orderId)) + .join(itemMaster, "im").on(orderLine.itemId, isEqualTo(itemMaster.itemId)) + .orderBy(orderMaster.orderId) + .build() + .render(RenderingStrategies.MYBATIS3); + + 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(expectedStatement); + + 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 testMultipleTableJoinNoAliasWithOrderBy() { + try (SqlSession session = sqlSessionFactory.openSession()) { + JoinMapper mapper = session.getMapper(JoinMapper.class); + + SelectStatementProvider selectStatement = select(orderMaster.orderId, orderDate, orderLine.lineNumber, itemMaster.description, orderLine.quantity) + .from(orderMaster) + .join(orderLine).on(orderMaster.orderId, isEqualTo(orderLine.orderId)) + .join(itemMaster).on(orderLine.itemId, isEqualTo(itemMaster.itemId)) + .where(orderMaster.orderId, isEqualTo(2)) + .orderBy(orderMaster.orderId) + .build() + .render(RenderingStrategies.MYBATIS3); + + 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(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()) { + 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, isEqualTo(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, isEqualTo(orderLine.orderId)) + .rightJoin(itemMaster, "im").on(orderLine.itemId, isEqualTo(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 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, isEqualTo(orderLine.orderId))) + .rightJoin(itemMaster, "im", on(orderLine.itemId, isEqualTo(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 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, isEqualTo(orderLine.orderId)) + .rightJoin(itemMaster).on(orderLine.itemId, isEqualTo(itemMaster.itemId)) + .orderBy(orderLine.orderId, itemMaster.itemId) + .build() + .render(RenderingStrategies.MYBATIS3); + + 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(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 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, isEqualTo(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, isEqualTo(orderLine.orderId)) + .leftJoin(itemMaster, "im").on(orderLine.itemId, isEqualTo(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 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, isEqualTo(orderLine.orderId))) + .leftJoin(itemMaster, "im", on(orderLine.itemId, isEqualTo(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 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, isEqualTo(orderLine.orderId)) + .leftJoin(itemMaster).on(orderLine.itemId, isEqualTo(itemMaster.itemId)) + .orderBy(orderLine.orderId, itemMaster.itemId) + .build() + .render(RenderingStrategies.MYBATIS3); + + 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(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 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, isEqualTo(orderLine.itemId)) + .orderBy(orderLine.orderId, 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 order_id, im_itemid"; + 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("IM_ITEMID", 55); + + 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("IM_ITEMID", 33); + + row = rows.get(3); + 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"); + } + } + + @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, isEqualTo(orderLine.orderId)) + .fullJoin(itemMaster, "im").on(orderLine.itemId, isEqualTo(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 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, isEqualTo(orderLine.orderId))) + .fullJoin(itemMaster, "im", on(orderLine.itemId, isEqualTo(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 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, isEqualTo(orderLine.orderId))) + .fullJoin(itemMaster, "im", on(orderLine.itemId, isEqualTo(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, isEqualTo(orderLine.orderId))) + .fullJoin(itemMaster, "im", on(orderLine.itemId, isEqualTo(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, isEqualTo(orderLine.orderId)) + .fullJoin(itemMaster).on(orderLine.itemId, isEqualTo(itemMaster.itemId)) + .orderBy(orderLine.orderId, itemMaster.itemId) + .build() + .render(RenderingStrategies.MYBATIS3); + + 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(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 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, isEqualTo(user2.parentId)) + .where(user2.userId, isEqualTo(4)) + .build() + .render(RenderingStrategies.MYBATIS3); + + 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(expectedStatement); + + 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 testSelfWithDuplicateAlias() { + QueryExpressionDSL dsl = select(user.userId, user.userName, user.parentId) + .from(user, "u1"); + + assertThatExceptionOfType(DuplicateTableAliasException.class).isThrownBy(() -> dsl.join(user, "u2")) + .withMessage(Messages.getString("ERROR.1", user.tableName(), "u2", "u1")); + } + + @Test + void testSelfWithNewAlias() { + try (SqlSession session = sqlSessionFactory.openSession()) { + JoinMapper mapper = session.getMapper(JoinMapper.class); + + // create second table instance for self-join + UserDynamicSQLSupport.User user2 = user.withAlias("u2"); + + // get Bamm Bamm's parent - should be Barney + SelectStatementProvider selectStatement = select(user.userId, user.userName, user.parentId) + .from(user) + .join(user2).on(user.userId, isEqualTo(user2.parentId)) + .where(user2.userId, isEqualTo(4)) + .build() + .render(RenderingStrategies.MYBATIS3); + + String expectedStatement = "select User.user_id, User.user_name, User.parent_id" + + " from User join User u2 on User.user_id = u2.parent_id" + + " where u2.user_id = #{parameters.p1,jdbcType=INTEGER}"; + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); + + 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 testSelfWithNewAliasAndOverride() { + try (SqlSession session = sqlSessionFactory.openSession()) { + JoinMapper mapper = session.getMapper(JoinMapper.class); + + // create second table instance for self-join + UserDynamicSQLSupport.User user2 = user.withAlias("other_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, isEqualTo(user2.parentId)) + .where(user2.userId, isEqualTo(4)) + .build() + .render(RenderingStrategies.MYBATIS3); + + 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(expectedStatement); + + 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, isEqualTo(itemMaster.itemId)) + .limit(2) + .offset(1) + .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" + + " limit #{parameters.p1} offset #{parameters.p2}"; + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); + + 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, isEqualTo(itemMaster.itemId)) + .limit(2) + .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" + + " limit #{parameters.p1}"; + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); + + 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, isEqualTo(itemMaster.itemId)) + .offset(2) + .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" + + " offset #{parameters.p1} rows"; + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); + + 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, isEqualTo(itemMaster.itemId)) + .offset(1) + .fetchFirst(2).rowsOnly() + .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" + + " offset #{parameters.p1} rows fetch first #{parameters.p2} rows only"; + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); + + 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, isEqualTo(itemMaster.itemId)) + .fetchFirst(2).rowsOnly() + .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" + + " fetch first #{parameters.p1} rows only"; + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); + + 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 testJoinWithParameterValue() { + try (SqlSession session = sqlSessionFactory.openSession()) { + CommonSelectMapper mapper = session.getMapper(CommonSelectMapper.class); + + SelectStatementProvider selectStatement = select(orderLine.orderId, orderLine.quantity, itemMaster.itemId, itemMaster.description) + .from(itemMaster, "im") + .join(orderLine, "ol").on(orderLine.itemId, isEqualTo(itemMaster.itemId)) + .and(orderLine.orderId, isEqualTo(1)) + .build() + .render(RenderingStrategies.MYBATIS3); + + String expectedStatement = "select ol.order_id, ol.quantity, im.item_id, im.description" + + " from ItemMaster im join OrderLine ol on ol.item_id = im.item_id" + + " and ol.order_id = #{parameters.p1,jdbcType=INTEGER}"; + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); + + List> 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", 1); + assertThat(row).containsEntry("QUANTITY", 1); + assertThat(row).containsEntry("DESCRIPTION", "First Base Glove"); + assertThat(row).containsEntry("ITEM_ID", 33); + } + } + + @Test + void testJoinWithConstant() { + try (SqlSession session = sqlSessionFactory.openSession()) { + CommonSelectMapper mapper = session.getMapper(CommonSelectMapper.class); + + SelectStatementProvider selectStatement = select(orderLine.orderId, orderLine.quantity, itemMaster.itemId, itemMaster.description) + .from(itemMaster, "im") + .join(orderLine, "ol").on(orderLine.itemId, isEqualTo(itemMaster.itemId)) + .and(orderLine.orderId, isEqualTo(constant("1"))) + .build() + .render(RenderingStrategies.MYBATIS3); + + String expectedStatement = "select ol.order_id, ol.quantity, im.item_id, im.description" + + " from ItemMaster im join OrderLine ol on ol.item_id = im.item_id" + + " and ol.order_id = 1"; + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); + + 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", 1); + assertThat(row).containsEntry("QUANTITY", 1); + assertThat(row).containsEntry("DESCRIPTION", "First Base Glove"); + assertThat(row).containsEntry("ITEM_ID", 33); + } + } +} From 6816dacbe6097495adfd044d8f3cd71607a026a2 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 12 Aug 2024 20:46:31 -0400 Subject: [PATCH 061/289] Remove obsolete code --- .../org/mybatis/dynamic/sql/SqlBuilder.java | 4 - .../sql/select/QueryExpressionDSL.java | 8 +- .../select/join/ColumnBasedJoinCondition.java | 37 ---------- .../dynamic/sql/select/join/EqualTo.java | 30 -------- .../dynamic/sql/select/join/EqualToValue.java | 27 ------- .../sql/select/join/JoinCondition.java | 22 ------ .../sql/select/join/JoinConditionVisitor.java | 22 ------ .../sql/select/join/JoinCriterion.java | 70 ------------------ .../sql/select/join/TypedJoinCondition.java | 35 --------- .../select/render/JoinConditionRenderer.java | 73 ------------------- 10 files changed, 4 insertions(+), 324 deletions(-) delete mode 100644 src/main/java/org/mybatis/dynamic/sql/select/join/ColumnBasedJoinCondition.java delete mode 100644 src/main/java/org/mybatis/dynamic/sql/select/join/EqualTo.java delete mode 100644 src/main/java/org/mybatis/dynamic/sql/select/join/EqualToValue.java delete mode 100644 src/main/java/org/mybatis/dynamic/sql/select/join/JoinCondition.java delete mode 100644 src/main/java/org/mybatis/dynamic/sql/select/join/JoinConditionVisitor.java delete mode 100644 src/main/java/org/mybatis/dynamic/sql/select/join/JoinCriterion.java delete mode 100644 src/main/java/org/mybatis/dynamic/sql/select/join/TypedJoinCondition.java delete mode 100644 src/main/java/org/mybatis/dynamic/sql/select/render/JoinConditionRenderer.java diff --git a/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java b/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java index 13f385e21..88871f6f0 100644 --- a/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java +++ b/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java @@ -56,10 +56,6 @@ import org.mybatis.dynamic.sql.select.function.Substring; import org.mybatis.dynamic.sql.select.function.Subtract; import org.mybatis.dynamic.sql.select.function.Upper; -import org.mybatis.dynamic.sql.select.join.EqualTo; -import org.mybatis.dynamic.sql.select.join.EqualToValue; -import org.mybatis.dynamic.sql.select.join.JoinCondition; -import org.mybatis.dynamic.sql.select.join.JoinCriterion; import org.mybatis.dynamic.sql.update.UpdateDSL; import org.mybatis.dynamic.sql.update.UpdateModel; import org.mybatis.dynamic.sql.util.Buildable; 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 4c025b660..be1121c85 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionDSL.java @@ -362,11 +362,11 @@ public JoinSpecificationFinisher(TableExpression table, BindableColumn jo this.joinType = joinType; addJoinSpecificationSupplier(this::buildJoinSpecification); - ColumnAndConditionCriterion c = ColumnAndConditionCriterion.withColumn(joinColumn) + ColumnAndConditionCriterion criterion = ColumnAndConditionCriterion.withColumn(joinColumn) .withCondition(joinCondition) .build(); - setInitialCriterion(c); + setInitialCriterion(criterion); } public JoinSpecificationFinisher(TableExpression table, BindableColumn joinColumn, @@ -375,12 +375,12 @@ public JoinSpecificationFinisher(TableExpression table, BindableColumn jo this.joinType = joinType; addJoinSpecificationSupplier(this::buildJoinSpecification); - ColumnAndConditionCriterion c = ColumnAndConditionCriterion.withColumn(joinColumn) + ColumnAndConditionCriterion criterion = ColumnAndConditionCriterion.withColumn(joinColumn) .withCondition(joinCondition) .withSubCriteria(Arrays.asList(subCriteria)) .build(); - setInitialCriterion(c); + setInitialCriterion(criterion); } private JoinSpecification buildJoinSpecification() { diff --git a/src/main/java/org/mybatis/dynamic/sql/select/join/ColumnBasedJoinCondition.java b/src/main/java/org/mybatis/dynamic/sql/select/join/ColumnBasedJoinCondition.java deleted file mode 100644 index 712010ca6..000000000 --- a/src/main/java/org/mybatis/dynamic/sql/select/join/ColumnBasedJoinCondition.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2016-2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.mybatis.dynamic.sql.select.join; - -import java.util.Objects; - -import org.mybatis.dynamic.sql.BasicColumn; - -public abstract class ColumnBasedJoinCondition implements JoinCondition { - private final BasicColumn rightColumn; - - protected ColumnBasedJoinCondition(BasicColumn rightColumn) { - this.rightColumn = Objects.requireNonNull(rightColumn); - } - - public BasicColumn rightColumn() { - return rightColumn; - } - - @Override - public R accept(JoinConditionVisitor visitor) { - return visitor.visit(this); - } -} diff --git a/src/main/java/org/mybatis/dynamic/sql/select/join/EqualTo.java b/src/main/java/org/mybatis/dynamic/sql/select/join/EqualTo.java deleted file mode 100644 index 6f12eb052..000000000 --- a/src/main/java/org/mybatis/dynamic/sql/select/join/EqualTo.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2016-2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.mybatis.dynamic.sql.select.join; - -import org.mybatis.dynamic.sql.BasicColumn; - -public class EqualTo extends ColumnBasedJoinCondition { - - public EqualTo(BasicColumn rightColumn) { - super(rightColumn); - } - - @Override - public String operator() { - return "="; //$NON-NLS-1$ - } -} diff --git a/src/main/java/org/mybatis/dynamic/sql/select/join/EqualToValue.java b/src/main/java/org/mybatis/dynamic/sql/select/join/EqualToValue.java deleted file mode 100644 index 2d038aa21..000000000 --- a/src/main/java/org/mybatis/dynamic/sql/select/join/EqualToValue.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2016-2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.mybatis.dynamic.sql.select.join; - -public class EqualToValue extends TypedJoinCondition { - public EqualToValue(T value) { - super(value); - } - - @Override - public String operator() { - return "="; //$NON-NLS-1$ - } -} diff --git a/src/main/java/org/mybatis/dynamic/sql/select/join/JoinCondition.java b/src/main/java/org/mybatis/dynamic/sql/select/join/JoinCondition.java deleted file mode 100644 index 183bd9a02..000000000 --- a/src/main/java/org/mybatis/dynamic/sql/select/join/JoinCondition.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2016-2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.mybatis.dynamic.sql.select.join; - -public interface JoinCondition { - String operator(); - - R accept(JoinConditionVisitor visitor); -} diff --git a/src/main/java/org/mybatis/dynamic/sql/select/join/JoinConditionVisitor.java b/src/main/java/org/mybatis/dynamic/sql/select/join/JoinConditionVisitor.java deleted file mode 100644 index 582b332f1..000000000 --- a/src/main/java/org/mybatis/dynamic/sql/select/join/JoinConditionVisitor.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2016-2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.mybatis.dynamic.sql.select.join; - -public interface JoinConditionVisitor { - R visit(TypedJoinCondition condition); - - R visit(ColumnBasedJoinCondition condition); -} diff --git a/src/main/java/org/mybatis/dynamic/sql/select/join/JoinCriterion.java b/src/main/java/org/mybatis/dynamic/sql/select/join/JoinCriterion.java deleted file mode 100644 index 81925f0e4..000000000 --- a/src/main/java/org/mybatis/dynamic/sql/select/join/JoinCriterion.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2016-2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.mybatis.dynamic.sql.select.join; - -import java.util.Objects; - -import org.mybatis.dynamic.sql.BindableColumn; - -public class JoinCriterion { - - private final String connector; - private final BindableColumn leftColumn; - private final JoinCondition joinCondition; - - private JoinCriterion(Builder builder) { - connector = Objects.requireNonNull(builder.connector); - leftColumn = Objects.requireNonNull(builder.joinColumn); - joinCondition = Objects.requireNonNull(builder.joinCondition); - } - - public String connector() { - return connector; - } - - public BindableColumn leftColumn() { - return leftColumn; - } - - public JoinCondition joinCondition() { - return joinCondition; - } - - public static class Builder { - private String connector; - private BindableColumn joinColumn; - private JoinCondition joinCondition; - - public Builder withConnector(String connector) { - this.connector = connector; - return this; - } - - public Builder withJoinColumn(BindableColumn joinColumn) { - this.joinColumn = joinColumn; - return this; - } - - public Builder withJoinCondition(JoinCondition joinCondition) { - this.joinCondition = joinCondition; - return this; - } - - public JoinCriterion build() { - return new JoinCriterion<>(this); - } - } -} diff --git a/src/main/java/org/mybatis/dynamic/sql/select/join/TypedJoinCondition.java b/src/main/java/org/mybatis/dynamic/sql/select/join/TypedJoinCondition.java deleted file mode 100644 index 12b310d1f..000000000 --- a/src/main/java/org/mybatis/dynamic/sql/select/join/TypedJoinCondition.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2016-2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.mybatis.dynamic.sql.select.join; - -import java.util.Objects; - -public abstract class TypedJoinCondition implements JoinCondition { - private final T value; - - protected TypedJoinCondition(T value) { - this.value = Objects.requireNonNull(value); - } - - public T value() { - return value; - } - - @Override - public R accept(JoinConditionVisitor visitor) { - return visitor.visit(this); - } -} diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/JoinConditionRenderer.java b/src/main/java/org/mybatis/dynamic/sql/select/render/JoinConditionRenderer.java deleted file mode 100644 index 2cba1a951..000000000 --- a/src/main/java/org/mybatis/dynamic/sql/select/render/JoinConditionRenderer.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2016-2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.mybatis.dynamic.sql.select.render; - -import static org.mybatis.dynamic.sql.util.StringUtilities.spaceBefore; - -import java.util.Objects; - -import org.mybatis.dynamic.sql.BindableColumn; -import org.mybatis.dynamic.sql.render.RenderedParameterInfo; -import org.mybatis.dynamic.sql.render.RenderingContext; -import org.mybatis.dynamic.sql.select.join.ColumnBasedJoinCondition; -import org.mybatis.dynamic.sql.select.join.JoinConditionVisitor; -import org.mybatis.dynamic.sql.select.join.TypedJoinCondition; -import org.mybatis.dynamic.sql.util.FragmentAndParameters; - -public class JoinConditionRenderer implements JoinConditionVisitor { - private final BindableColumn leftColumn; - private final RenderingContext renderingContext; - - private JoinConditionRenderer(Builder builder) { - leftColumn = Objects.requireNonNull(builder.leftColumn); - renderingContext = Objects.requireNonNull(builder.renderingContext); - } - - @Override - public FragmentAndParameters visit(TypedJoinCondition condition) { - RenderedParameterInfo parameterInfo = renderingContext.calculateParameterInfo(leftColumn); - - return FragmentAndParameters - .withFragment(condition.operator() + spaceBefore(parameterInfo.renderedPlaceHolder())) - .withParameter(parameterInfo.parameterMapKey(), condition.value()) - .build(); - } - - @Override - public FragmentAndParameters visit(ColumnBasedJoinCondition condition) { - return condition.rightColumn().render(renderingContext) - .mapFragment(s -> condition.operator() + spaceBefore(s)); - } - - public static class Builder { - private BindableColumn leftColumn; - private RenderingContext renderingContext; - - public Builder withLeftColumn(BindableColumn leftColumn) { - this.leftColumn = leftColumn; - return this; - } - - public Builder withRenderingContext(RenderingContext renderingContext) { - this.renderingContext = renderingContext; - return this; - } - - public JoinConditionRenderer build() { - return new JoinConditionRenderer<>(this); - } - } -} From 3cc83da9613e8c6fb04044ba91ac888c90ed42be Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Tue, 13 Aug 2024 20:55:43 -0400 Subject: [PATCH 062/289] Update Kotlin DSL for new Join syntax --- .../dynamic/sql/util/kotlin/JoinCollector.kt | 19 +- .../sql/util/kotlin/KotlinBaseBuilders.kt | 24 +- .../mybatis3/joins/JoinMapperNewSyntaxTest.kt | 818 ++++++++++++++++++ 3 files changed, 844 insertions(+), 17 deletions(-) create mode 100644 src/test/kotlin/examples/kotlin/mybatis3/joins/JoinMapperNewSyntaxTest.kt 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 6212167c1..0cb43d1d4 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 @@ -26,19 +26,28 @@ typealias JoinReceiver = JoinCollector.() -> Unit @MyBatisDslMarker class JoinCollector { - private var onJoinCriterion: SqlCriterion? = null - internal val andJoinCriteria = mutableListOf() + private var initialCriterion: SqlCriterion? = null + internal val subCriteria = mutableListOf() - internal fun onJoinCriterion() : SqlCriterion = invalidIfNull(onJoinCriterion, "ERROR.22") //$NON-NLS-1$ + internal fun initialCriterion() : SqlCriterion = invalidIfNull(initialCriterion, "ERROR.22") //$NON-NLS-1$ + fun on (receiver: GroupingCriteriaReceiver) { + GroupingCriteriaCollector().apply(receiver).also { + initialCriterion = it.initialCriterion + subCriteria.addAll(it.subCriteria) + } + } + + // TODO - Deprecate? fun on(leftColumn: BindableColumn): RightColumnCollector = RightColumnCollector { - onJoinCriterion = ColumnAndConditionCriterion.withColumn(leftColumn) + initialCriterion = ColumnAndConditionCriterion.withColumn(leftColumn) .withCondition(it) .build() } + // TODO - Deprecate? fun and(leftColumn: BindableColumn): RightColumnCollector = RightColumnCollector { - andJoinCriteria.add( + subCriteria.add( AndOrCriteriaGroup.Builder() .withConnector("and") //$NON-NLS-1$ .withInitialCriterion(ColumnAndConditionCriterion.withColumn(leftColumn).withCondition(it).build()) 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 4207905c6..e9d070320 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 @@ -66,12 +66,12 @@ abstract class KotlinBaseJoiningBuilder> : fun join(table: SqlTable, joinCriteria: JoinReceiver): Unit = applyToDsl(joinCriteria) { jc -> - join(table, jc.onJoinCriterion(), jc.andJoinCriteria) + join(table, jc.initialCriterion(), jc.subCriteria) } fun join(table: SqlTable, alias: String, joinCriteria: JoinReceiver): Unit = applyToDsl(joinCriteria) { jc -> - join(table, alias, jc.onJoinCriterion(), jc.andJoinCriteria) + join(table, alias, jc.initialCriterion(), jc.subCriteria) } fun join( @@ -79,17 +79,17 @@ abstract class KotlinBaseJoiningBuilder> : joinCriteria: JoinReceiver ): Unit = applyToDsl(subQuery, joinCriteria) { sq, jc -> - join(sq, sq.correlationName, jc.onJoinCriterion(), jc.andJoinCriteria) + join(sq, sq.correlationName, jc.initialCriterion(), jc.subCriteria) } fun fullJoin(table: SqlTable, joinCriteria: JoinReceiver): Unit = applyToDsl(joinCriteria) { jc -> - fullJoin(table, jc.onJoinCriterion(), jc.andJoinCriteria) + fullJoin(table, jc.initialCriterion(), jc.subCriteria) } fun fullJoin(table: SqlTable, alias: String, joinCriteria: JoinReceiver): Unit = applyToDsl(joinCriteria) { jc -> - fullJoin(table, alias, jc.onJoinCriterion(), jc.andJoinCriteria) + fullJoin(table, alias, jc.initialCriterion(), jc.subCriteria) } fun fullJoin( @@ -97,17 +97,17 @@ abstract class KotlinBaseJoiningBuilder> : joinCriteria: JoinReceiver ): Unit = applyToDsl(subQuery, joinCriteria) { sq, jc -> - fullJoin(sq, sq.correlationName, jc.onJoinCriterion(), jc.andJoinCriteria) + fullJoin(sq, sq.correlationName, jc.initialCriterion(), jc.subCriteria) } fun leftJoin(table: SqlTable, joinCriteria: JoinReceiver): Unit = applyToDsl(joinCriteria) { jc -> - leftJoin(table, jc.onJoinCriterion(), jc.andJoinCriteria) + leftJoin(table, jc.initialCriterion(), jc.subCriteria) } fun leftJoin(table: SqlTable, alias: String, joinCriteria: JoinReceiver): Unit = applyToDsl(joinCriteria) { jc -> - leftJoin(table, alias, jc.onJoinCriterion(), jc.andJoinCriteria) + leftJoin(table, alias, jc.initialCriterion(), jc.subCriteria) } fun leftJoin( @@ -115,17 +115,17 @@ abstract class KotlinBaseJoiningBuilder> : joinCriteria: JoinReceiver ): Unit = applyToDsl(subQuery, joinCriteria) { sq, jc -> - leftJoin(sq, sq.correlationName, jc.onJoinCriterion(), jc.andJoinCriteria) + leftJoin(sq, sq.correlationName, jc.initialCriterion(), jc.subCriteria) } fun rightJoin(table: SqlTable, joinCriteria: JoinReceiver): Unit = applyToDsl(joinCriteria) { jc -> - rightJoin(table, jc.onJoinCriterion(), jc.andJoinCriteria) + rightJoin(table, jc.initialCriterion(), jc.subCriteria) } fun rightJoin(table: SqlTable, alias: String, joinCriteria: JoinReceiver): Unit = applyToDsl(joinCriteria) { jc -> - rightJoin(table, alias, jc.onJoinCriterion(), jc.andJoinCriteria) + rightJoin(table, alias, jc.initialCriterion(), jc.subCriteria) } fun rightJoin( @@ -133,7 +133,7 @@ abstract class KotlinBaseJoiningBuilder> : joinCriteria: JoinReceiver ): Unit = applyToDsl(subQuery, joinCriteria) { sq, jc -> - rightJoin(sq, sq.correlationName, jc.onJoinCriterion(), jc.andJoinCriteria) + rightJoin(sq, sq.correlationName, jc.initialCriterion(), jc.subCriteria) } private fun applyToDsl(joinCriteria: JoinReceiver, applyJoin: D.(JoinCollector) -> Unit) { diff --git a/src/test/kotlin/examples/kotlin/mybatis3/joins/JoinMapperNewSyntaxTest.kt b/src/test/kotlin/examples/kotlin/mybatis3/joins/JoinMapperNewSyntaxTest.kt new file mode 100644 index 000000000..a99124a12 --- /dev/null +++ b/src/test/kotlin/examples/kotlin/mybatis3/joins/JoinMapperNewSyntaxTest.kt @@ -0,0 +1,818 @@ +/* + * Copyright 2016-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package examples.kotlin.mybatis3.joins + +import examples.kotlin.mybatis3.TestUtils +import examples.kotlin.mybatis3.joins.ItemMasterDynamicSQLSupport.itemMaster +import examples.kotlin.mybatis3.joins.OrderDetailDynamicSQLSupport.orderDetail +import examples.kotlin.mybatis3.joins.OrderLineDynamicSQLSupport.orderLine +import examples.kotlin.mybatis3.joins.OrderMasterDynamicSQLSupport.orderMaster +import examples.kotlin.mybatis3.joins.UserDynamicSQLSupport.user +import org.apache.ibatis.session.SqlSessionFactory +import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.assertThatExceptionOfType +import org.assertj.core.api.Assertions.entry +import org.junit.jupiter.api.BeforeAll +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.TestInstance +import org.mybatis.dynamic.sql.util.Messages +import org.mybatis.dynamic.sql.util.kotlin.KInvalidSQLException +import org.mybatis.dynamic.sql.util.kotlin.elements.constant +import org.mybatis.dynamic.sql.util.kotlin.elements.invoke +import org.mybatis.dynamic.sql.util.kotlin.mybatis3.select + +@Suppress("LargeClass") +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class JoinMapperNewSyntaxTest { + private lateinit var sqlSessionFactory: SqlSessionFactory + + @BeforeAll + fun setup() { + sqlSessionFactory = TestUtils.buildSqlSessionFactory { + withInitializationScript("/examples/kotlin/mybatis3/joins/CreateJoinDB.sql") + withMapper(JoinMapper::class) + } + } + + @Test + fun testSingleTableJoin() { + sqlSessionFactory.openSession().use { session -> + val mapper = session.getMapper(JoinMapper::class.java) + + val selectStatement = select( + orderMaster.orderId, orderMaster.orderDate, + orderDetail.lineNumber, orderDetail.description, orderDetail.quantity + ) { + from(orderMaster, "om") + join(orderDetail, "od") { + on { orderMaster.orderId isEqualTo orderDetail.orderId } + } + } + + val 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.selectStatement).isEqualTo(expectedStatement) + + val rows = mapper.selectMany(selectStatement) + + assertThat(rows).hasSize(2) + + with(rows[0]) { + assertThat(id).isEqualTo(1) + assertThat(details).hasSize(2) + assertThat(details?.get(0)?.lineNumber).isEqualTo(1) + assertThat(details?.get(1)?.lineNumber).isEqualTo(2) + } + + with(rows[1]) { + assertThat(id).isEqualTo(2) + assertThat(details).hasSize(1) + assertThat(details?.get(0)?.lineNumber).isEqualTo(1) + } + } + } + + @Test + fun testSingleTableJoinWithValue() { + sqlSessionFactory.openSession().use { session -> + val mapper = session.getMapper(JoinMapper::class.java) + + val selectStatement = select( + orderMaster.orderId, orderMaster.orderDate, + orderDetail.lineNumber, orderDetail.description, orderDetail.quantity + ) { + from(orderMaster, "om") + join(orderDetail, "od") { + on { + orderMaster.orderId isEqualTo orderDetail.orderId + and { orderMaster.orderId isEqualTo 1 } + } + } + } + + val 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 = #{parameters.p1,jdbcType=INTEGER}" + + assertThat(selectStatement.selectStatement).isEqualTo(expectedStatement) + + val rows = mapper.selectMany(selectStatement) + + assertThat(rows).hasSize(1) + + with(rows[0]) { + assertThat(id).isEqualTo(1) + assertThat(details).hasSize(2) + assertThat(details?.get(0)?.lineNumber).isEqualTo(1) + assertThat(details?.get(1)?.lineNumber).isEqualTo(2) + } + } + } + + @Test + fun testSingleTableJoinWithConstant() { + sqlSessionFactory.openSession().use { session -> + val mapper = session.getMapper(JoinMapper::class.java) + + val selectStatement = select( + orderMaster.orderId, orderMaster.orderDate, + orderDetail.lineNumber, orderDetail.description, orderDetail.quantity + ) { + from(orderMaster, "om") + join(orderDetail, "od") { + on { + orderMaster.orderId isEqualTo orderDetail.orderId + and { orderMaster.orderId isEqualTo constant("1") } + } + } + } + + val 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 = 1" + + assertThat(selectStatement.selectStatement).isEqualTo(expectedStatement) + + val rows = mapper.selectMany(selectStatement) + + assertThat(rows).hasSize(1) + + with(rows[0]) { + assertThat(id).isEqualTo(1) + assertThat(details).hasSize(2) + assertThat(details?.get(0)?.lineNumber).isEqualTo(1) + assertThat(details?.get(1)?.lineNumber).isEqualTo(2) + } + } + } + + @Test + fun testCompoundJoin1() { + // this is a nonsensical join, but it does test the "and" capability + val selectStatement = select( + orderMaster.orderId, orderMaster.orderDate, orderDetail.lineNumber, + orderDetail.description, orderDetail.quantity + ) { + from(orderMaster, "om") + join(orderDetail, "od") { + on { + orderMaster.orderId isEqualTo orderDetail.orderId + and { orderMaster.orderId isEqualTo orderDetail.orderId } + } + } + } + + val 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.selectStatement).isEqualTo(expectedStatement) + } + + @Test + fun testCompoundJoin2() { + // this is a nonsensical join, but it does test the "and" capability + val selectStatement = select( + orderMaster.orderId, orderMaster.orderDate, orderDetail.lineNumber, + orderDetail.description, orderDetail.quantity + ) { + from(orderMaster, "om") + join(orderDetail, "od") { + on { + orderMaster.orderId isEqualTo orderDetail.orderId + and { orderMaster.orderId isEqualTo orderDetail.orderId } + } + } + where { orderMaster.orderId isEqualTo 1 } + } + + val 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" + + " where om.order_id = #{parameters.p1,jdbcType=INTEGER}" + assertThat(selectStatement.selectStatement).isEqualTo(expectedStatement) + } + + @Test + fun testMultipleTableJoinWithWhereClause() { + sqlSessionFactory.openSession().use { session -> + val mapper = session.getMapper(JoinMapper::class.java) + + val selectStatement = select( + orderMaster.orderId, orderMaster.orderDate, orderLine.lineNumber, + itemMaster.description, orderLine.quantity + ) { + from(orderMaster, "om") + join(orderLine, "ol") { + on { orderMaster.orderId isEqualTo orderLine.orderId } + } + join(itemMaster, "im") { + on { orderLine.itemId isEqualTo itemMaster.itemId } + } + where { orderMaster.orderId isEqualTo 2 } + } + + val 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.selectStatement).isEqualTo(expectedStatement) + + val rows = mapper.selectMany(selectStatement) + + assertThat(rows).hasSize(1) + with(rows[0]) { + assertThat(id).isEqualTo(2) + assertThat(details).hasSize(2) + assertThat(details?.get(0)?.lineNumber).isEqualTo(1) + assertThat(details?.get(1)?.lineNumber).isEqualTo(2) + } + } + } + + @Test + fun testFullJoinWithAliases() { + sqlSessionFactory.openSession().use { session -> + val mapper = session.getMapper(JoinMapper::class.java) + + val selectStatement = select( + orderLine.orderId, orderLine.quantity, itemMaster.itemId, itemMaster.description + ) { + from(orderMaster, "om") + join(orderLine, "ol") { + on { orderMaster.orderId isEqualTo orderLine.orderId } + } + fullJoin(itemMaster, "im") { + on { orderLine.itemId isEqualTo itemMaster.itemId } + } + orderBy(orderLine.orderId, itemMaster.itemId) + } + + val 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.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 + @Suppress("LongMethod") + fun testFullJoinWithSubQuery() { + sqlSessionFactory.openSession().use { session -> + val mapper = session.getMapper(JoinMapper::class.java) + + val selectStatement = select( + "ol"(orderLine.orderId), orderLine.quantity, "im"(itemMaster.itemId), + itemMaster.description + ) { + from { + select(orderMaster.allColumns()) { + from(orderMaster) + } + + "om" + } + join( + subQuery = { + select(orderLine.allColumns()) { + from(orderLine) + } + + "ol" + }, + joinCriteria = { + on { "om"(orderMaster.orderId) isEqualTo "ol"(orderLine.orderId) } + } + ) + fullJoin( + { + select(itemMaster.allColumns()) { + from(itemMaster) + } + + "im" + } + ) { + on { "ol"(orderLine.itemId) isEqualTo "im"(itemMaster.itemId) } + } + 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() { + sqlSessionFactory.openSession().use { session -> + val mapper = session.getMapper(JoinMapper::class.java) + + val selectStatement = select( + orderLine.orderId, orderLine.quantity, itemMaster.itemId, itemMaster.description + ) { + from(orderMaster, "om") + join(orderLine, "ol") { + on { orderMaster.orderId isEqualTo orderLine.orderId } + } + fullJoin(itemMaster) { + on { orderLine.itemId isEqualTo itemMaster.itemId } + } + orderBy(orderLine.orderId, itemMaster.itemId) + } + + val expectedStatement = "select ol.order_id, ol.quantity, ItemMaster.item_id, ItemMaster.description" + + " from OrderMaster om join OrderLine ol on om.order_id = ol.order_id" + + " full join ItemMaster on ol.item_id = ItemMaster.item_id" + + " order by order_id, item_id" + + assertThat(selectStatement.selectStatement).isEqualTo(expectedStatement) + + val rows = mapper.selectManyMappedRows(selectStatement) + + assertThat(rows).hasSize(6) + + assertThat(rows[0]).containsExactly( + entry("DESCRIPTION", "Catcher Glove"), + entry("ITEM_ID", 55) + ) + + assertThat(rows[3]).containsExactly( + entry("ORDER_ID", 2), + entry("QUANTITY", 6) + ) + + assertThat(rows[5]).containsExactly( + entry("ORDER_ID", 2), + entry("QUANTITY", 1), + entry("DESCRIPTION", "Outfield Glove"), + entry("ITEM_ID", 44) + ) + } + } + + @Test + fun testLeftJoinWithAliases() { + sqlSessionFactory.openSession().use { session -> + val mapper = session.getMapper(JoinMapper::class.java) + + val selectStatement = select( + orderLine.orderId, orderLine.quantity, itemMaster.itemId, itemMaster.description + ) { + from(orderMaster, "om") + join(orderLine, "ol") { + on { orderMaster.orderId isEqualTo orderLine.orderId } + } + leftJoin(itemMaster, "im") { + on { orderLine.itemId isEqualTo itemMaster.itemId } + } + orderBy(orderLine.orderId, itemMaster.itemId) + } + + val 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.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 testLeftJoinWithSubQuery() { + sqlSessionFactory.openSession().use { session -> + val mapper = session.getMapper(JoinMapper::class.java) + + val selectStatement = select( + orderLine.orderId, orderLine.quantity, "im"(itemMaster.itemId), + itemMaster.description + ) { + from(orderMaster, "om") + join(orderLine, "ol") { + on { orderMaster.orderId isEqualTo orderLine.orderId } + } + leftJoin( + { + select(itemMaster.allColumns()) { + from(itemMaster) + } + + "im" + } + ) { + on { orderLine.itemId isEqualTo "im"(itemMaster.itemId) } + } + 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() { + sqlSessionFactory.openSession().use { session -> + val mapper = session.getMapper(JoinMapper::class.java) + + val selectStatement = select( + orderLine.orderId, orderLine.quantity, itemMaster.itemId, itemMaster.description + ) { + from(orderMaster, "om") + join(orderLine, "ol") { + on { orderMaster.orderId isEqualTo orderLine.orderId } + } + leftJoin(itemMaster) { + on { orderLine.itemId isEqualTo itemMaster.itemId } + } + orderBy(orderLine.orderId, itemMaster.itemId) + } + + val expectedStatement = "select ol.order_id, ol.quantity, ItemMaster.item_id, ItemMaster.description" + + " from OrderMaster om join OrderLine ol on om.order_id = ol.order_id" + + " left join ItemMaster on ol.item_id = ItemMaster.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 testRightJoinWithAliases() { + sqlSessionFactory.openSession().use { session -> + val mapper = session.getMapper(JoinMapper::class.java) + + val selectStatement = select( + orderLine.orderId, orderLine.quantity, itemMaster.itemId, itemMaster.description + ) { + from(orderMaster, "om") + join(orderLine, "ol") { + on { orderMaster.orderId isEqualTo orderLine.orderId } + } + rightJoin(itemMaster, "im") { + on { orderLine.itemId isEqualTo itemMaster.itemId } + } + orderBy(orderLine.orderId, itemMaster.itemId) + } + + val 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.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 testRightJoinWithSubQuery() { + sqlSessionFactory.openSession().use { session -> + val mapper = session.getMapper(JoinMapper::class.java) + + val selectStatement = select( + orderLine.orderId, orderLine.quantity, + "im"(itemMaster.itemId), itemMaster.description + ) { + from(orderMaster, "om") + join(orderLine, "ol") { + on { orderMaster.orderId isEqualTo orderLine.orderId } + } + rightJoin( + { + select(itemMaster.allColumns()) { + from(itemMaster) + } + + "im" + } + ) { + on { orderLine.itemId isEqualTo "im"(itemMaster.itemId) } + } + 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() { + sqlSessionFactory.openSession().use { session -> + val mapper = session.getMapper(JoinMapper::class.java) + + val selectStatement = select( + orderLine.orderId, orderLine.quantity, itemMaster.itemId, itemMaster.description + ) { + from(orderMaster, "om") + join(orderLine, "ol") { + on { orderMaster.orderId isEqualTo orderLine.orderId } + } + rightJoin(itemMaster) { + on { orderLine.itemId isEqualTo itemMaster.itemId } + } + orderBy(orderLine.orderId, itemMaster.itemId) + } + + val expectedStatement = "select ol.order_id, ol.quantity, ItemMaster.item_id, ItemMaster.description" + + " from OrderMaster om join OrderLine ol on om.order_id = ol.order_id" + + " right join ItemMaster on ol.item_id = ItemMaster.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 testSelf() { + sqlSessionFactory.openSession().use { session -> + val mapper = session.getMapper(JoinMapper::class.java) + + // create second table instance for self-join + val user2 = UserDynamicSQLSupport.User() + + // get Bamm Bamm's parent - should be Barney + val selectStatement = select(user.userId, user.userName, user.parentId) { + from(user, "u1") + join(user2, "u2") { + on { user.userId isEqualTo user2.parentId } + } + where { user2.userId isEqualTo 4 } + } + + val 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.selectStatement).isEqualTo(expectedStatement) + val rows = mapper.selectManyMappedRows(selectStatement) + + assertThat(rows).hasSize(1) + assertThat(rows[0]).containsExactly( + entry("USER_ID", 2), + entry("USER_NAME", "Barney"), + ) + } + } + + @Test + fun testSelfWithNewAlias() { + sqlSessionFactory.openSession().use { session -> + val mapper = session.getMapper(JoinMapper::class.java) + + // create second table instance for self-join + val user2 = user.withAlias("u2") + + // get Bamm Bamm's parent - should be Barney + val selectStatement = select(user.userId, user.userName, user.parentId) { + from(user) + join(user2) { + on { user.userId isEqualTo user2.parentId } + } + where { user2.userId isEqualTo 4 } + } + + val expectedStatement = "select User.user_id, User.user_name, User.parent_id" + + " from User join User u2 on User.user_id = u2.parent_id" + + " where u2.user_id = #{parameters.p1,jdbcType=INTEGER}" + assertThat(selectStatement.selectStatement).isEqualTo(expectedStatement) + + val rows = mapper.selectManyMappedRows(selectStatement) + assertThat(rows).hasSize(1) + + assertThat(rows[0]).containsExactly( + entry("USER_ID", 2), + entry("USER_NAME", "Barney"), + ) + } + } + + @Test + fun testSelfWithNewAliasAndOverride() { + sqlSessionFactory.openSession().use { session -> + val mapper = session.getMapper(JoinMapper::class.java) + + // create second table instance for self-join + val user2 = user.withAlias("other_user") + + // get Bamm Bamm's parent - should be Barney + val selectStatement = select(user.userId, user.userName, user.parentId) { + from(user, "u1") + join(user2, "u2") { + on { user.userId isEqualTo user2.parentId } + } + where { user2.userId isEqualTo 4 } + } + + val 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.selectStatement).isEqualTo(expectedStatement) + val rows = mapper.selectManyMappedRows(selectStatement) + assertThat(rows).hasSize(1) + + assertThat(rows[0]).containsExactly( + entry("USER_ID", 2), + entry("USER_NAME", "Barney"), + ) + } + } + + @Test + fun testJoinWithNoOnCondition() { + // create second table instance for self-join + val user2 = user.withAlias("other_user") + + assertThatExceptionOfType(KInvalidSQLException::class.java).isThrownBy { + select(user.userId, user.userName, user.parentId) { + from(user, "u1") + join(user2, "u2") { } + where { user2.userId isEqualTo 4 } + } + }.withMessage(Messages.getString("ERROR.22")) //$NON-NLS-1$ + } +} From d623287d61d214e5350efa0dd745080e84660298 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 14 Aug 2024 11:50:46 +0000 Subject: [PATCH 063/289] Update dependency org.springframework:spring-jdbc to v6.1.12 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9495ec37d..3e5d312db 100644 --- a/pom.xml +++ b/pom.xml @@ -94,7 +94,7 @@ org.springframework spring-jdbc - 6.1.11 + 6.1.12 provided true From 86859a2fa5974c2790cb54e56b4eaf422d43eac3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 14 Aug 2024 11:50:50 +0000 Subject: [PATCH 064/289] Update junit5 monorepo to v5.11.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9495ec37d..41c591522 100644 --- a/pom.xml +++ b/pom.xml @@ -58,7 +58,7 @@ 17 17 - 5.10.3 + 5.11.0 5.1.2 checkstyle-override.xml From f1c736229b5c972012ac476d89b46067caf653f3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 15 Aug 2024 17:35:50 +0000 Subject: [PATCH 065/289] Update dependency ch.qos.logback:logback-classic to v1.5.7 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b1a34f202..1cef97f04 100644 --- a/pom.xml +++ b/pom.xml @@ -163,7 +163,7 @@ ch.qos.logback logback-classic - 1.5.6 + 1.5.7 test From 22bc77f5b1f54a1e16268d116181e3bc6d8ad831 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Fri, 16 Aug 2024 15:22:48 -0400 Subject: [PATCH 066/289] Add "WhenPresent" versions of the paging methods --- .../mybatis/dynamic/sql/delete/DeleteDSL.java | 10 +- .../dynamic/sql/select/MultiSelectDSL.java | 25 +++- .../sql/select/QueryExpressionDSL.java | 90 ++++++++++-- .../mybatis/dynamic/sql/select/SelectDSL.java | 25 +++- .../mybatis/dynamic/sql/update/UpdateDSL.java | 10 +- .../sql/util/kotlin/KotlinDeleteBuilder.kt | 6 +- .../util/kotlin/KotlinMultiSelectBuilder.kt | 20 ++- .../sql/util/kotlin/KotlinSelectBuilder.kt | 18 ++- .../sql/util/kotlin/KotlinUpdateBuilder.kt | 6 +- .../examples/animal/data/AnimalDataTest.java | 18 +++ .../VariousPagingAndLimitScenariosTest.java | 132 ++++++++++++++++++ 11 files changed, 328 insertions(+), 32 deletions(-) create mode 100644 src/test/java/examples/animal/data/VariousPagingAndLimitScenariosTest.java diff --git a/src/main/java/org/mybatis/dynamic/sql/delete/DeleteDSL.java b/src/main/java/org/mybatis/dynamic/sql/delete/DeleteDSL.java index e7c1ad184..825eaa699 100644 --- a/src/main/java/org/mybatis/dynamic/sql/delete/DeleteDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/delete/DeleteDSL.java @@ -56,6 +56,10 @@ public DeleteWhereBuilder where() { } public DeleteDSL limit(long limit) { + return limitWhenPresent(limit); + } + + public DeleteDSL limitWhenPresent(Long limit) { this.limit = limit; return this; } @@ -115,7 +119,11 @@ private DeleteWhereBuilder() { } public DeleteDSL limit(long limit) { - return DeleteDSL.this.limit(limit); + return limitWhenPresent(limit); + } + + public DeleteDSL limitWhenPresent(Long limit) { + return DeleteDSL.this.limitWhenPresent(limit); } public DeleteDSL orderBy(SortSpecification... columns) { diff --git a/src/main/java/org/mybatis/dynamic/sql/select/MultiSelectDSL.java b/src/main/java/org/mybatis/dynamic/sql/select/MultiSelectDSL.java index ad0f2aba3..d23c6deb9 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/MultiSelectDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/MultiSelectDSL.java @@ -62,16 +62,28 @@ public MultiSelectDSL orderBy(Collection columns) { } public LimitFinisher limit(long limit) { + return limitWhenPresent(limit); + } + + public LimitFinisher limitWhenPresent(Long limit) { this.limit = limit; return new LimitFinisher(); } public OffsetFirstFinisher offset(long offset) { + return offsetWhenPresent(offset); + } + + public OffsetFirstFinisher offsetWhenPresent(Long offset) { this.offset = offset; return new OffsetFirstFinisher(); } public FetchFirstFinisher fetchFirst(long fetchFirstRows) { + return fetchFirstWhenPresent(fetchFirstRows); + } + + public FetchFirstFinisher fetchFirstWhenPresent(Long fetchFirstRows) { this.fetchFirstRows = fetchFirstRows; return new FetchFirstFinisher(); } @@ -104,7 +116,11 @@ public MultiSelectDSL configureStatement(Consumer consum public class LimitFinisher implements Buildable { public OffsetFinisher offset(long offset) { - MultiSelectDSL.this.offset(offset); + return offsetWhenPresent(offset); + } + + public OffsetFinisher offsetWhenPresent(Long offset) { + MultiSelectDSL.this.offsetWhenPresent(offset); return new OffsetFinisher(); } @@ -125,8 +141,11 @@ public MultiSelectModel build() { public class OffsetFirstFinisher implements Buildable { public FetchFirstFinisher fetchFirst(long fetchFirstRows) { - MultiSelectDSL.this.fetchFirst(fetchFirstRows); - return new FetchFirstFinisher(); + return fetchFirstWhenPresent(fetchFirstRows); + } + + public FetchFirstFinisher fetchFirstWhenPresent(Long fetchFirstRows) { + return MultiSelectDSL.this.fetchFirstWhenPresent(fetchFirstRows); } @NotNull 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 593252979..0fab5ad4c 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionDSL.java @@ -195,15 +195,27 @@ protected QueryExpressionModel buildModel() { } public SelectDSL.LimitFinisher limit(long limit) { - return selectDSL.limit(limit); + return limitWhenPresent(limit); + } + + public SelectDSL.LimitFinisher limitWhenPresent(Long limit) { + return selectDSL.limitWhenPresent(limit); } public SelectDSL.OffsetFirstFinisher offset(long offset) { - return selectDSL.offset(offset); + return offsetWhenPresent(offset); + } + + public SelectDSL.OffsetFirstFinisher offsetWhenPresent(Long offset) { + return selectDSL.offsetWhenPresent(offset); } public SelectDSL.FetchFirstFinisher fetchFirst(long fetchFirstRows) { - return selectDSL.fetchFirst(fetchFirstRows); + return fetchFirstWhenPresent(fetchFirstRows); + } + + public SelectDSL.FetchFirstFinisher fetchFirstWhenPresent(Long fetchFirstRows) { + return selectDSL.fetchFirstWhenPresent(fetchFirstRows); } @Override @@ -303,15 +315,27 @@ public GroupByFinisher groupBy(Collection columns) { } public SelectDSL.LimitFinisher limit(long limit) { - return QueryExpressionDSL.this.limit(limit); + return limitWhenPresent(limit); + } + + public SelectDSL.LimitFinisher limitWhenPresent(Long limit) { + return QueryExpressionDSL.this.limitWhenPresent(limit); } public SelectDSL.OffsetFirstFinisher offset(long offset) { - return QueryExpressionDSL.this.offset(offset); + return offsetWhenPresent(offset); + } + + public SelectDSL.OffsetFirstFinisher offsetWhenPresent(Long offset) { + return QueryExpressionDSL.this.offsetWhenPresent(offset); } public SelectDSL.FetchFirstFinisher fetchFirst(long fetchFirstRows) { - return QueryExpressionDSL.this.fetchFirst(fetchFirstRows); + return fetchFirstWhenPresent(fetchFirstRows); + } + + public SelectDSL.FetchFirstFinisher fetchFirstWhenPresent(Long fetchFirstRows) { + return QueryExpressionDSL.this.fetchFirstWhenPresent(fetchFirstRows); } @NotNull @@ -485,15 +509,27 @@ public SelectDSL orderBy(Collection columns) { } public SelectDSL.LimitFinisher limit(long limit) { - return QueryExpressionDSL.this.limit(limit); + return limitWhenPresent(limit); + } + + public SelectDSL.LimitFinisher limitWhenPresent(Long limit) { + return QueryExpressionDSL.this.limitWhenPresent(limit); } public SelectDSL.OffsetFirstFinisher offset(long offset) { - return QueryExpressionDSL.this.offset(offset); + return offsetWhenPresent(offset); + } + + public SelectDSL.OffsetFirstFinisher offsetWhenPresent(Long offset) { + return QueryExpressionDSL.this.offsetWhenPresent(offset); } public SelectDSL.FetchFirstFinisher fetchFirst(long fetchFirstRows) { - return QueryExpressionDSL.this.fetchFirst(fetchFirstRows); + return fetchFirstWhenPresent(fetchFirstRows); + } + + public SelectDSL.FetchFirstFinisher fetchFirstWhenPresent(Long fetchFirstRows) { + return QueryExpressionDSL.this.fetchFirstWhenPresent(fetchFirstRows); } } @@ -521,15 +557,27 @@ public UnionBuilder unionAll() { } public SelectDSL.LimitFinisher limit(long limit) { - return QueryExpressionDSL.this.limit(limit); + return limitWhenPresent(limit); + } + + public SelectDSL.LimitFinisher limitWhenPresent(Long limit) { + return QueryExpressionDSL.this.limitWhenPresent(limit); } public SelectDSL.OffsetFirstFinisher offset(long offset) { - return QueryExpressionDSL.this.offset(offset); + return offsetWhenPresent(offset); + } + + public SelectDSL.OffsetFirstFinisher offsetWhenPresent(Long offset) { + return QueryExpressionDSL.this.offsetWhenPresent(offset); } public SelectDSL.FetchFirstFinisher fetchFirst(long fetchFirstRows) { - return QueryExpressionDSL.this.fetchFirst(fetchFirstRows); + return fetchFirstWhenPresent(fetchFirstRows); + } + + public SelectDSL.FetchFirstFinisher fetchFirstWhenPresent(Long fetchFirstRows) { + return QueryExpressionDSL.this.fetchFirstWhenPresent(fetchFirstRows); } @Override @@ -575,15 +623,27 @@ public class QueryExpressionHavingBuilder extends AbstractHavingFinisher { public SelectDSL.FetchFirstFinisher fetchFirst(long fetchFirstRows) { - return QueryExpressionDSL.this.fetchFirst(fetchFirstRows); + return fetchFirstWhenPresent(fetchFirstRows); + } + + public SelectDSL.FetchFirstFinisher fetchFirstWhenPresent(Long fetchFirstRows) { + return QueryExpressionDSL.this.fetchFirstWhenPresent(fetchFirstRows); } public SelectDSL.OffsetFirstFinisher offset(long offset) { - return QueryExpressionDSL.this.offset(offset); + return offsetWhenPresent(offset); + } + + public SelectDSL.OffsetFirstFinisher offsetWhenPresent(Long offset) { + return QueryExpressionDSL.this.offsetWhenPresent(offset); } public SelectDSL.LimitFinisher limit(long limit) { - return QueryExpressionDSL.this.limit(limit); + return limitWhenPresent(limit); + } + + public SelectDSL.LimitFinisher limitWhenPresent(Long limit) { + return QueryExpressionDSL.this.limitWhenPresent(limit); } public SelectDSL orderBy(SortSpecification... columns) { diff --git a/src/main/java/org/mybatis/dynamic/sql/select/SelectDSL.java b/src/main/java/org/mybatis/dynamic/sql/select/SelectDSL.java index cb1fae92d..2c9aaea36 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/SelectDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/SelectDSL.java @@ -108,16 +108,28 @@ void orderBy(Collection columns) { } public LimitFinisher limit(long limit) { + return limitWhenPresent(limit); + } + + public LimitFinisher limitWhenPresent(Long limit) { this.limit = limit; return new LimitFinisher(); } public OffsetFirstFinisher offset(long offset) { + return offsetWhenPresent(offset); + } + + public OffsetFirstFinisher offsetWhenPresent(Long offset) { this.offset = offset; return new OffsetFirstFinisher(); } public FetchFirstFinisher fetchFirst(long fetchFirstRows) { + return fetchFirstWhenPresent(fetchFirstRows); + } + + public FetchFirstFinisher fetchFirstWhenPresent(Long fetchFirstRows) { this.fetchFirstRows = fetchFirstRows; return new FetchFirstFinisher(); } @@ -155,7 +167,11 @@ private Optional buildPagingModel() { public class LimitFinisher implements Buildable { public OffsetFinisher offset(long offset) { - SelectDSL.this.offset(offset); + return offsetWhenPresent(offset); + } + + public OffsetFinisher offsetWhenPresent(Long offset) { + SelectDSL.this.offsetWhenPresent(offset); return new OffsetFinisher(); } @@ -176,8 +192,11 @@ public R build() { public class OffsetFirstFinisher implements Buildable { public FetchFirstFinisher fetchFirst(long fetchFirstRows) { - SelectDSL.this.fetchFirst(fetchFirstRows); - return new FetchFirstFinisher(); + return fetchFirstWhenPresent(fetchFirstRows); + } + + public FetchFirstFinisher fetchFirstWhenPresent(Long fetchFirstRows) { + return SelectDSL.this.fetchFirstWhenPresent(fetchFirstRows); } @NotNull diff --git a/src/main/java/org/mybatis/dynamic/sql/update/UpdateDSL.java b/src/main/java/org/mybatis/dynamic/sql/update/UpdateDSL.java index 8cf7259a3..15f021b16 100644 --- a/src/main/java/org/mybatis/dynamic/sql/update/UpdateDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/update/UpdateDSL.java @@ -76,6 +76,10 @@ public UpdateWhereBuilder where() { } public UpdateDSL limit(long limit) { + return limitWhenPresent(limit); + } + + public UpdateDSL limitWhenPresent(Long limit) { this.limit = limit; return this; } @@ -196,7 +200,11 @@ private UpdateWhereBuilder() { } public UpdateDSL limit(long limit) { - return UpdateDSL.this.limit(limit); + return limitWhenPresent(limit); + } + + public UpdateDSL limitWhenPresent(Long limit) { + return UpdateDSL.this.limitWhenPresent(limit); } public UpdateDSL orderBy(SortSpecification... columns) { 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 011928b9e..3146d5e11 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 @@ -30,7 +30,11 @@ class KotlinDeleteBuilder(private val dsl: DeleteDSL) : } fun limit(limit: Long) { - dsl.limit(limit) + limitWhenPresent(limit) + } + + fun limitWhenPresent(limit: Long?) { + dsl.limitWhenPresent(limit) } override fun build(): DeleteModel = dsl.build() diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinMultiSelectBuilder.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinMultiSelectBuilder.kt index 440232397..3c3ab1f71 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinMultiSelectBuilder.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinMultiSelectBuilder.kt @@ -28,7 +28,7 @@ typealias MultiSelectCompleter = KotlinMultiSelectBuilder.() -> Unit @MyBatisDslMarker class KotlinMultiSelectBuilder: Buildable { private var dsl: MultiSelectDSL? = null - private set(value) { + set(value) { assertNull(field, "ERROR.33") //$NON-NLS-1$ field = value } @@ -64,15 +64,27 @@ class KotlinMultiSelectBuilder: Buildable { } fun limit(limit: Long) { - getDsl().limit(limit) + limitWhenPresent(limit) + } + + fun limitWhenPresent(limit: Long?) { + getDsl().limitWhenPresent(limit) } fun offset(offset: Long) { - getDsl().offset(offset) + offsetWhenPresent(offset) + } + + fun offsetWhenPresent(offset: Long?) { + getDsl().offsetWhenPresent(offset) } fun fetchFirst(fetchFirstRows: Long) { - getDsl().fetchFirst(fetchFirstRows).rowsOnly() + fetchFirstWhenPresent(fetchFirstRows) + } + + fun fetchFirstWhenPresent(fetchFirstRows: Long?) { + getDsl().fetchFirstWhenPresent(fetchFirstRows).rowsOnly() } fun configureStatement(c: StatementConfiguration.() -> Unit) { 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 e62b5ef26..4bd8cdefa 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 @@ -59,15 +59,27 @@ class KotlinSelectBuilder(private val fromGatherer: QueryExpressionDSL.FromGathe } fun limit(limit: Long) { - getDsl().limit(limit) + limitWhenPresent(limit) + } + + fun limitWhenPresent(limit: Long?) { + getDsl().limitWhenPresent(limit) } fun offset(offset: Long) { - getDsl().offset(offset) + offsetWhenPresent(offset) + } + + fun offsetWhenPresent(offset: Long?) { + getDsl().offsetWhenPresent(offset) } fun fetchFirst(fetchFirstRows: Long) { - getDsl().fetchFirst(fetchFirstRows).rowsOnly() + fetchFirstWhenPresent(fetchFirstRows) + } + + fun fetchFirstWhenPresent(fetchFirstRows: Long?) { + getDsl().fetchFirstWhenPresent(fetchFirstRows).rowsOnly() } fun union(union: KotlinUnionBuilder.() -> Unit): Unit = 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 ef7eb6804..93dbfaa8a 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 @@ -34,7 +34,11 @@ class KotlinUpdateBuilder(private val dsl: UpdateDSL) : } fun limit(limit: Long) { - dsl.limit(limit) + limitWhenPresent(limit) + } + + fun limitWhenPresent(limit: Long?) { + dsl.limitWhenPresent(limit) } override fun build(): UpdateModel = dsl.build() diff --git a/src/test/java/examples/animal/data/AnimalDataTest.java b/src/test/java/examples/animal/data/AnimalDataTest.java index d751decab..12a21e3f6 100644 --- a/src/test/java/examples/animal/data/AnimalDataTest.java +++ b/src/test/java/examples/animal/data/AnimalDataTest.java @@ -108,6 +108,24 @@ void testSelectAllRows() { } } + @Test + void testSelectAllRowsWithNullLimit() { + try (SqlSession sqlSession = sqlSessionFactory.openSession()) { + AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); + SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) + .from(animalData) + .limitWhenPresent(null) + .build() + .render(RenderingStrategies.MYBATIS3); + List animals = mapper.selectMany(selectStatement); + + assertAll( + () -> assertThat(animals).hasSize(65), + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + ); + } + } + @Test void testSelectAllRowsWithRowBounds() { try (SqlSession sqlSession = sqlSessionFactory.openSession()) { diff --git a/src/test/java/examples/animal/data/VariousPagingAndLimitScenariosTest.java b/src/test/java/examples/animal/data/VariousPagingAndLimitScenariosTest.java new file mode 100644 index 000000000..1fde45c49 --- /dev/null +++ b/src/test/java/examples/animal/data/VariousPagingAndLimitScenariosTest.java @@ -0,0 +1,132 @@ +/* + * Copyright 2016-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package examples.animal.data; + +import static examples.animal.data.AnimalDataDynamicSqlSupport.animalData; +import static examples.animal.data.AnimalDataDynamicSqlSupport.id; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mybatis.dynamic.sql.SqlBuilder.deleteFrom; +import static org.mybatis.dynamic.sql.SqlBuilder.isLessThan; +import static org.mybatis.dynamic.sql.SqlBuilder.select; +import static org.mybatis.dynamic.sql.SqlBuilder.update; + +import org.junit.jupiter.api.Test; +import org.mybatis.dynamic.sql.render.RenderingStrategies; + +class VariousPagingAndLimitScenariosTest { + + @Test + void testOptionalLimitOnDelete() { + var deleteStatement = deleteFrom(animalData) + .limitWhenPresent(null) + .build() + .render(RenderingStrategies.SPRING_NAMED_PARAMETER); + + assertThat(deleteStatement.getDeleteStatement()).isEqualTo("delete from AnimalData"); + } + + @Test + void testOptionalLimitOnDeleteWithWhere() { + var deleteStatement = deleteFrom(animalData) + .where(id, isLessThan(22)) + .limitWhenPresent(null) + .build() + .render(RenderingStrategies.SPRING_NAMED_PARAMETER); + + assertThat(deleteStatement.getDeleteStatement()) + .isEqualTo("delete from AnimalData where id < :p1"); + } + + @Test + void testOptionalLimitOnUpdate() { + var updateStatement = update(animalData) + .set(id).equalTo(1) + .limitWhenPresent(null) + .build() + .render(RenderingStrategies.SPRING_NAMED_PARAMETER); + + assertThat(updateStatement.getUpdateStatement()).isEqualTo("update AnimalData set id = :p1"); + } + + @Test + void testOptionalLimitOnUpdateWithWhere() { + var updateStatement = update(animalData) + .set(id).equalTo(1) + .where(id, isLessThan(22)) + .limitWhenPresent(null) + .build() + .render(RenderingStrategies.SPRING_NAMED_PARAMETER); + + assertThat(updateStatement.getUpdateStatement()).isEqualTo("update AnimalData set id = :p1 where id < :p2"); + } + + @Test + void testOptionalLimitOnSelect() { + var selectStatement = select(animalData.allColumns()) + .from(animalData) + .limitWhenPresent(null) + .build() + .render(RenderingStrategies.SPRING_NAMED_PARAMETER); + + assertThat(selectStatement.getSelectStatement()).isEqualTo("select * from AnimalData"); + } + + @Test + void testOptionalOffsetOnSelect() { + var selectStatement = select(animalData.allColumns()) + .from(animalData) + .offsetWhenPresent(null) + .build() + .render(RenderingStrategies.SPRING_NAMED_PARAMETER); + + assertThat(selectStatement.getSelectStatement()).isEqualTo("select * from AnimalData"); + } + + @Test + void testOptionalFetchFirstOnSelect() { + var selectStatement = select(animalData.allColumns()) + .from(animalData) + .fetchFirstWhenPresent(null).rowsOnly() + .build() + .render(RenderingStrategies.SPRING_NAMED_PARAMETER); + + assertThat(selectStatement.getSelectStatement()).isEqualTo("select * from AnimalData"); + } + + @Test + void testOptionalLimitAndOffsetOnSelect() { + var selectStatement = select(animalData.allColumns()) + .from(animalData) + .limitWhenPresent(null) + .offsetWhenPresent(null) + .build() + .render(RenderingStrategies.SPRING_NAMED_PARAMETER); + + assertThat(selectStatement.getSelectStatement()).isEqualTo("select * from AnimalData"); + } + + @Test + void testOptionalOffsetAndFetchOnSelect() { + var selectStatement = select(animalData.allColumns()) + .from(animalData) + .offsetWhenPresent(null) + .fetchFirstWhenPresent(null).rowsOnly() + .build() + .render(RenderingStrategies.SPRING_NAMED_PARAMETER); + + assertThat(selectStatement.getSelectStatement()).isEqualTo("select * from AnimalData"); + } +} From 5e275f10799e7e3eccd40266e34236f437ab4411 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Fri, 16 Aug 2024 17:36:16 -0400 Subject: [PATCH 067/289] Refactor Paging --- .../dynamic/sql/select/MultiSelectDSL.java | 74 +++------- .../mybatis/dynamic/sql/select/PagingDSL.java | 58 ++++++++ .../sql/select/QueryExpressionDSL.java | 120 +++++----------- .../mybatis/dynamic/sql/select/SelectDSL.java | 70 +++------ .../java/issues/gh100/FromGroupByTest.java | 8 +- .../java/issues/gh100/FromJoinWhereTest.java | 136 +++++++++--------- 6 files changed, 210 insertions(+), 256 deletions(-) create mode 100644 src/main/java/org/mybatis/dynamic/sql/select/PagingDSL.java diff --git a/src/main/java/org/mybatis/dynamic/sql/select/MultiSelectDSL.java b/src/main/java/org/mybatis/dynamic/sql/select/MultiSelectDSL.java index d23c6deb9..6b01f3696 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/MultiSelectDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/MultiSelectDSL.java @@ -29,7 +29,8 @@ import org.mybatis.dynamic.sql.util.Buildable; import org.mybatis.dynamic.sql.util.ConfigurableStatement; -public class MultiSelectDSL implements Buildable, ConfigurableStatement { +public class MultiSelectDSL implements Buildable, ConfigurableStatement, + PagingDSL { private final List unionQueries = new ArrayList<>(); private final SelectModel initialSelect; private OrderByModel orderByModel; @@ -61,31 +62,22 @@ public MultiSelectDSL orderBy(Collection columns) { return this; } - public LimitFinisher limit(long limit) { - return limitWhenPresent(limit); - } - - public LimitFinisher limitWhenPresent(Long limit) { + @Override + public LimitFinisher limitWhenPresent(Long limit) { this.limit = limit; - return new LimitFinisher(); + return new LF(); } - public OffsetFirstFinisher offset(long offset) { - return offsetWhenPresent(offset); - } - - public OffsetFirstFinisher offsetWhenPresent(Long offset) { + @Override + public OffsetFirstFinisher offsetWhenPresent(Long offset) { this.offset = offset; - return new OffsetFirstFinisher(); + return new OFF(); } - public FetchFirstFinisher fetchFirst(long fetchFirstRows) { - return fetchFirstWhenPresent(fetchFirstRows); - } - - public FetchFirstFinisher fetchFirstWhenPresent(Long fetchFirstRows) { + @Override + public FetchFirstFinisher fetchFirstWhenPresent(Long fetchFirstRows) { this.fetchFirstRows = fetchFirstRows; - return new FetchFirstFinisher(); + return new FFF(); } @NotNull @@ -114,38 +106,18 @@ public MultiSelectDSL configureStatement(Consumer consum return this; } - public class LimitFinisher implements Buildable { - public OffsetFinisher offset(long offset) { - return offsetWhenPresent(offset); - } - - public OffsetFinisher offsetWhenPresent(Long offset) { - MultiSelectDSL.this.offsetWhenPresent(offset); - return new OffsetFinisher(); - } - - @NotNull + class FFF implements FetchFirstFinisher { @Override - public MultiSelectModel build() { - return MultiSelectDSL.this.build(); + public Buildable rowsOnly() { + return MultiSelectDSL.this; } } - public class OffsetFinisher implements Buildable { - @NotNull + class LF implements LimitFinisher { @Override - public MultiSelectModel build() { - return MultiSelectDSL.this.build(); - } - } - - public class OffsetFirstFinisher implements Buildable { - public FetchFirstFinisher fetchFirst(long fetchFirstRows) { - return fetchFirstWhenPresent(fetchFirstRows); - } - - public FetchFirstFinisher fetchFirstWhenPresent(Long fetchFirstRows) { - return MultiSelectDSL.this.fetchFirstWhenPresent(fetchFirstRows); + public Buildable offsetWhenPresent(Long offset) { + MultiSelectDSL.this.offset = offset; + return MultiSelectDSL.this; } @NotNull @@ -155,13 +127,13 @@ public MultiSelectModel build() { } } - public class FetchFirstFinisher { - public RowsOnlyFinisher rowsOnly() { - return new RowsOnlyFinisher(); + class OFF implements OffsetFirstFinisher { + @Override + public FetchFirstFinisher fetchFirstWhenPresent(Long fetchFirstRows) { + MultiSelectDSL.this.fetchFirstRows = fetchFirstRows; + return new FFF(); } - } - public class RowsOnlyFinisher implements Buildable { @NotNull @Override public MultiSelectModel build() { diff --git a/src/main/java/org/mybatis/dynamic/sql/select/PagingDSL.java b/src/main/java/org/mybatis/dynamic/sql/select/PagingDSL.java new file mode 100644 index 000000000..89cfafafb --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/select/PagingDSL.java @@ -0,0 +1,58 @@ +/* + * Copyright 2016-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mybatis.dynamic.sql.select; + +import org.mybatis.dynamic.sql.util.Buildable; + +public interface PagingDSL { + default LimitFinisher limit(long limit) { + return limitWhenPresent(limit); + } + + LimitFinisher limitWhenPresent(Long limit); + + default OffsetFirstFinisher offset(long offset) { + return offsetWhenPresent(offset); + } + + OffsetFirstFinisher offsetWhenPresent(Long offset); + + default FetchFirstFinisher fetchFirst(long fetchFirstRows) { + return fetchFirstWhenPresent(fetchFirstRows); + } + + FetchFirstFinisher fetchFirstWhenPresent(Long fetchFirstRows); + + interface LimitFinisher extends Buildable { + default Buildable offset(long offset) { + return offsetWhenPresent(offset); + } + + Buildable offsetWhenPresent(Long offset); + } + + interface OffsetFirstFinisher extends Buildable { + default FetchFirstFinisher fetchFirst(long fetchFirstRows) { + return fetchFirstWhenPresent(fetchFirstRows); + } + + FetchFirstFinisher fetchFirstWhenPresent(Long fetchFirstRows); + } + + interface FetchFirstFinisher { + Buildable rowsOnly(); + } +} 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 0fab5ad4c..4e8bb4d76 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionDSL.java @@ -42,7 +42,7 @@ public class QueryExpressionDSL extends AbstractQueryExpressionDSL.QueryExpressionWhereBuilder, QueryExpressionDSL> - implements Buildable { + implements Buildable, PagingDSL { private final String connector; private final SelectDSL selectDSL; @@ -194,27 +194,18 @@ protected QueryExpressionModel buildModel() { .build(); } - public SelectDSL.LimitFinisher limit(long limit) { - return limitWhenPresent(limit); - } - - public SelectDSL.LimitFinisher limitWhenPresent(Long limit) { + @Override + public PagingDSL.LimitFinisher limitWhenPresent(Long limit) { return selectDSL.limitWhenPresent(limit); } - public SelectDSL.OffsetFirstFinisher offset(long offset) { - return offsetWhenPresent(offset); - } - - public SelectDSL.OffsetFirstFinisher offsetWhenPresent(Long offset) { + @Override + public PagingDSL.OffsetFirstFinisher offsetWhenPresent(Long offset) { return selectDSL.offsetWhenPresent(offset); } - public SelectDSL.FetchFirstFinisher fetchFirst(long fetchFirstRows) { - return fetchFirstWhenPresent(fetchFirstRows); - } - - public SelectDSL.FetchFirstFinisher fetchFirstWhenPresent(Long fetchFirstRows) { + @Override + public PagingDSL.FetchFirstFinisher fetchFirstWhenPresent(Long fetchFirstRows) { return selectDSL.fetchFirstWhenPresent(fetchFirstRows); } @@ -285,7 +276,7 @@ public FromGatherer build() { } public class QueryExpressionWhereBuilder extends AbstractWhereFinisher - implements Buildable { + implements Buildable, PagingDSL { private QueryExpressionWhereBuilder() { super(QueryExpressionDSL.this); } @@ -314,27 +305,18 @@ public GroupByFinisher groupBy(Collection columns) { return QueryExpressionDSL.this.groupBy(columns); } - public SelectDSL.LimitFinisher limit(long limit) { - return limitWhenPresent(limit); - } - - public SelectDSL.LimitFinisher limitWhenPresent(Long limit) { + @Override + public PagingDSL.LimitFinisher limitWhenPresent(Long limit) { return QueryExpressionDSL.this.limitWhenPresent(limit); } - public SelectDSL.OffsetFirstFinisher offset(long offset) { - return offsetWhenPresent(offset); - } - - public SelectDSL.OffsetFirstFinisher offsetWhenPresent(Long offset) { + @Override + public PagingDSL.OffsetFirstFinisher offsetWhenPresent(Long offset) { return QueryExpressionDSL.this.offsetWhenPresent(offset); } - public SelectDSL.FetchFirstFinisher fetchFirst(long fetchFirstRows) { - return fetchFirstWhenPresent(fetchFirstRows); - } - - public SelectDSL.FetchFirstFinisher fetchFirstWhenPresent(Long fetchFirstRows) { + @Override + public PagingDSL.FetchFirstFinisher fetchFirstWhenPresent(Long fetchFirstRows) { return QueryExpressionDSL.this.fetchFirstWhenPresent(fetchFirstRows); } @@ -375,7 +357,7 @@ public JoinSpecificationFinisher on(BindableColumn joinColumn, JoinCondit public class JoinSpecificationFinisher extends AbstractWhereStarter - implements Buildable { + implements Buildable, PagingDSL { private final JoinSpecification.Builder joinSpecificationBuilder; public JoinSpecificationFinisher(TableExpression table, BindableColumn joinColumn, @@ -508,32 +490,24 @@ public SelectDSL orderBy(Collection columns) { return QueryExpressionDSL.this.orderBy(columns); } - public SelectDSL.LimitFinisher limit(long limit) { - return limitWhenPresent(limit); - } - - public SelectDSL.LimitFinisher limitWhenPresent(Long limit) { + @Override + public PagingDSL.LimitFinisher limitWhenPresent(Long limit) { return QueryExpressionDSL.this.limitWhenPresent(limit); } - public SelectDSL.OffsetFirstFinisher offset(long offset) { - return offsetWhenPresent(offset); - } - - public SelectDSL.OffsetFirstFinisher offsetWhenPresent(Long offset) { + @Override + public PagingDSL.OffsetFirstFinisher offsetWhenPresent(Long offset) { return QueryExpressionDSL.this.offsetWhenPresent(offset); } - public SelectDSL.FetchFirstFinisher fetchFirst(long fetchFirstRows) { - return fetchFirstWhenPresent(fetchFirstRows); - } - - public SelectDSL.FetchFirstFinisher fetchFirstWhenPresent(Long fetchFirstRows) { + @Override + public PagingDSL.FetchFirstFinisher fetchFirstWhenPresent(Long fetchFirstRows) { return QueryExpressionDSL.this.fetchFirstWhenPresent(fetchFirstRows); } } - public class GroupByFinisher extends AbstractHavingStarter implements Buildable { + public class GroupByFinisher extends AbstractHavingStarter + implements Buildable, PagingDSL { public SelectDSL orderBy(SortSpecification... columns) { return orderBy(Arrays.asList(columns)); } @@ -556,27 +530,18 @@ public UnionBuilder unionAll() { return QueryExpressionDSL.this.unionAll(); } - public SelectDSL.LimitFinisher limit(long limit) { - return limitWhenPresent(limit); - } - - public SelectDSL.LimitFinisher limitWhenPresent(Long limit) { + @Override + public PagingDSL.LimitFinisher limitWhenPresent(Long limit) { return QueryExpressionDSL.this.limitWhenPresent(limit); } - public SelectDSL.OffsetFirstFinisher offset(long offset) { - return offsetWhenPresent(offset); - } - - public SelectDSL.OffsetFirstFinisher offsetWhenPresent(Long offset) { + @Override + public PagingDSL.OffsetFirstFinisher offsetWhenPresent(Long offset) { return QueryExpressionDSL.this.offsetWhenPresent(offset); } - public SelectDSL.FetchFirstFinisher fetchFirst(long fetchFirstRows) { - return fetchFirstWhenPresent(fetchFirstRows); - } - - public SelectDSL.FetchFirstFinisher fetchFirstWhenPresent(Long fetchFirstRows) { + @Override + public PagingDSL.FetchFirstFinisher fetchFirstWhenPresent(Long fetchFirstRows) { return QueryExpressionDSL.this.fetchFirstWhenPresent(fetchFirstRows); } @@ -620,30 +585,21 @@ public FromGatherer selectDistinct(List selectList) { } public class QueryExpressionHavingBuilder extends AbstractHavingFinisher - implements Buildable { - - public SelectDSL.FetchFirstFinisher fetchFirst(long fetchFirstRows) { - return fetchFirstWhenPresent(fetchFirstRows); - } - - public SelectDSL.FetchFirstFinisher fetchFirstWhenPresent(Long fetchFirstRows) { - return QueryExpressionDSL.this.fetchFirstWhenPresent(fetchFirstRows); - } + implements Buildable, PagingDSL { - public SelectDSL.OffsetFirstFinisher offset(long offset) { - return offsetWhenPresent(offset); + @Override + public PagingDSL.LimitFinisher limitWhenPresent(Long limit) { + return QueryExpressionDSL.this.limitWhenPresent(limit); } - public SelectDSL.OffsetFirstFinisher offsetWhenPresent(Long offset) { + @Override + public PagingDSL.OffsetFirstFinisher offsetWhenPresent(Long offset) { return QueryExpressionDSL.this.offsetWhenPresent(offset); } - public SelectDSL.LimitFinisher limit(long limit) { - return limitWhenPresent(limit); - } - - public SelectDSL.LimitFinisher limitWhenPresent(Long limit) { - return QueryExpressionDSL.this.limitWhenPresent(limit); + @Override + public PagingDSL.FetchFirstFinisher fetchFirstWhenPresent(Long fetchFirstRows) { + return QueryExpressionDSL.this.fetchFirstWhenPresent(fetchFirstRows); } public SelectDSL orderBy(SortSpecification... columns) { diff --git a/src/main/java/org/mybatis/dynamic/sql/select/SelectDSL.java b/src/main/java/org/mybatis/dynamic/sql/select/SelectDSL.java index 2c9aaea36..82e55aefb 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/SelectDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/SelectDSL.java @@ -41,7 +41,7 @@ * @param * the type of model produced by this builder, typically SelectModel */ -public class SelectDSL implements Buildable, ConfigurableStatement> { +public class SelectDSL implements Buildable, ConfigurableStatement>, PagingDSL { private final Function adapterFunction; private final List> queryExpressions = new ArrayList<>(); @@ -107,31 +107,19 @@ void orderBy(Collection columns) { orderByModel = OrderByModel.of(columns); } - public LimitFinisher limit(long limit) { - return limitWhenPresent(limit); - } - - public LimitFinisher limitWhenPresent(Long limit) { + public LimitFinisher limitWhenPresent(Long limit) { this.limit = limit; - return new LimitFinisher(); - } - - public OffsetFirstFinisher offset(long offset) { - return offsetWhenPresent(offset); + return new LF(); } - public OffsetFirstFinisher offsetWhenPresent(Long offset) { + public OffsetFirstFinisher offsetWhenPresent(Long offset) { this.offset = offset; - return new OffsetFirstFinisher(); - } - - public FetchFirstFinisher fetchFirst(long fetchFirstRows) { - return fetchFirstWhenPresent(fetchFirstRows); + return new OFF(); } - public FetchFirstFinisher fetchFirstWhenPresent(Long fetchFirstRows) { + public FetchFirstFinisher fetchFirstWhenPresent(Long fetchFirstRows) { this.fetchFirstRows = fetchFirstRows; - return new FetchFirstFinisher(); + return new FFF(); } @Override @@ -165,38 +153,18 @@ private Optional buildPagingModel() { .build(); } - public class LimitFinisher implements Buildable { - public OffsetFinisher offset(long offset) { - return offsetWhenPresent(offset); - } - - public OffsetFinisher offsetWhenPresent(Long offset) { - SelectDSL.this.offsetWhenPresent(offset); - return new OffsetFinisher(); - } - - @NotNull + class FFF implements FetchFirstFinisher { @Override - public R build() { - return SelectDSL.this.build(); + public Buildable rowsOnly() { + return SelectDSL.this; } } - public class OffsetFinisher implements Buildable { - @NotNull + class LF implements LimitFinisher { @Override - public R build() { - return SelectDSL.this.build(); - } - } - - public class OffsetFirstFinisher implements Buildable { - public FetchFirstFinisher fetchFirst(long fetchFirstRows) { - return fetchFirstWhenPresent(fetchFirstRows); - } - - public FetchFirstFinisher fetchFirstWhenPresent(Long fetchFirstRows) { - return SelectDSL.this.fetchFirstWhenPresent(fetchFirstRows); + public Buildable offsetWhenPresent(Long offset) { + SelectDSL.this.offset = offset; + return SelectDSL.this; } @NotNull @@ -206,13 +174,13 @@ public R build() { } } - public class FetchFirstFinisher { - public RowsOnlyFinisher rowsOnly() { - return new RowsOnlyFinisher(); + class OFF implements OffsetFirstFinisher { + @Override + public FetchFirstFinisher fetchFirstWhenPresent(Long fetchFirstRows) { + SelectDSL.this.fetchFirstRows = fetchFirstRows; + return new FFF(); } - } - public class RowsOnlyFinisher implements Buildable { @NotNull @Override public R build() { diff --git a/src/test/java/issues/gh100/FromGroupByTest.java b/src/test/java/issues/gh100/FromGroupByTest.java index 65b095f68..64fd15a04 100644 --- a/src/test/java/issues/gh100/FromGroupByTest.java +++ b/src/test/java/issues/gh100/FromGroupByTest.java @@ -105,7 +105,7 @@ void testFromGroupByLimitB3() { QueryExpressionDSL.GroupByFinisher builder2 = builder1.groupBy(StudentDynamicSqlSupport.name); - SelectDSL.LimitFinisher builder3 = builder2.limit(3); + var builder3 = builder2.limit(3); String expected = "select name, count(*)" + " from student" @@ -162,7 +162,7 @@ void testFromGroupByOffsetB3() { QueryExpressionDSL.GroupByFinisher builder2 = builder1.groupBy(StudentDynamicSqlSupport.name); - SelectDSL.OffsetFirstFinisher builder3 = builder2.offset(3); + var builder3 = builder2.offset(3); String expected = "select name, count(*)" + " from student" @@ -219,7 +219,7 @@ void testFromGroupByFetchFirstB3() { QueryExpressionDSL.GroupByFinisher builder2 = builder1.groupBy(StudentDynamicSqlSupport.name); - SelectDSL.RowsOnlyFinisher builder3 = builder2.fetchFirst(2).rowsOnly(); + var builder3 = builder2.fetchFirst(2).rowsOnly(); String expected = "select name, count(*)" + " from student" @@ -363,7 +363,7 @@ void testFromGroupByOrderByOffsetB4() { SelectDSL builder3 = builder2.orderBy(StudentDynamicSqlSupport.name); - SelectDSL.OffsetFirstFinisher builder4 = builder3.offset(2); + var builder4 = builder3.offset(2); String expected = "select name, count(*)" + " from student" diff --git a/src/test/java/issues/gh100/FromJoinWhereTest.java b/src/test/java/issues/gh100/FromJoinWhereTest.java index 651580e95..47867128d 100644 --- a/src/test/java/issues/gh100/FromJoinWhereTest.java +++ b/src/test/java/issues/gh100/FromJoinWhereTest.java @@ -793,7 +793,7 @@ void testFromJoinWhereUnionOrderByLimitB6() { SelectDSL builder5 = builder4.orderBy(StudentDynamicSqlSupport.id); - SelectDSL.LimitFinisher builder6 = builder5.limit(3); + var builder6 = builder5.limit(3); String expected = "select student.id, student.name, student.idcard" + " from student" @@ -826,7 +826,7 @@ void testFromJoinWhereUnionOrderByLimitOffsetB1() { SelectDSL builder5 = builder4.orderBy(StudentDynamicSqlSupport.id); - SelectDSL.LimitFinisher builder6 = builder5.limit(3); + var builder6 = builder5.limit(3); builder6.offset(2); @@ -862,7 +862,7 @@ void testFromJoinWhereUnionOrderByLimitOffsetB2() { SelectDSL builder5 = builder4.orderBy(StudentDynamicSqlSupport.id); - SelectDSL.LimitFinisher builder6 = builder5.limit(3); + var builder6 = builder5.limit(3); builder6.offset(2); @@ -898,7 +898,7 @@ void testFromJoinWhereUnionOrderByLimitOffsetB3() { SelectDSL builder5 = builder4.orderBy(StudentDynamicSqlSupport.id); - SelectDSL.LimitFinisher builder6 = builder5.limit(3); + var builder6 = builder5.limit(3); builder6.offset(2); @@ -934,7 +934,7 @@ void testFromJoinWhereUnionOrderByLimitOffsetB4() { SelectDSL builder5 = builder4.orderBy(StudentDynamicSqlSupport.id); - SelectDSL.LimitFinisher builder6 = builder5.limit(3); + var builder6 = builder5.limit(3); builder6.offset(2); @@ -970,7 +970,7 @@ void testFromJoinWhereUnionOrderByLimitOffsetB5() { SelectDSL builder5 = builder4.orderBy(StudentDynamicSqlSupport.id); - SelectDSL.LimitFinisher builder6 = builder5.limit(3); + var builder6 = builder5.limit(3); builder6.offset(2); @@ -1006,7 +1006,7 @@ void testFromJoinWhereUnionOrderByLimitOffsetB6() { SelectDSL builder5 = builder4.orderBy(StudentDynamicSqlSupport.id); - SelectDSL.LimitFinisher builder6 = builder5.limit(3); + var builder6 = builder5.limit(3); builder6.offset(2); @@ -1042,9 +1042,9 @@ void testFromJoinWhereUnionOrderByLimitOffsetB7() { SelectDSL builder5 = builder4.orderBy(StudentDynamicSqlSupport.id); - SelectDSL.LimitFinisher builder6 = builder5.limit(3); + var builder6 = builder5.limit(3); - SelectDSL.OffsetFinisher builder7 = builder6.offset(2); + var builder7 = builder6.offset(2); String expected = "select student.id, student.name, student.idcard" + " from student" @@ -1248,7 +1248,7 @@ void testFromJoinWhereUnionOrderByOffsetB6() { SelectDSL builder5 = builder4.orderBy(StudentDynamicSqlSupport.id); - SelectDSL.OffsetFirstFinisher builder6 = builder5.offset(2); + var builder6 = builder5.offset(2); String expected = "select student.id, student.name, student.idcard" + " from student" @@ -1282,7 +1282,7 @@ void testFromJoinWhereUnionOrderByOffsetFetchFirstB1() { SelectDSL builder5 = builder4.orderBy(StudentDynamicSqlSupport.id); - SelectDSL.OffsetFirstFinisher builder6 = builder5.offset(2); + var builder6 = builder5.offset(2); builder6.fetchFirst(3).rowsOnly(); @@ -1318,7 +1318,7 @@ void testFromJoinWhereUnionOrderByOffsetFetchFirstB2() { SelectDSL builder5 = builder4.orderBy(StudentDynamicSqlSupport.id); - SelectDSL.OffsetFirstFinisher builder6 = builder5.offset(2); + var builder6 = builder5.offset(2); builder6.fetchFirst(3).rowsOnly(); @@ -1354,7 +1354,7 @@ void testFromJoinWhereUnionOrderByOffsetFetchFirstB3() { SelectDSL builder5 = builder4.orderBy(StudentDynamicSqlSupport.id); - SelectDSL.OffsetFirstFinisher builder6 = builder5.offset(2); + var builder6 = builder5.offset(2); builder6.fetchFirst(3).rowsOnly(); @@ -1390,7 +1390,7 @@ void testFromJoinWhereUnionOrderByOffsetFetchFirstB4() { SelectDSL builder5 = builder4.orderBy(StudentDynamicSqlSupport.id); - SelectDSL.OffsetFirstFinisher builder6 = builder5.offset(2); + var builder6 = builder5.offset(2); builder6.fetchFirst(3).rowsOnly(); @@ -1426,7 +1426,7 @@ void testFromJoinWhereUnionOrderByOffsetFetchFirstB5() { SelectDSL builder5 = builder4.orderBy(StudentDynamicSqlSupport.id); - SelectDSL.OffsetFirstFinisher builder6 = builder5.offset(2); + var builder6 = builder5.offset(2); builder6.fetchFirst(3).rowsOnly(); @@ -1462,7 +1462,7 @@ void testFromJoinWhereUnionOrderByOffsetFetchFirstB6() { SelectDSL builder5 = builder4.orderBy(StudentDynamicSqlSupport.id); - SelectDSL.OffsetFirstFinisher builder6 = builder5.offset(2); + var builder6 = builder5.offset(2); builder6.fetchFirst(3).rowsOnly(); @@ -1498,9 +1498,9 @@ void testFromJoinWhereUnionOrderByOffsetFetchFirstB7() { SelectDSL builder5 = builder4.orderBy(StudentDynamicSqlSupport.id); - SelectDSL.OffsetFirstFinisher builder6 = builder5.offset(2); + var builder6 = builder5.offset(2); - SelectDSL.RowsOnlyFinisher builder7 = builder6.fetchFirst(3).rowsOnly(); + var builder7 = builder6.fetchFirst(3).rowsOnly(); String expected = "select student.id, student.name, student.idcard" + " from student" @@ -1699,7 +1699,7 @@ void testFromJoinWhereUnionOrderByFetchFirstB6() { SelectDSL builder5 = builder4.orderBy(StudentDynamicSqlSupport.id); - SelectDSL.RowsOnlyFinisher builder6 = builder5.fetchFirst(3).rowsOnly(); + var builder6 = builder5.fetchFirst(3).rowsOnly(); String expected = "select student.id, student.name, student.idcard" + " from student" @@ -1850,7 +1850,7 @@ void testFromJoinWhereUnionLimitB5() { .select(StudentDynamicSqlSupport.id, StudentDynamicSqlSupport.name, StudentDynamicSqlSupport.idcard) .from(StudentDynamicSqlSupport.student); - SelectDSL.LimitFinisher builder5 = builder4.limit(3); + var builder5 = builder4.limit(3); String expected = "select student.id, student.name, student.idcard" + " from student" @@ -1880,7 +1880,7 @@ void testFromJoinWhereUnionLimitOffsetB1() { .select(StudentDynamicSqlSupport.id, StudentDynamicSqlSupport.name, StudentDynamicSqlSupport.idcard) .from(StudentDynamicSqlSupport.student); - SelectDSL.LimitFinisher builder5 = builder4.limit(3); + var builder5 = builder4.limit(3); builder5.offset(2); @@ -1913,7 +1913,7 @@ void testFromJoinWhereUnionLimitOffsetB2() { .select(StudentDynamicSqlSupport.id, StudentDynamicSqlSupport.name, StudentDynamicSqlSupport.idcard) .from(StudentDynamicSqlSupport.student); - SelectDSL.LimitFinisher builder5 = builder4.limit(3); + var builder5 = builder4.limit(3); builder5.offset(2); @@ -1946,7 +1946,7 @@ void testFromJoinWhereUnionLimitOffsetB3() { .select(StudentDynamicSqlSupport.id, StudentDynamicSqlSupport.name, StudentDynamicSqlSupport.idcard) .from(StudentDynamicSqlSupport.student); - SelectDSL.LimitFinisher builder5 = builder4.limit(3); + var builder5 = builder4.limit(3); builder5.offset(2); @@ -1979,7 +1979,7 @@ void testFromJoinWhereUnionLimitOffsetB4() { .select(StudentDynamicSqlSupport.id, StudentDynamicSqlSupport.name, StudentDynamicSqlSupport.idcard) .from(StudentDynamicSqlSupport.student); - SelectDSL.LimitFinisher builder5 = builder4.limit(3); + var builder5 = builder4.limit(3); builder5.offset(2); @@ -2012,7 +2012,7 @@ void testFromJoinWhereUnionLimitOffsetB5() { .select(StudentDynamicSqlSupport.id, StudentDynamicSqlSupport.name, StudentDynamicSqlSupport.idcard) .from(StudentDynamicSqlSupport.student); - SelectDSL.LimitFinisher builder5 = builder4.limit(3); + var builder5 = builder4.limit(3); builder5.offset(2); @@ -2045,9 +2045,9 @@ void testFromJoinWhereUnionLimitOffsetB6() { .select(StudentDynamicSqlSupport.id, StudentDynamicSqlSupport.name, StudentDynamicSqlSupport.idcard) .from(StudentDynamicSqlSupport.student); - SelectDSL.LimitFinisher builder5 = builder4.limit(3); + var builder5 = builder4.limit(3); - SelectDSL.OffsetFinisher builder6 = builder5.offset(2); + var builder6 = builder5.offset(2); String expected = "select student.id, student.name, student.idcard" + " from student" @@ -2198,7 +2198,7 @@ void testFromJoinWhereUnionOffsetB5() { .select(StudentDynamicSqlSupport.id, StudentDynamicSqlSupport.name, StudentDynamicSqlSupport.idcard) .from(StudentDynamicSqlSupport.student); - SelectDSL.OffsetFirstFinisher builder5 = builder4.offset(2); + var builder5 = builder4.offset(2); String expected = "select student.id, student.name, student.idcard" + " from student" @@ -2228,7 +2228,7 @@ void testFromJoinWhereUnionOffsetFetchFirstB1() { .select(StudentDynamicSqlSupport.id, StudentDynamicSqlSupport.name, StudentDynamicSqlSupport.idcard) .from(StudentDynamicSqlSupport.student); - SelectDSL.OffsetFirstFinisher builder5 = builder4.offset(2); + var builder5 = builder4.offset(2); builder5.fetchFirst(2).rowsOnly(); @@ -2261,7 +2261,7 @@ void testFromJoinWhereUnionOffsetFetchFirstB2() { .select(StudentDynamicSqlSupport.id, StudentDynamicSqlSupport.name, StudentDynamicSqlSupport.idcard) .from(StudentDynamicSqlSupport.student); - SelectDSL.OffsetFirstFinisher builder5 = builder4.offset(2); + var builder5 = builder4.offset(2); builder5.fetchFirst(2).rowsOnly(); @@ -2294,7 +2294,7 @@ void testFromJoinWhereUnionOffsetFetchFirstB3() { .select(StudentDynamicSqlSupport.id, StudentDynamicSqlSupport.name, StudentDynamicSqlSupport.idcard) .from(StudentDynamicSqlSupport.student); - SelectDSL.OffsetFirstFinisher builder5 = builder4.offset(2); + var builder5 = builder4.offset(2); builder5.fetchFirst(2).rowsOnly(); @@ -2327,7 +2327,7 @@ void testFromJoinWhereUnionOffsetFetchFirstB4() { .select(StudentDynamicSqlSupport.id, StudentDynamicSqlSupport.name, StudentDynamicSqlSupport.idcard) .from(StudentDynamicSqlSupport.student); - SelectDSL.OffsetFirstFinisher builder5 = builder4.offset(2); + var builder5 = builder4.offset(2); builder5.fetchFirst(2).rowsOnly(); @@ -2360,7 +2360,7 @@ void testFromJoinWhereUnionOffsetFetchFirstB5() { .select(StudentDynamicSqlSupport.id, StudentDynamicSqlSupport.name, StudentDynamicSqlSupport.idcard) .from(StudentDynamicSqlSupport.student); - SelectDSL.OffsetFirstFinisher builder5 = builder4.offset(2); + var builder5 = builder4.offset(2); builder5.fetchFirst(2).rowsOnly(); @@ -2393,9 +2393,9 @@ void testFromJoinWhereUnionOffsetFetchFirstB6() { .select(StudentDynamicSqlSupport.id, StudentDynamicSqlSupport.name, StudentDynamicSqlSupport.idcard) .from(StudentDynamicSqlSupport.student); - SelectDSL.OffsetFirstFinisher builder5 = builder4.offset(2); + var builder5 = builder4.offset(2); - SelectDSL.RowsOnlyFinisher builder6 = builder5.fetchFirst(2).rowsOnly(); + var builder6 = builder5.fetchFirst(2).rowsOnly(); String expected = "select student.id, student.name, student.idcard" + " from student" @@ -2546,7 +2546,7 @@ void testFromJoinWhereUnionFetchFirstB5() { .select(StudentDynamicSqlSupport.id, StudentDynamicSqlSupport.name, StudentDynamicSqlSupport.idcard) .from(StudentDynamicSqlSupport.student); - SelectDSL.RowsOnlyFinisher builder5 = builder4.fetchFirst(2).rowsOnly(); + var builder5 = builder4.fetchFirst(2).rowsOnly(); String expected = "select student.id, student.name, student.idcard" + " from student" @@ -2770,7 +2770,7 @@ void testFromJoinWhereOrderByLimitB5() { SelectDSL builder4 = builder3.orderBy(StudentDynamicSqlSupport.id); - SelectDSL.LimitFinisher builder5 = builder4.limit(3); + var builder5 = builder4.limit(3); String expected = "select student.id, student.name, student.idcard" + " from student" @@ -2796,7 +2796,7 @@ void testFromJoinWhereOrderByLimitOffsetB1() { SelectDSL builder4 = builder3.orderBy(StudentDynamicSqlSupport.id); - SelectDSL.LimitFinisher builder5 = builder4.limit(3); + var builder5 = builder4.limit(3); builder5.offset(2); @@ -2825,7 +2825,7 @@ void testFromJoinWhereOrderByLimitOffsetB2() { SelectDSL builder4 = builder3.orderBy(StudentDynamicSqlSupport.id); - SelectDSL.LimitFinisher builder5 = builder4.limit(3); + var builder5 = builder4.limit(3); builder5.offset(2); @@ -2854,7 +2854,7 @@ void testFromJoinWhereOrderByLimitOffsetB3() { SelectDSL builder4 = builder3.orderBy(StudentDynamicSqlSupport.id); - SelectDSL.LimitFinisher builder5 = builder4.limit(3); + var builder5 = builder4.limit(3); builder5.offset(2); @@ -2883,7 +2883,7 @@ void testFromJoinWhereOrderByLimitOffsetB4() { SelectDSL builder4 = builder3.orderBy(StudentDynamicSqlSupport.id); - SelectDSL.LimitFinisher builder5 = builder4.limit(3); + var builder5 = builder4.limit(3); builder5.offset(2); @@ -2912,7 +2912,7 @@ void testFromJoinWhereOrderByLimitOffsetB5() { SelectDSL builder4 = builder3.orderBy(StudentDynamicSqlSupport.id); - SelectDSL.LimitFinisher builder5 = builder4.limit(3); + var builder5 = builder4.limit(3); builder5.offset(2); @@ -2941,9 +2941,9 @@ void testFromJoinWhereOrderByLimitOffsetB6() { SelectDSL builder4 = builder3.orderBy(StudentDynamicSqlSupport.id); - SelectDSL.LimitFinisher builder5 = builder4.limit(3); + var builder5 = builder4.limit(3); - SelectDSL.OffsetFinisher builder6 = builder5.offset(2); + var builder6 = builder5.offset(2); String expected = "select student.id, student.name, student.idcard" + " from student" @@ -3074,7 +3074,7 @@ void testFromJoinWhereOrderByOffsetB5() { SelectDSL builder4 = builder3.orderBy(StudentDynamicSqlSupport.id); - SelectDSL.OffsetFirstFinisher builder5 = builder4.offset(2); + var builder5 = builder4.offset(2); String expected = "select student.id, student.name, student.idcard" + " from student" @@ -3100,7 +3100,7 @@ void testFromJoinWhereOrderByOffsetFetchFirstB1() { SelectDSL builder4 = builder3.orderBy(StudentDynamicSqlSupport.id); - SelectDSL.OffsetFirstFinisher builder5 = builder4.offset(2); + var builder5 = builder4.offset(2); builder5.fetchFirst(3).rowsOnly(); @@ -3129,7 +3129,7 @@ void testFromJoinWhereOrderByOffsetFetchFirstB2() { SelectDSL builder4 = builder3.orderBy(StudentDynamicSqlSupport.id); - SelectDSL.OffsetFirstFinisher builder5 = builder4.offset(2); + var builder5 = builder4.offset(2); builder5.fetchFirst(3).rowsOnly(); @@ -3158,7 +3158,7 @@ void testFromJoinWhereOrderByOffsetFetchFirstB3() { SelectDSL builder4 = builder3.orderBy(StudentDynamicSqlSupport.id); - SelectDSL.OffsetFirstFinisher builder5 = builder4.offset(2); + var builder5 = builder4.offset(2); builder5.fetchFirst(3).rowsOnly(); @@ -3187,7 +3187,7 @@ void testFromJoinWhereOrderByOffsetFetchFirstB4() { SelectDSL builder4 = builder3.orderBy(StudentDynamicSqlSupport.id); - SelectDSL.OffsetFirstFinisher builder5 = builder4.offset(2); + var builder5 = builder4.offset(2); builder5.fetchFirst(3).rowsOnly(); @@ -3216,7 +3216,7 @@ void testFromJoinWhereOrderByOffsetFetchFirstB5() { SelectDSL builder4 = builder3.orderBy(StudentDynamicSqlSupport.id); - SelectDSL.OffsetFirstFinisher builder5 = builder4.offset(2); + var builder5 = builder4.offset(2); builder5.fetchFirst(3).rowsOnly(); @@ -3245,9 +3245,9 @@ void testFromJoinWhereOrderByOffsetFetchFirstB6() { SelectDSL builder4 = builder3.orderBy(StudentDynamicSqlSupport.id); - SelectDSL.OffsetFirstFinisher builder5 = builder4.offset(2); + var builder5 = builder4.offset(2); - SelectDSL.RowsOnlyFinisher builder6 = builder5.fetchFirst(3).rowsOnly(); + var builder6 = builder5.fetchFirst(3).rowsOnly(); String expected = "select student.id, student.name, student.idcard" + " from student" @@ -3378,7 +3378,7 @@ void testFromJoinWhereOrderByFetchFirstB5() { SelectDSL builder4 = builder3.orderBy(StudentDynamicSqlSupport.id); - SelectDSL.RowsOnlyFinisher builder5 = builder4.fetchFirst(3).rowsOnly(); + var builder5 = builder4.fetchFirst(3).rowsOnly(); String expected = "select student.id, student.name, student.idcard" + " from student" @@ -3471,7 +3471,7 @@ void testFromJoinWhereLimitB4() { QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); - SelectDSL.LimitFinisher builder4 = builder3.limit(2); + var builder4 = builder3.limit(2); String expected = "select student.id, student.name, student.idcard" + " from student" @@ -3494,7 +3494,7 @@ void testFromJoinWhereLimitOffsetB1() { QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); - SelectDSL.LimitFinisher builder4 = builder3.limit(2); + var builder4 = builder3.limit(2); builder4.offset(3); @@ -3520,7 +3520,7 @@ void testFromJoinWhereLimitOffsetB2() { QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); - SelectDSL.LimitFinisher builder4 = builder3.limit(2); + var builder4 = builder3.limit(2); builder4.offset(3); @@ -3546,7 +3546,7 @@ void testFromJoinWhereLimitOffsetB3() { QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); - SelectDSL.LimitFinisher builder4 = builder3.limit(2); + var builder4 = builder3.limit(2); builder4.offset(3); @@ -3572,7 +3572,7 @@ void testFromJoinWhereLimitOffsetB4() { QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); - SelectDSL.LimitFinisher builder4 = builder3.limit(2); + var builder4 = builder3.limit(2); builder4.offset(3); @@ -3598,9 +3598,9 @@ void testFromJoinWhereLimitOffsetB5() { QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); - SelectDSL.LimitFinisher builder4 = builder3.limit(2); + var builder4 = builder3.limit(2); - SelectDSL.OffsetFinisher builder5 = builder4.offset(3); + var builder5 = builder4.offset(3); String expected = "select student.id, student.name, student.idcard" + " from student" @@ -3693,7 +3693,7 @@ void testFromJoinWhereOffsetB4() { QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); - SelectDSL.OffsetFirstFinisher builder4 = builder3.offset(3); + var builder4 = builder3.offset(3); String expected = "select student.id, student.name, student.idcard" + " from student" @@ -3716,7 +3716,7 @@ void testFromJoinWhereOffsetFetchFirstB1() { QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); - SelectDSL.OffsetFirstFinisher builder4 = builder3.offset(3); + var builder4 = builder3.offset(3); builder4.fetchFirst(2).rowsOnly(); @@ -3742,7 +3742,7 @@ void testFromJoinWhereOffsetFetchFirstB2() { QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); - SelectDSL.OffsetFirstFinisher builder4 = builder3.offset(3); + var builder4 = builder3.offset(3); builder4.fetchFirst(2).rowsOnly(); @@ -3768,7 +3768,7 @@ void testFromJoinWhereOffsetFetchFirstB3() { QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); - SelectDSL.OffsetFirstFinisher builder4 = builder3.offset(3); + var builder4 = builder3.offset(3); builder4.fetchFirst(2).rowsOnly(); @@ -3794,7 +3794,7 @@ void testFromJoinWhereOffsetFetchFirstB4() { QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); - SelectDSL.OffsetFirstFinisher builder4 = builder3.offset(3); + var builder4 = builder3.offset(3); builder4.fetchFirst(2).rowsOnly(); @@ -3820,9 +3820,9 @@ void testFromJoinWhereOffsetFetchFirstB5() { QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); - SelectDSL.OffsetFirstFinisher builder4 = builder3.offset(3); + var builder4 = builder3.offset(3); - SelectDSL.RowsOnlyFinisher builder5 = builder4.fetchFirst(2).rowsOnly(); + var builder5 = builder4.fetchFirst(2).rowsOnly(); String expected = "select student.id, student.name, student.idcard" + " from student" @@ -3915,7 +3915,7 @@ void testFromJoinWhereFetchFirstB4() { QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); - SelectDSL.RowsOnlyFinisher builder4 = builder3.fetchFirst(2).rowsOnly(); + var builder4 = builder3.fetchFirst(2).rowsOnly(); String expected = "select student.id, student.name, student.idcard" + " from student" From 016ea3711118b138142c3590a4c5829399f77a94 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Fri, 16 Aug 2024 17:38:12 -0400 Subject: [PATCH 068/289] Checkstyle --- .../sql/exception/NonRenderingWhereClauseException.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/exception/NonRenderingWhereClauseException.java b/src/main/java/org/mybatis/dynamic/sql/exception/NonRenderingWhereClauseException.java index 23210e5a4..bcdcbf9a0 100644 --- a/src/main/java/org/mybatis/dynamic/sql/exception/NonRenderingWhereClauseException.java +++ b/src/main/java/org/mybatis/dynamic/sql/exception/NonRenderingWhereClauseException.java @@ -15,12 +15,12 @@ */ package org.mybatis.dynamic.sql.exception; +import java.io.Serial; + import org.mybatis.dynamic.sql.configuration.GlobalConfiguration; import org.mybatis.dynamic.sql.configuration.StatementConfiguration; import org.mybatis.dynamic.sql.util.Messages; -import java.io.Serial; - /** * This exception is thrown when the where clause in a statement will not render. * This can happen if all the optional conditions in a where clause fail to From 35706cdaa5361c50e6226b017c84d76defb6638f Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Fri, 16 Aug 2024 18:02:39 -0400 Subject: [PATCH 069/289] Refactor Kotlin Paging DSL --- .../util/kotlin/KotlinMultiSelectBuilder.kt | 20 +++-------- .../sql/util/kotlin/KotlinPagingDSL.kt | 36 +++++++++++++++++++ .../sql/util/kotlin/KotlinSelectBuilder.kt | 20 +++-------- 3 files changed, 44 insertions(+), 32 deletions(-) create mode 100644 src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinPagingDSL.kt diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinMultiSelectBuilder.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinMultiSelectBuilder.kt index 3c3ab1f71..b0512ed1f 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinMultiSelectBuilder.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinMultiSelectBuilder.kt @@ -26,7 +26,7 @@ import org.mybatis.dynamic.sql.util.Buildable typealias MultiSelectCompleter = KotlinMultiSelectBuilder.() -> Unit @MyBatisDslMarker -class KotlinMultiSelectBuilder: Buildable { +class KotlinMultiSelectBuilder: Buildable, KotlinPagingDSL { private var dsl: MultiSelectDSL? = null set(value) { assertNull(field, "ERROR.33") //$NON-NLS-1$ @@ -63,27 +63,15 @@ class KotlinMultiSelectBuilder: Buildable { getDsl().orderBy(columns.asList()) } - fun limit(limit: Long) { - limitWhenPresent(limit) - } - - fun limitWhenPresent(limit: Long?) { + override fun limitWhenPresent(limit: Long?) { getDsl().limitWhenPresent(limit) } - fun offset(offset: Long) { - offsetWhenPresent(offset) - } - - fun offsetWhenPresent(offset: Long?) { + override fun offsetWhenPresent(offset: Long?) { getDsl().offsetWhenPresent(offset) } - fun fetchFirst(fetchFirstRows: Long) { - fetchFirstWhenPresent(fetchFirstRows) - } - - fun fetchFirstWhenPresent(fetchFirstRows: Long?) { + override fun fetchFirstWhenPresent(fetchFirstRows: Long?) { getDsl().fetchFirstWhenPresent(fetchFirstRows).rowsOnly() } diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinPagingDSL.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinPagingDSL.kt new file mode 100644 index 000000000..f0b898dd1 --- /dev/null +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinPagingDSL.kt @@ -0,0 +1,36 @@ +/* + * Copyright 2016-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mybatis.dynamic.sql.util.kotlin + +interface KotlinPagingDSL { + fun limit(limit: Long) { + limitWhenPresent(limit) + } + + fun limitWhenPresent(limit: Long?) + + fun offset(offset: Long) { + offsetWhenPresent(offset) + } + + fun offsetWhenPresent(offset: Long?) + + fun fetchFirst(fetchFirstRows: Long) { + fetchFirstWhenPresent(fetchFirstRows) + } + + fun fetchFirstWhenPresent(fetchFirstRows: Long?) +} 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 4bd8cdefa..abaefebdc 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 @@ -28,7 +28,7 @@ typealias SelectCompleter = KotlinSelectBuilder.() -> Unit @Suppress("TooManyFunctions") class KotlinSelectBuilder(private val fromGatherer: QueryExpressionDSL.FromGatherer) : - KotlinBaseJoiningBuilder>(), Buildable { + KotlinBaseJoiningBuilder>(), Buildable, KotlinPagingDSL { private var dsl: KQueryExpressionDSL? = null @@ -58,27 +58,15 @@ class KotlinSelectBuilder(private val fromGatherer: QueryExpressionDSL.FromGathe getDsl().orderBy(columns.toList()) } - fun limit(limit: Long) { - limitWhenPresent(limit) - } - - fun limitWhenPresent(limit: Long?) { + override fun limitWhenPresent(limit: Long?) { getDsl().limitWhenPresent(limit) } - fun offset(offset: Long) { - offsetWhenPresent(offset) - } - - fun offsetWhenPresent(offset: Long?) { + override fun offsetWhenPresent(offset: Long?) { getDsl().offsetWhenPresent(offset) } - fun fetchFirst(fetchFirstRows: Long) { - fetchFirstWhenPresent(fetchFirstRows) - } - - fun fetchFirstWhenPresent(fetchFirstRows: Long?) { + override fun fetchFirstWhenPresent(fetchFirstRows: Long?) { getDsl().fetchFirstWhenPresent(fetchFirstRows).rowsOnly() } From e48c7f62a64ced24ff4bddb27412fd5caa64dbdc Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Fri, 16 Aug 2024 18:02:45 -0400 Subject: [PATCH 070/289] Docs --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 010c421c2..b4c7526c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,8 @@ Other important changes: an empty In condition would render as invalid SQL and would usually cause a runtime exception from the database. With this change, the exception thrown is more predictable and the error is caught before sending the SQL to the database. +- All the paging methods (limit, offset, fetchFirst) now have "WhenPresent" variations that will drop the phrase from + rendering if a null value is passed in ## Release 1.5.2 - June 3, 2024 From 52d897a8c537c8c79cd3dd2cb3a19c851cc192f7 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Sat, 17 Aug 2024 07:45:14 -0400 Subject: [PATCH 071/289] Add some kotlin error checking --- .../dynamic/sql/util/kotlin/JoinCollector.kt | 27 ++++++------------- .../sql/util/kotlin/KotlinBaseBuilders.kt | 24 ++++++++--------- .../dynamic/sql/util/messages.properties | 1 + .../mybatis3/joins/JoinMapperNewSyntaxTest.kt | 17 ++++++++++++ .../kotlin/mybatis3/joins/JoinMapperTest.kt | 17 ++++++++++++ 5 files changed, 55 insertions(+), 31 deletions(-) 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 0cb43d1d4..ec63179db 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/JoinCollector.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/JoinCollector.kt @@ -15,44 +15,33 @@ */ package org.mybatis.dynamic.sql.util.kotlin -import org.mybatis.dynamic.sql.AndOrCriteriaGroup import org.mybatis.dynamic.sql.BindableColumn -import org.mybatis.dynamic.sql.ColumnAndConditionCriterion import org.mybatis.dynamic.sql.SqlBuilder -import org.mybatis.dynamic.sql.SqlCriterion import org.mybatis.dynamic.sql.VisitableCondition typealias JoinReceiver = JoinCollector.() -> Unit @MyBatisDslMarker class JoinCollector { - private var initialCriterion: SqlCriterion? = null - internal val subCriteria = mutableListOf() + private val criteriaCollector = GroupingCriteriaCollector() - internal fun initialCriterion() : SqlCriterion = invalidIfNull(initialCriterion, "ERROR.22") //$NON-NLS-1$ + internal fun initialCriterion() = invalidIfNull(criteriaCollector.initialCriterion, "ERROR.22") //$NON-NLS-1$ + internal fun subCriteria() = criteriaCollector.subCriteria fun on (receiver: GroupingCriteriaReceiver) { - GroupingCriteriaCollector().apply(receiver).also { - initialCriterion = it.initialCriterion - subCriteria.addAll(it.subCriteria) - } + assertNull(criteriaCollector.initialCriterion, "ERROR.45") //$NON-NLS-1$ + criteriaCollector.apply(receiver) } // TODO - Deprecate? fun on(leftColumn: BindableColumn): RightColumnCollector = RightColumnCollector { - initialCriterion = ColumnAndConditionCriterion.withColumn(leftColumn) - .withCondition(it) - .build() + assertNull(criteriaCollector.initialCriterion, "ERROR.45") //$NON-NLS-1$ + criteriaCollector.apply { leftColumn.invoke(it) } } // TODO - Deprecate? fun and(leftColumn: BindableColumn): RightColumnCollector = RightColumnCollector { - subCriteria.add( - AndOrCriteriaGroup.Builder() - .withConnector("and") //$NON-NLS-1$ - .withInitialCriterion(ColumnAndConditionCriterion.withColumn(leftColumn).withCondition(it).build()) - .build() - ) + criteriaCollector.and { leftColumn.invoke(it) } } } 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 e9d070320..88386b2c1 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 @@ -66,12 +66,12 @@ abstract class KotlinBaseJoiningBuilder> : fun join(table: SqlTable, joinCriteria: JoinReceiver): Unit = applyToDsl(joinCriteria) { jc -> - join(table, jc.initialCriterion(), jc.subCriteria) + join(table, jc.initialCriterion(), jc.subCriteria()) } fun join(table: SqlTable, alias: String, joinCriteria: JoinReceiver): Unit = applyToDsl(joinCriteria) { jc -> - join(table, alias, jc.initialCriterion(), jc.subCriteria) + join(table, alias, jc.initialCriterion(), jc.subCriteria()) } fun join( @@ -79,17 +79,17 @@ abstract class KotlinBaseJoiningBuilder> : joinCriteria: JoinReceiver ): Unit = applyToDsl(subQuery, joinCriteria) { sq, jc -> - join(sq, sq.correlationName, jc.initialCriterion(), jc.subCriteria) + join(sq, sq.correlationName, jc.initialCriterion(), jc.subCriteria()) } fun fullJoin(table: SqlTable, joinCriteria: JoinReceiver): Unit = applyToDsl(joinCriteria) { jc -> - fullJoin(table, jc.initialCriterion(), jc.subCriteria) + fullJoin(table, jc.initialCriterion(), jc.subCriteria()) } fun fullJoin(table: SqlTable, alias: String, joinCriteria: JoinReceiver): Unit = applyToDsl(joinCriteria) { jc -> - fullJoin(table, alias, jc.initialCriterion(), jc.subCriteria) + fullJoin(table, alias, jc.initialCriterion(), jc.subCriteria()) } fun fullJoin( @@ -97,17 +97,17 @@ abstract class KotlinBaseJoiningBuilder> : joinCriteria: JoinReceiver ): Unit = applyToDsl(subQuery, joinCriteria) { sq, jc -> - fullJoin(sq, sq.correlationName, jc.initialCriterion(), jc.subCriteria) + fullJoin(sq, sq.correlationName, jc.initialCriterion(), jc.subCriteria()) } fun leftJoin(table: SqlTable, joinCriteria: JoinReceiver): Unit = applyToDsl(joinCriteria) { jc -> - leftJoin(table, jc.initialCriterion(), jc.subCriteria) + leftJoin(table, jc.initialCriterion(), jc.subCriteria()) } fun leftJoin(table: SqlTable, alias: String, joinCriteria: JoinReceiver): Unit = applyToDsl(joinCriteria) { jc -> - leftJoin(table, alias, jc.initialCriterion(), jc.subCriteria) + leftJoin(table, alias, jc.initialCriterion(), jc.subCriteria()) } fun leftJoin( @@ -115,17 +115,17 @@ abstract class KotlinBaseJoiningBuilder> : joinCriteria: JoinReceiver ): Unit = applyToDsl(subQuery, joinCriteria) { sq, jc -> - leftJoin(sq, sq.correlationName, jc.initialCriterion(), jc.subCriteria) + leftJoin(sq, sq.correlationName, jc.initialCriterion(), jc.subCriteria()) } fun rightJoin(table: SqlTable, joinCriteria: JoinReceiver): Unit = applyToDsl(joinCriteria) { jc -> - rightJoin(table, jc.initialCriterion(), jc.subCriteria) + rightJoin(table, jc.initialCriterion(), jc.subCriteria()) } fun rightJoin(table: SqlTable, alias: String, joinCriteria: JoinReceiver): Unit = applyToDsl(joinCriteria) { jc -> - rightJoin(table, alias, jc.initialCriterion(), jc.subCriteria) + rightJoin(table, alias, jc.initialCriterion(), jc.subCriteria()) } fun rightJoin( @@ -133,7 +133,7 @@ abstract class KotlinBaseJoiningBuilder> : joinCriteria: JoinReceiver ): Unit = applyToDsl(subQuery, joinCriteria) { sq, jc -> - rightJoin(sq, sq.correlationName, jc.initialCriterion(), jc.subCriteria) + rightJoin(sq, sq.correlationName, jc.initialCriterion(), jc.subCriteria()) } private fun applyToDsl(joinCriteria: JoinReceiver, applyJoin: D.(JoinCollector) -> Unit) { diff --git a/src/main/resources/org/mybatis/dynamic/sql/util/messages.properties b/src/main/resources/org/mybatis/dynamic/sql/util/messages.properties index ef092e651..8600b0437 100644 --- a/src/main/resources/org/mybatis/dynamic/sql/util/messages.properties +++ b/src/main/resources/org/mybatis/dynamic/sql/util/messages.properties @@ -61,4 +61,5 @@ ERROR.41=You cannot call "then" in a Kotlin case expression more than once ERROR.42=You cannot call `else` in a Kotlin case expression more than once ERROR.43=A Kotlin cast expression must have one, and only one, `as` element ERROR.44={0} conditions must contain at least one value +ERROR.45=You cannot call "on" in a Kotlin join expression more than once INTERNAL.ERROR=Internal Error {0} diff --git a/src/test/kotlin/examples/kotlin/mybatis3/joins/JoinMapperNewSyntaxTest.kt b/src/test/kotlin/examples/kotlin/mybatis3/joins/JoinMapperNewSyntaxTest.kt index a99124a12..cc2159c13 100644 --- a/src/test/kotlin/examples/kotlin/mybatis3/joins/JoinMapperNewSyntaxTest.kt +++ b/src/test/kotlin/examples/kotlin/mybatis3/joins/JoinMapperNewSyntaxTest.kt @@ -815,4 +815,21 @@ class JoinMapperNewSyntaxTest { } }.withMessage(Messages.getString("ERROR.22")) //$NON-NLS-1$ } + + @Test + fun testJoinWithDoubleOnCondition() { + // create second table instance for self-join + val user2 = user.withAlias("other_user") + + assertThatExceptionOfType(KInvalidSQLException::class.java).isThrownBy { + select(user.userId, user.userName, user.parentId) { + from(user, "u1") + join(user2, "u2") { + on { user.userId isEqualTo user2.parentId } + on { user.userId isEqualTo user2.parentId } + } + where { user2.userId isEqualTo 4 } + } + }.withMessage(Messages.getString("ERROR.45")) //$NON-NLS-1$ + } } diff --git a/src/test/kotlin/examples/kotlin/mybatis3/joins/JoinMapperTest.kt b/src/test/kotlin/examples/kotlin/mybatis3/joins/JoinMapperTest.kt index a60bc2105..5754fe631 100644 --- a/src/test/kotlin/examples/kotlin/mybatis3/joins/JoinMapperTest.kt +++ b/src/test/kotlin/examples/kotlin/mybatis3/joins/JoinMapperTest.kt @@ -813,6 +813,23 @@ class JoinMapperTest { }.withMessage(Messages.getString("ERROR.22")) //$NON-NLS-1$ } + @Test + fun testJoinWithDoubleOnCondition() { + // create second table instance for self-join + val user2 = user.withAlias("other_user") + + assertThatExceptionOfType(KInvalidSQLException::class.java).isThrownBy { + select(user.userId, user.userName, user.parentId) { + from(user, "u1") + join(user2, "u2") { + on(user.userId) equalTo user2.parentId + on(user.userId) equalTo user2.parentId + } + where { user2.userId isEqualTo 4 } + } + }.withMessage(Messages.getString("ERROR.45")) //$NON-NLS-1$ + } + @Test fun testThatAliasesPropagateToSubQueryConditions() { sqlSessionFactory.openSession().use { session -> From ffce2bc550b19c2592a94a7027af1630cf0ec73d Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Sat, 17 Aug 2024 09:10:24 -0400 Subject: [PATCH 072/289] Improvements to the Paging Implementation --- .../dynamic/sql/select/MultiSelectDSL.java | 33 +++++++------------ .../mybatis/dynamic/sql/select/PagingDSL.java | 1 + .../mybatis/dynamic/sql/select/SelectDSL.java | 33 +++++++------------ 3 files changed, 23 insertions(+), 44 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/select/MultiSelectDSL.java b/src/main/java/org/mybatis/dynamic/sql/select/MultiSelectDSL.java index 6b01f3696..42a20e551 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/MultiSelectDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/MultiSelectDSL.java @@ -65,19 +65,19 @@ public MultiSelectDSL orderBy(Collection columns) { @Override public LimitFinisher limitWhenPresent(Long limit) { this.limit = limit; - return new LF(); + return new LocalLimitFinisher(); } @Override public OffsetFirstFinisher offsetWhenPresent(Long offset) { this.offset = offset; - return new OFF(); + return new LocalOffsetFirstFinisher(); } @Override public FetchFirstFinisher fetchFirstWhenPresent(Long fetchFirstRows) { this.fetchFirstRows = fetchFirstRows; - return new FFF(); + return () -> MultiSelectDSL.this; } @NotNull @@ -106,20 +106,7 @@ public MultiSelectDSL configureStatement(Consumer consum return this; } - class FFF implements FetchFirstFinisher { - @Override - public Buildable rowsOnly() { - return MultiSelectDSL.this; - } - } - - class LF implements LimitFinisher { - @Override - public Buildable offsetWhenPresent(Long offset) { - MultiSelectDSL.this.offset = offset; - return MultiSelectDSL.this; - } - + abstract class BaseBuildable implements Buildable { @NotNull @Override public MultiSelectModel build() { @@ -127,17 +114,19 @@ public MultiSelectModel build() { } } - class OFF implements OffsetFirstFinisher { + class LocalOffsetFirstFinisher extends BaseBuildable implements OffsetFirstFinisher { @Override public FetchFirstFinisher fetchFirstWhenPresent(Long fetchFirstRows) { MultiSelectDSL.this.fetchFirstRows = fetchFirstRows; - return new FFF(); + return () -> MultiSelectDSL.this; } + } - @NotNull + class LocalLimitFinisher extends BaseBuildable implements LimitFinisher { @Override - public MultiSelectModel build() { - return MultiSelectDSL.this.build(); + public Buildable offsetWhenPresent(Long offset) { + MultiSelectDSL.this.offset = offset; + return MultiSelectDSL.this; } } } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/PagingDSL.java b/src/main/java/org/mybatis/dynamic/sql/select/PagingDSL.java index 89cfafafb..0d86e5e9a 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/PagingDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/PagingDSL.java @@ -52,6 +52,7 @@ default FetchFirstFinisher fetchFirst(long fetchFirstRows) { FetchFirstFinisher fetchFirstWhenPresent(Long fetchFirstRows); } + @FunctionalInterface interface FetchFirstFinisher { Buildable rowsOnly(); } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/SelectDSL.java b/src/main/java/org/mybatis/dynamic/sql/select/SelectDSL.java index 82e55aefb..4b5ef2077 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/SelectDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/SelectDSL.java @@ -109,17 +109,17 @@ void orderBy(Collection columns) { public LimitFinisher limitWhenPresent(Long limit) { this.limit = limit; - return new LF(); + return new LocalLimitFinisher(); } public OffsetFirstFinisher offsetWhenPresent(Long offset) { this.offset = offset; - return new OFF(); + return new LocalOffsetFirstFinisher(); } public FetchFirstFinisher fetchFirstWhenPresent(Long fetchFirstRows) { this.fetchFirstRows = fetchFirstRows; - return new FFF(); + return () -> SelectDSL.this; } @Override @@ -153,20 +153,7 @@ private Optional buildPagingModel() { .build(); } - class FFF implements FetchFirstFinisher { - @Override - public Buildable rowsOnly() { - return SelectDSL.this; - } - } - - class LF implements LimitFinisher { - @Override - public Buildable offsetWhenPresent(Long offset) { - SelectDSL.this.offset = offset; - return SelectDSL.this; - } - + abstract class BaseBuildable implements Buildable { @NotNull @Override public R build() { @@ -174,17 +161,19 @@ public R build() { } } - class OFF implements OffsetFirstFinisher { + class LocalOffsetFirstFinisher extends BaseBuildable implements OffsetFirstFinisher { @Override public FetchFirstFinisher fetchFirstWhenPresent(Long fetchFirstRows) { SelectDSL.this.fetchFirstRows = fetchFirstRows; - return new FFF(); + return () -> SelectDSL.this; } + } - @NotNull + class LocalLimitFinisher extends BaseBuildable implements LimitFinisher { @Override - public R build() { - return SelectDSL.this.build(); + public Buildable offsetWhenPresent(Long offset) { + SelectDSL.this.offset = offset; + return SelectDSL.this; } } } From fdda342a0728c4a6918e51bf15cc2f2ddcde7066 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 17 Aug 2024 19:29:52 +0000 Subject: [PATCH 073/289] Update dependency maven to v3.9.9 --- .mvn/wrapper/maven-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties index fd5166374..01aa6654c 100644 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -16,5 +16,5 @@ # under the License. wrapperVersion=3.3.2 distributionType=source -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.8/apache-maven-3.9.8-bin.zip +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar From 3cd872b2db21c05eac25526a62141d98879c2ec3 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 19 Aug 2024 11:02:46 -0400 Subject: [PATCH 074/289] Add deprecation notices --- .../org/mybatis/dynamic/sql/SqlBuilder.java | 36 +++++++++++++------ .../dynamic/sql/util/kotlin/JoinCollector.kt | 8 ++--- 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java b/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java index 88871f6f0..4468b523a 100644 --- a/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java +++ b/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java @@ -435,6 +435,32 @@ static ColumnAndConditionCriterion on(BindableColumn joinColumn, Visit .build(); } + /** + * Starting in version 2.0.0, this function is a synonym for {@link SqlBuilder#isEqualTo(BasicColumn)}. + * + * @param column the column + * @return an IsEqualToColumn condition + * @param the column type + * @deprecated since 2.0.0. Please replace with isEqualTo(column) + */ + @Deprecated(since = "2.0.0", forRemoval = true) + static IsEqualToColumn equalTo(BindableColumn column) { + return isEqualTo(column); + } + + /** + * Starting in version 2.0.0, this function is a synonym for {@link SqlBuilder#isEqualTo(Object)}. + * + * @param value the value + * @return an IsEqualTo condition + * @param the column type + * @deprecated since 2.0.0. Please replace with isEqualTo(value) + */ + @Deprecated(since = "2.0.0", forRemoval = true) + static IsEqualTo equalTo(T value) { + return isEqualTo(value); + } + // case expressions @SuppressWarnings("java:S100") static SimpleCaseDSL case_(BindableColumn column) { @@ -446,16 +472,6 @@ static SearchedCaseDSL case_() { return SearchedCaseDSL.searchedCase(); } - // TODO - Deprecate? - static IsEqualToColumn equalTo(BindableColumn column) { - return IsEqualToColumn.of(column); - } - - // TODO - Deprecate? - static IsEqualTo equalTo(T value) { - return IsEqualTo.of(value); - } - // aggregate support static CountAll count() { return new CountAll(); 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 ec63179db..ba68b4a8e 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 @@ -33,20 +33,20 @@ class JoinCollector { criteriaCollector.apply(receiver) } - // TODO - Deprecate? + @Deprecated("Please replace with the \"on\" lambda expression", level = DeprecationLevel.WARNING) fun on(leftColumn: BindableColumn): RightColumnCollector = RightColumnCollector { assertNull(criteriaCollector.initialCriterion, "ERROR.45") //$NON-NLS-1$ criteriaCollector.apply { leftColumn.invoke(it) } } - // TODO - Deprecate? + @Deprecated("Please move the \"and\" expression into an \"on\" lambda", level = DeprecationLevel.WARNING) fun and(leftColumn: BindableColumn): RightColumnCollector = RightColumnCollector { criteriaCollector.and { leftColumn.invoke(it) } } } class RightColumnCollector(private val joinConditionConsumer: (VisitableCondition) -> Unit) { - infix fun equalTo(rightColumn: BindableColumn) = joinConditionConsumer.invoke(SqlBuilder.equalTo(rightColumn)) + infix fun equalTo(rightColumn: BindableColumn) = joinConditionConsumer.invoke(SqlBuilder.isEqualTo(rightColumn)) - infix fun equalTo(value: T) = joinConditionConsumer.invoke(SqlBuilder.equalTo(value)) + infix fun equalTo(value: T) = joinConditionConsumer.invoke(SqlBuilder.isEqualTo(value)) } From f888b831b4a6fb1e8fe4bf1ef8bb2b7d29c493d9 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 19 Aug 2024 15:13:29 -0400 Subject: [PATCH 075/289] New join syntax for Kotlin --- .../sql/select/render/JoinRenderer.java | 20 +- .../dynamic/sql/util/kotlin/JoinCollector.kt | 7 - .../sql/util/kotlin/KotlinBaseBuilders.kt | 88 ++++++++ .../dynamic/sql/util/messages.properties | 1 + .../mybatis3/joins/JoinMapperNewSyntaxTest.kt | 191 +++++++++--------- 5 files changed, 192 insertions(+), 115 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/JoinRenderer.java b/src/main/java/org/mybatis/dynamic/sql/select/render/JoinRenderer.java index 0da029f59..6a437f010 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/render/JoinRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/render/JoinRenderer.java @@ -15,8 +15,6 @@ */ package org.mybatis.dynamic.sql.select.render; -import static org.mybatis.dynamic.sql.util.StringUtilities.spaceBefore; - import java.util.Objects; import java.util.stream.Collectors; @@ -26,6 +24,7 @@ import org.mybatis.dynamic.sql.select.join.JoinSpecification; import org.mybatis.dynamic.sql.util.FragmentAndParameters; import org.mybatis.dynamic.sql.util.FragmentCollector; +import org.mybatis.dynamic.sql.util.Messages; public class JoinRenderer { private final JoinModel joinModel; @@ -46,22 +45,17 @@ public FragmentAndParameters render() { } private FragmentAndParameters renderJoinSpecification(JoinSpecification joinSpecification) { - FragmentAndParameters renderedTable = joinSpecification.table().accept(tableExpressionRenderer); - FragmentAndParameters renderedJoinSpecification = JoinSpecificationRenderer + FragmentCollector fc = new FragmentCollector(); + fc.add(FragmentAndParameters.fromFragment(joinSpecification.joinType().type())); + fc.add(joinSpecification.table().accept(tableExpressionRenderer)); + fc.add(JoinSpecificationRenderer .withJoinSpecification(joinSpecification) .withRenderingContext(renderingContext) .build() .render() - .orElseThrow(() -> new InvalidSqlException("Join Specifications Must Render")); // TODO - - String fragment = joinSpecification.joinType().type() - + spaceBefore(renderedTable.fragment()) - + spaceBefore(renderedJoinSpecification.fragment()); + .orElseThrow(() -> new InvalidSqlException(Messages.getString("ERROR.46")))); //$NON-NLS-1$ - return FragmentAndParameters.withFragment(fragment) - .withParameters(renderedTable.parameters()) - .withParameters(renderedJoinSpecification.parameters()) - .build(); + return fc.toFragmentAndParameters(Collectors.joining(" ")); //$NON-NLS-1$ } public static Builder withJoinModel(JoinModel joinModel) { 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 ba68b4a8e..078ea2a34 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 @@ -28,18 +28,11 @@ class JoinCollector { internal fun initialCriterion() = invalidIfNull(criteriaCollector.initialCriterion, "ERROR.22") //$NON-NLS-1$ internal fun subCriteria() = criteriaCollector.subCriteria - fun on (receiver: GroupingCriteriaReceiver) { - assertNull(criteriaCollector.initialCriterion, "ERROR.45") //$NON-NLS-1$ - criteriaCollector.apply(receiver) - } - - @Deprecated("Please replace with the \"on\" lambda expression", level = DeprecationLevel.WARNING) fun on(leftColumn: BindableColumn): RightColumnCollector = RightColumnCollector { assertNull(criteriaCollector.initialCriterion, "ERROR.45") //$NON-NLS-1$ criteriaCollector.apply { leftColumn.invoke(it) } } - @Deprecated("Please move the \"and\" expression into an \"on\" lambda", level = DeprecationLevel.WARNING) fun and(leftColumn: BindableColumn): RightColumnCollector = RightColumnCollector { criteriaCollector.and { leftColumn.invoke(it) } } 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 88386b2c1..059792b2c 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 @@ -64,16 +64,19 @@ abstract class KotlinBaseBuilder> { @Suppress("TooManyFunctions") abstract class KotlinBaseJoiningBuilder> : KotlinBaseBuilder() { + @Deprecated("Please use the new form with the \"on\" keyword outside the lambda") fun join(table: SqlTable, joinCriteria: JoinReceiver): Unit = applyToDsl(joinCriteria) { jc -> join(table, jc.initialCriterion(), jc.subCriteria()) } + @Deprecated("Please use the new form with the \"on\" keyword outside the lambda") fun join(table: SqlTable, alias: String, joinCriteria: JoinReceiver): Unit = applyToDsl(joinCriteria) { jc -> join(table, alias, jc.initialCriterion(), jc.subCriteria()) } + @Deprecated("Please use the new form with the \"on\" keyword outside the lambda") fun join( subQuery: KotlinQualifiedSubQueryBuilder.() -> Unit, joinCriteria: JoinReceiver @@ -82,16 +85,36 @@ abstract class KotlinBaseJoiningBuilder> : join(sq, sq.correlationName, jc.initialCriterion(), jc.subCriteria()) } + fun join(table: SqlTable): JoinCriteriaGatherer = + JoinCriteriaGatherer { + getDsl().join(table, it.initialCriterion, it.subCriteria) + } + + fun join(table: SqlTable, alias: String): JoinCriteriaGatherer = + JoinCriteriaGatherer { + getDsl().join(table, alias, it.initialCriterion, it.subCriteria) + } + + fun join( + subQuery: KotlinQualifiedSubQueryBuilder.() -> Unit): JoinCriteriaGatherer = + JoinCriteriaGatherer { + val sq = KotlinQualifiedSubQueryBuilder().apply(subQuery) + getDsl().join(sq, sq.correlationName, it.initialCriterion, it.subCriteria) + } + + @Deprecated("Please use the new form with the \"on\" keyword outside the lambda") fun fullJoin(table: SqlTable, joinCriteria: JoinReceiver): Unit = applyToDsl(joinCriteria) { jc -> fullJoin(table, jc.initialCriterion(), jc.subCriteria()) } + @Deprecated("Please use the new form with the \"on\" keyword outside the lambda") fun fullJoin(table: SqlTable, alias: String, joinCriteria: JoinReceiver): Unit = applyToDsl(joinCriteria) { jc -> fullJoin(table, alias, jc.initialCriterion(), jc.subCriteria()) } + @Deprecated("Please use the new form with the \"on\" keyword outside the lambda") fun fullJoin( subQuery: KotlinQualifiedSubQueryBuilder.() -> Unit, joinCriteria: JoinReceiver @@ -100,16 +123,36 @@ abstract class KotlinBaseJoiningBuilder> : fullJoin(sq, sq.correlationName, jc.initialCriterion(), jc.subCriteria()) } + fun fullJoin(table: SqlTable): JoinCriteriaGatherer = + JoinCriteriaGatherer { + getDsl().fullJoin(table, it.initialCriterion, it.subCriteria) + } + + fun fullJoin(table: SqlTable, alias: String): JoinCriteriaGatherer = + JoinCriteriaGatherer { + getDsl().fullJoin(table, alias, it.initialCriterion, it.subCriteria) + } + + fun fullJoin( + subQuery: KotlinQualifiedSubQueryBuilder.() -> Unit): JoinCriteriaGatherer = + JoinCriteriaGatherer { + val sq = KotlinQualifiedSubQueryBuilder().apply(subQuery) + getDsl().fullJoin(sq, sq.correlationName, it.initialCriterion, it.subCriteria) + } + + @Deprecated("Please use the new form with the \"on\" keyword outside the lambda") fun leftJoin(table: SqlTable, joinCriteria: JoinReceiver): Unit = applyToDsl(joinCriteria) { jc -> leftJoin(table, jc.initialCriterion(), jc.subCriteria()) } + @Deprecated("Please use the new form with the \"on\" keyword outside the lambda") fun leftJoin(table: SqlTable, alias: String, joinCriteria: JoinReceiver): Unit = applyToDsl(joinCriteria) { jc -> leftJoin(table, alias, jc.initialCriterion(), jc.subCriteria()) } + @Deprecated("Please use the new form with the \"on\" keyword outside the lambda") fun leftJoin( subQuery: KotlinQualifiedSubQueryBuilder.() -> Unit, joinCriteria: JoinReceiver @@ -118,16 +161,36 @@ abstract class KotlinBaseJoiningBuilder> : leftJoin(sq, sq.correlationName, jc.initialCriterion(), jc.subCriteria()) } + fun leftJoin(table: SqlTable): JoinCriteriaGatherer = + JoinCriteriaGatherer { + getDsl().leftJoin(table, it.initialCriterion, it.subCriteria) + } + + fun leftJoin(table: SqlTable, alias: String): JoinCriteriaGatherer = + JoinCriteriaGatherer { + getDsl().leftJoin(table, alias, it.initialCriterion, it.subCriteria) + } + + fun leftJoin( + subQuery: KotlinQualifiedSubQueryBuilder.() -> Unit): JoinCriteriaGatherer = + JoinCriteriaGatherer { + val sq = KotlinQualifiedSubQueryBuilder().apply(subQuery) + getDsl().leftJoin(sq, sq.correlationName, it.initialCriterion, it.subCriteria) + } + + @Deprecated("Please use the new form with the \"on\" keyword outside the lambda") fun rightJoin(table: SqlTable, joinCriteria: JoinReceiver): Unit = applyToDsl(joinCriteria) { jc -> rightJoin(table, jc.initialCriterion(), jc.subCriteria()) } + @Deprecated("Please use the new form with the \"on\" keyword outside the lambda") fun rightJoin(table: SqlTable, alias: String, joinCriteria: JoinReceiver): Unit = applyToDsl(joinCriteria) { jc -> rightJoin(table, alias, jc.initialCriterion(), jc.subCriteria()) } + @Deprecated("Please use the new form with the \"on\" keyword outside the lambda") fun rightJoin( subQuery: KotlinQualifiedSubQueryBuilder.() -> Unit, joinCriteria: JoinReceiver @@ -136,6 +199,23 @@ abstract class KotlinBaseJoiningBuilder> : rightJoin(sq, sq.correlationName, jc.initialCriterion(), jc.subCriteria()) } + fun rightJoin(table: SqlTable): JoinCriteriaGatherer = + JoinCriteriaGatherer { + getDsl().rightJoin(table, it.initialCriterion, it.subCriteria) + } + + fun rightJoin(table: SqlTable, alias: String): JoinCriteriaGatherer = + JoinCriteriaGatherer { + getDsl().rightJoin(table, alias, it.initialCriterion, it.subCriteria) + } + + fun rightJoin( + subQuery: KotlinQualifiedSubQueryBuilder.() -> Unit): JoinCriteriaGatherer = + JoinCriteriaGatherer { + val sq = KotlinQualifiedSubQueryBuilder().apply(subQuery) + getDsl().rightJoin(sq, sq.correlationName, it.initialCriterion, it.subCriteria) + } + private fun applyToDsl(joinCriteria: JoinReceiver, applyJoin: D.(JoinCollector) -> Unit) { getDsl().applyJoin(JoinCollector().apply(joinCriteria)) } @@ -148,3 +228,11 @@ abstract class KotlinBaseJoiningBuilder> : getDsl().applyJoin(KotlinQualifiedSubQueryBuilder().apply(subQuery), JoinCollector().apply(joinCriteria)) } } + +class JoinCriteriaGatherer(private val consumer: (GroupingCriteriaCollector) -> Unit) { + infix fun on (joinCriteria: GroupingCriteriaReceiver): Unit = + with(GroupingCriteriaCollector().apply(joinCriteria)) { + assertTrue(initialCriterion != null || subCriteria.isNotEmpty(), "ERROR.22") //$NON-NLS-1$ + consumer.invoke(this) + } +} diff --git a/src/main/resources/org/mybatis/dynamic/sql/util/messages.properties b/src/main/resources/org/mybatis/dynamic/sql/util/messages.properties index 8600b0437..05ecfcfe8 100644 --- a/src/main/resources/org/mybatis/dynamic/sql/util/messages.properties +++ b/src/main/resources/org/mybatis/dynamic/sql/util/messages.properties @@ -62,4 +62,5 @@ ERROR.42=You cannot call `else` in a Kotlin case expression more than once ERROR.43=A Kotlin cast expression must have one, and only one, `as` element ERROR.44={0} conditions must contain at least one value ERROR.45=You cannot call "on" in a Kotlin join expression more than once +ERROR.46=At least one join criterion must render INTERNAL.ERROR=Internal Error {0} diff --git a/src/test/kotlin/examples/kotlin/mybatis3/joins/JoinMapperNewSyntaxTest.kt b/src/test/kotlin/examples/kotlin/mybatis3/joins/JoinMapperNewSyntaxTest.kt index cc2159c13..1b69ba5ec 100644 --- a/src/test/kotlin/examples/kotlin/mybatis3/joins/JoinMapperNewSyntaxTest.kt +++ b/src/test/kotlin/examples/kotlin/mybatis3/joins/JoinMapperNewSyntaxTest.kt @@ -57,8 +57,8 @@ class JoinMapperNewSyntaxTest { orderDetail.lineNumber, orderDetail.description, orderDetail.quantity ) { from(orderMaster, "om") - join(orderDetail, "od") { - on { orderMaster.orderId isEqualTo orderDetail.orderId } + join(orderDetail, "od") on { + orderMaster.orderId isEqualTo orderDetail.orderId } } @@ -96,11 +96,9 @@ class JoinMapperNewSyntaxTest { orderDetail.lineNumber, orderDetail.description, orderDetail.quantity ) { from(orderMaster, "om") - join(orderDetail, "od") { - on { - orderMaster.orderId isEqualTo orderDetail.orderId - and { orderMaster.orderId isEqualTo 1 } - } + join(orderDetail, "od") on { + orderMaster.orderId isEqualTo orderDetail.orderId + and { orderMaster.orderId isEqualTo 1 } } } @@ -133,11 +131,9 @@ class JoinMapperNewSyntaxTest { orderDetail.lineNumber, orderDetail.description, orderDetail.quantity ) { from(orderMaster, "om") - join(orderDetail, "od") { - on { - orderMaster.orderId isEqualTo orderDetail.orderId - and { orderMaster.orderId isEqualTo constant("1") } - } + join(orderDetail, "od") on { + orderMaster.orderId isEqualTo orderDetail.orderId + and { orderMaster.orderId isEqualTo constant("1") } } } @@ -168,11 +164,9 @@ class JoinMapperNewSyntaxTest { orderDetail.description, orderDetail.quantity ) { from(orderMaster, "om") - join(orderDetail, "od") { - on { - orderMaster.orderId isEqualTo orderDetail.orderId - and { orderMaster.orderId isEqualTo orderDetail.orderId } - } + join(orderDetail, "od") on { + orderMaster.orderId isEqualTo orderDetail.orderId + and { orderMaster.orderId isEqualTo orderDetail.orderId } } } @@ -189,11 +183,9 @@ class JoinMapperNewSyntaxTest { orderDetail.description, orderDetail.quantity ) { from(orderMaster, "om") - join(orderDetail, "od") { - on { - orderMaster.orderId isEqualTo orderDetail.orderId - and { orderMaster.orderId isEqualTo orderDetail.orderId } - } + join(orderDetail, "od") on { + orderMaster.orderId isEqualTo orderDetail.orderId + and { orderMaster.orderId isEqualTo orderDetail.orderId } } where { orderMaster.orderId isEqualTo 1 } } @@ -214,11 +206,11 @@ class JoinMapperNewSyntaxTest { itemMaster.description, orderLine.quantity ) { from(orderMaster, "om") - join(orderLine, "ol") { - on { orderMaster.orderId isEqualTo orderLine.orderId } + join(orderLine, "ol") on { + orderMaster.orderId isEqualTo orderLine.orderId } - join(itemMaster, "im") { - on { orderLine.itemId isEqualTo itemMaster.itemId } + join(itemMaster, "im") on { + orderLine.itemId isEqualTo itemMaster.itemId } where { orderMaster.orderId isEqualTo 2 } } @@ -250,11 +242,11 @@ class JoinMapperNewSyntaxTest { orderLine.orderId, orderLine.quantity, itemMaster.itemId, itemMaster.description ) { from(orderMaster, "om") - join(orderLine, "ol") { - on { orderMaster.orderId isEqualTo orderLine.orderId } + join(orderLine, "ol") on { + orderMaster.orderId isEqualTo orderLine.orderId } - fullJoin(itemMaster, "im") { - on { orderLine.itemId isEqualTo itemMaster.itemId } + fullJoin(itemMaster, "im") on { + orderLine.itemId isEqualTo itemMaster.itemId } orderBy(orderLine.orderId, itemMaster.itemId) } @@ -318,26 +310,21 @@ class JoinMapperNewSyntaxTest { } + "om" } - join( - subQuery = { - select(orderLine.allColumns()) { - from(orderLine) - } - + "ol" - }, - joinCriteria = { - on { "om"(orderMaster.orderId) isEqualTo "ol"(orderLine.orderId) } + join { + select(orderLine.allColumns()) { + from(orderLine) } - ) - fullJoin( - { - select(itemMaster.allColumns()) { - from(itemMaster) - } - + "im" + + "ol" + } on { + "om"(orderMaster.orderId) isEqualTo "ol"(orderLine.orderId) + } + fullJoin { + select(itemMaster.allColumns()) { + from(itemMaster) } - ) { - on { "ol"(orderLine.itemId) isEqualTo "im"(itemMaster.itemId) } + +"im" + } on { + "ol"(orderLine.itemId) isEqualTo "im"(itemMaster.itemId) } orderBy(orderLine.orderId, itemMaster.itemId) } @@ -395,11 +382,11 @@ class JoinMapperNewSyntaxTest { orderLine.orderId, orderLine.quantity, itemMaster.itemId, itemMaster.description ) { from(orderMaster, "om") - join(orderLine, "ol") { - on { orderMaster.orderId isEqualTo orderLine.orderId } + join(orderLine, "ol") on { + orderMaster.orderId isEqualTo orderLine.orderId } - fullJoin(itemMaster) { - on { orderLine.itemId isEqualTo itemMaster.itemId } + fullJoin(itemMaster) on { + orderLine.itemId isEqualTo itemMaster.itemId } orderBy(orderLine.orderId, itemMaster.itemId) } @@ -443,11 +430,11 @@ class JoinMapperNewSyntaxTest { orderLine.orderId, orderLine.quantity, itemMaster.itemId, itemMaster.description ) { from(orderMaster, "om") - join(orderLine, "ol") { - on { orderMaster.orderId isEqualTo orderLine.orderId } + join(orderLine, "ol") on { + orderMaster.orderId isEqualTo orderLine.orderId } - leftJoin(itemMaster, "im") { - on { orderLine.itemId isEqualTo itemMaster.itemId } + leftJoin(itemMaster, "im") on { + orderLine.itemId isEqualTo itemMaster.itemId } orderBy(orderLine.orderId, itemMaster.itemId) } @@ -487,8 +474,8 @@ class JoinMapperNewSyntaxTest { itemMaster.description ) { from(orderMaster, "om") - join(orderLine, "ol") { - on { orderMaster.orderId isEqualTo orderLine.orderId } + join(orderLine, "ol") on { + orderMaster.orderId isEqualTo orderLine.orderId } leftJoin( { @@ -497,8 +484,8 @@ class JoinMapperNewSyntaxTest { } + "im" } - ) { - on { orderLine.itemId isEqualTo "im"(itemMaster.itemId) } + ) on { + orderLine.itemId isEqualTo "im"(itemMaster.itemId) } orderBy(orderLine.orderId, itemMaster.itemId) } @@ -537,11 +524,11 @@ class JoinMapperNewSyntaxTest { orderLine.orderId, orderLine.quantity, itemMaster.itemId, itemMaster.description ) { from(orderMaster, "om") - join(orderLine, "ol") { - on { orderMaster.orderId isEqualTo orderLine.orderId } + join(orderLine, "ol") on { + orderMaster.orderId isEqualTo orderLine.orderId } - leftJoin(itemMaster) { - on { orderLine.itemId isEqualTo itemMaster.itemId } + leftJoin(itemMaster) on { + orderLine.itemId isEqualTo itemMaster.itemId } orderBy(orderLine.orderId, itemMaster.itemId) } @@ -580,11 +567,11 @@ class JoinMapperNewSyntaxTest { orderLine.orderId, orderLine.quantity, itemMaster.itemId, itemMaster.description ) { from(orderMaster, "om") - join(orderLine, "ol") { - on { orderMaster.orderId isEqualTo orderLine.orderId } + join(orderLine, "ol") on { + orderMaster.orderId isEqualTo orderLine.orderId } - rightJoin(itemMaster, "im") { - on { orderLine.itemId isEqualTo itemMaster.itemId } + rightJoin(itemMaster, "im") on { + orderLine.itemId isEqualTo itemMaster.itemId } orderBy(orderLine.orderId, itemMaster.itemId) } @@ -624,8 +611,8 @@ class JoinMapperNewSyntaxTest { "im"(itemMaster.itemId), itemMaster.description ) { from(orderMaster, "om") - join(orderLine, "ol") { - on { orderMaster.orderId isEqualTo orderLine.orderId } + join(orderLine, "ol") on { + orderMaster.orderId isEqualTo orderLine.orderId } rightJoin( { @@ -634,8 +621,8 @@ class JoinMapperNewSyntaxTest { } + "im" } - ) { - on { orderLine.itemId isEqualTo "im"(itemMaster.itemId) } + ) on { + orderLine.itemId isEqualTo "im"(itemMaster.itemId) } orderBy(orderLine.orderId, itemMaster.itemId) } @@ -674,11 +661,11 @@ class JoinMapperNewSyntaxTest { orderLine.orderId, orderLine.quantity, itemMaster.itemId, itemMaster.description ) { from(orderMaster, "om") - join(orderLine, "ol") { - on { orderMaster.orderId isEqualTo orderLine.orderId } + join(orderLine, "ol") on { + orderMaster.orderId isEqualTo orderLine.orderId } - rightJoin(itemMaster) { - on { orderLine.itemId isEqualTo itemMaster.itemId } + rightJoin(itemMaster) on { + orderLine.itemId isEqualTo itemMaster.itemId } orderBy(orderLine.orderId, itemMaster.itemId) } @@ -719,8 +706,8 @@ class JoinMapperNewSyntaxTest { // get Bamm Bamm's parent - should be Barney val selectStatement = select(user.userId, user.userName, user.parentId) { from(user, "u1") - join(user2, "u2") { - on { user.userId isEqualTo user2.parentId } + join(user2, "u2") on { + user.userId isEqualTo user2.parentId } where { user2.userId isEqualTo 4 } } @@ -750,8 +737,8 @@ class JoinMapperNewSyntaxTest { // get Bamm Bamm's parent - should be Barney val selectStatement = select(user.userId, user.userName, user.parentId) { from(user) - join(user2) { - on { user.userId isEqualTo user2.parentId } + join(user2) on { + user.userId isEqualTo user2.parentId } where { user2.userId isEqualTo 4 } } @@ -782,8 +769,8 @@ class JoinMapperNewSyntaxTest { // get Bamm Bamm's parent - should be Barney val selectStatement = select(user.userId, user.userName, user.parentId) { from(user, "u1") - join(user2, "u2") { - on { user.userId isEqualTo user2.parentId } + join(user2, "u2") on { + user.userId isEqualTo user2.parentId } where { user2.userId isEqualTo 4 } } @@ -803,33 +790,47 @@ class JoinMapperNewSyntaxTest { } @Test - fun testJoinWithNoOnCondition() { - // create second table instance for self-join - val user2 = user.withAlias("other_user") + fun testSelfWithNewAliasAndOverrideOddUsage() { + sqlSessionFactory.openSession().use { session -> + val mapper = session.getMapper(JoinMapper::class.java) - assertThatExceptionOfType(KInvalidSQLException::class.java).isThrownBy { - select(user.userId, user.userName, user.parentId) { + // create second table instance for self-join + val user2 = user.withAlias("other_user") + + // get Bamm Bamm's parent - should be Barney + val selectStatement = select(user.userId, user.userName, user.parentId) { from(user, "u1") - join(user2, "u2") { } + join(user2, "u2") on { + and { user.userId isEqualTo user2.parentId } + } where { user2.userId isEqualTo 4 } } - }.withMessage(Messages.getString("ERROR.22")) //$NON-NLS-1$ + + val 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.selectStatement).isEqualTo(expectedStatement) + val rows = mapper.selectManyMappedRows(selectStatement) + assertThat(rows).hasSize(1) + + assertThat(rows[0]).containsExactly( + entry("USER_ID", 2), + entry("USER_NAME", "Barney"), + ) + } } @Test - fun testJoinWithDoubleOnCondition() { + fun testJoinWithNoOnCondition() { // create second table instance for self-join val user2 = user.withAlias("other_user") assertThatExceptionOfType(KInvalidSQLException::class.java).isThrownBy { select(user.userId, user.userName, user.parentId) { from(user, "u1") - join(user2, "u2") { - on { user.userId isEqualTo user2.parentId } - on { user.userId isEqualTo user2.parentId } - } + join(user2, "u2") on { } where { user2.userId isEqualTo 4 } } - }.withMessage(Messages.getString("ERROR.45")) //$NON-NLS-1$ + }.withMessage(Messages.getString("ERROR.22")) //$NON-NLS-1$ } } From 4984924f2462e677a998320f21f17bffe0d8dd9b Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 19 Aug 2024 15:51:10 -0400 Subject: [PATCH 076/289] Docs --- CHANGELOG.md | 4 +- src/site/markdown/docs/kotlinOverview.md | 9 +- src/site/markdown/docs/migratingV1toV2.md | 69 +++++++++ src/site/markdown/docs/select.md | 168 ++++++++++++---------- src/site/site.xml | 1 + 5 files changed, 168 insertions(+), 83 deletions(-) create mode 100644 src/site/markdown/docs/migratingV1toV2.md diff --git a/CHANGELOG.md b/CHANGELOG.md index b4c7526c2..2d46635fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,7 +31,9 @@ Other important changes: With this change, the exception thrown is more predictable and the error is caught before sending the SQL to the database. - All the paging methods (limit, offset, fetchFirst) now have "WhenPresent" variations that will drop the phrase from - rendering if a null value is passed in + rendering if a null value is passed in +- The JOIN syntax is updated and now allows full boolean expressions like a WHERE clause. The prior JOIN syntax + is deprecated and will be removed in a future release. ## Release 1.5.2 - June 3, 2024 diff --git a/src/site/markdown/docs/kotlinOverview.md b/src/site/markdown/docs/kotlinOverview.md index 5b646a7b0..78dba6a78 100644 --- a/src/site/markdown/docs/kotlinOverview.md +++ b/src/site/markdown/docs/kotlinOverview.md @@ -417,9 +417,9 @@ val selectStatement = select(orderMaster.orderId, orderMaster.orderDate, orderDe orderDetail.description, orderDetail.quantity ) { from(orderMaster, "om") - join(orderDetail, "od") { - on(orderMaster.orderId) equalTo orderDetail.orderId - and(orderMaster.orderId) equalTo orderDetail.orderId + join(orderDetail, "od") on { + orderMaster.orderId isEqualTo orderDetail.orderId + and { orderMaster.orderId isEqualTo orderDetail.orderId } } where { orderMaster.orderId isEqualTo 1 } or { @@ -433,8 +433,7 @@ val selectStatement = select(orderMaster.orderId, orderMaster.orderDate, orderDe In a select statement you must specify a table in a `from` clause. Everything else is optional. -Multiple join clauses can be specified if you need to join additional tables. In a join clause, you must -specify an `on` condition, and you may specify additional `and` conditions as necessary. Full, left, right, inner, +Multiple join clauses can be specified if you need to join additional tables. Full, left, right, inner, and outer joins are supported. Where clauses can be of arbitrary complexity and support all SQL operators including exists operators, subqueries, etc. diff --git a/src/site/markdown/docs/migratingV1toV2.md b/src/site/markdown/docs/migratingV1toV2.md new file mode 100644 index 000000000..8d51e68f9 --- /dev/null +++ b/src/site/markdown/docs/migratingV1toV2.md @@ -0,0 +1,69 @@ +# V1 to V2 Migration Guide + +Version 2 of MyBatis Dynamic SQL introduced many new features. This page will document how to migrate code +from prior releases to version 2. + +## Java Join Syntax + +Version2 offers a fully flexible join specification and reuses the capabilities of where clauses. Of course, +not all capabilities are supported in databases, but you should now be able to code any type of join specification. + +The changes in the Java DSL are mostly internal and should not impact most users. The `equalTo` methods has been +deprecated in favor of `isEqualTo`, but all other changes should be hidden. + +V1 Join Specification Example: +```java +SelectStatementProvider selectStatement = select(orderMaster.orderId, orderDetail.lineNumber, orderDetail.quantity) + .from(orderMaster, "om") + .join(orderDetail, "od", on(orderMaster.orderId, equalTo(orderDetail.orderId))) + .build() + .render(RenderingStrategies.MYBATIS3); +``` + +V2 Join Specification Example: +```java +SelectStatementProvider selectStatement = select(orderMaster.orderId, orderDetail.lineNumber, orderDetail.quantity) + .from(orderMaster, "om") + .join(orderDetail, "od", on(orderMaster.orderId, isEqualTo(orderDetail.orderId))) + .build() + .render(RenderingStrategies.MYBATIS3); +``` + +## Kotlin Join Syntax + +Like the Java DSL, the V2 Kotlin DSL offers a fully flexible join specification and reuses the capabilities of where +clauses. Of course, not all capabilities are supported in databases, but you should now be able to code any type of +join specification. + +The changes in the Kotlin DSL allow a more natural expressions of a join specification. The main difference is that +the "on" keyword should be moved outside the join specification lambda (it is now an infix function). Inside the lambda, +the conditions should be rewritten to match the syntax of a where clause. + +V1 Join Specification Example: +```kotlin +val selectStatement = select( + orderMaster.orderId, orderMaster.orderDate, + orderDetail.lineNumber, orderDetail.description, orderDetail.quantity +) { + from(orderMaster, "om") + join(orderDetail, "od") { + on(orderMaster.orderId) equalTo orderDetail.orderId + and(orderMaster.orderId) equalTo constant("1") + } +} +``` + +V2 Join Specification Example: +```kotlin +val selectStatement = select( + orderMaster.orderId, orderMaster.orderDate, + orderDetail.lineNumber, orderDetail.description, orderDetail.quantity +) { + from(orderMaster, "om") + join(orderDetail, "od") on { + orderMaster.orderId isEqualTo orderDetail.orderId + and { orderMaster.orderId isEqualTo constant("1") } + } +} + +``` diff --git a/src/site/markdown/docs/select.md b/src/site/markdown/docs/select.md index 923c30c42..f73ef17dd 100644 --- a/src/site/markdown/docs/select.md +++ b/src/site/markdown/docs/select.md @@ -10,7 +10,7 @@ In general, the following are supported: 2. Tables can be aliased per select statement 3. Columns can be aliased per select statement 4. Some support for aggregates (avg, min, max, sum) -5. Equijoins of type INNER, LEFT OUTER, RIGHT OUTER, FULL OUTER +5. Joins of type INNER, LEFT OUTER, RIGHT OUTER, FULL OUTER 6. Subqueries in where clauses. For example, `where foo in (select foo from foos where id < 36)` 7. Select from another select. For example `select count(*) from (select foo from foos where id < 36)` 8. Multi-Selects. For example `(select * from foo order by id limit 3) union (select * from foo order by id desc limit 3)` @@ -21,47 +21,50 @@ At this time, the library does not support the following: 2. INTERSECT, EXCEPT, etc. The user guide page for WHERE Clauses shows examples of many types of SELECT statements with different complexities of -the WHERE clause including support for sub-queries. We will just show a single example here, including an ORDER BY clause: +the WHERE clause including support for sub-queries. We will just show a single example here, including an ORDER BY +clause: ```java - SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) - .from(animalData) - .where(id, isIn(1, 5, 7)) - .and(bodyWeight, isBetween(1.0).and(3.0)) - .orderBy(id.descending(), bodyWeight) - .build() - .render(RenderingStrategies.MYBATIS3); - - List animals = mapper.selectMany(selectStatement); +SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) + .from(animalData) + .where(id, isIn(1, 5, 7)) + .and(bodyWeight, isBetween(1.0).and(3.0)) + .orderBy(id.descending(), bodyWeight) + .build() + .render(RenderingStrategies.MYBATIS3); + +List animals = mapper.selectMany(selectStatement); ``` The WHERE and ORDER BY clauses are optional. ## Joins -The library supports the generation of equijoin statements - joins defined by column matching. For example: +The library supports the generation of join statements. For example: ```java - SelectStatementProvider selectStatement = select(orderMaster.orderId, orderDate, orderDetail.lineNumber, orderDetail.description, orderDetail.quantity) - .from(orderMaster, "om") - .join(orderDetail, "od").on(orderMaster.orderId, equalTo(orderDetail.orderId)) - .build() - .render(RenderingStrategies.MYBATIS3); +SelectStatementProvider selectStatement = select(orderMaster.orderId, orderDate, orderDetail.lineNumber, orderDetail.description, orderDetail.quantity) + .from(orderMaster, "om") + .join(orderDetail, "od").on(orderMaster.orderId, isEqualTo(orderDetail.orderId)) + .build() + .render(RenderingStrategies.MYBATIS3); ``` -Notice that you can give an alias to a table if desired. If you don't specify an alias, the full table name will be used in the generated SQL. +Notice that you can give an alias to a table if desired. If you don't specify an alias, the full table name will be +used in the generated SQL. Multiple tables can be joined in a single statement. For example: ```java - SelectStatementProvider selectStatement = select(orderMaster.orderId, 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)) - .build() - .render(RenderingStrategies.MYBATIS3); +SelectStatementProvider selectStatement = select(orderMaster.orderId, orderDate, orderLine.lineNumber, itemMaster.description, orderLine.quantity) + .from(orderMaster, "om") + .join(orderLine, "ol").on(orderMaster.orderId, isEqualTo(orderLine.orderId)) + .join(itemMaster, "im").on(orderLine.itemId, isEqualTo(itemMaster.itemId)) + .where(orderMaster.orderId, isEqualTo(2)) + .build() + .render(RenderingStrategies.MYBATIS3); ``` -Join queries will likely require you to define a MyBatis result mapping in XML. This is the only instance where XML is required. This is due to the limitations of the MyBatis annotations when mapping collections. +Join queries will likely require you to define a MyBatis result mapping in XML. This is the only instance where XML is +required. This is due to the limitations of the MyBatis annotations when mapping collections. The library supports four join types: @@ -74,14 +77,14 @@ The library supports four join types: The library supports the generation of UNION and UNION ALL queries. For example: ```java - SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) - .from(animalData) - .union() - .selectDistinct(id, animalName, bodyWeight, brainWeight) - .from(animalData) - .orderBy(id) - .build() - .render(RenderingStrategies.MYBATIS3); +SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) + .from(animalData) + .union() + .selectDistinct(id, animalName, bodyWeight, brainWeight) + .from(animalData) + .orderBy(id) + .build() + .render(RenderingStrategies.MYBATIS3); ``` Any number of SELECT statements can be added to a UNION query. Only one ORDER BY phrase is allowed. @@ -96,16 +99,16 @@ Multi-select queries are a special case of union select statements. The differen paging clauses can be applied to the merged queries. For example: ```java - SelectStatementProvider selectStatement = multiSelect( - select(id, animalName, bodyWeight, brainWeight) - .from(animalData) - .orderBy(id) - .limit(2) +SelectStatementProvider selectStatement = multiSelect( + select(id, animalName, bodyWeight, brainWeight) + .from(animalData) + .orderBy(id) + .limit(2) ).union( - selectDistinct(id, animalName, bodyWeight, brainWeight) - .from(animalData) - .orderBy(id.descending()) - .limit(3) + selectDistinct(id, animalName, bodyWeight, brainWeight) + .from(animalData) + .orderBy(id.descending()) + .limit(3) ) .build() .render(RenderingStrategies.MYBATIS3); @@ -114,7 +117,8 @@ paging clauses can be applied to the merged queries. For example: ## MyBatis Mapper for Select Statements The SelectStatementProvider object can be used as a parameter to a MyBatis mapper method directly. If you -are using an annotated mapper, the select method should look like this (note that we recommend coding a "selectMany" and a "selectOne" method with a shared result mapping): +are using an annotated mapper, the select method should look like this (note that we recommend coding a "selectMany" +and a "selectOne" method with a shared result mapping): ```java import org.apache.ibatis.annotations.Result; @@ -143,7 +147,9 @@ import org.mybatis.dynamic.sql.util.SqlProviderAdapter; ## XML Mapper for Join Statements -If you are coding a join, it is likely you will need to code an XML mapper to define the result map. This is due to a MyBatis limitation - the annotations cannot define a collection mapping. If you have to do this, the Java code looks like this: +If you are coding a join, it is likely you will need to code an XML mapper to define the result map. This is due to a +MyBatis limitation - the annotations cannot define a collection mapping. If you have to do this, the Java code looks +like this: ```java @SelectProvider(type=SqlProviderAdapter.class, method="select") @@ -171,7 +177,8 @@ And the corresponding XML looks like this: Notice that the resultMap is the only element in the XML mapper. This is our recommended practice. ## XML Mapper for Select Statements -We do not recommend using an XML mapper for select statements, but if you want to do so the SelectStatementProvider object can be used as a parameter to a MyBatis mapper method directly. +We do not recommend using an XML mapper for select statements, but if you want to do so the SelectStatementProvider +object can be used as a parameter to a MyBatis mapper method directly. If you are using an XML mapper, the select method should look like this in the Java interface: @@ -205,30 +212,33 @@ Order by phrases can be difficult to calculate when there are aliased columns, a This library has taken a relatively simple approach: 1. When specifying an SqlColumn in an ORDER BY phrase the library will either write the column alias or the column -name into the ORDER BY phrase. For the ORDER BY phrase, the table alias (if there is one) will be ignored. Use this pattern -when the ORDER BY column is a member of the select list. For example `orderBy(foo)`. If the column has an alias, then -it is easist to use the "arbitrary string" method with the column alias as shown below. -1. It is also possible to explicitly specify a table alias for a column in an ORDER BY phrase. Use this pattern when -there is a join, and the ORDER BY column is in two or more tables, and the ORDER BY column is not in the select -list. For example `orderBy(sortColumn("t1", foo))`. -1. If none of the above use cases meet your needs, then you can specify an arbitrary String to write into the rendered ORDER BY -phrase (see below for an example). + name into the ORDER BY phrase. For the ORDER BY phrase, the table alias (if there is one) will be ignored. Use this + pattern when the ORDER BY column is a member of the select list. For example `orderBy(foo)`. If the column has an + alias, then it is easiest to use the "arbitrary string" method with the column alias as shown below. +2. It is also possible to explicitly specify a table alias for a column in an ORDER BY phrase. Use this pattern when + there is a join, and the ORDER BY column is in two or more tables, and the ORDER BY column is not in the select + list. For example `orderBy(sortColumn("t1", foo))`. +3. If none of the above use cases meet your needs, then you can specify an arbitrary String to write into the rendered + ORDER BY phrase (see below for an example). In our testing, this caused an issue in only one case. When there is an outer join and the select list contains both the left and right join column. In that case, the workaround is to supply a column alias for both columns. -When using a column function (lower, upper, etc.), then it is customary to give the calculated column an alias so you will have a predictable result set. In cases like this there will not be a column to use for an alias. The library supports arbitrary values in an ORDER BY expression like this: +When using a column function (lower, upper, etc.), then it is customary to give the calculated column an alias so you +will have a predictable result set. In cases like this there will not be a column to use for an alias. The library +supports arbitrary values in an ORDER BY expression like this: ```java - SelectStatementProvider selectStatement = select(substring(gender, 1, 1).as("ShortGender"), avg(age).as("AverageAge")) - .from(person, "a") - .groupBy(substring(gender, 1, 1)) - .orderBy(sortColumn("ShortGender").descending()) - .build() - .render(RenderingStrategies.MYBATIS3); +SelectStatementProvider selectStatement = select(substring(gender, 1, 1).as("ShortGender"), avg(age).as("AverageAge")) + .from(person, "a") + .groupBy(substring(gender, 1, 1)) + .orderBy(sortColumn("ShortGender").descending()) + .build() + .render(RenderingStrategies.MYBATIS3); ``` -In this example the `substring` function is used in both the select list and the GROUP BY expression. In the ORDER BY expression, we use the `sortColumn` function to duplicate the alias given to the column in the select list. +In this example the `substring` function is used in both the select list and the GROUP BY expression. In the ORDER BY +expression, we use the `sortColumn` function to duplicate the alias given to the column in the select list. ## Limit and Offset Support Since version 1.1.1 the select statement supports limit and offset for paging (or slicing) queries. You can specify: @@ -237,18 +247,22 @@ Since version 1.1.1 the select statement supports limit and offset for paging (o - Offset only - Both limit and offset -It is important to note that the select renderer writes limit and offset clauses into the generated select statement as is. The library does not attempt to normalize those values for databases that don't support limit and offset directly. Therefore, it is very important for users to understand whether or not the target database supports limit and offset. If the target database does not support limit and offset, then it is likely that using this support will create SQL that has runtime errors. +It is important to note that the select renderer writes limit and offset clauses into the generated select statement as +is. The library does not attempt to normalize those values for databases that don't support limit and offset directly. +Therefore, it is very important for users to understand whether the target database supports limit and offset. +If the target database does not support limit and offset, then it is likely that using this support will create SQL +that has runtime errors. An example follows: ```java - SelectStatementProvider selectStatement = select(animalData.allColumns()) - .from(animalData) - .orderBy(id) - .limit(3) - .offset(22) - .build() - .render(RenderingStrategies.MYBATIS3); +SelectStatementProvider selectStatement = select(animalData.allColumns()) + .from(animalData) + .orderBy(id) + .limit(3) + .offset(22) + .build() + .render(RenderingStrategies.MYBATIS3); ``` ## Fetch First Support @@ -263,11 +277,11 @@ Fetch first is an SQL standard and is supported by most databases. An example follows: ```java - SelectStatementProvider selectStatement = select(animalData.allColumns()) - .from(animalData) - .orderBy(id) - .offset(22) - .fetchFirst(3).rowsOnly() - .build() - .render(RenderingStrategies.MYBATIS3); +SelectStatementProvider selectStatement = select(animalData.allColumns()) + .from(animalData) + .orderBy(id) + .offset(22) + .fetchFirst(3).rowsOnly() + .build() + .render(RenderingStrategies.MYBATIS3); ``` diff --git a/src/site/site.xml b/src/site/site.xml index e22bf264d..2a02c4a79 100644 --- a/src/site/site.xml +++ b/src/site/site.xml @@ -36,6 +36,7 @@

+ From f31473cba252f659bc0c1beabf4e6f0b95111160 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 19 Aug 2024 17:13:38 -0400 Subject: [PATCH 077/289] Docs --- src/site/markdown/docs/migratingV1toV2.md | 50 +++++++---------------- 1 file changed, 15 insertions(+), 35 deletions(-) diff --git a/src/site/markdown/docs/migratingV1toV2.md b/src/site/markdown/docs/migratingV1toV2.md index 8d51e68f9..f24fdaafc 100644 --- a/src/site/markdown/docs/migratingV1toV2.md +++ b/src/site/markdown/docs/migratingV1toV2.md @@ -1,45 +1,21 @@ # V1 to V2 Migration Guide -Version 2 of MyBatis Dynamic SQL introduced many new features. This page will document how to migrate code -from prior releases to version 2. +Version 2 of MyBatis Dynamic SQL introduced many new features. On this page we will provide examples for the more +significant changes - changes that are more substantial than following deprecation messages. -## Java Join Syntax - -Version2 offers a fully flexible join specification and reuses the capabilities of where clauses. Of course, -not all capabilities are supported in databases, but you should now be able to code any type of join specification. +## Kotlin Join Syntax +The Java DSL for joins was changed to allow much more flexible joins. Of course, not all capabilities are supported in +all databases, but you should now be able to code most joins specification that are supported by your database. The changes in the Java DSL are mostly internal and should not impact most users. The `equalTo` methods has been deprecated in favor of `isEqualTo`, but all other changes should be hidden. -V1 Join Specification Example: -```java -SelectStatementProvider selectStatement = select(orderMaster.orderId, orderDetail.lineNumber, orderDetail.quantity) - .from(orderMaster, "om") - .join(orderDetail, "od", on(orderMaster.orderId, equalTo(orderDetail.orderId))) - .build() - .render(RenderingStrategies.MYBATIS3); -``` +Like the Java DSL, the V2 Kotlin DSL offers a fully flexible join specification and allows for much more flexible join +specifications. The changes in the Kotlin DSL allow a more natural expressions of a join specification. The main +difference is that the "on" keyword should be moved outside the join specification lambda (it is now an infix function). +Inside the lambda, the conditions should be rewritten to match the syntax of a where clause. -V2 Join Specification Example: -```java -SelectStatementProvider selectStatement = select(orderMaster.orderId, orderDetail.lineNumber, orderDetail.quantity) - .from(orderMaster, "om") - .join(orderDetail, "od", on(orderMaster.orderId, isEqualTo(orderDetail.orderId))) - .build() - .render(RenderingStrategies.MYBATIS3); -``` - -## Kotlin Join Syntax - -Like the Java DSL, the V2 Kotlin DSL offers a fully flexible join specification and reuses the capabilities of where -clauses. Of course, not all capabilities are supported in databases, but you should now be able to code any type of -join specification. - -The changes in the Kotlin DSL allow a more natural expressions of a join specification. The main difference is that -the "on" keyword should be moved outside the join specification lambda (it is now an infix function). Inside the lambda, -the conditions should be rewritten to match the syntax of a where clause. - -V1 Join Specification Example: +V1 (Deprecated) Join Specification Example: ```kotlin val selectStatement = select( orderMaster.orderId, orderMaster.orderDate, @@ -65,5 +41,9 @@ val selectStatement = select( and { orderMaster.orderId isEqualTo constant("1") } } } - ``` + +Notice that the "on" keyword has been moved outside the lambda, and the conditions are coded with the same syntax used +by WHERE, HAVING, and CASE expressions. + +The prior syntax is deprecated and will be removed in a future release. From 0f1ad9c33f2f64033eb61f00f2ff1da42536948e Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 19 Aug 2024 17:25:46 -0400 Subject: [PATCH 078/289] Checkstyle --- src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java | 4 ++-- .../java/org/mybatis/dynamic/sql/select/MultiSelectDSL.java | 2 +- .../org/mybatis/dynamic/sql/select/QueryExpressionDSL.java | 3 ++- src/main/java/org/mybatis/dynamic/sql/select/SelectDSL.java | 2 +- src/site/markdown/docs/migratingV1toV2.md | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java b/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java index 4468b523a..2cf6ac277 100644 --- a/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java +++ b/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java @@ -439,8 +439,8 @@ static ColumnAndConditionCriterion on(BindableColumn joinColumn, Visit * Starting in version 2.0.0, this function is a synonym for {@link SqlBuilder#isEqualTo(BasicColumn)}. * * @param column the column - * @return an IsEqualToColumn condition * @param the column type + * @return an IsEqualToColumn condition * @deprecated since 2.0.0. Please replace with isEqualTo(column) */ @Deprecated(since = "2.0.0", forRemoval = true) @@ -452,8 +452,8 @@ static IsEqualToColumn equalTo(BindableColumn column) { * Starting in version 2.0.0, this function is a synonym for {@link SqlBuilder#isEqualTo(Object)}. * * @param value the value - * @return an IsEqualTo condition * @param the column type + * @return an IsEqualTo condition * @deprecated since 2.0.0. Please replace with isEqualTo(value) */ @Deprecated(since = "2.0.0", forRemoval = true) diff --git a/src/main/java/org/mybatis/dynamic/sql/select/MultiSelectDSL.java b/src/main/java/org/mybatis/dynamic/sql/select/MultiSelectDSL.java index 42a20e551..0c244481c 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/MultiSelectDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/MultiSelectDSL.java @@ -77,7 +77,7 @@ public OffsetFirstFinisher offsetWhenPresent(Long offset) { @Override public FetchFirstFinisher fetchFirstWhenPresent(Long fetchFirstRows) { this.fetchFirstRows = fetchFirstRows; - return () -> MultiSelectDSL.this; + return () -> this; } @NotNull 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 034e9b593..c4e2b5d9a 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionDSL.java @@ -359,7 +359,8 @@ public JoinSpecificationFinisher on(BindableColumn joinColumn, VisitableC public class JoinSpecificationFinisher extends AbstractBooleanExpressionDSL - implements AbstractWhereStarter, Buildable, PagingDSL { + implements AbstractWhereStarter, Buildable, + PagingDSL { private final TableExpression table; private final JoinType joinType; diff --git a/src/main/java/org/mybatis/dynamic/sql/select/SelectDSL.java b/src/main/java/org/mybatis/dynamic/sql/select/SelectDSL.java index 4b5ef2077..525e3282d 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/SelectDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/SelectDSL.java @@ -119,7 +119,7 @@ public OffsetFirstFinisher offsetWhenPresent(Long offset) { public FetchFirstFinisher fetchFirstWhenPresent(Long fetchFirstRows) { this.fetchFirstRows = fetchFirstRows; - return () -> SelectDSL.this; + return () -> this; } @Override diff --git a/src/site/markdown/docs/migratingV1toV2.md b/src/site/markdown/docs/migratingV1toV2.md index f24fdaafc..12b6adc37 100644 --- a/src/site/markdown/docs/migratingV1toV2.md +++ b/src/site/markdown/docs/migratingV1toV2.md @@ -11,7 +11,7 @@ The changes in the Java DSL are mostly internal and should not impact most users deprecated in favor of `isEqualTo`, but all other changes should be hidden. Like the Java DSL, the V2 Kotlin DSL offers a fully flexible join specification and allows for much more flexible join -specifications. The changes in the Kotlin DSL allow a more natural expressions of a join specification. The main +specifications. The changes in the Kotlin DSL allow a more natural expressions of a join specification. The main difference is that the "on" keyword should be moved outside the join specification lambda (it is now an infix function). Inside the lambda, the conditions should be rewritten to match the syntax of a where clause. From 9c0d7488a7c6419fe9a321dbc8d90e15004cfe5f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 22 Aug 2024 12:04:04 +0000 Subject: [PATCH 079/289] Update kotlin monorepo to v2.0.20 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1cef97f04..5def2d3ee 100644 --- a/pom.xml +++ b/pom.xml @@ -67,7 +67,7 @@ org.mybatis.dynamic.sql - 2.0.10 + 2.0.20 17 2.0 2.0 From 13e16ecd59cb4c3de0b0544aa0f3427fa28bc0ce Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 22 Aug 2024 20:44:42 +0000 Subject: [PATCH 080/289] Update dependency org.postgresql:postgresql to v42.7.4 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5def2d3ee..cd05834f0 100644 --- a/pom.xml +++ b/pom.xml @@ -181,7 +181,7 @@ org.postgresql postgresql - 42.7.3 + 42.7.4 test From b4415921d93d9e7f25c55fb83e5761b908132683 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 7 Sep 2024 13:13:59 +0000 Subject: [PATCH 081/289] Update dependency ch.qos.logback:logback-classic to v1.5.8 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index cd05834f0..2a7cbd9bb 100644 --- a/pom.xml +++ b/pom.xml @@ -163,7 +163,7 @@ ch.qos.logback logback-classic - 1.5.7 + 1.5.8 test From 5865325a020900db5af3fe442dfc112c4200ed10 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 12 Sep 2024 14:05:35 +0000 Subject: [PATCH 082/289] Update dependency org.springframework:spring-jdbc to v6.1.13 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2a7cbd9bb..8555c856f 100644 --- a/pom.xml +++ b/pom.xml @@ -94,7 +94,7 @@ org.springframework spring-jdbc - 6.1.12 + 6.1.13 provided true From 1bfc8e9d02c0b0b516ff75e9ea59d27347b91281 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 25 Sep 2024 10:52:10 +0000 Subject: [PATCH 083/289] Update junit5 monorepo to v5.11.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8555c856f..991746894 100644 --- a/pom.xml +++ b/pom.xml @@ -58,7 +58,7 @@ 17 17 - 5.11.0 + 5.11.1 5.1.2 checkstyle-override.xml From 187cfc2098713fa708ff9f512f175421798c27d7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 1 Oct 2024 01:34:38 +0000 Subject: [PATCH 084/289] Update testcontainers-java monorepo to v1.20.2 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 991746894..9b2d89a54 100644 --- a/pom.xml +++ b/pom.xml @@ -76,7 +76,7 @@ src/test/java,src/test/kotlin official - 1.20.1 + 1.20.2 org.mybatis.dynamic.sql.*;version=${project.version};-noimport:=true From 392f63850098ab2e0234dcbee2a3f1a228e82ef5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 4 Oct 2024 14:10:49 +0000 Subject: [PATCH 085/289] Update junit5 monorepo to v5.11.2 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9b2d89a54..048c066c3 100644 --- a/pom.xml +++ b/pom.xml @@ -58,7 +58,7 @@ 17 17 - 5.11.1 + 5.11.2 5.1.2 checkstyle-override.xml From 1bc43186e61257f3cf59013aa810603c7645a6e3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 8 Oct 2024 15:25:33 +0000 Subject: [PATCH 086/289] Update dependency ch.qos.logback:logback-classic to v1.5.9 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 048c066c3..e2ffb86d8 100644 --- a/pom.xml +++ b/pom.xml @@ -163,7 +163,7 @@ ch.qos.logback logback-classic - 1.5.8 + 1.5.9 test From d7632a7db2d7b9768c9c4d7a65ba91d0cb4c7cc0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 10 Oct 2024 09:59:09 +0000 Subject: [PATCH 087/289] Update kotlin monorepo to v2.0.21 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e2ffb86d8..d68c74ab0 100644 --- a/pom.xml +++ b/pom.xml @@ -67,7 +67,7 @@ org.mybatis.dynamic.sql - 2.0.20 + 2.0.21 17 2.0 2.0 From f604fd859a80150c0fb7615b4c2a23ab4bf7b0a3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 12 Oct 2024 10:32:43 +0000 Subject: [PATCH 088/289] Update dependency ch.qos.logback:logback-classic to v1.5.10 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d68c74ab0..301e22449 100644 --- a/pom.xml +++ b/pom.xml @@ -163,7 +163,7 @@ ch.qos.logback logback-classic - 1.5.9 + 1.5.10 test From 528dfe627eae11add14e1520903976746c42300f Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Sun, 13 Oct 2024 16:10:27 -0400 Subject: [PATCH 089/289] Refactor Spring Batch support for more flexibility The prior support was limited to limit and offset queries. --- .../dynamic/sql/render/RenderingContext.java | 12 ++++ .../dynamic/sql/render/RenderingStrategy.java | 12 ++++ .../render/FetchFirstPagingModelRenderer.java | 24 ++++---- .../LimitAndOffsetPagingModelRenderer.java | 18 +++--- .../SpringBatchCursorReaderSelectModel.java | 32 ---------- ...tchPagingItemReaderRenderingStrategy.java} | 27 ++++++--- .../SpringBatchPagingReaderSelectModel.java | 59 ------------------- .../SpringBatchProviderAdapter.java | 6 +- .../util/springbatch/SpringBatchUtility.java | 49 +++++++-------- .../CursorReaderBatchConfiguration.java | 6 +- .../PagingReaderBatchConfiguration.java | 7 ++- 11 files changed, 94 insertions(+), 158 deletions(-) delete mode 100644 src/main/java/org/mybatis/dynamic/sql/util/springbatch/SpringBatchCursorReaderSelectModel.java rename src/main/java/org/mybatis/dynamic/sql/util/springbatch/{SpringBatchReaderRenderingStrategy.java => SpringBatchPagingItemReaderRenderingStrategy.java} (54%) delete mode 100644 src/main/java/org/mybatis/dynamic/sql/util/springbatch/SpringBatchPagingReaderSelectModel.java diff --git a/src/main/java/org/mybatis/dynamic/sql/render/RenderingContext.java b/src/main/java/org/mybatis/dynamic/sql/render/RenderingContext.java index bc953f847..6eb15615c 100644 --- a/src/main/java/org/mybatis/dynamic/sql/render/RenderingContext.java +++ b/src/main/java/org/mybatis/dynamic/sql/render/RenderingContext.java @@ -66,6 +66,18 @@ private String renderedPlaceHolder(String mapKey, BindableColumn column) .getFormattedJdbcPlaceholder(column, calculatedParameterName, mapKey); } + public RenderedParameterInfo calculateLimitParameterInfo() { + String mapKey = renderingStrategy.formatParameterMapKeyForLimit(sequence); + return new RenderedParameterInfo(mapKey, + renderingStrategy.getFormattedJdbcPlaceholderForLimitOrOffset(calculatedParameterName, mapKey)); + } + + public RenderedParameterInfo calculateOffsetParameterInfo() { + String mapKey = renderingStrategy.formatParameterMapKeyForOffset(sequence); + return new RenderedParameterInfo(mapKey, + renderingStrategy.getFormattedJdbcPlaceholderForLimitOrOffset(calculatedParameterName, mapKey)); + } + public RenderedParameterInfo calculateParameterInfo() { String mapKey = nextMapKey(); return new RenderedParameterInfo(mapKey, renderedPlaceHolder(mapKey)); diff --git a/src/main/java/org/mybatis/dynamic/sql/render/RenderingStrategy.java b/src/main/java/org/mybatis/dynamic/sql/render/RenderingStrategy.java index 70b369c73..5924f356c 100644 --- a/src/main/java/org/mybatis/dynamic/sql/render/RenderingStrategy.java +++ b/src/main/java/org/mybatis/dynamic/sql/render/RenderingStrategy.java @@ -40,6 +40,14 @@ public String formatParameterMapKey(AtomicInteger sequence) { return "p" + sequence.getAndIncrement(); //$NON-NLS-1$ } + public String formatParameterMapKeyForLimit(AtomicInteger sequence) { + return formatParameterMapKey(sequence); + } + + public String formatParameterMapKeyForOffset(AtomicInteger sequence) { + return formatParameterMapKey(sequence); + } + /** * This method generates a binding for a parameter to a placeholder in a generated SQL statement. * @@ -78,6 +86,10 @@ public String formatParameterMapKey(AtomicInteger sequence) { */ public abstract String getFormattedJdbcPlaceholder(String prefix, String parameterName); + public String getFormattedJdbcPlaceholderForLimitOrOffset(String prefix, String parameterName) { + return getFormattedJdbcPlaceholder(prefix, parameterName); + } + /** * This method generates a binding for a parameter to a placeholder in a row based insert statement. * diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/FetchFirstPagingModelRenderer.java b/src/main/java/org/mybatis/dynamic/sql/select/render/FetchFirstPagingModelRenderer.java index fcd62264b..82b61cdf7 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/render/FetchFirstPagingModelRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/render/FetchFirstPagingModelRenderer.java @@ -51,30 +51,30 @@ private FragmentAndParameters renderFetchFirstRowsOnly() { } private FragmentAndParameters renderFetchFirstRowsOnly(Long fetchFirstRows) { - RenderedParameterInfo parameterInfo = renderingContext.calculateParameterInfo(); + RenderedParameterInfo limitParameterInfo = renderingContext.calculateLimitParameterInfo(); return FragmentAndParameters - .withFragment("fetch first " + parameterInfo.renderedPlaceHolder() //$NON-NLS-1$ + .withFragment("fetch first " + limitParameterInfo.renderedPlaceHolder() //$NON-NLS-1$ + " rows only") //$NON-NLS-1$ - .withParameter(parameterInfo.parameterMapKey(), fetchFirstRows) + .withParameter(limitParameterInfo.parameterMapKey(), fetchFirstRows) .build(); } private FragmentAndParameters renderOffsetOnly(Long offset) { - RenderedParameterInfo parameterInfo = renderingContext.calculateParameterInfo(); - return FragmentAndParameters.withFragment("offset " + parameterInfo.renderedPlaceHolder() //$NON-NLS-1$ + RenderedParameterInfo offsetParameterInfo = renderingContext.calculateOffsetParameterInfo(); + return FragmentAndParameters.withFragment("offset " + offsetParameterInfo.renderedPlaceHolder() //$NON-NLS-1$ + " rows") //$NON-NLS-1$ - .withParameter(parameterInfo.parameterMapKey(), offset) + .withParameter(offsetParameterInfo.parameterMapKey(), offset) .build(); } private FragmentAndParameters renderOffsetAndFetchFirstRows(Long offset, Long fetchFirstRows) { - RenderedParameterInfo parameterInfo1 = renderingContext.calculateParameterInfo(); - RenderedParameterInfo parameterInfo2 = renderingContext.calculateParameterInfo(); - return FragmentAndParameters.withFragment("offset " + parameterInfo1.renderedPlaceHolder() //$NON-NLS-1$ - + " rows fetch first " + parameterInfo2.renderedPlaceHolder() //$NON-NLS-1$ + RenderedParameterInfo offsetParameterInfo = renderingContext.calculateOffsetParameterInfo(); + RenderedParameterInfo limitParameterInfo = renderingContext.calculateParameterInfo(); + return FragmentAndParameters.withFragment("offset " + offsetParameterInfo.renderedPlaceHolder() //$NON-NLS-1$ + + " rows fetch first " + limitParameterInfo.renderedPlaceHolder() //$NON-NLS-1$ + " rows only") //$NON-NLS-1$ - .withParameter(parameterInfo1.parameterMapKey(), offset) - .withParameter(parameterInfo2.parameterMapKey(), fetchFirstRows) + .withParameter(offsetParameterInfo.parameterMapKey(), offset) + .withParameter(limitParameterInfo.parameterMapKey(), fetchFirstRows) .build(); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/LimitAndOffsetPagingModelRenderer.java b/src/main/java/org/mybatis/dynamic/sql/select/render/LimitAndOffsetPagingModelRenderer.java index 008c5a1af..609f4816a 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/render/LimitAndOffsetPagingModelRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/render/LimitAndOffsetPagingModelRenderer.java @@ -40,19 +40,19 @@ public FragmentAndParameters render() { } private FragmentAndParameters renderLimitOnly() { - RenderedParameterInfo parameterInfo = renderingContext.calculateParameterInfo(); - return FragmentAndParameters.withFragment("limit " + parameterInfo.renderedPlaceHolder()) //$NON-NLS-1$ - .withParameter(parameterInfo.parameterMapKey(), limit) + RenderedParameterInfo limitParameterInfo = renderingContext.calculateLimitParameterInfo(); + return FragmentAndParameters.withFragment("limit " + limitParameterInfo.renderedPlaceHolder()) //$NON-NLS-1$ + .withParameter(limitParameterInfo.parameterMapKey(), limit) .build(); } private FragmentAndParameters renderLimitAndOffset(Long offset) { - RenderedParameterInfo parameterInfo1 = renderingContext.calculateParameterInfo(); - RenderedParameterInfo parameterInfo2 = renderingContext.calculateParameterInfo(); - return FragmentAndParameters.withFragment("limit " + parameterInfo1.renderedPlaceHolder() //$NON-NLS-1$ - + " offset " + parameterInfo2.renderedPlaceHolder()) //$NON-NLS-1$ - .withParameter(parameterInfo1.parameterMapKey(), limit) - .withParameter(parameterInfo2.parameterMapKey(), offset) + RenderedParameterInfo limitParameterInfo = renderingContext.calculateLimitParameterInfo(); + RenderedParameterInfo offsetParameterInfo = renderingContext.calculateOffsetParameterInfo(); + return FragmentAndParameters.withFragment("limit " + limitParameterInfo.renderedPlaceHolder() //$NON-NLS-1$ + + " offset " + offsetParameterInfo.renderedPlaceHolder()) //$NON-NLS-1$ + .withParameter(limitParameterInfo.parameterMapKey(), limit) + .withParameter(offsetParameterInfo.parameterMapKey(), offset) .build(); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/util/springbatch/SpringBatchCursorReaderSelectModel.java b/src/main/java/org/mybatis/dynamic/sql/util/springbatch/SpringBatchCursorReaderSelectModel.java deleted file mode 100644 index 5486b31de..000000000 --- a/src/main/java/org/mybatis/dynamic/sql/util/springbatch/SpringBatchCursorReaderSelectModel.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2016-2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.mybatis.dynamic.sql.util.springbatch; - -import org.mybatis.dynamic.sql.select.SelectModel; -import org.mybatis.dynamic.sql.select.render.SelectStatementProvider; - -public class SpringBatchCursorReaderSelectModel { - - private final SelectModel selectModel; - - public SpringBatchCursorReaderSelectModel(SelectModel selectModel) { - this.selectModel = selectModel; - } - - public SelectStatementProvider render() { - return selectModel.render(SpringBatchUtility.SPRING_BATCH_READER_RENDERING_STRATEGY); - } -} diff --git a/src/main/java/org/mybatis/dynamic/sql/util/springbatch/SpringBatchReaderRenderingStrategy.java b/src/main/java/org/mybatis/dynamic/sql/util/springbatch/SpringBatchPagingItemReaderRenderingStrategy.java similarity index 54% rename from src/main/java/org/mybatis/dynamic/sql/util/springbatch/SpringBatchReaderRenderingStrategy.java rename to src/main/java/org/mybatis/dynamic/sql/util/springbatch/SpringBatchPagingItemReaderRenderingStrategy.java index 48b1b9b8c..566a78bcd 100644 --- a/src/main/java/org/mybatis/dynamic/sql/util/springbatch/SpringBatchReaderRenderingStrategy.java +++ b/src/main/java/org/mybatis/dynamic/sql/util/springbatch/SpringBatchPagingItemReaderRenderingStrategy.java @@ -15,20 +15,31 @@ */ package org.mybatis.dynamic.sql.util.springbatch; -import org.mybatis.dynamic.sql.BindableColumn; +import java.util.concurrent.atomic.AtomicInteger; + import org.mybatis.dynamic.sql.render.MyBatis3RenderingStrategy; /** - * This rendering strategy should be used for MyBatis3 statements using one of the - * Spring batch readers supplied by mybatis-spring integration (http://www.mybatis.org/spring/). - * Those readers are MyBatisPagingItemReader and MyBatisCursorItemReader. + * This rendering strategy should be used for MyBatis3 statements using the + * MyBatisPagingItemReader supplied by mybatis-spring integration (http://www.mybatis.org/spring/). * */ -public class SpringBatchReaderRenderingStrategy extends MyBatis3RenderingStrategy { +public class SpringBatchPagingItemReaderRenderingStrategy extends MyBatis3RenderingStrategy { + + @Override + public String getFormattedJdbcPlaceholderForLimitOrOffset(String prefix, String parameterName) { + return "#{" //$NON-NLS-1$ + + parameterName + + "}"; //$NON-NLS-1$ + } + + @Override + public String formatParameterMapKeyForLimit(AtomicInteger sequence) { + return "_pagesize"; //$NON-NLS-1$ + } @Override - public String getFormattedJdbcPlaceholder(BindableColumn column, String prefix, String parameterName) { - String newPrefix = SpringBatchUtility.PARAMETER_KEY + "." + prefix; //$NON-NLS-1$ - return super.getFormattedJdbcPlaceholder(column, newPrefix, parameterName); + public String formatParameterMapKeyForOffset(AtomicInteger sequence) { + return "_skiprows"; //$NON-NLS-1$ } } diff --git a/src/main/java/org/mybatis/dynamic/sql/util/springbatch/SpringBatchPagingReaderSelectModel.java b/src/main/java/org/mybatis/dynamic/sql/util/springbatch/SpringBatchPagingReaderSelectModel.java deleted file mode 100644 index 648d71218..000000000 --- a/src/main/java/org/mybatis/dynamic/sql/util/springbatch/SpringBatchPagingReaderSelectModel.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2016-2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.mybatis.dynamic.sql.util.springbatch; - -import java.util.HashMap; -import java.util.Map; - -import org.mybatis.dynamic.sql.select.SelectModel; -import org.mybatis.dynamic.sql.select.render.SelectStatementProvider; - -public class SpringBatchPagingReaderSelectModel { - - private final SelectModel selectModel; - - public SpringBatchPagingReaderSelectModel(SelectModel selectModel) { - this.selectModel = selectModel; - } - - public SelectStatementProvider render() { - SelectStatementProvider selectStatement = - selectModel.render(SpringBatchUtility.SPRING_BATCH_READER_RENDERING_STRATEGY); - return new LimitAndOffsetDecorator(selectStatement); - } - - public static class LimitAndOffsetDecorator implements SelectStatementProvider { - private final Map parameters = new HashMap<>(); - private final String selectStatement; - - public LimitAndOffsetDecorator(SelectStatementProvider delegate) { - parameters.putAll(delegate.getParameters()); - - selectStatement = delegate.getSelectStatement() - + " LIMIT #{_pagesize} OFFSET #{_skiprows}"; //$NON-NLS-1$ - } - - @Override - public Map getParameters() { - return parameters; - } - - @Override - public String getSelectStatement() { - return selectStatement; - } - } -} diff --git a/src/main/java/org/mybatis/dynamic/sql/util/springbatch/SpringBatchProviderAdapter.java b/src/main/java/org/mybatis/dynamic/sql/util/springbatch/SpringBatchProviderAdapter.java index f212a0d04..ce75697cd 100644 --- a/src/main/java/org/mybatis/dynamic/sql/util/springbatch/SpringBatchProviderAdapter.java +++ b/src/main/java/org/mybatis/dynamic/sql/util/springbatch/SpringBatchProviderAdapter.java @@ -17,13 +17,9 @@ import java.util.Map; -import org.mybatis.dynamic.sql.select.render.SelectStatementProvider; - public class SpringBatchProviderAdapter { public String select(Map parameterValues) { - SelectStatementProvider selectStatement = - (SelectStatementProvider) parameterValues.get(SpringBatchUtility.PARAMETER_KEY); - return selectStatement.getSelectStatement(); + return (String) parameterValues.get(SpringBatchUtility.PARAMETER_KEY); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/util/springbatch/SpringBatchUtility.java b/src/main/java/org/mybatis/dynamic/sql/util/springbatch/SpringBatchUtility.java index 63b64429a..1155da806 100644 --- a/src/main/java/org/mybatis/dynamic/sql/util/springbatch/SpringBatchUtility.java +++ b/src/main/java/org/mybatis/dynamic/sql/util/springbatch/SpringBatchUtility.java @@ -18,48 +18,39 @@ import java.util.HashMap; import java.util.Map; -import org.mybatis.dynamic.sql.BasicColumn; import org.mybatis.dynamic.sql.render.RenderingStrategy; -import org.mybatis.dynamic.sql.select.QueryExpressionDSL; -import org.mybatis.dynamic.sql.select.SelectDSL; import org.mybatis.dynamic.sql.select.render.SelectStatementProvider; public class SpringBatchUtility { private SpringBatchUtility() {} - public static final String PARAMETER_KEY = "mybatis3_dsql_query"; //$NON-NLS-1$ - - public static final RenderingStrategy SPRING_BATCH_READER_RENDERING_STRATEGY = - new SpringBatchReaderRenderingStrategy(); - - public static Map toParameterValues(SelectStatementProvider selectStatement) { - Map parameterValues = new HashMap<>(); - parameterValues.put(PARAMETER_KEY, selectStatement); - return parameterValues; - } + static final String PARAMETER_KEY = "mybatis3_dsql_query"; //$NON-NLS-1$ /** - * Select builder that renders in a manner appropriate for the MyBatisPagingItemReader. - * - *

Important rendered SQL will contain LIMIT and OFFSET clauses in the SELECT statement. If your database - * (Oracle) does not support LIMIT and OFFSET, the queries will fail. + * Constant for use in a query intended for use with the MyBatisPagingItemReader. + * This value will not be used in the query at runtime because MyBatis Spring integration + * will supply a value for _skiprows. * - * @param selectList a column list for the SELECT statement - * @return FromGatherer used to continue a SELECT statement + *

See https://mybatis.org/spring/batch.html for details. */ - public static QueryExpressionDSL.FromGatherer selectForPaging( - BasicColumn... selectList) { - return SelectDSL.select(SpringBatchPagingReaderSelectModel::new, selectList); - } + public static final long MYBATIS_SPRING_BATCH_SKIPROWS = -437L; /** - * Select builder that renders in a manner appropriate for the MyBatisCursorItemReader. + * Constant for use in a query intended for use with the MyBatisPagingItemReader. + * This value will not be used in the query at runtime because MyBatis Spring integration + * will supply a value for _pagesize. * - * @param selectList a column list for the SELECT statement - * @return FromGatherer used to continue a SELECT statement + *

See https://mybatis.org/spring/batch.html for details. */ - public static QueryExpressionDSL.FromGatherer selectForCursor( - BasicColumn... selectList) { - return SelectDSL.select(SpringBatchCursorReaderSelectModel::new, selectList); + public static final long MYBATIS_SPRING_BATCH_PAGESIZE = -439L; + + public static final RenderingStrategy SPRING_BATCH_PAGING_ITEM_READER_RENDERING_STRATEGY = + new SpringBatchPagingItemReaderRenderingStrategy(); + + public static Map toParameterValues(SelectStatementProvider selectStatement) { + Map parameterValues = new HashMap<>(); + parameterValues.put(PARAMETER_KEY, selectStatement.getSelectStatement()); + parameterValues.put("parameters", selectStatement.getParameters()); //$NON-NLS-1$ + return parameterValues; } } diff --git a/src/test/java/examples/springbatch/cursor/CursorReaderBatchConfiguration.java b/src/test/java/examples/springbatch/cursor/CursorReaderBatchConfiguration.java index 823f1c631..838fe9d41 100644 --- a/src/test/java/examples/springbatch/cursor/CursorReaderBatchConfiguration.java +++ b/src/test/java/examples/springbatch/cursor/CursorReaderBatchConfiguration.java @@ -18,10 +18,12 @@ import static examples.springbatch.mapper.PersonDynamicSqlSupport.lastName; import static examples.springbatch.mapper.PersonDynamicSqlSupport.person; import static org.mybatis.dynamic.sql.SqlBuilder.isEqualTo; +import static org.mybatis.dynamic.sql.SqlBuilder.select; import javax.sql.DataSource; import org.apache.ibatis.session.SqlSessionFactory; +import org.mybatis.dynamic.sql.render.RenderingStrategies; import org.mybatis.dynamic.sql.select.render.SelectStatementProvider; import org.mybatis.dynamic.sql.update.render.UpdateStatementProvider; import org.mybatis.dynamic.sql.util.springbatch.SpringBatchUtility; @@ -89,11 +91,11 @@ public PlatformTransactionManager transactionManager(DataSource dataSource) { @Bean public MyBatisCursorItemReader reader(SqlSessionFactory sqlSessionFactory) { - SelectStatementProvider selectStatement = SpringBatchUtility.selectForCursor(person.allColumns()) + SelectStatementProvider selectStatement = select(person.allColumns()) .from(person) .where(lastName, isEqualTo("flintstone")) .build() - .render(); + .render(RenderingStrategies.MYBATIS3); MyBatisCursorItemReader reader = new MyBatisCursorItemReader<>(); reader.setQueryId(PersonMapper.class.getName() + ".selectMany"); diff --git a/src/test/java/examples/springbatch/paging/PagingReaderBatchConfiguration.java b/src/test/java/examples/springbatch/paging/PagingReaderBatchConfiguration.java index 41353ab35..2fa74c862 100644 --- a/src/test/java/examples/springbatch/paging/PagingReaderBatchConfiguration.java +++ b/src/test/java/examples/springbatch/paging/PagingReaderBatchConfiguration.java @@ -17,6 +17,7 @@ import static examples.springbatch.mapper.PersonDynamicSqlSupport.*; import static org.mybatis.dynamic.sql.SqlBuilder.isEqualTo; +import static org.mybatis.dynamic.sql.SqlBuilder.select; import javax.sql.DataSource; @@ -88,12 +89,14 @@ public PlatformTransactionManager transactionManager(DataSource dataSource) { @Bean public MyBatisPagingItemReader reader(SqlSessionFactory sqlSessionFactory) { - SelectStatementProvider selectStatement = SpringBatchUtility.selectForPaging(person.allColumns()) + SelectStatementProvider selectStatement = select(person.allColumns()) .from(person) .where(forPagingTest, isEqualTo(true)) .orderBy(id) + .limit(SpringBatchUtility.MYBATIS_SPRING_BATCH_PAGESIZE) + .offset(SpringBatchUtility.MYBATIS_SPRING_BATCH_SKIPROWS) .build() - .render(); + .render(SpringBatchUtility.SPRING_BATCH_PAGING_ITEM_READER_RENDERING_STRATEGY); MyBatisPagingItemReader reader = new MyBatisPagingItemReader<>(); reader.setQueryId(PersonMapper.class.getName() + ".selectMany"); From 8214313b936c759f2b009c2dfaed6e623bd011ff Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Sun, 13 Oct 2024 16:26:49 -0400 Subject: [PATCH 090/289] Fix documentation link --- .../SpringBatchPagingItemReaderRenderingStrategy.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/util/springbatch/SpringBatchPagingItemReaderRenderingStrategy.java b/src/main/java/org/mybatis/dynamic/sql/util/springbatch/SpringBatchPagingItemReaderRenderingStrategy.java index 566a78bcd..d45d56c0e 100644 --- a/src/main/java/org/mybatis/dynamic/sql/util/springbatch/SpringBatchPagingItemReaderRenderingStrategy.java +++ b/src/main/java/org/mybatis/dynamic/sql/util/springbatch/SpringBatchPagingItemReaderRenderingStrategy.java @@ -21,8 +21,8 @@ /** * This rendering strategy should be used for MyBatis3 statements using the - * MyBatisPagingItemReader supplied by mybatis-spring integration (http://www.mybatis.org/spring/). - * + * MyBatisPagingItemReader supplied by mybatis-spring integration + * (http://www.mybatis.org/spring/). */ public class SpringBatchPagingItemReaderRenderingStrategy extends MyBatis3RenderingStrategy { From e6859feac052a6093e8bf9feea905882ec9173dc Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 15 Oct 2024 11:50:41 +0000 Subject: [PATCH 091/289] Update dependency ch.qos.logback:logback-classic to v1.5.11 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 301e22449..e29318619 100644 --- a/pom.xml +++ b/pom.xml @@ -163,7 +163,7 @@ ch.qos.logback logback-classic - 1.5.10 + 1.5.11 test From 86104fb8320de830b0b698e742d2d245d281e727 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Tue, 15 Oct 2024 09:55:51 -0400 Subject: [PATCH 092/289] Update test container versions --- src/test/java/config/TestContainersConfiguration.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/config/TestContainersConfiguration.java b/src/test/java/config/TestContainersConfiguration.java index ed2c95c96..fc6607dbb 100644 --- a/src/test/java/config/TestContainersConfiguration.java +++ b/src/test/java/config/TestContainersConfiguration.java @@ -21,6 +21,6 @@ * Utility interface to hold Docker image tags for the test containers we use */ public interface TestContainersConfiguration { - DockerImageName POSTGRES_LATEST = DockerImageName.parse("postgres:16.3"); - DockerImageName MARIADB_LATEST = DockerImageName.parse("mariadb:11.4.2"); + DockerImageName POSTGRES_LATEST = DockerImageName.parse("postgres:17.0"); + DockerImageName MARIADB_LATEST = DockerImageName.parse("mariadb:11.5.2"); } From e41a1129e66a78e692204436d86d538847628ffa Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Tue, 15 Oct 2024 14:38:12 -0400 Subject: [PATCH 093/289] Improve Javadocs --- .../sql/util/springbatch/SpringBatchUtility.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/util/springbatch/SpringBatchUtility.java b/src/main/java/org/mybatis/dynamic/sql/util/springbatch/SpringBatchUtility.java index 1155da806..01cae8964 100644 --- a/src/main/java/org/mybatis/dynamic/sql/util/springbatch/SpringBatchUtility.java +++ b/src/main/java/org/mybatis/dynamic/sql/util/springbatch/SpringBatchUtility.java @@ -31,6 +31,9 @@ private SpringBatchUtility() {} * This value will not be used in the query at runtime because MyBatis Spring integration * will supply a value for _skiprows. * + *

This value can be used as a parameter for the "offset" method in a query to make the intention + * clear that the actual runtime value will be supplied by MyBatis Spring integration. + * *

See https://mybatis.org/spring/batch.html for details. */ public static final long MYBATIS_SPRING_BATCH_SKIPROWS = -437L; @@ -40,6 +43,9 @@ private SpringBatchUtility() {} * This value will not be used in the query at runtime because MyBatis Spring integration * will supply a value for _pagesize. * + *

This value can be used as a parameter for the "limit" or "fetchFirst" method in a query to make the intention + * clear that the actual runtime value will be supplied by MyBatis Spring integration. + * *

See https://mybatis.org/spring/batch.html for details. */ public static final long MYBATIS_SPRING_BATCH_PAGESIZE = -439L; @@ -48,9 +54,9 @@ private SpringBatchUtility() {} new SpringBatchPagingItemReaderRenderingStrategy(); public static Map toParameterValues(SelectStatementProvider selectStatement) { - Map parameterValues = new HashMap<>(); + var parameterValues = new HashMap(); parameterValues.put(PARAMETER_KEY, selectStatement.getSelectStatement()); - parameterValues.put("parameters", selectStatement.getParameters()); //$NON-NLS-1$ + parameterValues.put(RenderingStrategy.DEFAULT_PARAMETER_PREFIX, selectStatement.getParameters()); return parameterValues; } } From e262018aecbca866561f7c78faf9dc9f07ed328a Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Wed, 16 Oct 2024 13:33:55 -0400 Subject: [PATCH 094/289] Improve Javadocs --- .../dynamic/sql/render/RenderingStrategy.java | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/main/java/org/mybatis/dynamic/sql/render/RenderingStrategy.java b/src/main/java/org/mybatis/dynamic/sql/render/RenderingStrategy.java index 5924f356c..afc588a7a 100644 --- a/src/main/java/org/mybatis/dynamic/sql/render/RenderingStrategy.java +++ b/src/main/java/org/mybatis/dynamic/sql/render/RenderingStrategy.java @@ -36,14 +36,38 @@ public abstract class RenderingStrategy { public static final String DEFAULT_PARAMETER_PREFIX = "parameters"; //$NON-NLS-1$ + /** + * Return a unique key that can be used to place a parameter value in the parameter map + * + * @param sequence a sequence for calculating a unique value + * @return a key used to place the parameter value in the parameter map + */ public String formatParameterMapKey(AtomicInteger sequence) { return "p" + sequence.getAndIncrement(); //$NON-NLS-1$ } + /** + * Return a parameter map key intended as a parameter for a limit or fetch first query. + * + *

By default, this parameter is treated the same as any other. This method is a hook to support + * MyBatis Spring Batch. + * + * @param sequence a sequence for calculating a unique value + * @return a key used to place the parameter value in the parameter map + */ public String formatParameterMapKeyForLimit(AtomicInteger sequence) { return formatParameterMapKey(sequence); } + /** + * Return a parameter map key intended as a parameter for a query offset. + * + *

By default, this parameter is treated the same as any other. This method is a hook to support + * MyBatis Spring Batch. + * + * @param sequence a sequence for calculating a unique value + * @return a key used to place the parameter value in the parameter map + */ public String formatParameterMapKeyForOffset(AtomicInteger sequence) { return formatParameterMapKey(sequence); } @@ -86,6 +110,19 @@ public String formatParameterMapKeyForOffset(AtomicInteger sequence) { */ public abstract String getFormattedJdbcPlaceholder(String prefix, String parameterName); + /** + * This method generates a binding for a parameter to a placeholder in a generated SQL statement. + * + *

This method is used to generate bindings for limit, offset, and fetch first parameters. By default, these + * parameters are treated the same as any other. This method supports MyBatis Spring Batch integration where the + * parameter keys have predefined values and need special handling. + * + * @param prefix parameter prefix used for locating the parameters in a SQL provider object. Typically, will be + * {@link RenderingStrategy#DEFAULT_PARAMETER_PREFIX}. This is ignored for Spring. + * @param parameterName name of the parameter. Typically generated by calling + * {@link RenderingStrategy#formatParameterMapKey(AtomicInteger)} + * @return the generated binding + */ public String getFormattedJdbcPlaceholderForLimitOrOffset(String prefix, String parameterName) { return getFormattedJdbcPlaceholder(prefix, parameterName); } From 4e8bf745f2fe257537b60305e304975a52889fcd Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Wed, 16 Oct 2024 13:34:18 -0400 Subject: [PATCH 095/289] Use new limit method for delete and update statements --- .../org/mybatis/dynamic/sql/delete/render/DeleteRenderer.java | 2 +- .../org/mybatis/dynamic/sql/update/render/UpdateRenderer.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/delete/render/DeleteRenderer.java b/src/main/java/org/mybatis/dynamic/sql/delete/render/DeleteRenderer.java index 8a9c945d4..fa4cd0d28 100644 --- a/src/main/java/org/mybatis/dynamic/sql/delete/render/DeleteRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/delete/render/DeleteRenderer.java @@ -84,7 +84,7 @@ private Optional calculateLimitClause() { } private FragmentAndParameters renderLimitClause(Long limit) { - RenderedParameterInfo parameterInfo = renderingContext.calculateParameterInfo(); + RenderedParameterInfo parameterInfo = renderingContext.calculateLimitParameterInfo(); return FragmentAndParameters.withFragment("limit " + parameterInfo.renderedPlaceHolder()) //$NON-NLS-1$ .withParameter(parameterInfo.parameterMapKey(), limit) diff --git a/src/main/java/org/mybatis/dynamic/sql/update/render/UpdateRenderer.java b/src/main/java/org/mybatis/dynamic/sql/update/render/UpdateRenderer.java index f11662c02..352c1de7a 100644 --- a/src/main/java/org/mybatis/dynamic/sql/update/render/UpdateRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/update/render/UpdateRenderer.java @@ -109,7 +109,7 @@ private Optional calculateLimitClause() { } private FragmentAndParameters renderLimitClause(Long limit) { - RenderedParameterInfo parameterInfo = renderingContext.calculateParameterInfo(); + RenderedParameterInfo parameterInfo = renderingContext.calculateLimitParameterInfo(); return FragmentAndParameters.withFragment("limit " + parameterInfo.renderedPlaceHolder()) //$NON-NLS-1$ .withParameter(parameterInfo.parameterMapKey(), limit) From 4bb5fdc6b7dd33fad46f9a14e1e918dfdeefc293 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 17 Oct 2024 10:26:02 +0000 Subject: [PATCH 096/289] Update dependency org.springframework:spring-jdbc to v6.1.14 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e29318619..20c63a9ec 100644 --- a/pom.xml +++ b/pom.xml @@ -94,7 +94,7 @@ org.springframework spring-jdbc - 6.1.13 + 6.1.14 provided true From ce2943fa45c0d90ff7e63f14fde0a288d52f2a56 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 21 Oct 2024 15:41:07 +0000 Subject: [PATCH 097/289] Update junit5 monorepo to v5.11.3 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 20c63a9ec..6312edf6d 100644 --- a/pom.xml +++ b/pom.xml @@ -58,7 +58,7 @@ 17 17 - 5.11.2 + 5.11.3 5.1.2 checkstyle-override.xml From dbd94e8ee9a8092cb015ac6483d46afeabb9e78c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 23 Oct 2024 01:54:29 +0000 Subject: [PATCH 098/289] Update testcontainers-java monorepo to v1.20.3 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6312edf6d..b49e7f205 100644 --- a/pom.xml +++ b/pom.xml @@ -76,7 +76,7 @@ src/test/java,src/test/kotlin official - 1.20.2 + 1.20.3 org.mybatis.dynamic.sql.*;version=${project.version};-noimport:=true From 3ade4fe06c7626799a10cf97ae7b42ed5c53f819 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Wed, 23 Oct 2024 16:37:32 -0400 Subject: [PATCH 099/289] Documentation --- CHANGELOG.md | 4 + src/site/markdown/docs/springBatch.md | 180 ++++++++++++++++---------- 2 files changed, 116 insertions(+), 68 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d46635fb..9a61b8b89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,10 @@ worked to make these changes as minimal as possible. **Potentially Breaking Changes:** +- If you use this library with MyBatis' Spring Batch integration, you will need to make changes as we have + refactored that support to be more flexible. Please see the + [Spring Batch](https://mybatis.org/mybatis-dynamic-sql/docs/springBatch.html) documentation page to see the new usage + details. - If you have created any custom implementations of `SortSpecification`, you will need to update those implementations due to a new rendering strategy for ORDER BY phrases. The old methods `isDescending` and `orderByName` are removed in favor of a new method `renderForOrderBy` diff --git a/src/site/markdown/docs/springBatch.md b/src/site/markdown/docs/springBatch.md index 4b1855a97..1c5bfda66 100644 --- a/src/site/markdown/docs/springBatch.md +++ b/src/site/markdown/docs/springBatch.md @@ -1,100 +1,144 @@ # Spring Batch Support This library provides some utilities to make it easier to interact with the MyBatis Spring Batch support. -## The Problem +MyBatis Spring provides support for interacting with Spring Batch (see +[http://www.mybatis.org/spring/batch.html](http://www.mybatis.org/spring/batch.html)). This support consists of +specialized implementations of Spring Batch's `ItemReader` and `ItemWriter` interfaces that have support for MyBatis +mappers. -MyBatis Spring support provides utility classes for interacting with Spring Batch (see [http://www.mybatis.org/spring/batch.html](http://www.mybatis.org/spring/batch.html)). These classes are specialized implementations of Spring Batch's `ItemReader` and `ItemWriter` interfaces that have support for MyBatis mappers. +The `ItemWriter` implementation works with SQL generated by MyBatis Dynamic SQL with no modification needed. -The `ItemWriter` implementations work with SQL generated by MyBatis Dynamic SQL with no modification needed. +The `ItemReader` implementations need special care. Those classes assume that all query parameters will be placed in a +Map (as per usual when using multiple parameters in a query). MyBatis Dynamic SQL, by default, builds a parameter +object that is intended to be the only parameter for a query. The library contains utilities for overcoming this +difficulty. -The `ItemReader` implementations need special care. Those classes assume that all query parameters will be placed in a Map (as per usual when using multiple parameters in a query). MyBatis Dynamic SQL, by default, builds a parameter object that should be the only parameter in a query and will not work when placed in a Map of parameters. +## Using MyBatisCursorItemReader -## The Solution +The `MyBatisCursorItemReader` class works with built-in support for cursor based queries in MyBatis. Queries of this +type will read row by row and MyBatis will convert each result row to a result object without having to read the entire +result set into memory. The normal rendering for MyBatis will work for queries using this reader, but special care +must be taken to prepare the parameter values for use with this reader. See the following example: -The solution involves these steps: - -1. The SQL must be rendered such that the parameter markers are aware of the enclosing parameter Map in the `ItemReader` -1. The `SelectStatementProvider` must be placed in the `ItemReader` parameter Map with a known key. -1. The `@SelectProvider` must be configured to be aware of the enclosing parameter Map - -MyBatis Dynamic SQL provides utilities for each of these requirements. Each utility uses a shared Map key for consistency. - -## Spring Batch Item Readers - -MyBatis Spring support supplies two implementations of the `ItemReader` interface: - -1. `org.mybatis.spring.batch.MyBatisCursorItemReader` - for queries that can be efficiently processed through a single select statement and a cursor -1. `org.mybatis.spring.batch.MyBatisPagingItemReader` - for queries that should be processed as a series of paged selects. Note that MyBatis does not provide any native support for paged queries - it is up to the user to write SQL for paging. The `MyBatisPagingItemWriter` simply makes properties available that specify which page should be read currently. - -MyBatis Dynamic SQL supplies specialized select statements that will render properly for the different implementations of `ItemReader`: - -1. `SpringBatchUtility.selectForCursor(...)` will create a select statement that is appropriate for the `MyBatisCursorItemReader` - a single select statement that will be read with a cursor -1. `SpringBatchUtility.selectForPaging(...)` will create a select statement that is appropriate for the `MyBatisPagingItemReader` - a select statement that will be called multiple times - one for each page as configured on the batch job. - -**Very Important:** The paging implementation will only work for databases that support limit and offset in select statements. Fortunately, most databases do support this - with the notable exception of Oracle. - - -### Rendering for Cursor +```java +@Bean +public MyBatisCursorItemReader reader(SqlSessionFactory sqlSessionFactory) { + SelectStatementProvider selectStatement = select(person.allColumns()) + .from(person) + .where(lastName, isEqualTo("flintstone")) + .build() + .render(RenderingStrategies.MYBATIS3); + + MyBatisCursorItemReader reader = new MyBatisCursorItemReader<>(); + reader.setQueryId(PersonMapper.class.getName() + ".selectMany"); + reader.setSqlSessionFactory(sqlSessionFactory); + reader.setParameterValues(SpringBatchUtility.toParameterValues(selectStatement)); + return reader; +} +``` -Queries intended for the `MyBatisCursorItemReader` should be rendered as follows: +Note the use of `SpringBatchUtility.toParameterValues(...)`. This utility will set up the parameter Map correctly for the +rendered statement, and for use with a library supplied `@selectProvider`. See the following for an example of the mapper +method used for the query coded above: ```java - SelectStatementProvider selectStatement = SpringBatchUtility.selectForCursor(person.allColumns()) - .from(person) - .where(lastName, isEqualTo("flintstone")) - .build() - .render(); // renders for MyBatisCursorItemReader +@Mapper +public interface PersonMapper { + + @SelectProvider(type=SpringBatchProviderAdapter.class, method="select") + @Results({ + @Result(column="id", property="id", id=true), + @Result(column="first_name", property="firstName"), + @Result(column="last_name", property="lastName") + }) + List selectMany(Map parameterValues); +} ``` -### Rendering for Paging +Note the use of the `SpringBatchProviderAdapter` - that adapter knows how to retrieve the rendered queries from the +parameter map initialed in the method above. -Queries intended for the `MyBatisPagingItemReader` should be rendered as follows: +### Migrating from 1.x Support for MyBatisCursorItemReader + +In version 1.x, the library supplied a special utility for creating a select statement as follows: ```java - SelectStatementProvider selectStatement = SpringBatchUtility.selectForPaging(person.allColumns()) - .from(person) - .where(lastName, isEqualTo("flintstone")) - .build() - .render(); // renders for MyBatisPagingItemReader +SelectStatementProvider selectStatement = SpringBatchUtility.selectForCursor(person.allColumns()) + .from(person) + .where(lastName, isEqualTo("flintstone")) + .build() + .render(); ``` -## Creating the Parameter Map +That utility method was limited in capability. The new method allows the full capabilities of the library. To migrate, +follow these steps: -The `SpringBatchUtility` provides a method to create the parameter values Map needed by the MyBatis Spring `ItemReader` implementations. It can be used as follows: +1. Replace `SpringBatchUtility.selectForCursor(...)` with `SqlBuilder.select(...)` +2. Replace `render()` with `render(RenderingStrategies.MYBATIS3)` -For cursor based queries... +## Using MyBatisPagingItemReader -```java - MyBatisCursorItemReader reader = new MyBatisCursorItemReader<>(); - reader.setQueryId(PersonMapper.class.getName() + ".selectMany"); - reader.setSqlSessionFactory(sqlSessionFactory); - reader.setParameterValues(SpringBatchUtility.toParameterValues(selectStatement)); // create parameter map -``` -For paging based queries... +The `MyBatisPagingItemReader` class works with paging queries - queries that read rows in pages and process page by page +rather than row by row. The normal rendering for MyBatis will work NOT for queries using this reader because MyBatis +Spring support supplies specially named parameters for page size, offset, etc. So the query must be rendered properly +to respond to these parameter values that are supplied at runtime. As with the other reader, special care +must also be taken to prepare the parameter values for use with this reader. See the following example: ```java - MyBatisPagingItemReader reader = new MyBatisPagingItemReader<>(); - reader.setQueryId(PersonMapper.class.getName() + ".selectMany"); - reader.setSqlSessionFactory(sqlSessionFactory); - reader.setPageSize(7); - reader.setParameterValues(SpringBatchUtility.toParameterValues(selectStatement)); // create parameter map +@Bean +public MyBatisPagingItemReader reader(SqlSessionFactory sqlSessionFactory) { + SelectStatementProvider selectStatement = select(person.allColumns()) + .from(person) + .where(forPagingTest, isEqualTo(true)) + .orderBy(id) + .limit(SpringBatchUtility.MYBATIS_SPRING_BATCH_PAGESIZE) + .offset(SpringBatchUtility.MYBATIS_SPRING_BATCH_SKIPROWS) + .build() + .render(SpringBatchUtility.SPRING_BATCH_PAGING_ITEM_READER_RENDERING_STRATEGY); + + MyBatisPagingItemReader reader = new MyBatisPagingItemReader<>(); + reader.setQueryId(PersonMapper.class.getName() + ".selectMany"); + reader.setSqlSessionFactory(sqlSessionFactory); + reader.setParameterValues(SpringBatchUtility.toParameterValues(selectStatement)); + reader.setPageSize(7); + return reader; +} ``` +Notice the following important items: +1. The `limit` and `offset` methods in the query are used to set up paging support in the query. With MyBatis Spring + batch support, the integration library will supply values for those parameters at runtime. Any values you code in the + select statement will be ignored - only the values supplied by the library will be used. We supply two constants + to make this clearer: `MYBATIS_SPRING_BATCH_PAGESIZE` and `MYBATIS_SPRING_BATCH_SKIPROWS`. You can use these values + to make the code clearer, but again the values will be ignored at runtime. +2. The query must be rendered with the `SPRING_BATCH_PAGING_ITEM_READER_RENDERING_STRATEGY` rendering strategy. This + rendering strategy will render the query so that it will respond properly to the runtime values supplied for page size + and skip rows. -## Specialized @SelectProvider Adapter +### Migrating from 1.x Support for MyBatisPagingItemReader -MyBatis mapper methods should be configured to use the specialized `@SelectProvider` adapter as follows: +In version 1.x, the library supplied a special utility for creating a select statement as follows: ```java - @SelectProvider(type=SpringBatchProviderAdapter.class, method="select") // use the Spring batch adapter - @Results({ - @Result(column="id", property="id", id=true), - @Result(column="first_name", property="firstName"), - @Result(column="last_name", property="lastName") - }) - List selectMany(Map parameterValues); +SelectStatementProvider selectStatement = SpringBatchUtility.selectForPaging(person.allColumns()) + .from(person) + .where(forPagingTest, isEqualTo(true)) + .orderBy(id) + .build() + .render(); ``` -## Complete Example +That utility method was very limited in capability. It only supported limit and offset based queries - which are not +supported in all databases. The new method allows the full capabilities of the library. To migrate, +follow these steps: + +1. Replace `SpringBatchUtility.selectForPaging(...)` with `SqlBuilder.select(...)` +2. Add `limit()`, `fetchFirst()`, and `offset()` method calls as appropriate for your query and database +3. Replace `render()` with `render(RenderingStrategies.SPRING_BATCH_PAGING_ITEM_READER_RENDERING_STRATEGY)` + + +## Complete Examples -The unit tests for MyBatis Dynamic SQL include a complete example of using MyBatis Spring Batch support using the MyBatis supplied reader as well as both types of MyBatis supplied writers. You can see the full example here: [https://github.com/mybatis/mybatis-dynamic-sql/tree/master/src/test/java/examples/springbatch](https://github.com/mybatis/mybatis-dynamic-sql/tree/master/src/test/java/examples/springbatch) +The unit tests for MyBatis Dynamic SQL include a complete example of using MyBatis Spring Batch support using the +MyBatis supplied reader as well as both types of MyBatis supplied writers. You can see the full example +here: [https://github.com/mybatis/mybatis-dynamic-sql/tree/master/src/test/java/examples/springbatch](https://github.com/mybatis/mybatis-dynamic-sql/tree/master/src/test/java/examples/springbatch) From d4005a757e49d554d95692b73e841bf9f6145ec6 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Wed, 23 Oct 2024 17:51:58 -0400 Subject: [PATCH 100/289] Coverage --- pom.xml | 2 + .../dynamic/sql/render/RenderingContext.java | 19 +++--- .../dynamic/sql/render/RenderingStrategy.java | 19 +++++- .../render/FetchFirstPagingModelRenderer.java | 12 ++-- ...atchPagingItemReaderRenderingStrategy.java | 2 +- src/site/markdown/docs/springBatch.md | 2 +- .../examples/simple/MyBatisMapToRowTest.java | 1 - .../springbatch/SpringBatchRenderingTest.java | 65 +++++++++++++++++++ 8 files changed, 99 insertions(+), 23 deletions(-) create mode 100644 src/test/java/examples/springbatch/SpringBatchRenderingTest.java diff --git a/pom.xml b/pom.xml index 991746894..772950c2b 100644 --- a/pom.xml +++ b/pom.xml @@ -58,6 +58,8 @@ 17 17 + 17 + 17 5.11.1 5.1.2 diff --git a/src/main/java/org/mybatis/dynamic/sql/render/RenderingContext.java b/src/main/java/org/mybatis/dynamic/sql/render/RenderingContext.java index 6eb15615c..553ecd090 100644 --- a/src/main/java/org/mybatis/dynamic/sql/render/RenderingContext.java +++ b/src/main/java/org/mybatis/dynamic/sql/render/RenderingContext.java @@ -57,30 +57,27 @@ private String nextMapKey() { return renderingStrategy.formatParameterMapKey(sequence); } - private String renderedPlaceHolder(String mapKey) { - return renderingStrategy.getFormattedJdbcPlaceholder(calculatedParameterName, mapKey); - } - private String renderedPlaceHolder(String mapKey, BindableColumn column) { return column.renderingStrategy().orElse(renderingStrategy) .getFormattedJdbcPlaceholder(column, calculatedParameterName, mapKey); } + public RenderedParameterInfo calculateFetchFirstRowsParameterInfo() { + String mapKey = renderingStrategy.formatParameterMapKeyForFetchFirstRows(sequence); + return new RenderedParameterInfo(mapKey, + renderingStrategy.getFormattedJdbcPlaceholderForPagingParameters(calculatedParameterName, mapKey)); + } + public RenderedParameterInfo calculateLimitParameterInfo() { String mapKey = renderingStrategy.formatParameterMapKeyForLimit(sequence); return new RenderedParameterInfo(mapKey, - renderingStrategy.getFormattedJdbcPlaceholderForLimitOrOffset(calculatedParameterName, mapKey)); + renderingStrategy.getFormattedJdbcPlaceholderForPagingParameters(calculatedParameterName, mapKey)); } public RenderedParameterInfo calculateOffsetParameterInfo() { String mapKey = renderingStrategy.formatParameterMapKeyForOffset(sequence); return new RenderedParameterInfo(mapKey, - renderingStrategy.getFormattedJdbcPlaceholderForLimitOrOffset(calculatedParameterName, mapKey)); - } - - public RenderedParameterInfo calculateParameterInfo() { - String mapKey = nextMapKey(); - return new RenderedParameterInfo(mapKey, renderedPlaceHolder(mapKey)); + renderingStrategy.getFormattedJdbcPlaceholderForPagingParameters(calculatedParameterName, mapKey)); } public RenderedParameterInfo calculateParameterInfo(BindableColumn column) { diff --git a/src/main/java/org/mybatis/dynamic/sql/render/RenderingStrategy.java b/src/main/java/org/mybatis/dynamic/sql/render/RenderingStrategy.java index afc588a7a..969a5e094 100644 --- a/src/main/java/org/mybatis/dynamic/sql/render/RenderingStrategy.java +++ b/src/main/java/org/mybatis/dynamic/sql/render/RenderingStrategy.java @@ -37,7 +37,7 @@ public abstract class RenderingStrategy { public static final String DEFAULT_PARAMETER_PREFIX = "parameters"; //$NON-NLS-1$ /** - * Return a unique key that can be used to place a parameter value in the parameter map + * Generate a unique key that can be used to place a parameter value in the parameter map * * @param sequence a sequence for calculating a unique value * @return a key used to place the parameter value in the parameter map @@ -47,7 +47,20 @@ public String formatParameterMapKey(AtomicInteger sequence) { } /** - * Return a parameter map key intended as a parameter for a limit or fetch first query. + * Return a parameter map key intended as a parameter for a fetch first query. + * + *

By default, this parameter is treated the same as any other. This method is a hook to support + * MyBatis Spring Batch. + * + * @param sequence a sequence for calculating a unique value + * @return a key used to place the parameter value in the parameter map + */ + public String formatParameterMapKeyForFetchFirstRows(AtomicInteger sequence) { + return formatParameterMapKeyForLimit(sequence); + } + + /** + * Return a parameter map key intended as a parameter for a limit query. * *

By default, this parameter is treated the same as any other. This method is a hook to support * MyBatis Spring Batch. @@ -123,7 +136,7 @@ public String formatParameterMapKeyForOffset(AtomicInteger sequence) { * {@link RenderingStrategy#formatParameterMapKey(AtomicInteger)} * @return the generated binding */ - public String getFormattedJdbcPlaceholderForLimitOrOffset(String prefix, String parameterName) { + public String getFormattedJdbcPlaceholderForPagingParameters(String prefix, String parameterName) { return getFormattedJdbcPlaceholder(prefix, parameterName); } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/FetchFirstPagingModelRenderer.java b/src/main/java/org/mybatis/dynamic/sql/select/render/FetchFirstPagingModelRenderer.java index 82b61cdf7..0ad493620 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/render/FetchFirstPagingModelRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/render/FetchFirstPagingModelRenderer.java @@ -51,11 +51,11 @@ private FragmentAndParameters renderFetchFirstRowsOnly() { } private FragmentAndParameters renderFetchFirstRowsOnly(Long fetchFirstRows) { - RenderedParameterInfo limitParameterInfo = renderingContext.calculateLimitParameterInfo(); + RenderedParameterInfo fetchFirstParameterInfo = renderingContext.calculateFetchFirstRowsParameterInfo(); return FragmentAndParameters - .withFragment("fetch first " + limitParameterInfo.renderedPlaceHolder() //$NON-NLS-1$ + .withFragment("fetch first " + fetchFirstParameterInfo.renderedPlaceHolder() //$NON-NLS-1$ + " rows only") //$NON-NLS-1$ - .withParameter(limitParameterInfo.parameterMapKey(), fetchFirstRows) + .withParameter(fetchFirstParameterInfo.parameterMapKey(), fetchFirstRows) .build(); } @@ -69,12 +69,12 @@ private FragmentAndParameters renderOffsetOnly(Long offset) { private FragmentAndParameters renderOffsetAndFetchFirstRows(Long offset, Long fetchFirstRows) { RenderedParameterInfo offsetParameterInfo = renderingContext.calculateOffsetParameterInfo(); - RenderedParameterInfo limitParameterInfo = renderingContext.calculateParameterInfo(); + RenderedParameterInfo fetchFirstParameterInfo = renderingContext.calculateFetchFirstRowsParameterInfo(); return FragmentAndParameters.withFragment("offset " + offsetParameterInfo.renderedPlaceHolder() //$NON-NLS-1$ - + " rows fetch first " + limitParameterInfo.renderedPlaceHolder() //$NON-NLS-1$ + + " rows fetch first " + fetchFirstParameterInfo.renderedPlaceHolder() //$NON-NLS-1$ + " rows only") //$NON-NLS-1$ .withParameter(offsetParameterInfo.parameterMapKey(), offset) - .withParameter(limitParameterInfo.parameterMapKey(), fetchFirstRows) + .withParameter(fetchFirstParameterInfo.parameterMapKey(), fetchFirstRows) .build(); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/util/springbatch/SpringBatchPagingItemReaderRenderingStrategy.java b/src/main/java/org/mybatis/dynamic/sql/util/springbatch/SpringBatchPagingItemReaderRenderingStrategy.java index d45d56c0e..791e89bfc 100644 --- a/src/main/java/org/mybatis/dynamic/sql/util/springbatch/SpringBatchPagingItemReaderRenderingStrategy.java +++ b/src/main/java/org/mybatis/dynamic/sql/util/springbatch/SpringBatchPagingItemReaderRenderingStrategy.java @@ -27,7 +27,7 @@ public class SpringBatchPagingItemReaderRenderingStrategy extends MyBatis3RenderingStrategy { @Override - public String getFormattedJdbcPlaceholderForLimitOrOffset(String prefix, String parameterName) { + public String getFormattedJdbcPlaceholderForPagingParameters(String prefix, String parameterName) { return "#{" //$NON-NLS-1$ + parameterName + "}"; //$NON-NLS-1$ diff --git a/src/site/markdown/docs/springBatch.md b/src/site/markdown/docs/springBatch.md index 1c5bfda66..11ec90d6d 100644 --- a/src/site/markdown/docs/springBatch.md +++ b/src/site/markdown/docs/springBatch.md @@ -85,7 +85,7 @@ to respond to these parameter values that are supplied at runtime. As with the o must also be taken to prepare the parameter values for use with this reader. See the following example: ```java -@Bean +@Bean public MyBatisPagingItemReader reader(SqlSessionFactory sqlSessionFactory) { SelectStatementProvider selectStatement = select(person.allColumns()) .from(person) diff --git a/src/test/java/examples/simple/MyBatisMapToRowTest.java b/src/test/java/examples/simple/MyBatisMapToRowTest.java index 2b6f714b2..a542d36f6 100644 --- a/src/test/java/examples/simple/MyBatisMapToRowTest.java +++ b/src/test/java/examples/simple/MyBatisMapToRowTest.java @@ -28,7 +28,6 @@ import java.io.InputStreamReader; import java.sql.Connection; import java.sql.DriverManager; -import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.stream.IntStream; diff --git a/src/test/java/examples/springbatch/SpringBatchRenderingTest.java b/src/test/java/examples/springbatch/SpringBatchRenderingTest.java new file mode 100644 index 000000000..48873b375 --- /dev/null +++ b/src/test/java/examples/springbatch/SpringBatchRenderingTest.java @@ -0,0 +1,65 @@ +/* + * Copyright 2016-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package examples.springbatch; + +import static examples.springbatch.mapper.PersonDynamicSqlSupport.*; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mybatis.dynamic.sql.SqlBuilder.isLike; +import static org.mybatis.dynamic.sql.SqlBuilder.select; + +import org.junit.jupiter.api.Test; +import org.mybatis.dynamic.sql.util.springbatch.SpringBatchUtility; + +class SpringBatchRenderingTest { + + @Test + void renderLimit() { + var selectStatement = select(person.allColumns()) + .from(person) + .where(firstName, isLike("%f%")) + .limit(SpringBatchUtility.MYBATIS_SPRING_BATCH_PAGESIZE) + .offset(SpringBatchUtility.MYBATIS_SPRING_BATCH_SKIPROWS) + .build() + .render(SpringBatchUtility.SPRING_BATCH_PAGING_ITEM_READER_RENDERING_STRATEGY); + + assertThat(selectStatement.getSelectStatement()) + .isEqualTo(""" + select * \ + from person \ + where first_name like #{parameters.p1,jdbcType=VARCHAR} \ + limit #{_pagesize} \ + offset #{_skiprows}"""); + } + + @Test + void renderFetchFirst() { + var selectStatement = select(person.allColumns()) + .from(person) + .where(firstName, isLike("%f%")) + .offset(SpringBatchUtility.MYBATIS_SPRING_BATCH_SKIPROWS) + .fetchFirst(SpringBatchUtility.MYBATIS_SPRING_BATCH_PAGESIZE).rowsOnly() + .build() + .render(SpringBatchUtility.SPRING_BATCH_PAGING_ITEM_READER_RENDERING_STRATEGY); + + assertThat(selectStatement.getSelectStatement()) + .isEqualTo(""" + select * \ + from person \ + where first_name like #{parameters.p1,jdbcType=VARCHAR} \ + offset #{_skiprows} rows \ + fetch first #{_pagesize} rows only"""); + } +} From adc2931b74bc9d67c6f25d058b0b8c4a24eb3803 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Thu, 24 Oct 2024 11:08:54 -0400 Subject: [PATCH 101/289] Better pattern for fetch first --- .../org/mybatis/dynamic/sql/render/RenderingStrategy.java | 2 +- .../SpringBatchPagingItemReaderRenderingStrategy.java | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/render/RenderingStrategy.java b/src/main/java/org/mybatis/dynamic/sql/render/RenderingStrategy.java index 969a5e094..fb10ea99b 100644 --- a/src/main/java/org/mybatis/dynamic/sql/render/RenderingStrategy.java +++ b/src/main/java/org/mybatis/dynamic/sql/render/RenderingStrategy.java @@ -56,7 +56,7 @@ public String formatParameterMapKey(AtomicInteger sequence) { * @return a key used to place the parameter value in the parameter map */ public String formatParameterMapKeyForFetchFirstRows(AtomicInteger sequence) { - return formatParameterMapKeyForLimit(sequence); + return formatParameterMapKey(sequence); } /** diff --git a/src/main/java/org/mybatis/dynamic/sql/util/springbatch/SpringBatchPagingItemReaderRenderingStrategy.java b/src/main/java/org/mybatis/dynamic/sql/util/springbatch/SpringBatchPagingItemReaderRenderingStrategy.java index 791e89bfc..c87c4a03e 100644 --- a/src/main/java/org/mybatis/dynamic/sql/util/springbatch/SpringBatchPagingItemReaderRenderingStrategy.java +++ b/src/main/java/org/mybatis/dynamic/sql/util/springbatch/SpringBatchPagingItemReaderRenderingStrategy.java @@ -33,6 +33,11 @@ public String getFormattedJdbcPlaceholderForPagingParameters(String prefix, Stri + "}"; //$NON-NLS-1$ } + @Override + public String formatParameterMapKeyForFetchFirstRows(AtomicInteger sequence) { + return "_pagesize"; //$NON-NLS-1$ + } + @Override public String formatParameterMapKeyForLimit(AtomicInteger sequence) { return "_pagesize"; //$NON-NLS-1$ From cfb47bce398b6592851be7b0cb4a2568a72c2e30 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Thu, 24 Oct 2024 11:31:47 -0400 Subject: [PATCH 102/289] Doc updates --- .../dynamic/sql/render/RenderingStrategy.java | 2 +- src/site/markdown/docs/springBatch.md | 30 +++++++++++++++---- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/render/RenderingStrategy.java b/src/main/java/org/mybatis/dynamic/sql/render/RenderingStrategy.java index fb10ea99b..6beb7bc24 100644 --- a/src/main/java/org/mybatis/dynamic/sql/render/RenderingStrategy.java +++ b/src/main/java/org/mybatis/dynamic/sql/render/RenderingStrategy.java @@ -37,7 +37,7 @@ public abstract class RenderingStrategy { public static final String DEFAULT_PARAMETER_PREFIX = "parameters"; //$NON-NLS-1$ /** - * Generate a unique key that can be used to place a parameter value in the parameter map + * Generate a unique key that can be used to place a parameter value in the parameter map. * * @param sequence a sequence for calculating a unique value * @return a key used to place the parameter value in the parameter map diff --git a/src/site/markdown/docs/springBatch.md b/src/site/markdown/docs/springBatch.md index 11ec90d6d..aca011c39 100644 --- a/src/site/markdown/docs/springBatch.md +++ b/src/site/markdown/docs/springBatch.md @@ -70,8 +70,8 @@ SelectStatementProvider selectStatement = SpringBatchUtility.selectForCursor(pe .render(); ``` -That utility method was limited in capability. The new method allows the full capabilities of the library. To migrate, -follow these steps: +That utility method was limited in capability and has been removed. The new method described above allows the full +capabilities of the library. To migrate, follow these steps: 1. Replace `SpringBatchUtility.selectForCursor(...)` with `SqlBuilder.select(...)` 2. Replace `render()` with `render(RenderingStrategies.MYBATIS3)` @@ -114,6 +114,26 @@ Notice the following important items: 2. The query must be rendered with the `SPRING_BATCH_PAGING_ITEM_READER_RENDERING_STRATEGY` rendering strategy. This rendering strategy will render the query so that it will respond properly to the runtime values supplied for page size and skip rows. +3. Note the use of `SpringBatchUtility.toParameterValues(...)`. This utility will set up the parameter Map correctly for + the rendered statement, and for use with a library supplied `@selectProvider`. See the following for an example of + the mapper method used for the query coded above: + +```java +@Mapper +public interface PersonMapper { + + @SelectProvider(type=SpringBatchProviderAdapter.class, method="select") + @Results({ + @Result(column="id", property="id", id=true), + @Result(column="first_name", property="firstName"), + @Result(column="last_name", property="lastName") + }) + List selectMany(Map parameterValues); +} +``` + +Note the use of the `SpringBatchProviderAdapter` - that adapter knows how to retrieve the rendered queries from the +parameter map initialed in the method above. ### Migrating from 1.x Support for MyBatisPagingItemReader @@ -128,9 +148,9 @@ SelectStatementProvider selectStatement = SpringBatchUtility.selectForPaging(pe .render(); ``` -That utility method was very limited in capability. It only supported limit and offset based queries - which are not -supported in all databases. The new method allows the full capabilities of the library. To migrate, -follow these steps: +That utility method was very limited in capability and has been removed. The prior method only supported limit and +offset based queries - which are not supported in all databases. The new method described above allows the full +capabilities of the library to be used. To migrate, follow these steps: 1. Replace `SpringBatchUtility.selectForPaging(...)` with `SqlBuilder.select(...)` 2. Add `limit()`, `fetchFirst()`, and `offset()` method calls as appropriate for your query and database From 7e0c665d8ff25f50e15c2bbd039c6c06738d1b17 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Thu, 24 Oct 2024 16:51:48 -0400 Subject: [PATCH 103/289] Remove many deprecated method calls --- .../examples/emptywhere/EmptyWhereTest.java | 4 +- .../java/examples/groupby/GroupByTest.java | 10 +- .../java/examples/joins/JoinMapperTest.java | 112 +- .../java/examples/joins/JoinSubQueryTest.java | 29 +- .../joins/NewSyntaxJoinMapperTest.java | 1270 ----------------- .../simple/PersonWithAddressMapper.java | 6 +- .../examples/spring/PersonTemplateTest.java | 12 +- .../java/issues/gh100/FromJoinWhereTest.java | 264 ++-- .../gh100/Issue100StartAfterJoinTest.java | 14 +- src/test/java/issues/gh100/Issue100Test.java | 20 +- .../PersonWithAddressMapperExtensions.kt | 12 +- .../mybatis3/general/GeneralKotlinTest.kt | 12 +- ...perTest.kt => DeprecatedJoinMapperTest.kt} | 284 +--- ...CanonicalSpringKotlinTemplateDirectTest.kt | 4 +- .../canonical/CanonicalSpringKotlinTest.kt | 4 +- 15 files changed, 257 insertions(+), 1800 deletions(-) delete mode 100644 src/test/java/examples/joins/NewSyntaxJoinMapperTest.java rename src/test/kotlin/examples/kotlin/mybatis3/joins/{JoinMapperTest.kt => DeprecatedJoinMapperTest.kt} (66%) diff --git a/src/test/java/examples/emptywhere/EmptyWhereTest.java b/src/test/java/examples/emptywhere/EmptyWhereTest.java index 8b3fdc546..eca321cd9 100644 --- a/src/test/java/examples/emptywhere/EmptyWhereTest.java +++ b/src/test/java/examples/emptywhere/EmptyWhereTest.java @@ -170,7 +170,7 @@ void testJoinThreeConditions() { String lName = "Flintstone"; QueryExpressionDSL.QueryExpressionWhereBuilder builder = select(id, firstName, PersonDynamicSqlSupport.lastName, orderDate) - .from(person).join(order).on(person.id, equalTo(order.personId)) + .from(person).join(order).on(person.id, isEqualTo(order.personId)) .where(id, isEqualTo(3)); builder.and(firstName, isEqualTo(fName).filter(Objects::nonNull)); @@ -192,7 +192,7 @@ void testJoinThreeConditions() { @MethodSource("joinWhereVariations") void testJoinVariations(Variation variation) { QueryExpressionDSL.QueryExpressionWhereBuilder builder = select(id, firstName, PersonDynamicSqlSupport.lastName, orderDate) - .from(person).join(order).on(person.id, equalTo(order.personId)) + .from(person).join(order).on(person.id, isEqualTo(order.personId)) .where(); builder.and(firstName, isEqualTo(variation.firstName).filter(Objects::nonNull)); diff --git a/src/test/java/examples/groupby/GroupByTest.java b/src/test/java/examples/groupby/GroupByTest.java index 0a5ce6645..793fe2429 100644 --- a/src/test/java/examples/groupby/GroupByTest.java +++ b/src/test/java/examples/groupby/GroupByTest.java @@ -126,7 +126,7 @@ void testGroupByAfterJoin() { CommonSelectMapper mapper = session.getMapper(CommonSelectMapper.class); SelectStatementProvider selectStatement = select(lastName, streetAddress, count().as("count")) - .from(person, "p").join(address, "a").on(person.addressId, equalTo(address.id)) + .from(person, "p").join(address, "a").on(person.addressId, isEqualTo(address.id)) .groupBy(lastName, streetAddress) .build() .render(RenderingStrategies.MYBATIS3); @@ -156,10 +156,10 @@ void testUnionAfterJoin() { CommonSelectMapper mapper = session.getMapper(CommonSelectMapper.class); SelectStatementProvider selectStatement = select(lastName, firstName, streetAddress) - .from(person, "p").join(address, "a").on(person.addressId, equalTo(address.id)) + .from(person, "p").join(address, "a").on(person.addressId, isEqualTo(address.id)) .union() .select(person2.lastName, person2.firstName, streetAddress) - .from(person2, "p").join(address, "a").on(person2.addressId, equalTo(address.id)) + .from(person2, "p").join(address, "a").on(person2.addressId, isEqualTo(address.id)) .orderBy(lastName, firstName) .build() .render(RenderingStrategies.MYBATIS3); @@ -192,10 +192,10 @@ void testUnionAllAfterJoin() { CommonSelectMapper mapper = session.getMapper(CommonSelectMapper.class); SelectStatementProvider selectStatement = select(lastName, firstName, streetAddress) - .from(person, "p").join(address, "a").on(person.addressId, equalTo(address.id)) + .from(person, "p").join(address, "a").on(person.addressId, isEqualTo(address.id)) .unionAll() .select(person2.lastName, person2.firstName, streetAddress) - .from(person2, "p").join(address, "a").on(person2.addressId, equalTo(address.id)) + .from(person2, "p").join(address, "a").on(person2.addressId, isEqualTo(address.id)) .orderBy(lastName, firstName) .build() .render(RenderingStrategies.MYBATIS3); diff --git a/src/test/java/examples/joins/JoinMapperTest.java b/src/test/java/examples/joins/JoinMapperTest.java index 50c8e30f5..1b22697e1 100644 --- a/src/test/java/examples/joins/JoinMapperTest.java +++ b/src/test/java/examples/joins/JoinMapperTest.java @@ -83,7 +83,7 @@ void testSingleTableJoin1() { SelectStatementProvider selectStatement = select(orderMaster.orderId, orderDate, orderDetail.lineNumber, orderDetail.description, orderDetail.quantity) .from(orderMaster, "om") - .join(orderDetail, "od").on(orderMaster.orderId, equalTo(orderDetail.orderId)) + .join(orderDetail, "od").on(orderMaster.orderId, isEqualTo(orderDetail.orderId)) .build() .render(RenderingStrategies.MYBATIS3); @@ -117,7 +117,7 @@ void testSingleTableJoin2() { SelectStatementProvider selectStatement = select(orderMaster.orderId, orderDate, orderDetail.lineNumber, orderDetail.description, orderDetail.quantity) .from(orderMaster, "om") - .join(orderDetail, "od", on(orderMaster.orderId, equalTo(orderDetail.orderId))) + .join(orderDetail, "od", on(orderMaster.orderId, isEqualTo(orderDetail.orderId))) .build() .render(RenderingStrategies.MYBATIS3); @@ -149,7 +149,7 @@ void testCompoundJoin1() { // this is a nonsensical join, but it does test the "and" capability SelectStatementProvider selectStatement = select(orderMaster.orderId, orderDate, orderDetail.lineNumber, orderDetail.description, orderDetail.quantity) .from(orderMaster, "om") - .join(orderDetail, "od").on(orderMaster.orderId, equalTo(orderDetail.orderId), and(orderMaster.orderId, equalTo(orderDetail.orderId))) + .join(orderDetail, "od").on(orderMaster.orderId, isEqualTo(orderDetail.orderId), and(orderMaster.orderId, isEqualTo(orderDetail.orderId))) .build() .render(RenderingStrategies.MYBATIS3); @@ -163,9 +163,9 @@ void testCompoundJoin2() { // this is a nonsensical join, but it does test the "and" capability SelectStatementProvider selectStatement = select(orderMaster.orderId, orderDate, orderDetail.lineNumber, orderDetail.description, orderDetail.quantity) .from(orderMaster, "om") - .join(orderDetail, "od").on(orderMaster.orderId, equalTo(orderDetail.orderId)) + .join(orderDetail, "od").on(orderMaster.orderId, isEqualTo(orderDetail.orderId)) .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) - .and(orderMaster.orderId, equalTo(orderDetail.orderId)) + .and(orderMaster.orderId, isEqualTo(orderDetail.orderId)) .build() .render(RenderingStrategies.MYBATIS3); @@ -179,7 +179,7 @@ void testCompoundJoin3() { // this is a nonsensical join, but it does test the "and" capability SelectStatementProvider selectStatement = select(orderMaster.orderId, orderDate, orderDetail.lineNumber, orderDetail.description, orderDetail.quantity) .from(orderMaster, "om") - .join(orderDetail, "od", on(orderMaster.orderId, equalTo(orderDetail.orderId)), and(orderMaster.orderId, equalTo(orderDetail.orderId))) + .join(orderDetail, "od", on(orderMaster.orderId, isEqualTo(orderDetail.orderId)), and(orderMaster.orderId, isEqualTo(orderDetail.orderId))) .build() .render(RenderingStrategies.MYBATIS3); @@ -193,7 +193,7 @@ void testCompoundJoin4() { // this is a nonsensical join, but it does test the "and" capability SelectStatementProvider selectStatement = select(orderMaster.orderId, orderDate, orderDetail.lineNumber, orderDetail.description, orderDetail.quantity) .from(orderMaster, "om") - .leftJoin(orderDetail, "od", on(orderMaster.orderId, equalTo(orderDetail.orderId)), and(orderMaster.orderId, equalTo(orderDetail.orderId))) + .leftJoin(orderDetail, "od", on(orderMaster.orderId, isEqualTo(orderDetail.orderId)), and(orderMaster.orderId, isEqualTo(orderDetail.orderId))) .build() .render(RenderingStrategies.MYBATIS3); @@ -207,7 +207,7 @@ void testCompoundJoin5() { // this is a nonsensical join, but it does test the "and" capability SelectStatementProvider selectStatement = select(orderMaster.orderId, orderDate, orderDetail.lineNumber, orderDetail.description, orderDetail.quantity) .from(orderMaster, "om") - .rightJoin(orderDetail, "od", on(orderMaster.orderId, equalTo(orderDetail.orderId)), and(orderMaster.orderId, equalTo(orderDetail.orderId))) + .rightJoin(orderDetail, "od", on(orderMaster.orderId, isEqualTo(orderDetail.orderId)), and(orderMaster.orderId, isEqualTo(orderDetail.orderId))) .build() .render(RenderingStrategies.MYBATIS3); @@ -221,7 +221,7 @@ void testCompoundJoin6() { // this is a nonsensical join, but it does test the "and" capability SelectStatementProvider selectStatement = select(orderMaster.orderId, orderDate, orderDetail.lineNumber, orderDetail.description, orderDetail.quantity) .from(orderMaster, "om") - .fullJoin(orderDetail, "od", on(orderMaster.orderId, equalTo(orderDetail.orderId)), and(orderMaster.orderId, equalTo(orderDetail.orderId))) + .fullJoin(orderDetail, "od", on(orderMaster.orderId, isEqualTo(orderDetail.orderId)), and(orderMaster.orderId, isEqualTo(orderDetail.orderId))) .build() .render(RenderingStrategies.MYBATIS3); @@ -237,8 +237,8 @@ void testMultipleTableJoinWithWhereClause() { SelectStatementProvider selectStatement = select(orderMaster.orderId, 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)) + .join(orderLine, "ol").on(orderMaster.orderId, isEqualTo(orderLine.orderId)) + .join(itemMaster, "im").on(orderLine.itemId, isEqualTo(itemMaster.itemId)) .where(orderMaster.orderId, isEqualTo(2)) .build() .render(RenderingStrategies.MYBATIS3); @@ -268,8 +268,8 @@ void testMultipleTableJoinWithApplyWhere() { SelectStatementProvider selectStatement = select(orderMaster.orderId, 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)) + .join(orderLine, "ol").on(orderMaster.orderId, isEqualTo(orderLine.orderId)) + .join(itemMaster, "im").on(orderLine.itemId, isEqualTo(itemMaster.itemId)) .applyWhere(where(orderMaster.orderId, isEqualTo(2)).toWhereApplier()) .build() .render(RenderingStrategies.MYBATIS3); @@ -299,8 +299,8 @@ void testMultipleTableJoinWithComplexWhereClause() { SelectStatementProvider selectStatement = select(orderMaster.orderId, 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)) + .join(orderLine, "ol").on(orderMaster.orderId, isEqualTo(orderLine.orderId)) + .join(itemMaster, "im").on(orderLine.itemId, isEqualTo(itemMaster.itemId)) .where(orderMaster.orderId, isEqualTo(2), and(orderLine.lineNumber, isEqualTo(2))) .build() .render(RenderingStrategies.MYBATIS3); @@ -328,8 +328,8 @@ void testMultipleTableJoinWithOrderBy() { SelectStatementProvider selectStatement = select(orderMaster.orderId, 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)) + .join(orderLine, "ol").on(orderMaster.orderId, isEqualTo(orderLine.orderId)) + .join(itemMaster, "im").on(orderLine.itemId, isEqualTo(itemMaster.itemId)) .orderBy(orderMaster.orderId) .build() .render(RenderingStrategies.MYBATIS3); @@ -365,8 +365,8 @@ void testMultipleTableJoinNoAliasWithOrderBy() { SelectStatementProvider selectStatement = select(orderMaster.orderId, 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)) + .join(orderLine).on(orderMaster.orderId, isEqualTo(orderLine.orderId)) + .join(itemMaster).on(orderLine.itemId, isEqualTo(itemMaster.itemId)) .where(orderMaster.orderId, isEqualTo(2)) .orderBy(orderMaster.orderId) .build() @@ -398,7 +398,7 @@ void testRightJoin() { SelectStatementProvider selectStatement = select(orderLine.orderId, orderLine.quantity, itemMaster.itemId, itemMaster.description) .from(orderLine, "ol") - .rightJoin(itemMaster, "im").on(orderLine.itemId, equalTo(itemMaster.itemId)) + .rightJoin(itemMaster, "im").on(orderLine.itemId, isEqualTo(itemMaster.itemId)) .orderBy(itemMaster.itemId) .build() .render(RenderingStrategies.MYBATIS3); @@ -432,8 +432,8 @@ void testRightJoin2() { 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)) + .join(orderLine, "ol").on(orderMaster.orderId, isEqualTo(orderLine.orderId)) + .rightJoin(itemMaster, "im").on(orderLine.itemId, isEqualTo(itemMaster.itemId)) .orderBy(orderLine.orderId, itemMaster.itemId) .build() .render(RenderingStrategies.MYBATIS3); @@ -468,8 +468,8 @@ void testRightJoin3() { 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))) + .join(orderLine, "ol", on(orderMaster.orderId, isEqualTo(orderLine.orderId))) + .rightJoin(itemMaster, "im", on(orderLine.itemId, isEqualTo(itemMaster.itemId))) .orderBy(orderLine.orderId, itemMaster.itemId) .build() .render(RenderingStrategies.MYBATIS3); @@ -504,8 +504,8 @@ void testRightJoinNoAliases() { 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)) + .join(orderLine).on(orderMaster.orderId, isEqualTo(orderLine.orderId)) + .rightJoin(itemMaster).on(orderLine.itemId, isEqualTo(itemMaster.itemId)) .orderBy(orderLine.orderId, itemMaster.itemId) .build() .render(RenderingStrategies.MYBATIS3); @@ -540,7 +540,7 @@ void testLeftJoin() { SelectStatementProvider selectStatement = select(orderLine.orderId, orderLine.quantity, itemMaster.itemId, itemMaster.description) .from(itemMaster, "im") - .leftJoin(orderLine, "ol").on(orderLine.itemId, equalTo(itemMaster.itemId)) + .leftJoin(orderLine, "ol").on(orderLine.itemId, isEqualTo(itemMaster.itemId)) .orderBy(itemMaster.itemId) .build() .render(RenderingStrategies.MYBATIS3); @@ -574,8 +574,8 @@ void testLeftJoin2() { 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)) + .join(orderLine, "ol").on(orderMaster.orderId, isEqualTo(orderLine.orderId)) + .leftJoin(itemMaster, "im").on(orderLine.itemId, isEqualTo(itemMaster.itemId)) .orderBy(orderLine.orderId, itemMaster.itemId) .build() .render(RenderingStrategies.MYBATIS3); @@ -610,8 +610,8 @@ void testLeftJoin3() { 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))) + .join(orderLine, "ol", on(orderMaster.orderId, isEqualTo(orderLine.orderId))) + .leftJoin(itemMaster, "im", on(orderLine.itemId, isEqualTo(itemMaster.itemId))) .orderBy(orderLine.orderId, itemMaster.itemId) .build() .render(RenderingStrategies.MYBATIS3); @@ -646,8 +646,8 @@ void testLeftJoinNoAliases() { 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)) + .join(orderLine).on(orderMaster.orderId, isEqualTo(orderLine.orderId)) + .leftJoin(itemMaster).on(orderLine.itemId, isEqualTo(itemMaster.itemId)) .orderBy(orderLine.orderId, itemMaster.itemId) .build() .render(RenderingStrategies.MYBATIS3); @@ -682,7 +682,7 @@ void testFullJoin() { 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)) + .fullJoin(orderLine, "ol").on(itemMaster.itemId, isEqualTo(orderLine.itemId)) .orderBy(orderLine.orderId, sortColumn("im_itemid")) .build() .render(RenderingStrategies.MYBATIS3); @@ -723,8 +723,8 @@ void testFullJoin2() { 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)) + .join(orderLine, "ol").on(orderMaster.orderId, isEqualTo(orderLine.orderId)) + .fullJoin(itemMaster, "im").on(orderLine.itemId, isEqualTo(itemMaster.itemId)) .orderBy(orderLine.orderId, itemMaster.itemId) .build() .render(RenderingStrategies.MYBATIS3); @@ -765,8 +765,8 @@ void testFullJoin3() { 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))) + .join(orderLine, "ol", on(orderMaster.orderId, isEqualTo(orderLine.orderId))) + .fullJoin(itemMaster, "im", on(orderLine.itemId, isEqualTo(itemMaster.itemId))) .orderBy(orderLine.orderId, itemMaster.itemId) .build() .render(RenderingStrategies.MYBATIS3); @@ -807,8 +807,8 @@ void testFullJoin4() { 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))) + .join(orderLine, "ol", on(orderMaster.orderId, isEqualTo(orderLine.orderId))) + .fullJoin(itemMaster, "im", on(orderLine.itemId, isEqualTo(itemMaster.itemId))) .orderBy(orderLine.orderId, sortColumn("im", itemMaster.itemId)) .build() .render(RenderingStrategies.MYBATIS3); @@ -846,8 +846,8 @@ void testFullJoin5() { 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))) + .join(orderLine, "ol", on(orderMaster.orderId, isEqualTo(orderLine.orderId))) + .fullJoin(itemMaster, "im", on(orderLine.itemId, isEqualTo(itemMaster.itemId))) .orderBy(orderLine.orderId, sortColumn("im", itemMaster.itemId).descending()) .build() .render(RenderingStrategies.MYBATIS3); @@ -885,8 +885,8 @@ void testFullJoinNoAliases() { 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)) + .join(orderLine).on(orderMaster.orderId, isEqualTo(orderLine.orderId)) + .fullJoin(itemMaster).on(orderLine.itemId, isEqualTo(itemMaster.itemId)) .orderBy(orderLine.orderId, itemMaster.itemId) .build() .render(RenderingStrategies.MYBATIS3); @@ -931,7 +931,7 @@ void testSelf() { // 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)) + .join(user2, "u2").on(user.userId, isEqualTo(user2.parentId)) .where(user2.userId, isEqualTo(4)) .build() .render(RenderingStrategies.MYBATIS3); @@ -971,7 +971,7 @@ void testSelfWithNewAlias() { // get Bamm Bamm's parent - should be Barney SelectStatementProvider selectStatement = select(user.userId, user.userName, user.parentId) .from(user) - .join(user2).on(user.userId, equalTo(user2.parentId)) + .join(user2).on(user.userId, isEqualTo(user2.parentId)) .where(user2.userId, isEqualTo(4)) .build() .render(RenderingStrategies.MYBATIS3); @@ -1002,7 +1002,7 @@ void testSelfWithNewAliasAndOverride() { // 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)) + .join(user2, "u2").on(user.userId, isEqualTo(user2.parentId)) .where(user2.userId, isEqualTo(4)) .build() .render(RenderingStrategies.MYBATIS3); @@ -1029,7 +1029,7 @@ void testLimitAndOffsetAfterJoin() { SelectStatementProvider selectStatement = select(orderLine.orderId, orderLine.quantity, itemMaster.itemId, itemMaster.description) .from(itemMaster, "im") - .leftJoin(orderLine, "ol").on(orderLine.itemId, equalTo(itemMaster.itemId)) + .leftJoin(orderLine, "ol").on(orderLine.itemId, isEqualTo(itemMaster.itemId)) .limit(2) .offset(1) .build() @@ -1064,7 +1064,7 @@ void testLimitOnlyAfterJoin() { SelectStatementProvider selectStatement = select(orderLine.orderId, orderLine.quantity, itemMaster.itemId, itemMaster.description) .from(itemMaster, "im") - .leftJoin(orderLine, "ol").on(orderLine.itemId, equalTo(itemMaster.itemId)) + .leftJoin(orderLine, "ol").on(orderLine.itemId, isEqualTo(itemMaster.itemId)) .limit(2) .build() .render(RenderingStrategies.MYBATIS3); @@ -1098,7 +1098,7 @@ void testOffsetOnlyAfterJoin() { SelectStatementProvider selectStatement = select(orderLine.orderId, orderLine.quantity, itemMaster.itemId, itemMaster.description) .from(itemMaster, "im") - .leftJoin(orderLine, "ol").on(orderLine.itemId, equalTo(itemMaster.itemId)) + .leftJoin(orderLine, "ol").on(orderLine.itemId, isEqualTo(itemMaster.itemId)) .offset(2) .build() .render(RenderingStrategies.MYBATIS3); @@ -1132,7 +1132,7 @@ void testOffsetAndFetchFirstAfterJoin() { SelectStatementProvider selectStatement = select(orderLine.orderId, orderLine.quantity, itemMaster.itemId, itemMaster.description) .from(itemMaster, "im") - .leftJoin(orderLine, "ol").on(orderLine.itemId, equalTo(itemMaster.itemId)) + .leftJoin(orderLine, "ol").on(orderLine.itemId, isEqualTo(itemMaster.itemId)) .offset(1) .fetchFirst(2).rowsOnly() .build() @@ -1167,7 +1167,7 @@ void testFetchFirstOnlyAfterJoin() { SelectStatementProvider selectStatement = select(orderLine.orderId, orderLine.quantity, itemMaster.itemId, itemMaster.description) .from(itemMaster, "im") - .leftJoin(orderLine, "ol").on(orderLine.itemId, equalTo(itemMaster.itemId)) + .leftJoin(orderLine, "ol").on(orderLine.itemId, isEqualTo(itemMaster.itemId)) .fetchFirst(2).rowsOnly() .build() .render(RenderingStrategies.MYBATIS3); @@ -1201,8 +1201,8 @@ void testJoinWithParameterValue() { SelectStatementProvider selectStatement = select(orderLine.orderId, orderLine.quantity, itemMaster.itemId, itemMaster.description) .from(itemMaster, "im") - .join(orderLine, "ol").on(orderLine.itemId, equalTo(itemMaster.itemId)) - .and(orderLine.orderId, equalTo(1)) + .join(orderLine, "ol").on(orderLine.itemId, isEqualTo(itemMaster.itemId)) + .and(orderLine.orderId, isEqualTo(1)) .build() .render(RenderingStrategies.MYBATIS3); @@ -1235,8 +1235,8 @@ void testJoinWithConstant() { SelectStatementProvider selectStatement = select(orderLine.orderId, orderLine.quantity, itemMaster.itemId, itemMaster.description) .from(itemMaster, "im") - .join(orderLine, "ol").on(orderLine.itemId, equalTo(itemMaster.itemId)) - .and(orderLine.orderId, equalTo(constant("1"))) + .join(orderLine, "ol").on(orderLine.itemId, isEqualTo(itemMaster.itemId)) + .and(orderLine.orderId, isEqualTo(constant("1"))) .build() .render(RenderingStrategies.MYBATIS3); diff --git a/src/test/java/examples/joins/JoinSubQueryTest.java b/src/test/java/examples/joins/JoinSubQueryTest.java index 588844828..1bda4983e 100644 --- a/src/test/java/examples/joins/JoinSubQueryTest.java +++ b/src/test/java/examples/joins/JoinSubQueryTest.java @@ -20,7 +20,6 @@ import static examples.joins.OrderLineDynamicSQLSupport.orderLine; import static examples.joins.OrderMasterDynamicSQLSupport.orderMaster; import static org.assertj.core.api.Assertions.assertThat; -import static org.mybatis.dynamic.sql.SqlBuilder.equalTo; import static org.mybatis.dynamic.sql.SqlBuilder.isEqualTo; import static org.mybatis.dynamic.sql.SqlBuilder.select; import static org.mybatis.dynamic.sql.SqlBuilder.sortColumn; @@ -82,7 +81,7 @@ void testSingleTableJoin1() { .from(orderMaster, "om") .join(select(orderDetail.orderId, orderDetail.lineNumber, orderDetail.description, orderDetail.quantity) .from(orderDetail), - "od").on(orderMaster.orderId, equalTo(orderDetail.orderId.qualifiedWith("od"))) + "od").on(orderMaster.orderId, isEqualTo(orderDetail.orderId.qualifiedWith("od"))) .build() .render(RenderingStrategies.MYBATIS3); @@ -121,11 +120,11 @@ void testMultipleTableJoinWithWhereClause() { .join(select(orderLine.orderId, orderLine.itemId, orderLine.quantity, orderLine.lineNumber) .from(orderLine), "ol") - .on(orderMaster.orderId, equalTo(orderLine.orderId.qualifiedWith("ol"))) + .on(orderMaster.orderId, isEqualTo(orderLine.orderId.qualifiedWith("ol"))) .join(select(itemMaster.itemId, itemMaster.description) .from(itemMaster), "im") - .on(orderLine.itemId.qualifiedWith("ol"), equalTo(itemMaster.itemId.qualifiedWith("im"))) + .on(orderLine.itemId.qualifiedWith("ol"), isEqualTo(itemMaster.itemId.qualifiedWith("im"))) .where(orderMaster.orderId, isEqualTo(2)) .build() .render(RenderingStrategies.MYBATIS3); @@ -158,9 +157,9 @@ void testMultipleTableJoinWithSelectStar() { 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"))) + .on(orderMaster.orderId, isEqualTo(orderLine.orderId.qualifiedWith("ol"))) .join(select(itemMaster.allColumns()).from(itemMaster), "im") - .on(orderLine.itemId.qualifiedWith("ol"), equalTo(itemMaster.itemId.qualifiedWith("im"))) + .on(orderLine.itemId.qualifiedWith("ol"), isEqualTo(itemMaster.itemId.qualifiedWith("im"))) .where(orderMaster.orderId, isEqualTo(2)) .orderBy(orderMaster.orderId) .build() @@ -197,7 +196,7 @@ void testRightJoin() { itemMaster.itemId.qualifiedWith("im"), itemMaster.description) .from(orderLine, "ol") .rightJoin(select(itemMaster.allColumns()).from(itemMaster), "im") - .on(orderLine.itemId, equalTo(itemMaster.itemId.qualifiedWith("im"))) + .on(orderLine.itemId, isEqualTo(itemMaster.itemId.qualifiedWith("im"))) .orderBy(itemMaster.itemId) .build() .render(RenderingStrategies.MYBATIS3); @@ -232,9 +231,9 @@ void testRightJoin2() { 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)) + .join(orderLine, "ol").on(orderMaster.orderId, isEqualTo(orderLine.orderId)) .rightJoin(select(itemMaster.allColumns()).from(itemMaster), "im") - .on(orderLine.itemId, equalTo(itemMaster.itemId.qualifiedWith("im"))) + .on(orderLine.itemId, isEqualTo(itemMaster.itemId.qualifiedWith("im"))) .orderBy(orderLine.orderId, itemMaster.itemId) .build() .render(RenderingStrategies.MYBATIS3); @@ -271,7 +270,7 @@ void testLeftJoin() { itemMaster.itemId.qualifiedWith("im"), itemMaster.description) .from(itemMaster, "im") .leftJoin(select(orderLine.allColumns()).from(orderLine), "ol") - .on(orderLine.itemId.qualifiedWith("ol"), equalTo(itemMaster.itemId)) + .on(orderLine.itemId.qualifiedWith("ol"), isEqualTo(itemMaster.itemId)) .orderBy(itemMaster.itemId) .build() .render(RenderingStrategies.MYBATIS3); @@ -307,9 +306,9 @@ void testLeftJoin2() { 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)) + .join(orderLine, "ol").on(orderMaster.orderId, isEqualTo(orderLine.orderId)) .leftJoin(select(itemMaster.allColumns()).from(itemMaster), "im") - .on(orderLine.itemId, equalTo(itemMaster.itemId.qualifiedWith("im"))) + .on(orderLine.itemId, isEqualTo(itemMaster.itemId.qualifiedWith("im"))) .orderBy(orderLine.orderId, itemMaster.itemId) .build() .render(RenderingStrategies.MYBATIS3); @@ -346,7 +345,7 @@ void testFullJoin() { 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"))) + .on(itemMaster.itemId, isEqualTo(orderLine.itemId.qualifiedWith("ol"))) .orderBy(orderLine.orderId, sortColumn("im_itemid")) .build() .render(RenderingStrategies.MYBATIS3); @@ -389,9 +388,9 @@ void testFullJoin2() { 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)) + .join(orderLine, "ol").on(orderMaster.orderId, isEqualTo(orderLine.orderId)) .fullJoin(select(itemMaster.allColumns()).from(itemMaster), "im") - .on(orderLine.itemId, equalTo(itemMaster.itemId.qualifiedWith("im"))) + .on(orderLine.itemId, isEqualTo(itemMaster.itemId.qualifiedWith("im"))) .orderBy(orderLine.orderId, itemMaster.itemId) .build() .render(RenderingStrategies.MYBATIS3); diff --git a/src/test/java/examples/joins/NewSyntaxJoinMapperTest.java b/src/test/java/examples/joins/NewSyntaxJoinMapperTest.java deleted file mode 100644 index ae8f5d0f0..000000000 --- a/src/test/java/examples/joins/NewSyntaxJoinMapperTest.java +++ /dev/null @@ -1,1270 +0,0 @@ -/* - * Copyright 2016-2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package 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.exception.DuplicateTableAliasException; -import org.mybatis.dynamic.sql.render.RenderingStrategies; -import org.mybatis.dynamic.sql.select.QueryExpressionDSL; -import org.mybatis.dynamic.sql.select.SelectModel; -import org.mybatis.dynamic.sql.select.render.SelectStatementProvider; -import org.mybatis.dynamic.sql.util.Messages; -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.orderDate; -import static examples.joins.OrderMasterDynamicSQLSupport.orderMaster; -import static examples.joins.UserDynamicSQLSupport.user; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -import static org.mybatis.dynamic.sql.SqlBuilder.and; -import static org.mybatis.dynamic.sql.SqlBuilder.constant; -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; -import static org.mybatis.dynamic.sql.SqlBuilder.where; - -class NewSyntaxJoinMapperTest { - - 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"); - assert is != null; - 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, orderDate, orderDetail.lineNumber, orderDetail.description, orderDetail.quantity) - .from(orderMaster, "om") - .join(orderDetail, "od").on(orderMaster.orderId, isEqualTo(orderDetail.orderId)) - .build() - .render(RenderingStrategies.MYBATIS3); - - 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(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 testSingleTableJoin2() { - try (SqlSession session = sqlSessionFactory.openSession()) { - JoinMapper mapper = session.getMapper(JoinMapper.class); - - SelectStatementProvider selectStatement = select(orderMaster.orderId, orderDate, orderDetail.lineNumber, orderDetail.description, orderDetail.quantity) - .from(orderMaster, "om") - .join(orderDetail, "od", on(orderMaster.orderId, isEqualTo(orderDetail.orderId))) - .build() - .render(RenderingStrategies.MYBATIS3); - - 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(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 testCompoundJoin1() { - // this is a nonsensical join, but it does test the "and" capability - SelectStatementProvider selectStatement = select(orderMaster.orderId, orderDate, orderDetail.lineNumber, orderDetail.description, orderDetail.quantity) - .from(orderMaster, "om") - .join(orderDetail, "od").on(orderMaster.orderId, isEqualTo(orderDetail.orderId), and(orderMaster.orderId, isEqualTo(orderDetail.orderId))) - .build() - .render(RenderingStrategies.MYBATIS3); - - 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(expectedStatement); - } - - @Test - void testCompoundJoin2() { - // this is a nonsensical join, but it does test the "and" capability - SelectStatementProvider selectStatement = select(orderMaster.orderId, orderDate, orderDetail.lineNumber, orderDetail.description, orderDetail.quantity) - .from(orderMaster, "om") - .join(orderDetail, "od").on(orderMaster.orderId, isEqualTo(orderDetail.orderId)) - .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) - .and(orderMaster.orderId, isEqualTo(orderDetail.orderId)) - .build() - .render(RenderingStrategies.MYBATIS3); - - 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(expectedStatement); - } - - @Test - void testCompoundJoin3() { - // this is a nonsensical join, but it does test the "and" capability - SelectStatementProvider selectStatement = select(orderMaster.orderId, orderDate, orderDetail.lineNumber, orderDetail.description, orderDetail.quantity) - .from(orderMaster, "om") - .join(orderDetail, "od", on(orderMaster.orderId, isEqualTo(orderDetail.orderId)), and(orderMaster.orderId, isEqualTo(orderDetail.orderId))) - .build() - .render(RenderingStrategies.MYBATIS3); - - 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(expectedStatement); - } - - @Test - void testCompoundJoin4() { - // this is a nonsensical join, but it does test the "and" capability - SelectStatementProvider selectStatement = select(orderMaster.orderId, orderDate, orderDetail.lineNumber, orderDetail.description, orderDetail.quantity) - .from(orderMaster, "om") - .leftJoin(orderDetail, "od", on(orderMaster.orderId, isEqualTo(orderDetail.orderId)), and(orderMaster.orderId, isEqualTo(orderDetail.orderId))) - .build() - .render(RenderingStrategies.MYBATIS3); - - 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(expectedStatement); - } - - @Test - void testCompoundJoin5() { - // this is a nonsensical join, but it does test the "and" capability - SelectStatementProvider selectStatement = select(orderMaster.orderId, orderDate, orderDetail.lineNumber, orderDetail.description, orderDetail.quantity) - .from(orderMaster, "om") - .rightJoin(orderDetail, "od", on(orderMaster.orderId, isEqualTo(orderDetail.orderId)), and(orderMaster.orderId, isEqualTo(orderDetail.orderId))) - .build() - .render(RenderingStrategies.MYBATIS3); - - 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(expectedStatement); - } - - @Test - void testCompoundJoin6() { - // this is a nonsensical join, but it does test the "and" capability - SelectStatementProvider selectStatement = select(orderMaster.orderId, orderDate, orderDetail.lineNumber, orderDetail.description, orderDetail.quantity) - .from(orderMaster, "om") - .fullJoin(orderDetail, "od", on(orderMaster.orderId, isEqualTo(orderDetail.orderId)), and(orderMaster.orderId, isEqualTo(orderDetail.orderId))) - .build() - .render(RenderingStrategies.MYBATIS3); - - 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(expectedStatement); - } - - @Test - void testMultipleTableJoinWithWhereClause() { - try (SqlSession session = sqlSessionFactory.openSession()) { - JoinMapper mapper = session.getMapper(JoinMapper.class); - - SelectStatementProvider selectStatement = select(orderMaster.orderId, orderDate, orderLine.lineNumber, itemMaster.description, orderLine.quantity) - .from(orderMaster, "om") - .join(orderLine, "ol").on(orderMaster.orderId, isEqualTo(orderLine.orderId)) - .join(itemMaster, "im").on(orderLine.itemId, isEqualTo(itemMaster.itemId)) - .where(orderMaster.orderId, isEqualTo(2)) - .build() - .render(RenderingStrategies.MYBATIS3); - - 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(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 testMultipleTableJoinWithApplyWhere() { - try (SqlSession session = sqlSessionFactory.openSession()) { - JoinMapper mapper = session.getMapper(JoinMapper.class); - - SelectStatementProvider selectStatement = select(orderMaster.orderId, orderDate, orderLine.lineNumber, itemMaster.description, orderLine.quantity) - .from(orderMaster, "om") - .join(orderLine, "ol").on(orderMaster.orderId, isEqualTo(orderLine.orderId)) - .join(itemMaster, "im").on(orderLine.itemId, isEqualTo(itemMaster.itemId)) - .applyWhere(where(orderMaster.orderId, isEqualTo(2)).toWhereApplier()) - .build() - .render(RenderingStrategies.MYBATIS3); - - 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(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 testMultipleTableJoinWithComplexWhereClause() { - try (SqlSession session = sqlSessionFactory.openSession()) { - JoinMapper mapper = session.getMapper(JoinMapper.class); - - SelectStatementProvider selectStatement = select(orderMaster.orderId, orderDate, orderLine.lineNumber, itemMaster.description, orderLine.quantity) - .from(orderMaster, "om") - .join(orderLine, "ol").on(orderMaster.orderId, isEqualTo(orderLine.orderId)) - .join(itemMaster, "im").on(orderLine.itemId, isEqualTo(itemMaster.itemId)) - .where(orderMaster.orderId, isEqualTo(2), and(orderLine.lineNumber, isEqualTo(2))) - .build() - .render(RenderingStrategies.MYBATIS3); - - 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(expectedStatement); - - 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, orderDate, orderLine.lineNumber, itemMaster.description, orderLine.quantity) - .from(orderMaster, "om") - .join(orderLine, "ol").on(orderMaster.orderId, isEqualTo(orderLine.orderId)) - .join(itemMaster, "im").on(orderLine.itemId, isEqualTo(itemMaster.itemId)) - .orderBy(orderMaster.orderId) - .build() - .render(RenderingStrategies.MYBATIS3); - - 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(expectedStatement); - - 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 testMultipleTableJoinNoAliasWithOrderBy() { - try (SqlSession session = sqlSessionFactory.openSession()) { - JoinMapper mapper = session.getMapper(JoinMapper.class); - - SelectStatementProvider selectStatement = select(orderMaster.orderId, orderDate, orderLine.lineNumber, itemMaster.description, orderLine.quantity) - .from(orderMaster) - .join(orderLine).on(orderMaster.orderId, isEqualTo(orderLine.orderId)) - .join(itemMaster).on(orderLine.itemId, isEqualTo(itemMaster.itemId)) - .where(orderMaster.orderId, isEqualTo(2)) - .orderBy(orderMaster.orderId) - .build() - .render(RenderingStrategies.MYBATIS3); - - 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(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()) { - 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, isEqualTo(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, isEqualTo(orderLine.orderId)) - .rightJoin(itemMaster, "im").on(orderLine.itemId, isEqualTo(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 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, isEqualTo(orderLine.orderId))) - .rightJoin(itemMaster, "im", on(orderLine.itemId, isEqualTo(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 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, isEqualTo(orderLine.orderId)) - .rightJoin(itemMaster).on(orderLine.itemId, isEqualTo(itemMaster.itemId)) - .orderBy(orderLine.orderId, itemMaster.itemId) - .build() - .render(RenderingStrategies.MYBATIS3); - - 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(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 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, isEqualTo(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, isEqualTo(orderLine.orderId)) - .leftJoin(itemMaster, "im").on(orderLine.itemId, isEqualTo(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 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, isEqualTo(orderLine.orderId))) - .leftJoin(itemMaster, "im", on(orderLine.itemId, isEqualTo(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 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, isEqualTo(orderLine.orderId)) - .leftJoin(itemMaster).on(orderLine.itemId, isEqualTo(itemMaster.itemId)) - .orderBy(orderLine.orderId, itemMaster.itemId) - .build() - .render(RenderingStrategies.MYBATIS3); - - 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(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 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, isEqualTo(orderLine.itemId)) - .orderBy(orderLine.orderId, 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 order_id, im_itemid"; - 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("IM_ITEMID", 55); - - 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("IM_ITEMID", 33); - - row = rows.get(3); - 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"); - } - } - - @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, isEqualTo(orderLine.orderId)) - .fullJoin(itemMaster, "im").on(orderLine.itemId, isEqualTo(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 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, isEqualTo(orderLine.orderId))) - .fullJoin(itemMaster, "im", on(orderLine.itemId, isEqualTo(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 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, isEqualTo(orderLine.orderId))) - .fullJoin(itemMaster, "im", on(orderLine.itemId, isEqualTo(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, isEqualTo(orderLine.orderId))) - .fullJoin(itemMaster, "im", on(orderLine.itemId, isEqualTo(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, isEqualTo(orderLine.orderId)) - .fullJoin(itemMaster).on(orderLine.itemId, isEqualTo(itemMaster.itemId)) - .orderBy(orderLine.orderId, itemMaster.itemId) - .build() - .render(RenderingStrategies.MYBATIS3); - - 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(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 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, isEqualTo(user2.parentId)) - .where(user2.userId, isEqualTo(4)) - .build() - .render(RenderingStrategies.MYBATIS3); - - 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(expectedStatement); - - 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 testSelfWithDuplicateAlias() { - QueryExpressionDSL dsl = select(user.userId, user.userName, user.parentId) - .from(user, "u1"); - - assertThatExceptionOfType(DuplicateTableAliasException.class).isThrownBy(() -> dsl.join(user, "u2")) - .withMessage(Messages.getString("ERROR.1", user.tableName(), "u2", "u1")); - } - - @Test - void testSelfWithNewAlias() { - try (SqlSession session = sqlSessionFactory.openSession()) { - JoinMapper mapper = session.getMapper(JoinMapper.class); - - // create second table instance for self-join - UserDynamicSQLSupport.User user2 = user.withAlias("u2"); - - // get Bamm Bamm's parent - should be Barney - SelectStatementProvider selectStatement = select(user.userId, user.userName, user.parentId) - .from(user) - .join(user2).on(user.userId, isEqualTo(user2.parentId)) - .where(user2.userId, isEqualTo(4)) - .build() - .render(RenderingStrategies.MYBATIS3); - - String expectedStatement = "select User.user_id, User.user_name, User.parent_id" - + " from User join User u2 on User.user_id = u2.parent_id" - + " where u2.user_id = #{parameters.p1,jdbcType=INTEGER}"; - assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); - - 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 testSelfWithNewAliasAndOverride() { - try (SqlSession session = sqlSessionFactory.openSession()) { - JoinMapper mapper = session.getMapper(JoinMapper.class); - - // create second table instance for self-join - UserDynamicSQLSupport.User user2 = user.withAlias("other_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, isEqualTo(user2.parentId)) - .where(user2.userId, isEqualTo(4)) - .build() - .render(RenderingStrategies.MYBATIS3); - - 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(expectedStatement); - - 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, isEqualTo(itemMaster.itemId)) - .limit(2) - .offset(1) - .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" - + " limit #{parameters.p1} offset #{parameters.p2}"; - assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); - - 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, isEqualTo(itemMaster.itemId)) - .limit(2) - .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" - + " limit #{parameters.p1}"; - assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); - - 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, isEqualTo(itemMaster.itemId)) - .offset(2) - .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" - + " offset #{parameters.p1} rows"; - assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); - - 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, isEqualTo(itemMaster.itemId)) - .offset(1) - .fetchFirst(2).rowsOnly() - .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" - + " offset #{parameters.p1} rows fetch first #{parameters.p2} rows only"; - assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); - - 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, isEqualTo(itemMaster.itemId)) - .fetchFirst(2).rowsOnly() - .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" - + " fetch first #{parameters.p1} rows only"; - assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); - - 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 testJoinWithParameterValue() { - try (SqlSession session = sqlSessionFactory.openSession()) { - CommonSelectMapper mapper = session.getMapper(CommonSelectMapper.class); - - SelectStatementProvider selectStatement = select(orderLine.orderId, orderLine.quantity, itemMaster.itemId, itemMaster.description) - .from(itemMaster, "im") - .join(orderLine, "ol").on(orderLine.itemId, isEqualTo(itemMaster.itemId)) - .and(orderLine.orderId, isEqualTo(1)) - .build() - .render(RenderingStrategies.MYBATIS3); - - String expectedStatement = "select ol.order_id, ol.quantity, im.item_id, im.description" - + " from ItemMaster im join OrderLine ol on ol.item_id = im.item_id" - + " and ol.order_id = #{parameters.p1,jdbcType=INTEGER}"; - assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); - - List> 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", 1); - assertThat(row).containsEntry("QUANTITY", 1); - assertThat(row).containsEntry("DESCRIPTION", "First Base Glove"); - assertThat(row).containsEntry("ITEM_ID", 33); - } - } - - @Test - void testJoinWithConstant() { - try (SqlSession session = sqlSessionFactory.openSession()) { - CommonSelectMapper mapper = session.getMapper(CommonSelectMapper.class); - - SelectStatementProvider selectStatement = select(orderLine.orderId, orderLine.quantity, itemMaster.itemId, itemMaster.description) - .from(itemMaster, "im") - .join(orderLine, "ol").on(orderLine.itemId, isEqualTo(itemMaster.itemId)) - .and(orderLine.orderId, isEqualTo(constant("1"))) - .build() - .render(RenderingStrategies.MYBATIS3); - - String expectedStatement = "select ol.order_id, ol.quantity, im.item_id, im.description" - + " from ItemMaster im join OrderLine ol on ol.item_id = im.item_id" - + " and ol.order_id = 1"; - assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); - - 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", 1); - assertThat(row).containsEntry("QUANTITY", 1); - assertThat(row).containsEntry("DESCRIPTION", "First Base Glove"); - assertThat(row).containsEntry("ITEM_ID", 33); - } - } -} diff --git a/src/test/java/examples/simple/PersonWithAddressMapper.java b/src/test/java/examples/simple/PersonWithAddressMapper.java index a36946bad..5a51cf465 100644 --- a/src/test/java/examples/simple/PersonWithAddressMapper.java +++ b/src/test/java/examples/simple/PersonWithAddressMapper.java @@ -80,13 +80,13 @@ public interface PersonWithAddressMapper extends CommonCountMapper { default Optional selectOne(SelectDSLCompleter completer) { QueryExpressionDSL start = SqlBuilder.select(selectList).from(person) - .join(address, on(person.addressId, equalTo(address.id))); + .join(address, on(person.addressId, isEqualTo(address.id))); return MyBatis3Utils.selectOne(this::selectOne, start, completer); } default List select(SelectDSLCompleter completer) { QueryExpressionDSL start = SqlBuilder.select(selectList).from(person) - .join(address, on(person.addressId, equalTo(address.id))); + .join(address, on(person.addressId, isEqualTo(address.id))); return MyBatis3Utils.selectList(this::selectMany, start, completer); } @@ -98,7 +98,7 @@ default Optional selectByPrimaryKey(Integer id_) { default long count(CountDSLCompleter completer) { CountDSL start = countFrom(person) - .join(address, on(person.addressId, equalTo(address.id))); + .join(address, on(person.addressId, isEqualTo(address.id))); return MyBatis3Utils.countFrom(this::count, start, completer); } } diff --git a/src/test/java/examples/spring/PersonTemplateTest.java b/src/test/java/examples/spring/PersonTemplateTest.java index 2cd2b6b42..2f0e5b2dc 100644 --- a/src/test/java/examples/spring/PersonTemplateTest.java +++ b/src/test/java/examples/spring/PersonTemplateTest.java @@ -633,7 +633,7 @@ void testJoinAllRows() { Buildable selectStatement = select(id, firstName, lastName, birthDate, employed, occupation, address.id, address.streetAddress, address.city, address.state) .from(person) - .join(address, on(person.addressId, equalTo(address.id))) + .join(address, on(person.addressId, isEqualTo(address.id))) .orderBy(id); List records = template.selectList(selectStatement, personWithAddressRowMapper); @@ -656,7 +656,7 @@ void testJoinOneRow() { Buildable selectStatement = select(id, firstName, lastName, birthDate, employed, occupation, address.id, address.streetAddress, address.city, address.state) .from(person) - .join(address, on(person.addressId, equalTo(address.id))) + .join(address, on(person.addressId, isEqualTo(address.id))) .where(id, isEqualTo(1)); List records = template.selectList(selectStatement, personWithAddressRowMapper); @@ -679,7 +679,7 @@ void testJoinPrimaryKey() { Buildable selectStatement = select(id, firstName, lastName, birthDate, employed, occupation, address.id, address.streetAddress, address.city, address.state) .from(person) - .join(address, on(person.addressId, equalTo(address.id))) + .join(address, on(person.addressId, isEqualTo(address.id))) .where(id, isEqualTo(1)); Optional row = template.selectOne(selectStatement, personWithAddressRowMapper); @@ -703,7 +703,7 @@ void testJoinPrimaryKeyInvalidRecord() { Buildable selectStatement = select(id, firstName, lastName, birthDate, employed, occupation, address.id, address.streetAddress, address.city, address.state) .from(person) - .join(address, on(person.addressId, equalTo(address.id))) + .join(address, on(person.addressId, isEqualTo(address.id))) .where(id, isEqualTo(55)); Optional row = template.selectOne(selectStatement, personWithAddressRowMapper); @@ -713,7 +713,7 @@ void testJoinPrimaryKeyInvalidRecord() { @Test void testJoinCount() { Buildable countStatement = countFrom(person) - .join(address, on(person.addressId, equalTo(address.id))) + .join(address, on(person.addressId, isEqualTo(address.id))) .where(id, isEqualTo(55)); long count = template.count(countStatement); @@ -723,7 +723,7 @@ void testJoinCount() { @Test void testJoinCountWithSubCriteria() { Buildable countStatement = countFrom(person) - .join(address, on(person.addressId, equalTo(address.id))) + .join(address, on(person.addressId, isEqualTo(address.id))) .where(person.id, isEqualTo(55), or(person.id, isEqualTo(1))); long count = template.count(countStatement); diff --git a/src/test/java/issues/gh100/FromJoinWhereTest.java b/src/test/java/issues/gh100/FromJoinWhereTest.java index 47867128d..6695d56a6 100644 --- a/src/test/java/issues/gh100/FromJoinWhereTest.java +++ b/src/test/java/issues/gh100/FromJoinWhereTest.java @@ -32,7 +32,7 @@ void testNormalUsage() { SelectStatementProvider selectStatement = select(StudentDynamicSqlSupport.id, StudentDynamicSqlSupport.name, StudentDynamicSqlSupport.idcard) .from(StudentDynamicSqlSupport.student) .join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)) + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)) .where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")) .union() .select(StudentDynamicSqlSupport.id, StudentDynamicSqlSupport.name, StudentDynamicSqlSupport.idcard) @@ -76,7 +76,7 @@ void testFromJoinB1() { .from(StudentDynamicSqlSupport.student); builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); String expected = "select student.id, student.name, student.idcard" + " from student" @@ -93,7 +93,7 @@ void testFromJoinB2() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); String expected = "select student.id, student.name, student.idcard" + " from student" @@ -110,7 +110,7 @@ void testfromJoinWhereB1() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -130,7 +130,7 @@ void testfromJoinWhereB2() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -150,7 +150,7 @@ void testfromJoinWhereB3() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -170,7 +170,7 @@ void testFromJoinWhereUnionB1() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -197,7 +197,7 @@ void testFromJoinWhereUnionB2() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -224,7 +224,7 @@ void testFromJoinWhereUnionB3() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -251,7 +251,7 @@ void testFromJoinWhereUnionB4() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -278,7 +278,7 @@ void testFromJoinWhereUnionUnionB1() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -316,7 +316,7 @@ void testFromJoinWhereUnionUnionB2() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -354,7 +354,7 @@ void testFromJoinWhereUnionUnionB3() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -392,7 +392,7 @@ void testFromJoinWhereUnionUnionB4() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -430,7 +430,7 @@ void testFromJoinWhereUnionUnionB5() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -468,7 +468,7 @@ void testFromJoinWhereUnionOrderByB1() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -498,7 +498,7 @@ void testFromJoinWhereUnionOrderByB2() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -528,7 +528,7 @@ void testFromJoinWhereUnionOrderByB3() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -558,7 +558,7 @@ void testFromJoinWhereUnionOrderByB4() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -588,7 +588,7 @@ void testFromJoinWhereUnionOrderByB5() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -618,7 +618,7 @@ void testFromJoinWhereUnionOrderByLimitB1() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -651,7 +651,7 @@ void testFromJoinWhereUnionOrderByLimitB2() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -684,7 +684,7 @@ void testFromJoinWhereUnionOrderByLimitB3() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -717,7 +717,7 @@ void testFromJoinWhereUnionOrderByLimitB4() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -750,7 +750,7 @@ void testFromJoinWhereUnionOrderByLimitB5() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -783,7 +783,7 @@ void testFromJoinWhereUnionOrderByLimitB6() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -816,7 +816,7 @@ void testFromJoinWhereUnionOrderByLimitOffsetB1() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -852,7 +852,7 @@ void testFromJoinWhereUnionOrderByLimitOffsetB2() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -888,7 +888,7 @@ void testFromJoinWhereUnionOrderByLimitOffsetB3() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -924,7 +924,7 @@ void testFromJoinWhereUnionOrderByLimitOffsetB4() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -960,7 +960,7 @@ void testFromJoinWhereUnionOrderByLimitOffsetB5() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -996,7 +996,7 @@ void testFromJoinWhereUnionOrderByLimitOffsetB6() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -1032,7 +1032,7 @@ void testFromJoinWhereUnionOrderByLimitOffsetB7() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -1068,7 +1068,7 @@ void testFromJoinWhereUnionOrderByOffsetB1() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -1102,7 +1102,7 @@ void testFromJoinWhereUnionOrderByOffsetB2() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -1136,7 +1136,7 @@ void testFromJoinWhereUnionOrderByOffsetB3() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -1170,7 +1170,7 @@ void testFromJoinWhereUnionOrderByOffsetB4() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -1204,7 +1204,7 @@ void testFromJoinWhereUnionOrderByOffsetB5() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -1238,7 +1238,7 @@ void testFromJoinWhereUnionOrderByOffsetB6() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -1272,7 +1272,7 @@ void testFromJoinWhereUnionOrderByOffsetFetchFirstB1() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -1308,7 +1308,7 @@ void testFromJoinWhereUnionOrderByOffsetFetchFirstB2() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -1344,7 +1344,7 @@ void testFromJoinWhereUnionOrderByOffsetFetchFirstB3() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -1380,7 +1380,7 @@ void testFromJoinWhereUnionOrderByOffsetFetchFirstB4() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -1416,7 +1416,7 @@ void testFromJoinWhereUnionOrderByOffsetFetchFirstB5() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -1452,7 +1452,7 @@ void testFromJoinWhereUnionOrderByOffsetFetchFirstB6() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -1488,7 +1488,7 @@ void testFromJoinWhereUnionOrderByOffsetFetchFirstB7() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -1524,7 +1524,7 @@ void testFromJoinWhereUnionOrderByFetchFirstB1() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -1557,7 +1557,7 @@ void testFromJoinWhereUnionOrderByFetchFirstB2() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -1590,7 +1590,7 @@ void testFromJoinWhereUnionOrderByFetchFirstB3() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -1623,7 +1623,7 @@ void testFromJoinWhereUnionOrderByFetchFirstB4() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -1656,7 +1656,7 @@ void testFromJoinWhereUnionOrderByFetchFirstB5() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -1689,7 +1689,7 @@ void testFromJoinWhereUnionOrderByFetchFirstB6() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -1722,7 +1722,7 @@ void testFromJoinWhereUnionLimitB1() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -1752,7 +1752,7 @@ void testFromJoinWhereUnionLimitB2() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -1782,7 +1782,7 @@ void testFromJoinWhereUnionLimitB3() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -1812,7 +1812,7 @@ void testFromJoinWhereUnionLimitB4() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -1842,7 +1842,7 @@ void testFromJoinWhereUnionLimitB5() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -1872,7 +1872,7 @@ void testFromJoinWhereUnionLimitOffsetB1() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -1905,7 +1905,7 @@ void testFromJoinWhereUnionLimitOffsetB2() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -1938,7 +1938,7 @@ void testFromJoinWhereUnionLimitOffsetB3() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -1971,7 +1971,7 @@ void testFromJoinWhereUnionLimitOffsetB4() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -2004,7 +2004,7 @@ void testFromJoinWhereUnionLimitOffsetB5() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -2037,7 +2037,7 @@ void testFromJoinWhereUnionLimitOffsetB6() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -2070,7 +2070,7 @@ void testFromJoinWhereUnionOffsetB1() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -2100,7 +2100,7 @@ void testFromJoinWhereUnionOffsetB2() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -2130,7 +2130,7 @@ void testFromJoinWhereUnionOffsetB3() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -2160,7 +2160,7 @@ void testFromJoinWhereUnionOffsetB4() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -2190,7 +2190,7 @@ void testFromJoinWhereUnionOffsetB5() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -2220,7 +2220,7 @@ void testFromJoinWhereUnionOffsetFetchFirstB1() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -2253,7 +2253,7 @@ void testFromJoinWhereUnionOffsetFetchFirstB2() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -2286,7 +2286,7 @@ void testFromJoinWhereUnionOffsetFetchFirstB3() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -2319,7 +2319,7 @@ void testFromJoinWhereUnionOffsetFetchFirstB4() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -2352,7 +2352,7 @@ void testFromJoinWhereUnionOffsetFetchFirstB5() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -2385,7 +2385,7 @@ void testFromJoinWhereUnionOffsetFetchFirstB6() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -2418,7 +2418,7 @@ void testFromJoinWhereUnionFetchFirstB1() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -2448,7 +2448,7 @@ void testFromJoinWhereUnionFetchFirstB2() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -2478,7 +2478,7 @@ void testFromJoinWhereUnionFetchFirstB3() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -2508,7 +2508,7 @@ void testFromJoinWhereUnionFetchFirstB4() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -2538,7 +2538,7 @@ void testFromJoinWhereUnionFetchFirstB5() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -2568,7 +2568,7 @@ void testFromJoinWhereOrderByB1() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -2591,7 +2591,7 @@ void testFromJoinWhereOrderByB2() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -2614,7 +2614,7 @@ void testFromJoinWhereOrderByB3() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -2637,7 +2637,7 @@ void testFromJoinWhereOrderByB4() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -2660,7 +2660,7 @@ void testFromJoinWhereOrderByLimitB1() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -2686,7 +2686,7 @@ void testFromJoinWhereOrderByLimitB2() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -2712,7 +2712,7 @@ void testFromJoinWhereOrderByLimitB3() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -2738,7 +2738,7 @@ void testFromJoinWhereOrderByLimitB4() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -2764,7 +2764,7 @@ void testFromJoinWhereOrderByLimitB5() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -2790,7 +2790,7 @@ void testFromJoinWhereOrderByLimitOffsetB1() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -2819,7 +2819,7 @@ void testFromJoinWhereOrderByLimitOffsetB2() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -2848,7 +2848,7 @@ void testFromJoinWhereOrderByLimitOffsetB3() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -2877,7 +2877,7 @@ void testFromJoinWhereOrderByLimitOffsetB4() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -2906,7 +2906,7 @@ void testFromJoinWhereOrderByLimitOffsetB5() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -2935,7 +2935,7 @@ void testFromJoinWhereOrderByLimitOffsetB6() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -2964,7 +2964,7 @@ void testFromJoinWhereOrderByOffsetB1() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -2990,7 +2990,7 @@ void testFromJoinWhereOrderByOffsetB2() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -3016,7 +3016,7 @@ void testFromJoinWhereOrderByOffsetB3() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -3042,7 +3042,7 @@ void testFromJoinWhereOrderByOffsetB4() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -3068,7 +3068,7 @@ void testFromJoinWhereOrderByOffsetB5() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -3094,7 +3094,7 @@ void testFromJoinWhereOrderByOffsetFetchFirstB1() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -3123,7 +3123,7 @@ void testFromJoinWhereOrderByOffsetFetchFirstB2() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -3152,7 +3152,7 @@ void testFromJoinWhereOrderByOffsetFetchFirstB3() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -3181,7 +3181,7 @@ void testFromJoinWhereOrderByOffsetFetchFirstB4() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -3210,7 +3210,7 @@ void testFromJoinWhereOrderByOffsetFetchFirstB5() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -3239,7 +3239,7 @@ void testFromJoinWhereOrderByOffsetFetchFirstB6() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -3268,7 +3268,7 @@ void testFromJoinWhereOrderByFetchFirstB1() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -3294,7 +3294,7 @@ void testFromJoinWhereOrderByFetchFirstB2() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -3320,7 +3320,7 @@ void testFromJoinWhereOrderByFetchFirstB3() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -3346,7 +3346,7 @@ void testFromJoinWhereOrderByFetchFirstB4() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -3372,7 +3372,7 @@ void testFromJoinWhereOrderByFetchFirstB5() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -3398,7 +3398,7 @@ void testFromJoinWhereLimitB1() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -3421,7 +3421,7 @@ void testFromJoinWhereLimitB2() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -3444,7 +3444,7 @@ void testFromJoinWhereLimitB3() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -3467,7 +3467,7 @@ void testFromJoinWhereLimitB4() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -3490,7 +3490,7 @@ void testFromJoinWhereLimitOffsetB1() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -3516,7 +3516,7 @@ void testFromJoinWhereLimitOffsetB2() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -3542,7 +3542,7 @@ void testFromJoinWhereLimitOffsetB3() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -3568,7 +3568,7 @@ void testFromJoinWhereLimitOffsetB4() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -3594,7 +3594,7 @@ void testFromJoinWhereLimitOffsetB5() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -3620,7 +3620,7 @@ void testFromJoinWhereOffsetB1() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -3643,7 +3643,7 @@ void testFromJoinWhereOffsetB2() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -3666,7 +3666,7 @@ void testFromJoinWhereOffsetB3() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -3689,7 +3689,7 @@ void testFromJoinWhereOffsetB4() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -3712,7 +3712,7 @@ void testFromJoinWhereOffsetFetchFirstB1() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -3738,7 +3738,7 @@ void testFromJoinWhereOffsetFetchFirstB2() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -3764,7 +3764,7 @@ void testFromJoinWhereOffsetFetchFirstB3() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -3790,7 +3790,7 @@ void testFromJoinWhereOffsetFetchFirstB4() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -3816,7 +3816,7 @@ void testFromJoinWhereOffsetFetchFirstB5() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -3842,7 +3842,7 @@ void testFromJoinWhereFetchFirstB1() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -3865,7 +3865,7 @@ void testFromJoinWhereFetchFirstB2() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -3888,7 +3888,7 @@ void testFromJoinWhereFetchFirstB3() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -3911,7 +3911,7 @@ void testFromJoinWhereFetchFirstB4() { .from(StudentDynamicSqlSupport.student); QueryExpressionDSL.JoinSpecificationFinisher builder2 = builder1.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); QueryExpressionDSL.QueryExpressionWhereBuilder builder3 = builder2.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); diff --git a/src/test/java/issues/gh100/Issue100StartAfterJoinTest.java b/src/test/java/issues/gh100/Issue100StartAfterJoinTest.java index 9c3631c4d..aff76db96 100644 --- a/src/test/java/issues/gh100/Issue100StartAfterJoinTest.java +++ b/src/test/java/issues/gh100/Issue100StartAfterJoinTest.java @@ -32,7 +32,7 @@ void testSuccessiveBuild02() { QueryExpressionDSL.JoinSpecificationFinisher builder = select(StudentDynamicSqlSupport.id, StudentDynamicSqlSupport.name, StudentDynamicSqlSupport.idcard) .from(StudentDynamicSqlSupport.student) .join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); builder.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); @@ -50,7 +50,7 @@ void testSuccessiveBuild03() { QueryExpressionDSL.JoinSpecificationFinisher builder = select(StudentDynamicSqlSupport.id, StudentDynamicSqlSupport.name, StudentDynamicSqlSupport.idcard) .from(StudentDynamicSqlSupport.student) .join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); SelectDSL selectModel = builder.orderBy(StudentDynamicSqlSupport.id); @@ -71,7 +71,7 @@ void testSuccessiveBuild04() { QueryExpressionDSL.JoinSpecificationFinisher builder = select(StudentDynamicSqlSupport.id, StudentDynamicSqlSupport.name, StudentDynamicSqlSupport.idcard) .from(StudentDynamicSqlSupport.student) .join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); builder.limit(3); @@ -89,7 +89,7 @@ void testSuccessiveBuild05() { QueryExpressionDSL.JoinSpecificationFinisher builder = select(StudentDynamicSqlSupport.id, StudentDynamicSqlSupport.name, StudentDynamicSqlSupport.idcard) .from(StudentDynamicSqlSupport.student) .join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); builder.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")) .orderBy(StudentDynamicSqlSupport.id) @@ -113,7 +113,7 @@ void testSuccessiveBuild06() { QueryExpressionDSL.JoinSpecificationFinisher builder = select(StudentDynamicSqlSupport.id, StudentDynamicSqlSupport.name, StudentDynamicSqlSupport.idcard) .from(StudentDynamicSqlSupport.student) .join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); builder.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")) .orderBy(StudentDynamicSqlSupport.id) @@ -135,7 +135,7 @@ void testSuccessiveBuild07() { QueryExpressionDSL.JoinSpecificationFinisher builder = select(StudentDynamicSqlSupport.id, StudentDynamicSqlSupport.name, StudentDynamicSqlSupport.idcard) .from(StudentDynamicSqlSupport.student) .join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); builder.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")) .orderBy(StudentDynamicSqlSupport.id) @@ -159,7 +159,7 @@ void testSuccessiveBuild08() { QueryExpressionDSL.JoinSpecificationFinisher builder = select(StudentDynamicSqlSupport.id, StudentDynamicSqlSupport.name, StudentDynamicSqlSupport.idcard) .from(StudentDynamicSqlSupport.student) .join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); builder.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")) .orderBy(StudentDynamicSqlSupport.id) diff --git a/src/test/java/issues/gh100/Issue100Test.java b/src/test/java/issues/gh100/Issue100Test.java index f0411c774..01a8e0b0e 100644 --- a/src/test/java/issues/gh100/Issue100Test.java +++ b/src/test/java/issues/gh100/Issue100Test.java @@ -31,7 +31,7 @@ void testNormalUsage() { SelectStatementProvider selectStatement = select(StudentDynamicSqlSupport.id, StudentDynamicSqlSupport.name, StudentDynamicSqlSupport.idcard) .from(StudentDynamicSqlSupport.student) .join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)) + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)) .where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")) .union() .select(StudentDynamicSqlSupport.id, StudentDynamicSqlSupport.name, StudentDynamicSqlSupport.idcard) @@ -60,7 +60,7 @@ void testSuccessiveBuild01() { .from(StudentDynamicSqlSupport.student); builder.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); SelectStatementProvider selectStatement = builder.build() .render(RenderingStrategies.MYBATIS3); @@ -76,7 +76,7 @@ void testSuccessiveBuild02() { .from(StudentDynamicSqlSupport.student); builder.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)) + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)) .where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); SelectStatementProvider selectStatement = builder.build() @@ -94,7 +94,7 @@ void testSuccessiveBuild03() { .from(StudentDynamicSqlSupport.student); builder.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)) + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)) .where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")) .orderBy(StudentDynamicSqlSupport.id); @@ -114,7 +114,7 @@ void testSuccessiveBuild04() { .from(StudentDynamicSqlSupport.student); builder.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)) + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)) .where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")) .orderBy(StudentDynamicSqlSupport.id) .limit(3); @@ -136,7 +136,7 @@ void testSuccessiveBuild05() { .from(StudentDynamicSqlSupport.student); builder.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)) + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)) .where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")) .orderBy(StudentDynamicSqlSupport.id) .limit(3) @@ -182,8 +182,8 @@ void testSuccessiveBuild07() { .from(StudentDynamicSqlSupport.student); builder.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)) - .where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")) + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)) + .where(StudentDynamicSqlSupport.idcard, equalTo("fred")) .orderBy(StudentDynamicSqlSupport.id) .offset(2) .fetchFirst(3).rowsOnly(); @@ -206,7 +206,7 @@ void testSuccessiveBuild08() { .from(StudentDynamicSqlSupport.student); builder.join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)) + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)) .where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")) .orderBy(StudentDynamicSqlSupport.id) .fetchFirst(3).rowsOnly(); @@ -227,7 +227,7 @@ void test3() { QueryExpressionDSL.JoinSpecificationFinisher on = select(StudentDynamicSqlSupport.id, StudentDynamicSqlSupport.name, StudentDynamicSqlSupport.idcard) .from(StudentDynamicSqlSupport.student) .join(StudentRegDynamicSqlSupport.studentReg) - .on(StudentDynamicSqlSupport.id, equalTo(StudentRegDynamicSqlSupport.studentid)); + .on(StudentDynamicSqlSupport.id, isEqualTo(StudentRegDynamicSqlSupport.studentid)); on.where(StudentDynamicSqlSupport.idcard, isEqualTo("fred")); diff --git a/src/test/kotlin/examples/kotlin/mybatis3/canonical/PersonWithAddressMapperExtensions.kt b/src/test/kotlin/examples/kotlin/mybatis3/canonical/PersonWithAddressMapperExtensions.kt index c24c3a967..df4c91da8 100644 --- a/src/test/kotlin/examples/kotlin/mybatis3/canonical/PersonWithAddressMapperExtensions.kt +++ b/src/test/kotlin/examples/kotlin/mybatis3/canonical/PersonWithAddressMapperExtensions.kt @@ -35,8 +35,8 @@ private val columnList = listOf(id `as` "A_ID", firstName, lastName, birthDate, fun PersonWithAddressMapper.selectOne(completer: SelectCompleter): PersonWithAddress? = select(columnList) { from(person) - fullJoin(address) { - on(person.addressId) equalTo address.id + fullJoin(address) on { + person.addressId isEqualTo address.id } completer() }.run(this::selectOne) @@ -44,8 +44,8 @@ fun PersonWithAddressMapper.selectOne(completer: SelectCompleter): PersonWithAdd fun PersonWithAddressMapper.select(completer: SelectCompleter): List = select(columnList) { from(person, "p") - fullJoin(address) { - on(person.addressId) equalTo address.id + fullJoin(address) on { + person.addressId isEqualTo address.id } completer() }.run(this::selectMany) @@ -53,8 +53,8 @@ fun PersonWithAddressMapper.select(completer: SelectCompleter): List = selectDistinct(columnList) { from(person) - fullJoin(address) { - on(person.addressId) equalTo address.id + fullJoin(address) on { + person.addressId isEqualTo address.id } completer() }.run(this::selectMany) diff --git a/src/test/kotlin/examples/kotlin/mybatis3/general/GeneralKotlinTest.kt b/src/test/kotlin/examples/kotlin/mybatis3/general/GeneralKotlinTest.kt index 68d073cc9..4f0368248 100644 --- a/src/test/kotlin/examples/kotlin/mybatis3/general/GeneralKotlinTest.kt +++ b/src/test/kotlin/examples/kotlin/mybatis3/general/GeneralKotlinTest.kt @@ -367,8 +367,8 @@ class GeneralKotlinTest { address.id, address.streetAddress, address.city, address.state ) { from(person) - join(address) { - on(addressId) equalTo address.id + join(address) on { + addressId isEqualTo address.id } where { id isLessThan 4 } orderBy(id) @@ -403,8 +403,8 @@ class GeneralKotlinTest { address.id, address.streetAddress, address.city, address.state ) { from(person) - join(address) { - on(addressId) equalTo address.id + join(address) on { + addressId isEqualTo address.id } where { id isLessThan 5 @@ -446,8 +446,8 @@ class GeneralKotlinTest { address.id, address.streetAddress, address.city, address.state ) { from(person) - join(address) { - on(addressId) equalTo address.id + join(address) on { + addressId isEqualTo address.id } where { id isEqualTo 5 diff --git a/src/test/kotlin/examples/kotlin/mybatis3/joins/JoinMapperTest.kt b/src/test/kotlin/examples/kotlin/mybatis3/joins/DeprecatedJoinMapperTest.kt similarity index 66% rename from src/test/kotlin/examples/kotlin/mybatis3/joins/JoinMapperTest.kt rename to src/test/kotlin/examples/kotlin/mybatis3/joins/DeprecatedJoinMapperTest.kt index 5754fe631..7a05b79e4 100644 --- a/src/test/kotlin/examples/kotlin/mybatis3/joins/JoinMapperTest.kt +++ b/src/test/kotlin/examples/kotlin/mybatis3/joins/DeprecatedJoinMapperTest.kt @@ -30,14 +30,12 @@ import org.junit.jupiter.api.Test import org.junit.jupiter.api.TestInstance import org.mybatis.dynamic.sql.util.Messages import org.mybatis.dynamic.sql.util.kotlin.KInvalidSQLException -import org.mybatis.dynamic.sql.util.kotlin.elements.constant import org.mybatis.dynamic.sql.util.kotlin.elements.invoke -import org.mybatis.dynamic.sql.util.kotlin.elements.max import org.mybatis.dynamic.sql.util.kotlin.mybatis3.select @Suppress("LargeClass") @TestInstance(TestInstance.Lifecycle.PER_CLASS) -class JoinMapperTest { +class DeprecatedJoinMapperTest { private lateinit var sqlSessionFactory: SqlSessionFactory @BeforeAll @@ -48,45 +46,6 @@ class JoinMapperTest { } } - @Test - fun testSingleTableJoin() { - sqlSessionFactory.openSession().use { session -> - val mapper = session.getMapper(JoinMapper::class.java) - - val selectStatement = select( - orderMaster.orderId, orderMaster.orderDate, - orderDetail.lineNumber, orderDetail.description, orderDetail.quantity - ) { - from(orderMaster, "om") - join(orderDetail, "od") { - on(orderMaster.orderId) equalTo orderDetail.orderId - } - } - - val 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.selectStatement).isEqualTo(expectedStatement) - - val rows = mapper.selectMany(selectStatement) - - assertThat(rows).hasSize(2) - - with(rows[0]) { - assertThat(id).isEqualTo(1) - assertThat(details).hasSize(2) - assertThat(details?.get(0)?.lineNumber).isEqualTo(1) - assertThat(details?.get(1)?.lineNumber).isEqualTo(2) - } - - with(rows[1]) { - assertThat(id).isEqualTo(2) - assertThat(details).hasSize(1) - assertThat(details?.get(0)?.lineNumber).isEqualTo(1) - } - } - } - @Test fun testSingleTableJoinWithValue() { sqlSessionFactory.openSession().use { session -> @@ -96,51 +55,16 @@ class JoinMapperTest { orderMaster.orderId, orderMaster.orderDate, orderDetail.lineNumber, orderDetail.description, orderDetail.quantity ) { - from(orderMaster, "om") - join(orderDetail, "od") { + from(orderMaster) + join(orderDetail) { on(orderMaster.orderId) equalTo orderDetail.orderId and(orderMaster.orderId) equalTo 1 } } - val 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 = #{parameters.p1,jdbcType=INTEGER}" - - assertThat(selectStatement.selectStatement).isEqualTo(expectedStatement) - - val rows = mapper.selectMany(selectStatement) - - assertThat(rows).hasSize(1) - - with(rows[0]) { - assertThat(id).isEqualTo(1) - assertThat(details).hasSize(2) - assertThat(details?.get(0)?.lineNumber).isEqualTo(1) - assertThat(details?.get(1)?.lineNumber).isEqualTo(2) - } - } - } - - @Test - fun testSingleTableJoinWithConstant() { - sqlSessionFactory.openSession().use { session -> - val mapper = session.getMapper(JoinMapper::class.java) - - val selectStatement = select( - orderMaster.orderId, orderMaster.orderDate, - orderDetail.lineNumber, orderDetail.description, orderDetail.quantity - ) { - from(orderMaster, "om") - join(orderDetail, "od") { - on(orderMaster.orderId) equalTo orderDetail.orderId - and(orderMaster.orderId) equalTo constant("1") - } - } - - val 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 = 1" + val expectedStatement = "select OrderMaster.order_id, OrderMaster.order_date, OrderDetail.line_number, OrderDetail.description, OrderDetail.quantity" + + " from OrderMaster join OrderDetail on OrderMaster.order_id = OrderDetail.order_id" + + " and OrderMaster.order_id = #{parameters.p1,jdbcType=INTEGER}" assertThat(selectStatement.selectStatement).isEqualTo(expectedStatement) @@ -176,64 +100,6 @@ class JoinMapperTest { assertThat(selectStatement.selectStatement).isEqualTo(expectedStatement) } - @Test - fun testCompoundJoin2() { - // this is a nonsensical join, but it does test the "and" capability - val selectStatement = select( - orderMaster.orderId, orderMaster.orderDate, orderDetail.lineNumber, - orderDetail.description, orderDetail.quantity - ) { - from(orderMaster, "om") - join(orderDetail, "od") { - on(orderMaster.orderId) equalTo orderDetail.orderId - and(orderMaster.orderId) equalTo orderDetail.orderId - } - where { orderMaster.orderId isEqualTo 1 } - } - - val 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" + - " where om.order_id = #{parameters.p1,jdbcType=INTEGER}" - assertThat(selectStatement.selectStatement).isEqualTo(expectedStatement) - } - - @Test - fun testMultipleTableJoinWithWhereClause() { - sqlSessionFactory.openSession().use { session -> - val mapper = session.getMapper(JoinMapper::class.java) - - val 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 } - } - - val 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.selectStatement).isEqualTo(expectedStatement) - - val rows = mapper.selectMany(selectStatement) - - assertThat(rows).hasSize(1) - with(rows[0]) { - assertThat(id).isEqualTo(2) - assertThat(details).hasSize(2) - assertThat(details?.get(0)?.lineNumber).isEqualTo(1) - assertThat(details?.get(1)?.lineNumber).isEqualTo(2) - } - } - } - @Test fun testFullJoinWithAliases() { sqlSessionFactory.openSession().use { session -> @@ -703,100 +569,6 @@ class JoinMapperTest { } } - @Test - fun testSelf() { - sqlSessionFactory.openSession().use { session -> - val mapper = session.getMapper(JoinMapper::class.java) - - // create second table instance for self-join - val user2 = UserDynamicSQLSupport.User() - - // get Bamm Bamm's parent - should be Barney - val 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 } - } - - val 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.selectStatement).isEqualTo(expectedStatement) - val rows = mapper.selectManyMappedRows(selectStatement) - - assertThat(rows).hasSize(1) - assertThat(rows[0]).containsExactly( - entry("USER_ID", 2), - entry("USER_NAME", "Barney"), - ) - } - } - - @Test - fun testSelfWithNewAlias() { - sqlSessionFactory.openSession().use { session -> - val mapper = session.getMapper(JoinMapper::class.java) - - // create second table instance for self-join - val user2 = user.withAlias("u2") - - // get Bamm Bamm's parent - should be Barney - val selectStatement = select(user.userId, user.userName, user.parentId) { - from(user) - join(user2) { - on(user.userId) equalTo user2.parentId - } - where { user2.userId isEqualTo 4 } - } - - val expectedStatement = "select User.user_id, User.user_name, User.parent_id" + - " from User join User u2 on User.user_id = u2.parent_id" + - " where u2.user_id = #{parameters.p1,jdbcType=INTEGER}" - assertThat(selectStatement.selectStatement).isEqualTo(expectedStatement) - - val rows = mapper.selectManyMappedRows(selectStatement) - assertThat(rows).hasSize(1) - - assertThat(rows[0]).containsExactly( - entry("USER_ID", 2), - entry("USER_NAME", "Barney"), - ) - } - } - - @Test - fun testSelfWithNewAliasAndOverride() { - sqlSessionFactory.openSession().use { session -> - val mapper = session.getMapper(JoinMapper::class.java) - - // create second table instance for self-join - val user2 = user.withAlias("other_user") - - // get Bamm Bamm's parent - should be Barney - val 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 } - } - - val 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.selectStatement).isEqualTo(expectedStatement) - val rows = mapper.selectManyMappedRows(selectStatement) - assertThat(rows).hasSize(1) - - assertThat(rows[0]).containsExactly( - entry("USER_ID", 2), - entry("USER_NAME", "Barney"), - ) - } - } - @Test fun testJoinWithNoOnCondition() { // create second table instance for self-join @@ -829,48 +601,4 @@ class JoinMapperTest { } }.withMessage(Messages.getString("ERROR.45")) //$NON-NLS-1$ } - - @Test - fun testThatAliasesPropagateToSubQueryConditions() { - sqlSessionFactory.openSession().use { session -> - val mapper = session.getMapper(JoinMapper::class.java) - - val orderLine2 = OrderLineDynamicSQLSupport.OrderLine() - - val selectStatement = select(orderLine.orderId, orderLine.lineNumber) { - from(orderLine, "ol") - where { - orderLine.lineNumber isEqualTo { - select(max(orderLine2.lineNumber)) { - from(orderLine2, "ol2") - where { orderLine2.orderId isEqualTo orderLine.orderId } - } - } - } - orderBy(orderLine.orderId) - } - - val expectedStatement = "select ol.order_id, ol.line_number " + - "from OrderLine ol " + - "where ol.line_number = " + - "(select max(ol2.line_number) from OrderLine ol2 where ol2.order_id = ol.order_id) " + - "order by order_id" - - assertThat(selectStatement.selectStatement).isEqualTo(expectedStatement) - - val rows = mapper.selectManyMappedRows(selectStatement) - - assertThat(rows).hasSize(2) - - assertThat(rows[0]).containsOnly( - entry("ORDER_ID", 1), - entry("LINE_NUMBER", 2) - ) - - assertThat(rows[1]).containsOnly( - entry("ORDER_ID", 2), - entry("LINE_NUMBER", 3) - ) - } - } } diff --git a/src/test/kotlin/examples/kotlin/spring/canonical/CanonicalSpringKotlinTemplateDirectTest.kt b/src/test/kotlin/examples/kotlin/spring/canonical/CanonicalSpringKotlinTemplateDirectTest.kt index 7157e709a..18b4f9922 100644 --- a/src/test/kotlin/examples/kotlin/spring/canonical/CanonicalSpringKotlinTemplateDirectTest.kt +++ b/src/test/kotlin/examples/kotlin/spring/canonical/CanonicalSpringKotlinTemplateDirectTest.kt @@ -577,8 +577,8 @@ open class CanonicalSpringKotlinTemplateDirectTest { address.id, address.streetAddress, address.city, address.state ) { from(person, "p") - join(address, "a") { - on(addressId) equalTo address.id + join(address, "a") on { + addressId isEqualTo address.id } where { id isLessThan 4 } orderBy(id) diff --git a/src/test/kotlin/examples/kotlin/spring/canonical/CanonicalSpringKotlinTest.kt b/src/test/kotlin/examples/kotlin/spring/canonical/CanonicalSpringKotlinTest.kt index 7b9093892..23c6e8058 100644 --- a/src/test/kotlin/examples/kotlin/spring/canonical/CanonicalSpringKotlinTest.kt +++ b/src/test/kotlin/examples/kotlin/spring/canonical/CanonicalSpringKotlinTest.kt @@ -1122,8 +1122,8 @@ open class CanonicalSpringKotlinTest { address.streetAddress, address.city, address.state ) { from(person, "p") - join(address, "a") { - on(addressId) equalTo address.id + join(address, "a") on { + addressId isEqualTo address.id } where { id isLessThan 4 } orderBy(id) From d401491f66468dd074c6612f20907137dd2fd3ed Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Thu, 24 Oct 2024 17:12:25 -0400 Subject: [PATCH 104/289] Various Sonar warning cleanup --- .../array/StringArrayTypeHandler.java | 3 +- .../examples/complexquery/GroupingTest.java | 58 +++++++++---------- .../always/mybatis/GeneratedAlwaysMapper.java | 4 +- .../java/examples/simple/PersonMapper.java | 8 +-- .../simple/PersonWithAddressMapper.java | 4 +- .../examples/spring/SpringMapToRowTest.java | 1 - .../java/issues/gh324/NameTableMapper.java | 4 +- .../sql/where/condition/FilterAndMapTest.java | 13 ++--- 8 files changed, 46 insertions(+), 49 deletions(-) diff --git a/src/test/java/examples/array/StringArrayTypeHandler.java b/src/test/java/examples/array/StringArrayTypeHandler.java index 50f2d2907..238124a58 100644 --- a/src/test/java/examples/array/StringArrayTypeHandler.java +++ b/src/test/java/examples/array/StringArrayTypeHandler.java @@ -22,7 +22,6 @@ import java.sql.SQLException; import java.util.Arrays; import java.util.List; -import java.util.stream.Collectors; import org.apache.ibatis.type.BaseTypeHandler; import org.apache.ibatis.type.JdbcType; @@ -59,7 +58,7 @@ private String[] extractArray(Array array) throws SQLException { List stringList = Arrays.stream(objArray) .map(Object::toString) - .collect(Collectors.toList()); + .toList(); String[] stringArray = new String[stringList.size()]; return stringList.toArray(stringArray); diff --git a/src/test/java/examples/complexquery/GroupingTest.java b/src/test/java/examples/complexquery/GroupingTest.java index c7e09c467..683fa9d11 100644 --- a/src/test/java/examples/complexquery/GroupingTest.java +++ b/src/test/java/examples/complexquery/GroupingTest.java @@ -33,9 +33,9 @@ class GroupingTest { private static class Foo extends SqlTable { - public SqlColumn A = column("A"); - public SqlColumn B = column("B"); - public SqlColumn C = column("C"); + public SqlColumn columnA = column("A"); + public SqlColumn columnB = column("B"); + public SqlColumn columnC = column("C"); public Foo() { super("Foo"); @@ -43,16 +43,16 @@ public Foo() { } private static final Foo foo = new Foo(); - private static final SqlColumn A = foo.A; - private static final SqlColumn B = foo.B; - private static final SqlColumn C = foo.C; + private static final SqlColumn columnA = foo.columnA; + private static final SqlColumn columnB = foo.columnB; + private static final SqlColumn columnC = foo.columnC; @Test void testSimpleGrouping() { - SelectStatementProvider selectStatement = select(A, B, C) + SelectStatementProvider selectStatement = select(columnA, columnB, columnC) .from(foo) - .where(A, isEqualTo(1), or(A, isEqualTo(2))) - .and(B, isEqualTo(3)) + .where(columnA, isEqualTo(1), or(columnA, isEqualTo(2))) + .and(columnB, isEqualTo(3)) .build() .render(RenderingStrategies.MYBATIS3); @@ -68,14 +68,14 @@ void testSimpleGrouping() { @Test void testComplexGrouping() { - SelectStatementProvider selectStatement = select(A, B, C) + SelectStatementProvider selectStatement = select(columnA, columnB, columnC) .from(foo) .where( - group(A, isEqualTo(1), or(A, isGreaterThan(5))), - and(B, isEqualTo(1)), - or(A, isLessThan(0), and(B, isEqualTo(2))) + group(columnA, isEqualTo(1), or(columnA, isGreaterThan(5))), + and(columnB, isEqualTo(1)), + or(columnA, isLessThan(0), and(columnB, isEqualTo(2))) ) - .and(C, isEqualTo(1)) + .and(columnC, isEqualTo(1)) .build() .render(RenderingStrategies.MYBATIS3); @@ -94,14 +94,14 @@ void testComplexGrouping() { @Test void testGroupAndExists() { - SelectStatementProvider selectStatement = select(A, B, C) + SelectStatementProvider selectStatement = select(columnA, columnB, columnC) .from(foo) .where( - group(exists(select(foo.allColumns()).from(foo).where(A, isEqualTo(3))), and (A, isEqualTo(1)), or(A, isGreaterThan(5))), - and(B, isEqualTo(1)), - or(A, isLessThan(0), and(B, isEqualTo(2))) + group(exists(select(foo.allColumns()).from(foo).where(columnA, isEqualTo(3))), and (columnA, isEqualTo(1)), or(columnA, isGreaterThan(5))), + and(columnB, isEqualTo(1)), + or(columnA, isLessThan(0), and(columnB, isEqualTo(2))) ) - .and(C, isEqualTo(1)) + .and(columnC, isEqualTo(1)) .build() .render(RenderingStrategies.MYBATIS3); @@ -121,14 +121,14 @@ void testGroupAndExists() { @Test void testNestedGrouping() { - SelectStatementProvider selectStatement = select(A, B, C) + SelectStatementProvider selectStatement = select(columnA, columnB, columnC) .from(foo) .where( - group(group(A, isEqualTo(1), or(A, isGreaterThan(5))), and(A, isGreaterThan(5))), - and(group(A, isEqualTo(1), or(A, isGreaterThan(5))), or(B, isEqualTo(1))), - or(group(A, isEqualTo(1), or(A, isGreaterThan(5))), and(A, isLessThan(0), and(B, isEqualTo(2)))) + group(group(columnA, isEqualTo(1), or(columnA, isGreaterThan(5))), and(columnA, isGreaterThan(5))), + and(group(columnA, isEqualTo(1), or(columnA, isGreaterThan(5))), or(columnB, isEqualTo(1))), + or(group(columnA, isEqualTo(1), or(columnA, isGreaterThan(5))), and(columnA, isLessThan(0), and(columnB, isEqualTo(2)))) ) - .and(C, isEqualTo(1)) + .and(columnC, isEqualTo(1)) .build() .render(RenderingStrategies.MYBATIS3); @@ -152,12 +152,12 @@ void testNestedGrouping() { @Test void testAndOrCriteriaGroups() { - SelectStatementProvider selectStatement = select(A, B, C) + SelectStatementProvider selectStatement = select(columnA, columnB, columnC) .from(foo) - .where(A, isEqualTo(6)) - .and(C, isEqualTo(1)) - .and(group(A, isEqualTo(1), or(A, isGreaterThan(5))), or(B, isEqualTo(1))) - .or(group(A, isEqualTo(1), or(A, isGreaterThan(5))), and(A, isLessThan(0), and(B, isEqualTo(2)))) + .where(columnA, isEqualTo(6)) + .and(columnC, isEqualTo(1)) + .and(group(columnA, isEqualTo(1), or(columnA, isGreaterThan(5))), or(columnB, isEqualTo(1))) + .or(group(columnA, isEqualTo(1), or(columnA, isGreaterThan(5))), and(columnA, isLessThan(0), and(columnB, isEqualTo(2)))) .build() .render(RenderingStrategies.MYBATIS3); diff --git a/src/test/java/examples/generated/always/mybatis/GeneratedAlwaysMapper.java b/src/test/java/examples/generated/always/mybatis/GeneratedAlwaysMapper.java index ac2f7f86b..38521f063 100644 --- a/src/test/java/examples/generated/always/mybatis/GeneratedAlwaysMapper.java +++ b/src/test/java/examples/generated/always/mybatis/GeneratedAlwaysMapper.java @@ -76,8 +76,8 @@ default List select(SelectDSLCompleter completer) { return MyBatis3Utils.selectList(this::selectMany, selectList, generatedAlways, completer); } - default Optional selectByPrimaryKey(Integer _id) { - return selectOne(c -> c.where(id, isEqualTo(_id))); + default Optional selectByPrimaryKey(Integer recordId) { + return selectOne(c -> c.where(id, isEqualTo(recordId))); } default int insert(GeneratedAlwaysRecord row) { diff --git a/src/test/java/examples/simple/PersonMapper.java b/src/test/java/examples/simple/PersonMapper.java index bb9560f75..d31f4af1a 100644 --- a/src/test/java/examples/simple/PersonMapper.java +++ b/src/test/java/examples/simple/PersonMapper.java @@ -90,9 +90,9 @@ default int delete(DeleteDSLCompleter completer) { return MyBatis3Utils.deleteFrom(this::delete, person, completer); } - default int deleteByPrimaryKey(Integer id_) { + default int deleteByPrimaryKey(Integer recordId) { return delete(c -> - c.where(id, isEqualTo(id_)) + c.where(id, isEqualTo(recordId)) ); } @@ -152,9 +152,9 @@ default List selectDistinct(SelectDSLCompleter completer) { return MyBatis3Utils.selectDistinct(this::selectMany, selectList, person, completer); } - default Optional selectByPrimaryKey(Integer id_) { + default Optional selectByPrimaryKey(Integer recordId) { return selectOne(c -> - c.where(id, isEqualTo(id_)) + c.where(id, isEqualTo(recordId)) ); } diff --git a/src/test/java/examples/simple/PersonWithAddressMapper.java b/src/test/java/examples/simple/PersonWithAddressMapper.java index 5a51cf465..dc47df896 100644 --- a/src/test/java/examples/simple/PersonWithAddressMapper.java +++ b/src/test/java/examples/simple/PersonWithAddressMapper.java @@ -90,9 +90,9 @@ default List select(SelectDSLCompleter completer) { return MyBatis3Utils.selectList(this::selectMany, start, completer); } - default Optional selectByPrimaryKey(Integer id_) { + default Optional selectByPrimaryKey(Integer recordId) { return selectOne(c -> - c.where(id, isEqualTo(id_)) + c.where(id, isEqualTo(recordId)) ); } diff --git a/src/test/java/examples/spring/SpringMapToRowTest.java b/src/test/java/examples/spring/SpringMapToRowTest.java index c3b1077c9..d87c67201 100644 --- a/src/test/java/examples/spring/SpringMapToRowTest.java +++ b/src/test/java/examples/spring/SpringMapToRowTest.java @@ -24,7 +24,6 @@ import static org.mybatis.dynamic.sql.SqlBuilder.insertMultiple; import static org.mybatis.dynamic.sql.SqlBuilder.select; -import java.util.ArrayList; import java.util.List; import java.util.stream.IntStream; diff --git a/src/test/java/issues/gh324/NameTableMapper.java b/src/test/java/issues/gh324/NameTableMapper.java index 1ba3d0428..6a71f7cc0 100644 --- a/src/test/java/issues/gh324/NameTableMapper.java +++ b/src/test/java/issues/gh324/NameTableMapper.java @@ -49,9 +49,9 @@ default Optional selectOne(SelectDSLCompleter completer) { return MyBatis3Utils.selectOne(this::selectOne, selectList, nameTable, completer); } - default Optional selectByPrimaryKey(Integer id_) { + default Optional selectByPrimaryKey(Integer recordId) { return selectOne(c -> - c.where(id, isEqualTo(id_)) + c.where(id, isEqualTo(recordId)) ); } diff --git a/src/test/java/org/mybatis/dynamic/sql/where/condition/FilterAndMapTest.java b/src/test/java/org/mybatis/dynamic/sql/where/condition/FilterAndMapTest.java index 3e35af01b..3ab419b33 100644 --- a/src/test/java/org/mybatis/dynamic/sql/where/condition/FilterAndMapTest.java +++ b/src/test/java/org/mybatis/dynamic/sql/where/condition/FilterAndMapTest.java @@ -20,7 +20,6 @@ import java.util.List; import java.util.Objects; -import java.util.stream.Collectors; import org.junit.jupiter.api.Test; import org.mybatis.dynamic.sql.SqlBuilder; @@ -432,7 +431,7 @@ void testIsInRenderableMapShouldReturnMappedObject() { IsIn cond = SqlBuilder.isIn("Fred", "Wilma"); assertThat(cond.isEmpty()).isFalse(); IsIn mapped = cond.map(String::toUpperCase); - List mappedValues = mapped.values().collect(Collectors.toList()); + List mappedValues = mapped.values().toList(); assertThat(mappedValues).containsExactly("FRED", "WILMA"); } @@ -441,31 +440,31 @@ void testIsNotInRenderableMapShouldReturnMappedObject() { IsNotIn cond = SqlBuilder.isNotIn("Fred", "Wilma"); assertThat(cond.isEmpty()).isFalse(); IsNotIn mapped = cond.map(String::toUpperCase); - List mappedValues = mapped.values().collect(Collectors.toList()); + List mappedValues = mapped.values().toList(); assertThat(mappedValues).containsExactly("FRED", "WILMA"); } @Test void testIsNotInCaseInsensitiveRenderableMapShouldReturnMappedObject() { IsNotInCaseInsensitive cond = SqlBuilder.isNotInCaseInsensitive("Fred ", "Wilma "); - List values = cond.values().collect(Collectors.toList()); + List values = cond.values().toList(); assertThat(values).containsExactly("FRED ", "WILMA "); assertThat(cond.isEmpty()).isFalse(); IsNotInCaseInsensitive mapped = cond.map(String::trim); - List mappedValues = mapped.values().collect(Collectors.toList()); + List mappedValues = mapped.values().toList(); assertThat(mappedValues).containsExactly("FRED", "WILMA"); } @Test void testIsInCaseInsensitiveRenderableMapShouldReturnMappedObject() { IsInCaseInsensitive cond = SqlBuilder.isInCaseInsensitive("Fred ", "Wilma "); - List values = cond.values().collect(Collectors.toList()); + List values = cond.values().toList(); assertThat(values).containsExactly("FRED ", "WILMA "); assertThat(cond.isEmpty()).isFalse(); IsInCaseInsensitive mapped = cond.map(String::trim); - List mappedValues = mapped.values().collect(Collectors.toList()); + List mappedValues = mapped.values().toList(); assertThat(mappedValues).containsExactly("FRED", "WILMA"); } From ecea6da4eec7128199237bb9a5d4164dbff24e5e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 25 Oct 2024 00:36:25 +0000 Subject: [PATCH 105/289] Update dependency org.mariadb.jdbc:mariadb-java-client to v3.5.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8f73f520e..30c8fd38f 100644 --- a/pom.xml +++ b/pom.xml @@ -195,7 +195,7 @@ org.mariadb.jdbc mariadb-java-client - 3.4.1 + 3.5.0 test From 163e7a03b082e1eb1c56715504621baa568c7594 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 25 Oct 2024 21:54:35 +0000 Subject: [PATCH 106/289] Update dependency ch.qos.logback:logback-classic to v1.5.12 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 30c8fd38f..994ba2058 100644 --- a/pom.xml +++ b/pom.xml @@ -165,7 +165,7 @@ ch.qos.logback logback-classic - 1.5.11 + 1.5.12 test From 16593d3c58e46111677bf98f10afc91866894aee Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Fri, 25 Oct 2024 18:10:05 -0400 Subject: [PATCH 107/289] Refactor to remove renderer cycles --- .../dynamic/sql/delete/DeleteModel.java | 9 +- .../dynamic/sql/insert/BatchInsertModel.java | 8 +- .../sql/insert/GeneralInsertModel.java | 9 +- .../dynamic/sql/insert/InsertModel.java | 8 +- .../dynamic/sql/insert/InsertSelectModel.java | 9 +- .../sql/insert/MultiRowInsertModel.java | 8 +- .../dynamic/sql/render/Renderable.java | 21 +++ .../dynamic/sql/render/RendererFactory.java | 135 ++++++++++++++++++ .../dynamic/sql/select/MultiSelectModel.java | 10 +- .../dynamic/sql/select/SelectModel.java | 13 +- .../dynamic/sql/update/UpdateModel.java | 9 +- 11 files changed, 184 insertions(+), 55 deletions(-) create mode 100644 src/main/java/org/mybatis/dynamic/sql/render/Renderable.java create mode 100644 src/main/java/org/mybatis/dynamic/sql/render/RendererFactory.java diff --git a/src/main/java/org/mybatis/dynamic/sql/delete/DeleteModel.java b/src/main/java/org/mybatis/dynamic/sql/delete/DeleteModel.java index 54770d5d4..015f9823c 100644 --- a/src/main/java/org/mybatis/dynamic/sql/delete/DeleteModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/delete/DeleteModel.java @@ -23,8 +23,8 @@ import org.mybatis.dynamic.sql.common.CommonBuilder; import org.mybatis.dynamic.sql.common.OrderByModel; import org.mybatis.dynamic.sql.configuration.StatementConfiguration; -import org.mybatis.dynamic.sql.delete.render.DeleteRenderer; import org.mybatis.dynamic.sql.delete.render.DeleteStatementProvider; +import org.mybatis.dynamic.sql.render.RendererFactory; import org.mybatis.dynamic.sql.render.RenderingStrategy; import org.mybatis.dynamic.sql.where.EmbeddedWhereModel; @@ -67,11 +67,8 @@ public Optional orderByModel() { @NotNull public DeleteStatementProvider render(RenderingStrategy renderingStrategy) { - return DeleteRenderer.withDeleteModel(this) - .withRenderingStrategy(renderingStrategy) - .withStatementConfiguration(statementConfiguration) - .build() - .render(); + return RendererFactory.createDeleteRenderer(this, statementConfiguration) + .render(renderingStrategy); } public static Builder withTable(SqlTable table) { diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/BatchInsertModel.java b/src/main/java/org/mybatis/dynamic/sql/insert/BatchInsertModel.java index b591753a2..5e48e9035 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/BatchInsertModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/BatchInsertModel.java @@ -19,7 +19,7 @@ import org.jetbrains.annotations.NotNull; import org.mybatis.dynamic.sql.insert.render.BatchInsert; -import org.mybatis.dynamic.sql.insert.render.BatchInsertRenderer; +import org.mybatis.dynamic.sql.render.RendererFactory; import org.mybatis.dynamic.sql.render.RenderingStrategy; import org.mybatis.dynamic.sql.util.Validator; @@ -33,10 +33,8 @@ private BatchInsertModel(Builder builder) { @NotNull public BatchInsert render(RenderingStrategy renderingStrategy) { - return BatchInsertRenderer.withBatchInsertModel(this) - .withRenderingStrategy(renderingStrategy) - .build() - .render(); + return RendererFactory.createBatchInsertRenderer(this) + .render(renderingStrategy); } public static Builder withRecords(Collection records) { diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/GeneralInsertModel.java b/src/main/java/org/mybatis/dynamic/sql/insert/GeneralInsertModel.java index 7f219027d..f3fb146ee 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/GeneralInsertModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/GeneralInsertModel.java @@ -23,8 +23,8 @@ import org.jetbrains.annotations.NotNull; import org.mybatis.dynamic.sql.SqlTable; import org.mybatis.dynamic.sql.configuration.StatementConfiguration; -import org.mybatis.dynamic.sql.insert.render.GeneralInsertRenderer; import org.mybatis.dynamic.sql.insert.render.GeneralInsertStatementProvider; +import org.mybatis.dynamic.sql.render.RendererFactory; import org.mybatis.dynamic.sql.render.RenderingStrategy; import org.mybatis.dynamic.sql.util.AbstractColumnMapping; import org.mybatis.dynamic.sql.util.Validator; @@ -52,11 +52,8 @@ public SqlTable table() { @NotNull public GeneralInsertStatementProvider render(RenderingStrategy renderingStrategy) { - return GeneralInsertRenderer.withInsertModel(this) - .withRenderingStrategy(renderingStrategy) - .withStatementConfiguration(statementConfiguration) - .build() - .render(); + return RendererFactory.createGeneralInsertRenderer(this, statementConfiguration) + .render(renderingStrategy); } public static class Builder { diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/InsertModel.java b/src/main/java/org/mybatis/dynamic/sql/insert/InsertModel.java index 7f740051e..07fac79ed 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/InsertModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/InsertModel.java @@ -22,8 +22,8 @@ import org.jetbrains.annotations.NotNull; import org.mybatis.dynamic.sql.SqlTable; -import org.mybatis.dynamic.sql.insert.render.InsertRenderer; import org.mybatis.dynamic.sql.insert.render.InsertStatementProvider; +import org.mybatis.dynamic.sql.render.RendererFactory; import org.mybatis.dynamic.sql.render.RenderingStrategy; import org.mybatis.dynamic.sql.util.AbstractColumnMapping; import org.mybatis.dynamic.sql.util.Validator; @@ -54,10 +54,8 @@ public SqlTable table() { @NotNull public InsertStatementProvider render(RenderingStrategy renderingStrategy) { - return InsertRenderer.withInsertModel(this) - .withRenderingStrategy(renderingStrategy) - .build() - .render(); + return RendererFactory.createInsertRenderer(this) + .render(renderingStrategy); } public static Builder withRow(T row) { diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/InsertSelectModel.java b/src/main/java/org/mybatis/dynamic/sql/insert/InsertSelectModel.java index 4da2cef1c..5b22eaeb7 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/InsertSelectModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/InsertSelectModel.java @@ -21,8 +21,8 @@ import org.jetbrains.annotations.NotNull; import org.mybatis.dynamic.sql.SqlTable; import org.mybatis.dynamic.sql.configuration.StatementConfiguration; -import org.mybatis.dynamic.sql.insert.render.InsertSelectRenderer; import org.mybatis.dynamic.sql.insert.render.InsertSelectStatementProvider; +import org.mybatis.dynamic.sql.render.RendererFactory; import org.mybatis.dynamic.sql.render.RenderingStrategy; import org.mybatis.dynamic.sql.select.SelectModel; @@ -53,11 +53,8 @@ public Optional columnList() { @NotNull public InsertSelectStatementProvider render(RenderingStrategy renderingStrategy) { - return InsertSelectRenderer.withInsertSelectModel(this) - .withRenderingStrategy(renderingStrategy) - .withStatementConfiguration(statementConfiguration) - .build() - .render(); + return RendererFactory.createInsertSelectRenderer(this, statementConfiguration) + .render(renderingStrategy); } public static Builder withTable(SqlTable table) { diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/MultiRowInsertModel.java b/src/main/java/org/mybatis/dynamic/sql/insert/MultiRowInsertModel.java index 406c02b7a..d5d7f478d 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/MultiRowInsertModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/MultiRowInsertModel.java @@ -18,8 +18,8 @@ import java.util.Collection; import org.jetbrains.annotations.NotNull; -import org.mybatis.dynamic.sql.insert.render.MultiRowInsertRenderer; import org.mybatis.dynamic.sql.insert.render.MultiRowInsertStatementProvider; +import org.mybatis.dynamic.sql.render.RendererFactory; import org.mybatis.dynamic.sql.render.RenderingStrategy; import org.mybatis.dynamic.sql.util.Validator; @@ -33,10 +33,8 @@ private MultiRowInsertModel(Builder builder) { @NotNull public MultiRowInsertStatementProvider render(RenderingStrategy renderingStrategy) { - return MultiRowInsertRenderer.withMultiRowInsertModel(this) - .withRenderingStrategy(renderingStrategy) - .build() - .render(); + return RendererFactory.createMultiRowInsertRenderer(this) + .render(renderingStrategy); } public static Builder withRecords(Collection records) { diff --git a/src/main/java/org/mybatis/dynamic/sql/render/Renderable.java b/src/main/java/org/mybatis/dynamic/sql/render/Renderable.java new file mode 100644 index 000000000..da999bfb8 --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/render/Renderable.java @@ -0,0 +1,21 @@ +/* + * Copyright 2016-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mybatis.dynamic.sql.render; + +@FunctionalInterface +public interface Renderable { + R render(T t); +} diff --git a/src/main/java/org/mybatis/dynamic/sql/render/RendererFactory.java b/src/main/java/org/mybatis/dynamic/sql/render/RendererFactory.java new file mode 100644 index 000000000..2b8208272 --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/render/RendererFactory.java @@ -0,0 +1,135 @@ +/* + * Copyright 2016-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mybatis.dynamic.sql.render; + +import org.mybatis.dynamic.sql.configuration.StatementConfiguration; +import org.mybatis.dynamic.sql.delete.DeleteModel; +import org.mybatis.dynamic.sql.delete.render.DeleteRenderer; +import org.mybatis.dynamic.sql.delete.render.DeleteStatementProvider; +import org.mybatis.dynamic.sql.insert.BatchInsertModel; +import org.mybatis.dynamic.sql.insert.GeneralInsertModel; +import org.mybatis.dynamic.sql.insert.InsertModel; +import org.mybatis.dynamic.sql.insert.InsertSelectModel; +import org.mybatis.dynamic.sql.insert.MultiRowInsertModel; +import org.mybatis.dynamic.sql.insert.render.BatchInsert; +import org.mybatis.dynamic.sql.insert.render.BatchInsertRenderer; +import org.mybatis.dynamic.sql.insert.render.GeneralInsertRenderer; +import org.mybatis.dynamic.sql.insert.render.GeneralInsertStatementProvider; +import org.mybatis.dynamic.sql.insert.render.InsertRenderer; +import org.mybatis.dynamic.sql.insert.render.InsertSelectRenderer; +import org.mybatis.dynamic.sql.insert.render.InsertSelectStatementProvider; +import org.mybatis.dynamic.sql.insert.render.InsertStatementProvider; +import org.mybatis.dynamic.sql.insert.render.MultiRowInsertRenderer; +import org.mybatis.dynamic.sql.insert.render.MultiRowInsertStatementProvider; +import org.mybatis.dynamic.sql.select.MultiSelectModel; +import org.mybatis.dynamic.sql.select.SelectModel; +import org.mybatis.dynamic.sql.select.render.MultiSelectRenderer; +import org.mybatis.dynamic.sql.select.render.SelectRenderer; +import org.mybatis.dynamic.sql.select.render.SelectStatementProvider; +import org.mybatis.dynamic.sql.update.UpdateModel; +import org.mybatis.dynamic.sql.update.render.UpdateRenderer; +import org.mybatis.dynamic.sql.update.render.UpdateStatementProvider; + +public interface RendererFactory { + static Renderable createDeleteRenderer(DeleteModel deleteModel, + StatementConfiguration statementConfiguration) { + return renderingStrategy -> DeleteRenderer.withDeleteModel(deleteModel) + .withStatementConfiguration(statementConfiguration) + .withRenderingStrategy(renderingStrategy) + .build() + .render(); + } + + static Renderable> createBatchInsertRenderer( + BatchInsertModel batchInsertModel) { + return renderingStrategy -> BatchInsertRenderer.withBatchInsertModel(batchInsertModel) + .withRenderingStrategy(renderingStrategy) + .build() + .render(); + } + + static Renderable createGeneralInsertRenderer( + GeneralInsertModel generalInsertModel, StatementConfiguration statementConfiguration) { + return renderingStrategy -> GeneralInsertRenderer.withInsertModel(generalInsertModel) + .withStatementConfiguration(statementConfiguration) + .withRenderingStrategy(renderingStrategy) + .build() + .render(); + } + + static Renderable> createInsertRenderer( + InsertModel insertModel) { + return renderingStrategy -> InsertRenderer.withInsertModel(insertModel) + .withRenderingStrategy(renderingStrategy) + .build() + .render(); + } + + static Renderable createInsertSelectRenderer( + InsertSelectModel insertSelectModel, StatementConfiguration statementConfiguration) { + return renderingStrategy -> InsertSelectRenderer.withInsertSelectModel(insertSelectModel) + .withStatementConfiguration(statementConfiguration) + .withRenderingStrategy(renderingStrategy) + .build() + .render(); + } + + static Renderable> createMultiRowInsertRenderer( + MultiRowInsertModel multiRowInsertModel) { + return renderingStrategy -> MultiRowInsertRenderer.withMultiRowInsertModel(multiRowInsertModel) + .withRenderingStrategy(renderingStrategy) + .build() + .render(); + } + + static Renderable createMultiSelectRenderer( + MultiSelectModel multiSelectModel, StatementConfiguration statementConfiguration) { + return renderingStrategy -> new MultiSelectRenderer.Builder() + .withMultiSelectModel(multiSelectModel) + .withStatementConfiguration(statementConfiguration) + .withRenderingStrategy(renderingStrategy) + .build() + .render(); + } + + static Renderable createSelectRenderer( + SelectModel selectModel, StatementConfiguration statementConfiguration) { + return renderingStrategy -> { + RenderingContext renderingContext = RenderingContext.withRenderingStrategy(renderingStrategy) + .withStatementConfiguration(statementConfiguration) + .build(); + + return createSelectRenderer(selectModel).render(renderingContext); + }; + } + + static Renderable createSelectRenderer( + SelectModel selectModel) { + return renderingContext -> SelectRenderer.withSelectModel(selectModel) + .withRenderingContext(renderingContext) + .build() + .render(); + } + + static Renderable createUpdateRenderer( + UpdateModel updateModel, StatementConfiguration statementConfiguration) { + return renderingStrategy -> UpdateRenderer.withUpdateModel(updateModel) + .withStatementConfiguration(statementConfiguration) + .withRenderingStrategy(renderingStrategy) + .build() + .render(); + } +} diff --git a/src/main/java/org/mybatis/dynamic/sql/select/MultiSelectModel.java b/src/main/java/org/mybatis/dynamic/sql/select/MultiSelectModel.java index f9a1a388a..607378c20 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/MultiSelectModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/MultiSelectModel.java @@ -21,8 +21,8 @@ import java.util.stream.Stream; import org.jetbrains.annotations.NotNull; +import org.mybatis.dynamic.sql.render.RendererFactory; import org.mybatis.dynamic.sql.render.RenderingStrategy; -import org.mybatis.dynamic.sql.select.render.MultiSelectRenderer; import org.mybatis.dynamic.sql.select.render.SelectStatementProvider; import org.mybatis.dynamic.sql.util.Validator; @@ -47,12 +47,8 @@ public Stream unionQueries() { @NotNull public SelectStatementProvider render(RenderingStrategy renderingStrategy) { - return new MultiSelectRenderer.Builder() - .withMultiSelectModel(this) - .withRenderingStrategy(renderingStrategy) - .withStatementConfiguration(statementConfiguration) - .build() - .render(); + return RendererFactory.createMultiSelectRenderer(this, statementConfiguration) + .render(renderingStrategy); } public static class Builder extends AbstractBuilder { diff --git a/src/main/java/org/mybatis/dynamic/sql/select/SelectModel.java b/src/main/java/org/mybatis/dynamic/sql/select/SelectModel.java index 57fd06a43..32b745e0e 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/SelectModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/SelectModel.java @@ -21,9 +21,9 @@ import java.util.stream.Stream; import org.jetbrains.annotations.NotNull; +import org.mybatis.dynamic.sql.render.RendererFactory; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.render.RenderingStrategy; -import org.mybatis.dynamic.sql.select.render.SelectRenderer; import org.mybatis.dynamic.sql.select.render.SelectStatementProvider; import org.mybatis.dynamic.sql.util.Validator; @@ -42,10 +42,8 @@ public Stream queryExpressions() { @NotNull public SelectStatementProvider render(RenderingStrategy renderingStrategy) { - RenderingContext renderingContext = RenderingContext.withRenderingStrategy(renderingStrategy) - .withStatementConfiguration(statementConfiguration) - .build(); - return render(renderingContext); + return RendererFactory.createSelectRenderer(this, statementConfiguration) + .render(renderingStrategy); } /** @@ -56,10 +54,7 @@ public SelectStatementProvider render(RenderingStrategy renderingStrategy) { */ @NotNull public SelectStatementProvider render(RenderingContext renderingContext) { - return SelectRenderer.withSelectModel(this) - .withRenderingContext(renderingContext) - .build() - .render(); + return RendererFactory.createSelectRenderer(this).render(renderingContext); } public static Builder withQueryExpressions(List queryExpressions) { diff --git a/src/main/java/org/mybatis/dynamic/sql/update/UpdateModel.java b/src/main/java/org/mybatis/dynamic/sql/update/UpdateModel.java index 7ff82df26..672b08c44 100644 --- a/src/main/java/org/mybatis/dynamic/sql/update/UpdateModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/update/UpdateModel.java @@ -26,8 +26,8 @@ import org.mybatis.dynamic.sql.common.CommonBuilder; import org.mybatis.dynamic.sql.common.OrderByModel; import org.mybatis.dynamic.sql.configuration.StatementConfiguration; +import org.mybatis.dynamic.sql.render.RendererFactory; import org.mybatis.dynamic.sql.render.RenderingStrategy; -import org.mybatis.dynamic.sql.update.render.UpdateRenderer; import org.mybatis.dynamic.sql.update.render.UpdateStatementProvider; import org.mybatis.dynamic.sql.util.AbstractColumnMapping; import org.mybatis.dynamic.sql.util.Validator; @@ -79,11 +79,8 @@ public Optional orderByModel() { @NotNull public UpdateStatementProvider render(RenderingStrategy renderingStrategy) { - return UpdateRenderer.withUpdateModel(this) - .withRenderingStrategy(renderingStrategy) - .withStatementConfiguration(statementConfiguration) - .build() - .render(); + return RendererFactory.createUpdateRenderer(this, statementConfiguration) + .render(renderingStrategy); } public static Builder withTable(SqlTable table) { From df83f4331dec9579e7c29c5b39278bc82ecf7bcf Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Sun, 27 Oct 2024 14:32:12 -0400 Subject: [PATCH 108/289] Method reuse --- .../mybatis/dynamic/sql/render/RendererFactory.java | 11 ----------- .../org/mybatis/dynamic/sql/select/SelectModel.java | 6 ++++-- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/render/RendererFactory.java b/src/main/java/org/mybatis/dynamic/sql/render/RendererFactory.java index 2b8208272..b925d8fde 100644 --- a/src/main/java/org/mybatis/dynamic/sql/render/RendererFactory.java +++ b/src/main/java/org/mybatis/dynamic/sql/render/RendererFactory.java @@ -105,17 +105,6 @@ static Renderable createMultiSelectR .render(); } - static Renderable createSelectRenderer( - SelectModel selectModel, StatementConfiguration statementConfiguration) { - return renderingStrategy -> { - RenderingContext renderingContext = RenderingContext.withRenderingStrategy(renderingStrategy) - .withStatementConfiguration(statementConfiguration) - .build(); - - return createSelectRenderer(selectModel).render(renderingContext); - }; - } - static Renderable createSelectRenderer( SelectModel selectModel) { return renderingContext -> SelectRenderer.withSelectModel(selectModel) diff --git a/src/main/java/org/mybatis/dynamic/sql/select/SelectModel.java b/src/main/java/org/mybatis/dynamic/sql/select/SelectModel.java index 32b745e0e..85196be7b 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/SelectModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/SelectModel.java @@ -42,8 +42,10 @@ public Stream queryExpressions() { @NotNull public SelectStatementProvider render(RenderingStrategy renderingStrategy) { - return RendererFactory.createSelectRenderer(this, statementConfiguration) - .render(renderingStrategy); + RenderingContext renderingContext = RenderingContext.withRenderingStrategy(renderingStrategy) + .withStatementConfiguration(statementConfiguration) + .build(); + return render(renderingContext); } /** From 3ddf8bd601ac29dede66c4d2b521c79e54eb2b73 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 28 Oct 2024 09:35:50 -0400 Subject: [PATCH 109/289] Better name --- .../render/{Renderable.java => Renderer.java} | 2 +- .../dynamic/sql/render/RendererFactory.java | 20 +++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) rename src/main/java/org/mybatis/dynamic/sql/render/{Renderable.java => Renderer.java} (95%) diff --git a/src/main/java/org/mybatis/dynamic/sql/render/Renderable.java b/src/main/java/org/mybatis/dynamic/sql/render/Renderer.java similarity index 95% rename from src/main/java/org/mybatis/dynamic/sql/render/Renderable.java rename to src/main/java/org/mybatis/dynamic/sql/render/Renderer.java index da999bfb8..acb84a98f 100644 --- a/src/main/java/org/mybatis/dynamic/sql/render/Renderable.java +++ b/src/main/java/org/mybatis/dynamic/sql/render/Renderer.java @@ -16,6 +16,6 @@ package org.mybatis.dynamic.sql.render; @FunctionalInterface -public interface Renderable { +public interface Renderer { R render(T t); } diff --git a/src/main/java/org/mybatis/dynamic/sql/render/RendererFactory.java b/src/main/java/org/mybatis/dynamic/sql/render/RendererFactory.java index b925d8fde..c47ca1f78 100644 --- a/src/main/java/org/mybatis/dynamic/sql/render/RendererFactory.java +++ b/src/main/java/org/mybatis/dynamic/sql/render/RendererFactory.java @@ -44,8 +44,8 @@ import org.mybatis.dynamic.sql.update.render.UpdateStatementProvider; public interface RendererFactory { - static Renderable createDeleteRenderer(DeleteModel deleteModel, - StatementConfiguration statementConfiguration) { + static Renderer createDeleteRenderer(DeleteModel deleteModel, + StatementConfiguration statementConfiguration) { return renderingStrategy -> DeleteRenderer.withDeleteModel(deleteModel) .withStatementConfiguration(statementConfiguration) .withRenderingStrategy(renderingStrategy) @@ -53,7 +53,7 @@ static Renderable createDeleteRender .render(); } - static Renderable> createBatchInsertRenderer( + static Renderer> createBatchInsertRenderer( BatchInsertModel batchInsertModel) { return renderingStrategy -> BatchInsertRenderer.withBatchInsertModel(batchInsertModel) .withRenderingStrategy(renderingStrategy) @@ -61,7 +61,7 @@ static Renderable> createBatchInsertRender .render(); } - static Renderable createGeneralInsertRenderer( + static Renderer createGeneralInsertRenderer( GeneralInsertModel generalInsertModel, StatementConfiguration statementConfiguration) { return renderingStrategy -> GeneralInsertRenderer.withInsertModel(generalInsertModel) .withStatementConfiguration(statementConfiguration) @@ -70,7 +70,7 @@ static Renderable createGener .render(); } - static Renderable> createInsertRenderer( + static Renderer> createInsertRenderer( InsertModel insertModel) { return renderingStrategy -> InsertRenderer.withInsertModel(insertModel) .withRenderingStrategy(renderingStrategy) @@ -78,7 +78,7 @@ static Renderable> createInser .render(); } - static Renderable createInsertSelectRenderer( + static Renderer createInsertSelectRenderer( InsertSelectModel insertSelectModel, StatementConfiguration statementConfiguration) { return renderingStrategy -> InsertSelectRenderer.withInsertSelectModel(insertSelectModel) .withStatementConfiguration(statementConfiguration) @@ -87,7 +87,7 @@ static Renderable createInsert .render(); } - static Renderable> createMultiRowInsertRenderer( + static Renderer> createMultiRowInsertRenderer( MultiRowInsertModel multiRowInsertModel) { return renderingStrategy -> MultiRowInsertRenderer.withMultiRowInsertModel(multiRowInsertModel) .withRenderingStrategy(renderingStrategy) @@ -95,7 +95,7 @@ static Renderable> cre .render(); } - static Renderable createMultiSelectRenderer( + static Renderer createMultiSelectRenderer( MultiSelectModel multiSelectModel, StatementConfiguration statementConfiguration) { return renderingStrategy -> new MultiSelectRenderer.Builder() .withMultiSelectModel(multiSelectModel) @@ -105,7 +105,7 @@ static Renderable createMultiSelectR .render(); } - static Renderable createSelectRenderer( + static Renderer createSelectRenderer( SelectModel selectModel) { return renderingContext -> SelectRenderer.withSelectModel(selectModel) .withRenderingContext(renderingContext) @@ -113,7 +113,7 @@ static Renderable createSelectRendere .render(); } - static Renderable createUpdateRenderer( + static Renderer createUpdateRenderer( UpdateModel updateModel, StatementConfiguration statementConfiguration) { return renderingStrategy -> UpdateRenderer.withUpdateModel(updateModel) .withStatementConfiguration(statementConfiguration) From 8d6b2264bd250d1e7b64c7dbb47721bd05eee424 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 3 Nov 2024 05:14:02 +0000 Subject: [PATCH 110/289] Update dependency org.hsqldb:hsqldb to v2.7.4 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 994ba2058..bb41c7c12 100644 --- a/pom.xml +++ b/pom.xml @@ -141,7 +141,7 @@ org.hsqldb hsqldb - 2.7.3 + 2.7.4 test From ade363dacca6c22789aef6f18f4bffe1b6a40f30 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 15 Nov 2024 12:10:12 +0000 Subject: [PATCH 111/289] Update dependency org.springframework:spring-jdbc to v6.2.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index bb41c7c12..fc513913c 100644 --- a/pom.xml +++ b/pom.xml @@ -96,7 +96,7 @@ org.springframework spring-jdbc - 6.1.14 + 6.2.0 provided true From 506d30e1c3fb169512f63e9c622503f277be8d89 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 18 Nov 2024 17:52:45 -0500 Subject: [PATCH 112/289] Use Fragment Mapping where it makes sense --- .../sql/select/render/QueryExpressionRenderer.java | 8 ++------ .../dynamic/sql/where/render/DefaultConditionVisitor.java | 8 ++------ src/test/java/examples/animal/data/Length.java | 7 ++----- src/test/java/examples/type_conversion/ToBase64.java | 7 ++----- 4 files changed, 8 insertions(+), 22 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/QueryExpressionRenderer.java b/src/main/java/org/mybatis/dynamic/sql/select/render/QueryExpressionRenderer.java index 0f3ddcb01..618ea2f9c 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/render/QueryExpressionRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/render/QueryExpressionRenderer.java @@ -139,12 +139,8 @@ private FragmentAndParameters calculateColumnList() { private FragmentAndParameters renderColumnAndAlias(BasicColumn selectListItem) { FragmentAndParameters renderedColumn = selectListItem.render(renderingContext); - String nameAndTableAlias = selectListItem.alias().map(a -> renderedColumn.fragment() + " as " + a) //$NON-NLS-1$ - .orElse(renderedColumn.fragment()); - - return FragmentAndParameters.withFragment(nameAndTableAlias) - .withParameters(renderedColumn.parameters()) - .build(); + return selectListItem.alias().map(a -> renderedColumn.mapFragment(f -> f + " as " + a)) //$NON-NLS-1$ + .orElse(renderedColumn); } private FragmentAndParameters renderTableExpression(TableExpression table) { diff --git a/src/main/java/org/mybatis/dynamic/sql/where/render/DefaultConditionVisitor.java b/src/main/java/org/mybatis/dynamic/sql/where/render/DefaultConditionVisitor.java index 9adda9f64..309a10f3b 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/render/DefaultConditionVisitor.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/render/DefaultConditionVisitor.java @@ -109,12 +109,8 @@ public FragmentAndParameters visit(AbstractSubselectCondition condition) { @Override public FragmentAndParameters visit(AbstractColumnComparisonCondition condition) { - FragmentAndParameters renderedRightColumn = condition.rightColumn().render(renderingContext); - String finalFragment = condition.operator() - + spaceBefore(renderedRightColumn.fragment()); - return FragmentAndParameters.withFragment(finalFragment) - .withParameters(renderedRightColumn.parameters()) - .build(); + return condition.rightColumn().render(renderingContext) + .mapFragment(f -> condition.operator() + spaceBefore(f)); } private Object convertValue(T value) { diff --git a/src/test/java/examples/animal/data/Length.java b/src/test/java/examples/animal/data/Length.java index 6fb90e40d..34bb7f3c9 100644 --- a/src/test/java/examples/animal/data/Length.java +++ b/src/test/java/examples/animal/data/Length.java @@ -36,11 +36,8 @@ public Optional jdbcType() { @Override public FragmentAndParameters render(RenderingContext renderingContext) { - FragmentAndParameters renderedColumn = column.render(renderingContext); - - return FragmentAndParameters.withFragment("length(" + renderedColumn.fragment() + ")") //$NON-NLS-1$ //$NON-NLS-2$ - .withParameters(renderedColumn.parameters()) - .build(); + return column.render(renderingContext) + .mapFragment(f -> "length(" + f + ")"); //$NON-NLS-1$ //$NON-NLS-2$ } @Override diff --git a/src/test/java/examples/type_conversion/ToBase64.java b/src/test/java/examples/type_conversion/ToBase64.java index ce5ab5891..42bfe40d1 100644 --- a/src/test/java/examples/type_conversion/ToBase64.java +++ b/src/test/java/examples/type_conversion/ToBase64.java @@ -37,11 +37,8 @@ public Optional jdbcType() { @Override public FragmentAndParameters render(RenderingContext renderingContext) { - FragmentAndParameters renderedColumn = column.render(renderingContext); - - return FragmentAndParameters.withFragment("TO_BASE64(" + renderedColumn.fragment() + ")") //$NON-NLS-1$ //$NON-NLS-2$ - .withParameters(renderedColumn.parameters()) - .build(); + return column.render(renderingContext) + .mapFragment(f -> "TO_BASE64(" + f + ")"); //$NON-NLS-1$ //$NON-NLS-2$ } @Override From 283f0a5f281cdb604e4f637b84111cb800089cee Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Tue, 19 Nov 2024 10:27:56 -0500 Subject: [PATCH 113/289] SelectRenderer should return FragmentAndParameters Many usages of the select renderer are for sub queries - no need to build an intermediate statement provider in those cases. --- .../insert/render/InsertSelectRenderer.java | 8 +++---- .../dynamic/sql/render/RendererFactory.java | 3 ++- .../dynamic/sql/select/SelectModel.java | 9 +++++-- .../select/render/MultiSelectRenderer.java | 16 ++++--------- .../sql/select/render/SelectRenderer.java | 11 ++------- .../render/TableExpressionRenderer.java | 11 ++------- .../sql/update/render/SetPhraseVisitor.java | 24 ++++--------------- .../sql/where/render/CriterionRenderer.java | 14 ++--------- .../where/render/DefaultConditionVisitor.java | 13 ++-------- 9 files changed, 30 insertions(+), 79 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/render/InsertSelectRenderer.java b/src/main/java/org/mybatis/dynamic/sql/insert/render/InsertSelectRenderer.java index 16afe6767..3825d4e3d 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/render/InsertSelectRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/render/InsertSelectRenderer.java @@ -27,7 +27,7 @@ import org.mybatis.dynamic.sql.insert.InsertSelectModel; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.render.RenderingStrategy; -import org.mybatis.dynamic.sql.select.render.SelectStatementProvider; +import org.mybatis.dynamic.sql.util.FragmentAndParameters; import org.mybatis.dynamic.sql.util.StringUtilities; public class InsertSelectRenderer { @@ -43,18 +43,18 @@ private InsertSelectRenderer(Builder builder) { } public InsertSelectStatementProvider render() { - SelectStatementProvider selectStatement = model.selectModel().render(renderingContext); + FragmentAndParameters selectStatement = model.selectModel().render(renderingContext); String statementStart = InsertRenderingUtilities.calculateInsertStatementStart(model.table()); Optional columnsPhrase = calculateColumnsPhrase(); - String renderedSelectStatement = selectStatement.getSelectStatement(); + String renderedSelectStatement = selectStatement.fragment(); String insertStatement = statementStart + columnsPhrase.map(StringUtilities::spaceBefore).orElse("") //$NON-NLS-1$ + spaceBefore(renderedSelectStatement); return DefaultGeneralInsertStatementProvider.withInsertStatement(insertStatement) - .withParameters(selectStatement.getParameters()) + .withParameters(selectStatement.parameters()) .build(); } diff --git a/src/main/java/org/mybatis/dynamic/sql/render/RendererFactory.java b/src/main/java/org/mybatis/dynamic/sql/render/RendererFactory.java index c47ca1f78..0ac97d702 100644 --- a/src/main/java/org/mybatis/dynamic/sql/render/RendererFactory.java +++ b/src/main/java/org/mybatis/dynamic/sql/render/RendererFactory.java @@ -42,6 +42,7 @@ import org.mybatis.dynamic.sql.update.UpdateModel; import org.mybatis.dynamic.sql.update.render.UpdateRenderer; import org.mybatis.dynamic.sql.update.render.UpdateStatementProvider; +import org.mybatis.dynamic.sql.util.FragmentAndParameters; public interface RendererFactory { static Renderer createDeleteRenderer(DeleteModel deleteModel, @@ -105,7 +106,7 @@ static Renderer createMultiSelectRen .render(); } - static Renderer createSelectRenderer( + static Renderer createSelectRenderer( SelectModel selectModel) { return renderingContext -> SelectRenderer.withSelectModel(selectModel) .withRenderingContext(renderingContext) diff --git a/src/main/java/org/mybatis/dynamic/sql/select/SelectModel.java b/src/main/java/org/mybatis/dynamic/sql/select/SelectModel.java index 85196be7b..3dff3162e 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/SelectModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/SelectModel.java @@ -24,7 +24,9 @@ import org.mybatis.dynamic.sql.render.RendererFactory; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.render.RenderingStrategy; +import org.mybatis.dynamic.sql.select.render.DefaultSelectStatementProvider; import org.mybatis.dynamic.sql.select.render.SelectStatementProvider; +import org.mybatis.dynamic.sql.util.FragmentAndParameters; import org.mybatis.dynamic.sql.util.Validator; public class SelectModel extends AbstractSelectModel { @@ -45,7 +47,10 @@ public SelectStatementProvider render(RenderingStrategy renderingStrategy) { RenderingContext renderingContext = RenderingContext.withRenderingStrategy(renderingStrategy) .withStatementConfiguration(statementConfiguration) .build(); - return render(renderingContext); + FragmentAndParameters fragmentAndParameters = render(renderingContext); + return DefaultSelectStatementProvider.withSelectStatement(fragmentAndParameters.fragment()) + .withParameters(fragmentAndParameters.parameters()) + .build(); } /** @@ -55,7 +60,7 @@ public SelectStatementProvider render(RenderingStrategy renderingStrategy) { * @return a rendered select statement and parameters */ @NotNull - public SelectStatementProvider render(RenderingContext renderingContext) { + public FragmentAndParameters render(RenderingContext renderingContext) { return RendererFactory.createSelectRenderer(this).render(renderingContext); } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/MultiSelectRenderer.java b/src/main/java/org/mybatis/dynamic/sql/select/render/MultiSelectRenderer.java index c063e7866..78d6ae8ff 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/render/MultiSelectRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/render/MultiSelectRenderer.java @@ -65,21 +65,13 @@ private SelectStatementProvider toSelectStatementProvider(FragmentCollector frag } private FragmentAndParameters renderSelect(SelectModel selectModel) { - SelectStatementProvider selectStatement = selectModel.render(renderingContext); - - return FragmentAndParameters - .withFragment("(" + selectStatement.getSelectStatement() + ")") //$NON-NLS-1$ //$NON-NLS-2$ - .withParameters(selectStatement.getParameters()) - .build(); + return selectModel.render(renderingContext) + .mapFragment(f -> "(" + f + ")"); //$NON-NLS-1$ //$NON-NLS-2$ } private FragmentAndParameters renderSelect(UnionQuery unionQuery) { - SelectStatementProvider selectStatement = unionQuery.selectModel().render(renderingContext); - - return FragmentAndParameters.withFragment( - unionQuery.connector() + " (" + selectStatement.getSelectStatement() + ")") //$NON-NLS-1$ //$NON-NLS-2$ - .withParameters(selectStatement.getParameters()) - .build(); + return unionQuery.selectModel().render(renderingContext) + .mapFragment(f -> unionQuery.connector() + " (" + f + ")"); //$NON-NLS-1$ //$NON-NLS-2$ } private Optional renderOrderBy() { diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/SelectRenderer.java b/src/main/java/org/mybatis/dynamic/sql/select/render/SelectRenderer.java index 128ab3e8e..25e2e408b 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/render/SelectRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/render/SelectRenderer.java @@ -37,7 +37,7 @@ private SelectRenderer(Builder builder) { renderingContext = Objects.requireNonNull(builder.renderingContext); } - public SelectStatementProvider render() { + public FragmentAndParameters render() { FragmentCollector fragmentCollector = selectModel .queryExpressions() .map(this::renderQueryExpression) @@ -46,14 +46,7 @@ public SelectStatementProvider render() { renderOrderBy().ifPresent(fragmentCollector::add); renderPagingModel().ifPresent(fragmentCollector::add); - return toSelectStatementProvider(fragmentCollector); - } - - private SelectStatementProvider toSelectStatementProvider(FragmentCollector fragmentCollector) { - return DefaultSelectStatementProvider - .withSelectStatement(fragmentCollector.collectFragments(Collectors.joining(" "))) //$NON-NLS-1$ - .withParameters(fragmentCollector.parameters()) - .build(); + return fragmentCollector.toFragmentAndParameters(Collectors.joining(" ")); //$NON-NLS-1$ } private FragmentAndParameters renderQueryExpression(QueryExpressionModel queryExpressionModel) { diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/TableExpressionRenderer.java b/src/main/java/org/mybatis/dynamic/sql/select/render/TableExpressionRenderer.java index ccb9b1d84..3ba013825 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/render/TableExpressionRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/render/TableExpressionRenderer.java @@ -39,15 +39,8 @@ public FragmentAndParameters visit(SqlTable table) { @Override public FragmentAndParameters visit(SubQuery subQuery) { - SelectStatementProvider selectStatement = subQuery.selectModel().render(renderingContext); - - String fragment = "(" + selectStatement.getSelectStatement() + ")"; //$NON-NLS-1$ //$NON-NLS-2$ - - fragment = applyAlias(fragment, subQuery); - - return FragmentAndParameters.withFragment(fragment) - .withParameters(selectStatement.getParameters()) - .build(); + return subQuery.selectModel().render(renderingContext) + .mapFragment(f -> applyAlias("(" + f + ")", subQuery)); //$NON-NLS-1$ //$NON-NLS-2$ } private String applyAlias(String fragment, SubQuery subQuery) { diff --git a/src/main/java/org/mybatis/dynamic/sql/update/render/SetPhraseVisitor.java b/src/main/java/org/mybatis/dynamic/sql/update/render/SetPhraseVisitor.java index 07d955c80..77a898ea2 100644 --- a/src/main/java/org/mybatis/dynamic/sql/update/render/SetPhraseVisitor.java +++ b/src/main/java/org/mybatis/dynamic/sql/update/render/SetPhraseVisitor.java @@ -20,7 +20,6 @@ import org.mybatis.dynamic.sql.render.RenderedParameterInfo; import org.mybatis.dynamic.sql.render.RenderingContext; -import org.mybatis.dynamic.sql.select.render.SelectStatementProvider; import org.mybatis.dynamic.sql.util.AbstractColumnMapping; import org.mybatis.dynamic.sql.util.ColumnToColumnMapping; import org.mybatis.dynamic.sql.util.ConstantMapping; @@ -84,28 +83,15 @@ public Optional visit(ValueWhenPresentMapping mapp @Override public Optional visit(SelectMapping mapping) { - SelectStatementProvider selectStatement = mapping.selectModel().render(renderingContext); - String fragment = renderingContext.aliasedColumnName(mapping.column()) - + " = (" //$NON-NLS-1$ - + selectStatement.getSelectStatement() - + ")"; //$NON-NLS-1$ - - return FragmentAndParameters.withFragment(fragment) - .withParameters(selectStatement.getParameters()) - .buildOptional(); + return Optional.of(mapping.selectModel().render(renderingContext) + .mapFragment(f -> renderingContext.aliasedColumnName(mapping.column()) + + " = (" + f + ")")); //$NON-NLS-1$ //$NON-NLS-2$ } @Override public Optional visit(ColumnToColumnMapping mapping) { - FragmentAndParameters renderedColumn = mapping.rightColumn().render(renderingContext); - - String setPhrase = renderingContext.aliasedColumnName(mapping.column()) - + " = " //$NON-NLS-1$ - + renderedColumn.fragment(); - - return FragmentAndParameters.withFragment(setPhrase) - .withParameters(renderedColumn.parameters()) - .buildOptional(); + return Optional.of(mapping.rightColumn().render(renderingContext) + .mapFragment(f -> renderingContext.aliasedColumnName(mapping.column()) + " = " + f)); //$NON-NLS-1$ } private Optional buildValueFragment(AbstractColumnMapping mapping, T value) { diff --git a/src/main/java/org/mybatis/dynamic/sql/where/render/CriterionRenderer.java b/src/main/java/org/mybatis/dynamic/sql/where/render/CriterionRenderer.java index 0e4325179..f56fc3e79 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/render/CriterionRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/render/CriterionRenderer.java @@ -30,7 +30,6 @@ import org.mybatis.dynamic.sql.SqlCriterion; import org.mybatis.dynamic.sql.SqlCriterionVisitor; import org.mybatis.dynamic.sql.render.RenderingContext; -import org.mybatis.dynamic.sql.select.render.SelectStatementProvider; import org.mybatis.dynamic.sql.util.FragmentAndParameters; import org.mybatis.dynamic.sql.util.FragmentCollector; @@ -120,17 +119,8 @@ private Optional renderColumnAndCondition(ColumnAndCo private FragmentAndParameters renderExists(ExistsCriterion criterion) { ExistsPredicate existsPredicate = criterion.existsPredicate(); - SelectStatementProvider selectStatement = existsPredicate.selectModelBuilder().build().render(renderingContext); - - String fragment = existsPredicate.operator() - + " (" //$NON-NLS-1$ - + selectStatement.getSelectStatement() - + ")"; //$NON-NLS-1$ - - return FragmentAndParameters - .withFragment(fragment) - .withParameters(selectStatement.getParameters()) - .build(); + return existsPredicate.selectModelBuilder().build().render(renderingContext) + .mapFragment(f -> existsPredicate.operator() + " (" + f + ")"); //$NON-NLS-1$ //$NON-NLS-2$ } private List renderSubCriteria(List subCriteria) { diff --git a/src/main/java/org/mybatis/dynamic/sql/where/render/DefaultConditionVisitor.java b/src/main/java/org/mybatis/dynamic/sql/where/render/DefaultConditionVisitor.java index 309a10f3b..6bd518663 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/render/DefaultConditionVisitor.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/render/DefaultConditionVisitor.java @@ -30,7 +30,6 @@ import org.mybatis.dynamic.sql.ConditionVisitor; import org.mybatis.dynamic.sql.render.RenderedParameterInfo; import org.mybatis.dynamic.sql.render.RenderingContext; -import org.mybatis.dynamic.sql.select.render.SelectStatementProvider; import org.mybatis.dynamic.sql.util.FragmentAndParameters; import org.mybatis.dynamic.sql.util.FragmentCollector; @@ -95,16 +94,8 @@ public FragmentAndParameters visit(AbstractTwoValueCondition condition) { @Override public FragmentAndParameters visit(AbstractSubselectCondition condition) { - SelectStatementProvider selectStatement = condition.selectModel().render(renderingContext); - - String finalFragment = condition.operator() - + " (" //$NON-NLS-1$ - + selectStatement.getSelectStatement() - + ")"; //$NON-NLS-1$ - - return FragmentAndParameters.withFragment(finalFragment) - .withParameters(selectStatement.getParameters()) - .build(); + return condition.selectModel().render(renderingContext) + .mapFragment(f -> condition.operator() + " (" + f + ")"); //$NON-NLS-1$ //$NON-NLS-2$ } @Override From d4c3d113321ba6b4ea76b8d2bd8d63240fc96250 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 20 Nov 2024 22:01:20 +0000 Subject: [PATCH 114/289] Update dependency org.mariadb.jdbc:mariadb-java-client to v3.5.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index fc513913c..ab0869db9 100644 --- a/pom.xml +++ b/pom.xml @@ -195,7 +195,7 @@ org.mariadb.jdbc mariadb-java-client - 3.5.0 + 3.5.1 test From fd9f44e35d83b80d222c61b3f52486873edec04b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 20 Nov 2024 22:43:02 +0000 Subject: [PATCH 115/289] Update dependency org.testcontainers:postgresql to v1.20.4 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ab0869db9..441e52cb5 100644 --- a/pom.xml +++ b/pom.xml @@ -78,7 +78,7 @@ src/test/java,src/test/kotlin official - 1.20.3 + 1.20.4 org.mybatis.dynamic.sql.*;version=${project.version};-noimport:=true From 9aab3fabf735945ed9928c4e81c42db240460830 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 14:38:47 +0000 Subject: [PATCH 116/289] Update dependency org.springframework.batch:spring-batch-core to v5.2.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 441e52cb5..d914073b2 100644 --- a/pom.xml +++ b/pom.xml @@ -61,7 +61,7 @@ 17 17 5.11.3 - 5.1.2 + 5.2.0 checkstyle-override.xml From d8f631b1aa9bf04bf6d9e97caa08248c528199f4 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Fri, 22 Nov 2024 10:53:47 -0500 Subject: [PATCH 117/289] Simplify renderer factory --- .../dynamic/sql/delete/DeleteModel.java | 6 +++++- .../sql/delete/render/DeleteRenderer.java | 9 +------- .../sql/insert/GeneralInsertModel.java | 6 +++++- .../dynamic/sql/insert/InsertSelectModel.java | 6 +++++- .../insert/render/GeneralInsertRenderer.java | 9 +------- .../insert/render/InsertSelectRenderer.java | 9 +------- .../dynamic/sql/render/RendererFactory.java | 21 ++++++------------- .../sql/select/AbstractSelectModel.java | 4 ++++ .../dynamic/sql/select/MultiSelectModel.java | 2 +- .../select/render/MultiSelectRenderer.java | 11 ++-------- .../dynamic/sql/update/UpdateModel.java | 6 +++++- .../sql/update/render/UpdateRenderer.java | 9 +------- 12 files changed, 37 insertions(+), 61 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/delete/DeleteModel.java b/src/main/java/org/mybatis/dynamic/sql/delete/DeleteModel.java index 015f9823c..581d2250a 100644 --- a/src/main/java/org/mybatis/dynamic/sql/delete/DeleteModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/delete/DeleteModel.java @@ -65,9 +65,13 @@ public Optional orderByModel() { return Optional.ofNullable(orderByModel); } + public StatementConfiguration statementConfiguration() { + return statementConfiguration; + } + @NotNull public DeleteStatementProvider render(RenderingStrategy renderingStrategy) { - return RendererFactory.createDeleteRenderer(this, statementConfiguration) + return RendererFactory.createDeleteRenderer(this) .render(renderingStrategy); } diff --git a/src/main/java/org/mybatis/dynamic/sql/delete/render/DeleteRenderer.java b/src/main/java/org/mybatis/dynamic/sql/delete/render/DeleteRenderer.java index fa4cd0d28..7b3dbfc97 100644 --- a/src/main/java/org/mybatis/dynamic/sql/delete/render/DeleteRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/delete/render/DeleteRenderer.java @@ -21,7 +21,6 @@ import org.mybatis.dynamic.sql.common.OrderByModel; import org.mybatis.dynamic.sql.common.OrderByRenderer; -import org.mybatis.dynamic.sql.configuration.StatementConfiguration; import org.mybatis.dynamic.sql.delete.DeleteModel; import org.mybatis.dynamic.sql.render.ExplicitTableAliasCalculator; import org.mybatis.dynamic.sql.render.RenderedParameterInfo; @@ -44,7 +43,7 @@ private DeleteRenderer(Builder builder) { renderingContext = RenderingContext .withRenderingStrategy(Objects.requireNonNull(builder.renderingStrategy)) .withTableAliasCalculator(tableAliasCalculator) - .withStatementConfiguration(builder.statementConfiguration) + .withStatementConfiguration(deleteModel.statementConfiguration()) .build(); } @@ -106,7 +105,6 @@ public static Builder withDeleteModel(DeleteModel deleteModel) { public static class Builder { private DeleteModel deleteModel; private RenderingStrategy renderingStrategy; - private StatementConfiguration statementConfiguration; public Builder withDeleteModel(DeleteModel deleteModel) { this.deleteModel = deleteModel; @@ -118,11 +116,6 @@ public Builder withRenderingStrategy(RenderingStrategy renderingStrategy) { return this; } - public Builder withStatementConfiguration(StatementConfiguration statementConfiguration) { - this.statementConfiguration = statementConfiguration; - return this; - } - public DeleteRenderer build() { return new DeleteRenderer(this); } diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/GeneralInsertModel.java b/src/main/java/org/mybatis/dynamic/sql/insert/GeneralInsertModel.java index f3fb146ee..955d5fe7c 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/GeneralInsertModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/GeneralInsertModel.java @@ -50,9 +50,13 @@ public SqlTable table() { return table; } + public StatementConfiguration statementConfiguration() { + return statementConfiguration; + } + @NotNull public GeneralInsertStatementProvider render(RenderingStrategy renderingStrategy) { - return RendererFactory.createGeneralInsertRenderer(this, statementConfiguration) + return RendererFactory.createGeneralInsertRenderer(this) .render(renderingStrategy); } diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/InsertSelectModel.java b/src/main/java/org/mybatis/dynamic/sql/insert/InsertSelectModel.java index 5b22eaeb7..37df5e10e 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/InsertSelectModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/InsertSelectModel.java @@ -51,9 +51,13 @@ public Optional columnList() { return Optional.ofNullable(columnList); } + public StatementConfiguration statementConfiguration() { + return statementConfiguration; + } + @NotNull public InsertSelectStatementProvider render(RenderingStrategy renderingStrategy) { - return RendererFactory.createInsertSelectRenderer(this, statementConfiguration) + return RendererFactory.createInsertSelectRenderer(this) .render(renderingStrategy); } diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/render/GeneralInsertRenderer.java b/src/main/java/org/mybatis/dynamic/sql/insert/render/GeneralInsertRenderer.java index c5378b493..de91037a6 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/render/GeneralInsertRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/render/GeneralInsertRenderer.java @@ -18,7 +18,6 @@ import java.util.Objects; import java.util.Optional; -import org.mybatis.dynamic.sql.configuration.StatementConfiguration; import org.mybatis.dynamic.sql.insert.GeneralInsertModel; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.render.RenderingStrategy; @@ -32,7 +31,7 @@ public class GeneralInsertRenderer { private GeneralInsertRenderer(Builder builder) { model = Objects.requireNonNull(builder.model); RenderingContext renderingContext = RenderingContext.withRenderingStrategy(builder.renderingStrategy) - .withStatementConfiguration(builder.statementConfiguration) + .withStatementConfiguration(model.statementConfiguration()) .build(); visitor = new GeneralInsertValuePhraseVisitor(renderingContext); } @@ -59,7 +58,6 @@ public static Builder withInsertModel(GeneralInsertModel model) { public static class Builder { private GeneralInsertModel model; private RenderingStrategy renderingStrategy; - private StatementConfiguration statementConfiguration; public Builder withInsertModel(GeneralInsertModel model) { this.model = model; @@ -71,11 +69,6 @@ public Builder withRenderingStrategy(RenderingStrategy renderingStrategy) { return this; } - public Builder withStatementConfiguration(StatementConfiguration statementConfiguration) { - this.statementConfiguration = statementConfiguration; - return this; - } - public GeneralInsertRenderer build() { return new GeneralInsertRenderer(this); } diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/render/InsertSelectRenderer.java b/src/main/java/org/mybatis/dynamic/sql/insert/render/InsertSelectRenderer.java index 3825d4e3d..77adaa0df 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/render/InsertSelectRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/render/InsertSelectRenderer.java @@ -22,7 +22,6 @@ import java.util.stream.Collectors; import org.mybatis.dynamic.sql.SqlColumn; -import org.mybatis.dynamic.sql.configuration.StatementConfiguration; import org.mybatis.dynamic.sql.insert.InsertColumnListModel; import org.mybatis.dynamic.sql.insert.InsertSelectModel; import org.mybatis.dynamic.sql.render.RenderingContext; @@ -38,7 +37,7 @@ public class InsertSelectRenderer { private InsertSelectRenderer(Builder builder) { model = Objects.requireNonNull(builder.model); renderingContext = RenderingContext.withRenderingStrategy(builder.renderingStrategy) - .withStatementConfiguration(builder.statementConfiguration) + .withStatementConfiguration(model.statementConfiguration()) .build(); } @@ -75,7 +74,6 @@ public static Builder withInsertSelectModel(InsertSelectModel model) { public static class Builder { private InsertSelectModel model; private RenderingStrategy renderingStrategy; - private StatementConfiguration statementConfiguration; public Builder withInsertSelectModel(InsertSelectModel model) { this.model = model; @@ -87,11 +85,6 @@ public Builder withRenderingStrategy(RenderingStrategy renderingStrategy) { return this; } - public Builder withStatementConfiguration(StatementConfiguration statementConfiguration) { - this.statementConfiguration = statementConfiguration; - return this; - } - public InsertSelectRenderer build() { return new InsertSelectRenderer(this); } diff --git a/src/main/java/org/mybatis/dynamic/sql/render/RendererFactory.java b/src/main/java/org/mybatis/dynamic/sql/render/RendererFactory.java index 0ac97d702..edf6e71a2 100644 --- a/src/main/java/org/mybatis/dynamic/sql/render/RendererFactory.java +++ b/src/main/java/org/mybatis/dynamic/sql/render/RendererFactory.java @@ -15,7 +15,6 @@ */ package org.mybatis.dynamic.sql.render; -import org.mybatis.dynamic.sql.configuration.StatementConfiguration; import org.mybatis.dynamic.sql.delete.DeleteModel; import org.mybatis.dynamic.sql.delete.render.DeleteRenderer; import org.mybatis.dynamic.sql.delete.render.DeleteStatementProvider; @@ -45,10 +44,8 @@ import org.mybatis.dynamic.sql.util.FragmentAndParameters; public interface RendererFactory { - static Renderer createDeleteRenderer(DeleteModel deleteModel, - StatementConfiguration statementConfiguration) { + static Renderer createDeleteRenderer(DeleteModel deleteModel) { return renderingStrategy -> DeleteRenderer.withDeleteModel(deleteModel) - .withStatementConfiguration(statementConfiguration) .withRenderingStrategy(renderingStrategy) .build() .render(); @@ -63,9 +60,8 @@ static Renderer> createBatchInsertRenderer } static Renderer createGeneralInsertRenderer( - GeneralInsertModel generalInsertModel, StatementConfiguration statementConfiguration) { + GeneralInsertModel generalInsertModel) { return renderingStrategy -> GeneralInsertRenderer.withInsertModel(generalInsertModel) - .withStatementConfiguration(statementConfiguration) .withRenderingStrategy(renderingStrategy) .build() .render(); @@ -80,9 +76,8 @@ static Renderer> createInsertR } static Renderer createInsertSelectRenderer( - InsertSelectModel insertSelectModel, StatementConfiguration statementConfiguration) { + InsertSelectModel insertSelectModel) { return renderingStrategy -> InsertSelectRenderer.withInsertSelectModel(insertSelectModel) - .withStatementConfiguration(statementConfiguration) .withRenderingStrategy(renderingStrategy) .build() .render(); @@ -97,27 +92,23 @@ static Renderer> creat } static Renderer createMultiSelectRenderer( - MultiSelectModel multiSelectModel, StatementConfiguration statementConfiguration) { + MultiSelectModel multiSelectModel) { return renderingStrategy -> new MultiSelectRenderer.Builder() .withMultiSelectModel(multiSelectModel) - .withStatementConfiguration(statementConfiguration) .withRenderingStrategy(renderingStrategy) .build() .render(); } - static Renderer createSelectRenderer( - SelectModel selectModel) { + static Renderer createSelectRenderer(SelectModel selectModel) { return renderingContext -> SelectRenderer.withSelectModel(selectModel) .withRenderingContext(renderingContext) .build() .render(); } - static Renderer createUpdateRenderer( - UpdateModel updateModel, StatementConfiguration statementConfiguration) { + static Renderer createUpdateRenderer(UpdateModel updateModel) { return renderingStrategy -> UpdateRenderer.withUpdateModel(updateModel) - .withStatementConfiguration(statementConfiguration) .withRenderingStrategy(renderingStrategy) .build() .render(); diff --git a/src/main/java/org/mybatis/dynamic/sql/select/AbstractSelectModel.java b/src/main/java/org/mybatis/dynamic/sql/select/AbstractSelectModel.java index 49c20789f..8fc3fb898 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/AbstractSelectModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/AbstractSelectModel.java @@ -40,6 +40,10 @@ public Optional pagingModel() { return Optional.ofNullable(pagingModel); } + public StatementConfiguration statementConfiguration() { + return statementConfiguration; + } + public abstract static class AbstractBuilder> { private OrderByModel orderByModel; private PagingModel pagingModel; diff --git a/src/main/java/org/mybatis/dynamic/sql/select/MultiSelectModel.java b/src/main/java/org/mybatis/dynamic/sql/select/MultiSelectModel.java index 607378c20..443a42c56 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/MultiSelectModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/MultiSelectModel.java @@ -47,7 +47,7 @@ public Stream unionQueries() { @NotNull public SelectStatementProvider render(RenderingStrategy renderingStrategy) { - return RendererFactory.createMultiSelectRenderer(this, statementConfiguration) + return RendererFactory.createMultiSelectRenderer(this) .render(renderingStrategy); } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/MultiSelectRenderer.java b/src/main/java/org/mybatis/dynamic/sql/select/render/MultiSelectRenderer.java index 78d6ae8ff..9eb11e84a 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/render/MultiSelectRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/render/MultiSelectRenderer.java @@ -21,7 +21,6 @@ import org.mybatis.dynamic.sql.common.OrderByModel; import org.mybatis.dynamic.sql.common.OrderByRenderer; -import org.mybatis.dynamic.sql.configuration.StatementConfiguration; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.render.RenderingStrategy; import org.mybatis.dynamic.sql.select.MultiSelectModel; @@ -36,11 +35,11 @@ public class MultiSelectRenderer { private final RenderingContext renderingContext; private MultiSelectRenderer(Builder builder) { + multiSelectModel = Objects.requireNonNull(builder.multiSelectModel); renderingContext = RenderingContext .withRenderingStrategy(builder.renderingStrategy) - .withStatementConfiguration(builder.statementConfiguration) + .withStatementConfiguration(multiSelectModel.statementConfiguration()) .build(); - multiSelectModel = Objects.requireNonNull(builder.multiSelectModel); } public SelectStatementProvider render() { @@ -97,7 +96,6 @@ private FragmentAndParameters renderPagingModel(PagingModel pagingModel) { public static class Builder { private RenderingStrategy renderingStrategy; private MultiSelectModel multiSelectModel; - private StatementConfiguration statementConfiguration; public Builder withRenderingStrategy(RenderingStrategy renderingStrategy) { this.renderingStrategy = renderingStrategy; @@ -109,11 +107,6 @@ public Builder withMultiSelectModel(MultiSelectModel multiSelectModel) { return this; } - public Builder withStatementConfiguration(StatementConfiguration statementConfiguration) { - this.statementConfiguration = statementConfiguration; - return this; - } - public MultiSelectRenderer build() { return new MultiSelectRenderer(this); } diff --git a/src/main/java/org/mybatis/dynamic/sql/update/UpdateModel.java b/src/main/java/org/mybatis/dynamic/sql/update/UpdateModel.java index 672b08c44..f4ad201e5 100644 --- a/src/main/java/org/mybatis/dynamic/sql/update/UpdateModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/update/UpdateModel.java @@ -77,9 +77,13 @@ public Optional orderByModel() { return Optional.ofNullable(orderByModel); } + public StatementConfiguration statementConfiguration() { + return statementConfiguration; + } + @NotNull public UpdateStatementProvider render(RenderingStrategy renderingStrategy) { - return RendererFactory.createUpdateRenderer(this, statementConfiguration) + return RendererFactory.createUpdateRenderer(this) .render(renderingStrategy); } diff --git a/src/main/java/org/mybatis/dynamic/sql/update/render/UpdateRenderer.java b/src/main/java/org/mybatis/dynamic/sql/update/render/UpdateRenderer.java index 352c1de7a..3af6aa6d2 100644 --- a/src/main/java/org/mybatis/dynamic/sql/update/render/UpdateRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/update/render/UpdateRenderer.java @@ -22,7 +22,6 @@ import org.mybatis.dynamic.sql.common.OrderByModel; import org.mybatis.dynamic.sql.common.OrderByRenderer; -import org.mybatis.dynamic.sql.configuration.StatementConfiguration; import org.mybatis.dynamic.sql.render.ExplicitTableAliasCalculator; import org.mybatis.dynamic.sql.render.RenderedParameterInfo; import org.mybatis.dynamic.sql.render.RenderingContext; @@ -47,7 +46,7 @@ private UpdateRenderer(Builder builder) { renderingContext = RenderingContext .withRenderingStrategy(Objects.requireNonNull(builder.renderingStrategy)) .withTableAliasCalculator(tableAliasCalculator) - .withStatementConfiguration(builder.statementConfiguration) + .withStatementConfiguration(updateModel.statementConfiguration()) .build(); visitor = new SetPhraseVisitor(renderingContext); } @@ -131,7 +130,6 @@ public static Builder withUpdateModel(UpdateModel updateModel) { public static class Builder { private UpdateModel updateModel; private RenderingStrategy renderingStrategy; - private StatementConfiguration statementConfiguration; public Builder withUpdateModel(UpdateModel updateModel) { this.updateModel = updateModel; @@ -143,11 +141,6 @@ public Builder withRenderingStrategy(RenderingStrategy renderingStrategy) { return this; } - public Builder withStatementConfiguration(StatementConfiguration statementConfiguration) { - this.statementConfiguration = statementConfiguration; - return this; - } - public UpdateRenderer build() { return new UpdateRenderer(this); } From 1321973a0e3ce80bc689d251582786471bdcd8cf Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Fri, 22 Nov 2024 13:12:01 -0500 Subject: [PATCH 118/289] Make an explicit subquery renderer --- .../insert/render/InsertSelectRenderer.java | 2 +- .../dynamic/sql/render/RendererFactory.java | 12 ++- .../dynamic/sql/select/SelectModel.java | 13 +-- .../select/render/MultiSelectRenderer.java | 4 +- .../sql/select/render/SelectRenderer.java | 62 +++-------- .../sql/select/render/SubQueryRenderer.java | 101 ++++++++++++++++++ .../render/TableExpressionRenderer.java | 2 +- .../sql/update/render/SetPhraseVisitor.java | 2 +- .../sql/where/render/CriterionRenderer.java | 2 +- .../where/render/DefaultConditionVisitor.java | 2 +- 10 files changed, 135 insertions(+), 67 deletions(-) create mode 100644 src/main/java/org/mybatis/dynamic/sql/select/render/SubQueryRenderer.java diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/render/InsertSelectRenderer.java b/src/main/java/org/mybatis/dynamic/sql/insert/render/InsertSelectRenderer.java index 77adaa0df..eb53e333b 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/render/InsertSelectRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/render/InsertSelectRenderer.java @@ -42,7 +42,7 @@ private InsertSelectRenderer(Builder builder) { } public InsertSelectStatementProvider render() { - FragmentAndParameters selectStatement = model.selectModel().render(renderingContext); + FragmentAndParameters selectStatement = model.selectModel().renderSubQuery(renderingContext); String statementStart = InsertRenderingUtilities.calculateInsertStatementStart(model.table()); Optional columnsPhrase = calculateColumnsPhrase(); diff --git a/src/main/java/org/mybatis/dynamic/sql/render/RendererFactory.java b/src/main/java/org/mybatis/dynamic/sql/render/RendererFactory.java index edf6e71a2..380585358 100644 --- a/src/main/java/org/mybatis/dynamic/sql/render/RendererFactory.java +++ b/src/main/java/org/mybatis/dynamic/sql/render/RendererFactory.java @@ -38,6 +38,7 @@ import org.mybatis.dynamic.sql.select.render.MultiSelectRenderer; import org.mybatis.dynamic.sql.select.render.SelectRenderer; import org.mybatis.dynamic.sql.select.render.SelectStatementProvider; +import org.mybatis.dynamic.sql.select.render.SubQueryRenderer; import org.mybatis.dynamic.sql.update.UpdateModel; import org.mybatis.dynamic.sql.update.render.UpdateRenderer; import org.mybatis.dynamic.sql.update.render.UpdateStatementProvider; @@ -100,8 +101,15 @@ static Renderer createMultiSelectRen .render(); } - static Renderer createSelectRenderer(SelectModel selectModel) { - return renderingContext -> SelectRenderer.withSelectModel(selectModel) + static Renderer createSelectRenderer(SelectModel selectModel) { + return renderingStrategy -> SelectRenderer.withSelectModel(selectModel) + .withRenderingStrategy(renderingStrategy) + .build() + .render(); + } + + static Renderer createSubQueryRenderer(SelectModel selectModel) { + return renderingContext -> SubQueryRenderer.withSelectModel(selectModel) .withRenderingContext(renderingContext) .build() .render(); diff --git a/src/main/java/org/mybatis/dynamic/sql/select/SelectModel.java b/src/main/java/org/mybatis/dynamic/sql/select/SelectModel.java index 3dff3162e..ae9e9027f 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/SelectModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/SelectModel.java @@ -24,7 +24,6 @@ import org.mybatis.dynamic.sql.render.RendererFactory; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.render.RenderingStrategy; -import org.mybatis.dynamic.sql.select.render.DefaultSelectStatementProvider; import org.mybatis.dynamic.sql.select.render.SelectStatementProvider; import org.mybatis.dynamic.sql.util.FragmentAndParameters; import org.mybatis.dynamic.sql.util.Validator; @@ -44,13 +43,7 @@ public Stream queryExpressions() { @NotNull public SelectStatementProvider render(RenderingStrategy renderingStrategy) { - RenderingContext renderingContext = RenderingContext.withRenderingStrategy(renderingStrategy) - .withStatementConfiguration(statementConfiguration) - .build(); - FragmentAndParameters fragmentAndParameters = render(renderingContext); - return DefaultSelectStatementProvider.withSelectStatement(fragmentAndParameters.fragment()) - .withParameters(fragmentAndParameters.parameters()) - .build(); + return RendererFactory.createSelectRenderer(this).render(renderingStrategy); } /** @@ -60,8 +53,8 @@ public SelectStatementProvider render(RenderingStrategy renderingStrategy) { * @return a rendered select statement and parameters */ @NotNull - public FragmentAndParameters render(RenderingContext renderingContext) { - return RendererFactory.createSelectRenderer(this).render(renderingContext); + public FragmentAndParameters renderSubQuery(RenderingContext renderingContext) { + return RendererFactory.createSubQueryRenderer(this).render(renderingContext); } public static Builder withQueryExpressions(List queryExpressions) { diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/MultiSelectRenderer.java b/src/main/java/org/mybatis/dynamic/sql/select/render/MultiSelectRenderer.java index 9eb11e84a..b90c8d6cb 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/render/MultiSelectRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/render/MultiSelectRenderer.java @@ -64,12 +64,12 @@ private SelectStatementProvider toSelectStatementProvider(FragmentCollector frag } private FragmentAndParameters renderSelect(SelectModel selectModel) { - return selectModel.render(renderingContext) + return selectModel.renderSubQuery(renderingContext) .mapFragment(f -> "(" + f + ")"); //$NON-NLS-1$ //$NON-NLS-2$ } private FragmentAndParameters renderSelect(UnionQuery unionQuery) { - return unionQuery.selectModel().render(renderingContext) + return unionQuery.selectModel().renderSubQuery(renderingContext) .mapFragment(f -> unionQuery.connector() + " (" + f + ")"); //$NON-NLS-1$ //$NON-NLS-2$ } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/SelectRenderer.java b/src/main/java/org/mybatis/dynamic/sql/select/render/SelectRenderer.java index 25e2e408b..76617f038 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/render/SelectRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/render/SelectRenderer.java @@ -16,17 +16,12 @@ package org.mybatis.dynamic.sql.select.render; import java.util.Objects; -import java.util.Optional; -import java.util.stream.Collectors; -import org.mybatis.dynamic.sql.common.OrderByModel; -import org.mybatis.dynamic.sql.common.OrderByRenderer; +import org.mybatis.dynamic.sql.render.RendererFactory; import org.mybatis.dynamic.sql.render.RenderingContext; -import org.mybatis.dynamic.sql.select.PagingModel; -import org.mybatis.dynamic.sql.select.QueryExpressionModel; +import org.mybatis.dynamic.sql.render.RenderingStrategy; import org.mybatis.dynamic.sql.select.SelectModel; import org.mybatis.dynamic.sql.util.FragmentAndParameters; -import org.mybatis.dynamic.sql.util.FragmentCollector; public class SelectRenderer { private final SelectModel selectModel; @@ -34,46 +29,17 @@ public class SelectRenderer { private SelectRenderer(Builder builder) { selectModel = Objects.requireNonNull(builder.selectModel); - renderingContext = Objects.requireNonNull(builder.renderingContext); + renderingContext = RenderingContext.withRenderingStrategy(builder.renderingStrategy) + .withStatementConfiguration(selectModel.statementConfiguration()) + .build(); } - public FragmentAndParameters render() { - FragmentCollector fragmentCollector = selectModel - .queryExpressions() - .map(this::renderQueryExpression) - .collect(FragmentCollector.collect()); - - renderOrderBy().ifPresent(fragmentCollector::add); - renderPagingModel().ifPresent(fragmentCollector::add); - - return fragmentCollector.toFragmentAndParameters(Collectors.joining(" ")); //$NON-NLS-1$ - } - - private FragmentAndParameters renderQueryExpression(QueryExpressionModel queryExpressionModel) { - return QueryExpressionRenderer.withQueryExpression(queryExpressionModel) - .withRenderingContext(renderingContext) - .build() - .render(); - } - - private Optional renderOrderBy() { - return selectModel.orderByModel().map(this::renderOrderBy); - } - - private FragmentAndParameters renderOrderBy(OrderByModel orderByModel) { - return new OrderByRenderer(renderingContext).render(orderByModel); - } - - private Optional renderPagingModel() { - return selectModel.pagingModel().map(this::renderPagingModel); - } - - private FragmentAndParameters renderPagingModel(PagingModel pagingModel) { - return new PagingModelRenderer.Builder() - .withPagingModel(pagingModel) - .withRenderingContext(renderingContext) - .build() - .render(); + public SelectStatementProvider render() { + FragmentAndParameters fragmentAndParameters = RendererFactory.createSubQueryRenderer(selectModel) + .render(renderingContext); + return DefaultSelectStatementProvider.withSelectStatement(fragmentAndParameters.fragment()) + .withParameters(fragmentAndParameters.parameters()) + .build(); } public static Builder withSelectModel(SelectModel selectModel) { @@ -82,10 +48,10 @@ public static Builder withSelectModel(SelectModel selectModel) { public static class Builder { private SelectModel selectModel; - private RenderingContext renderingContext; + private RenderingStrategy renderingStrategy; - public Builder withRenderingContext(RenderingContext renderingContext) { - this.renderingContext = renderingContext; + public Builder withRenderingStrategy(RenderingStrategy renderingStrategy) { + this.renderingStrategy = renderingStrategy; return this; } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/SubQueryRenderer.java b/src/main/java/org/mybatis/dynamic/sql/select/render/SubQueryRenderer.java new file mode 100644 index 000000000..013cae505 --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/select/render/SubQueryRenderer.java @@ -0,0 +1,101 @@ +/* + * Copyright 2016-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mybatis.dynamic.sql.select.render; + +import org.mybatis.dynamic.sql.common.OrderByModel; +import org.mybatis.dynamic.sql.common.OrderByRenderer; +import org.mybatis.dynamic.sql.render.RenderingContext; +import org.mybatis.dynamic.sql.select.PagingModel; +import org.mybatis.dynamic.sql.select.QueryExpressionModel; +import org.mybatis.dynamic.sql.select.SelectModel; +import org.mybatis.dynamic.sql.util.FragmentAndParameters; +import org.mybatis.dynamic.sql.util.FragmentCollector; + +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; + +public class SubQueryRenderer { + private final SelectModel selectModel; + private final RenderingContext renderingContext; + + private SubQueryRenderer(Builder builder) { + selectModel = Objects.requireNonNull(builder.selectModel); + renderingContext = Objects.requireNonNull(builder.renderingContext); + } + + public FragmentAndParameters render() { + FragmentCollector fragmentCollector = selectModel + .queryExpressions() + .map(this::renderQueryExpression) + .collect(FragmentCollector.collect()); + + renderOrderBy().ifPresent(fragmentCollector::add); + renderPagingModel().ifPresent(fragmentCollector::add); + + return fragmentCollector.toFragmentAndParameters(Collectors.joining(" ")); //$NON-NLS-1$ + } + + private FragmentAndParameters renderQueryExpression(QueryExpressionModel queryExpressionModel) { + return QueryExpressionRenderer.withQueryExpression(queryExpressionModel) + .withRenderingContext(renderingContext) + .build() + .render(); + } + + private Optional renderOrderBy() { + return selectModel.orderByModel().map(this::renderOrderBy); + } + + private FragmentAndParameters renderOrderBy(OrderByModel orderByModel) { + return new OrderByRenderer(renderingContext).render(orderByModel); + } + + private Optional renderPagingModel() { + return selectModel.pagingModel().map(this::renderPagingModel); + } + + private FragmentAndParameters renderPagingModel(PagingModel pagingModel) { + return new PagingModelRenderer.Builder() + .withPagingModel(pagingModel) + .withRenderingContext(renderingContext) + .build() + .render(); + } + + public static Builder withSelectModel(SelectModel selectModel) { + return new Builder().withSelectModel(selectModel); + } + + public static class Builder { + private SelectModel selectModel; + private RenderingContext renderingContext; + + public Builder withRenderingContext(RenderingContext renderingContext) { + this.renderingContext = renderingContext; + return this; + } + + public Builder withSelectModel(SelectModel selectModel) { + this.selectModel = selectModel; + return this; + } + + public SubQueryRenderer build() { + return new SubQueryRenderer(this); + } + } +} diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/TableExpressionRenderer.java b/src/main/java/org/mybatis/dynamic/sql/select/render/TableExpressionRenderer.java index 3ba013825..0448a2396 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/render/TableExpressionRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/render/TableExpressionRenderer.java @@ -39,7 +39,7 @@ public FragmentAndParameters visit(SqlTable table) { @Override public FragmentAndParameters visit(SubQuery subQuery) { - return subQuery.selectModel().render(renderingContext) + return subQuery.selectModel().renderSubQuery(renderingContext) .mapFragment(f -> applyAlias("(" + f + ")", subQuery)); //$NON-NLS-1$ //$NON-NLS-2$ } diff --git a/src/main/java/org/mybatis/dynamic/sql/update/render/SetPhraseVisitor.java b/src/main/java/org/mybatis/dynamic/sql/update/render/SetPhraseVisitor.java index 77a898ea2..dd3d6ed78 100644 --- a/src/main/java/org/mybatis/dynamic/sql/update/render/SetPhraseVisitor.java +++ b/src/main/java/org/mybatis/dynamic/sql/update/render/SetPhraseVisitor.java @@ -83,7 +83,7 @@ public Optional visit(ValueWhenPresentMapping mapp @Override public Optional visit(SelectMapping mapping) { - return Optional.of(mapping.selectModel().render(renderingContext) + return Optional.of(mapping.selectModel().renderSubQuery(renderingContext) .mapFragment(f -> renderingContext.aliasedColumnName(mapping.column()) + " = (" + f + ")")); //$NON-NLS-1$ //$NON-NLS-2$ } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/render/CriterionRenderer.java b/src/main/java/org/mybatis/dynamic/sql/where/render/CriterionRenderer.java index f56fc3e79..f19a6b340 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/render/CriterionRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/render/CriterionRenderer.java @@ -119,7 +119,7 @@ private Optional renderColumnAndCondition(ColumnAndCo private FragmentAndParameters renderExists(ExistsCriterion criterion) { ExistsPredicate existsPredicate = criterion.existsPredicate(); - return existsPredicate.selectModelBuilder().build().render(renderingContext) + return existsPredicate.selectModelBuilder().build().renderSubQuery(renderingContext) .mapFragment(f -> existsPredicate.operator() + " (" + f + ")"); //$NON-NLS-1$ //$NON-NLS-2$ } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/render/DefaultConditionVisitor.java b/src/main/java/org/mybatis/dynamic/sql/where/render/DefaultConditionVisitor.java index 6bd518663..debb4d9c8 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/render/DefaultConditionVisitor.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/render/DefaultConditionVisitor.java @@ -94,7 +94,7 @@ public FragmentAndParameters visit(AbstractTwoValueCondition condition) { @Override public FragmentAndParameters visit(AbstractSubselectCondition condition) { - return condition.selectModel().render(renderingContext) + return condition.selectModel().renderSubQuery(renderingContext) .mapFragment(f -> condition.operator() + " (" + f + ")"); //$NON-NLS-1$ //$NON-NLS-2$ } From de7d595b62e0a576043512013ff7e982092637ea Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Fri, 22 Nov 2024 14:17:40 -0500 Subject: [PATCH 119/289] Use the subquery renderer directly - less garbage --- .../insert/render/InsertSelectRenderer.java | 27 +++++++++---------- .../dynamic/sql/render/RendererFactory.java | 8 ++++++ .../dynamic/sql/select/SelectModel.java | 13 --------- .../select/render/MultiSelectRenderer.java | 13 ++++++--- .../sql/select/render/SubQueryRenderer.java | 13 ++++++++- .../render/TableExpressionRenderer.java | 14 ++++------ .../sql/update/render/SetPhraseVisitor.java | 10 ++++--- .../sql/where/render/CriterionRenderer.java | 8 +++--- .../where/render/DefaultConditionVisitor.java | 7 +++-- 9 files changed, 63 insertions(+), 50 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/render/InsertSelectRenderer.java b/src/main/java/org/mybatis/dynamic/sql/insert/render/InsertSelectRenderer.java index eb53e333b..fb3b37503 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/render/InsertSelectRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/render/InsertSelectRenderer.java @@ -15,19 +15,18 @@ */ package org.mybatis.dynamic.sql.insert.render; -import static org.mybatis.dynamic.sql.util.StringUtilities.spaceBefore; +import static org.mybatis.dynamic.sql.util.StringUtilities.spaceAfter; import java.util.Objects; -import java.util.Optional; import java.util.stream.Collectors; import org.mybatis.dynamic.sql.SqlColumn; import org.mybatis.dynamic.sql.insert.InsertColumnListModel; import org.mybatis.dynamic.sql.insert.InsertSelectModel; +import org.mybatis.dynamic.sql.render.RendererFactory; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.render.RenderingStrategy; import org.mybatis.dynamic.sql.util.FragmentAndParameters; -import org.mybatis.dynamic.sql.util.StringUtilities; public class InsertSelectRenderer { @@ -42,29 +41,27 @@ private InsertSelectRenderer(Builder builder) { } public InsertSelectStatementProvider render() { - FragmentAndParameters selectStatement = model.selectModel().renderSubQuery(renderingContext); - String statementStart = InsertRenderingUtilities.calculateInsertStatementStart(model.table()); - Optional columnsPhrase = calculateColumnsPhrase(); - String renderedSelectStatement = selectStatement.fragment(); + String columnsPhrase = calculateColumnsPhrase(); + String prefix = statementStart + spaceAfter(columnsPhrase); - String insertStatement = statementStart - + columnsPhrase.map(StringUtilities::spaceBefore).orElse("") //$NON-NLS-1$ - + spaceBefore(renderedSelectStatement); + FragmentAndParameters fragmentAndParameters = RendererFactory.createSubQueryRenderer(model.selectModel(), + prefix, "") //$NON-NLS-1$ + .render(renderingContext); - return DefaultGeneralInsertStatementProvider.withInsertStatement(insertStatement) - .withParameters(selectStatement.parameters()) + return DefaultGeneralInsertStatementProvider.withInsertStatement(fragmentAndParameters.fragment()) + .withParameters(fragmentAndParameters.parameters()) .build(); } - private Optional calculateColumnsPhrase() { - return model.columnList().map(this::calculateColumnsPhrase); + private String calculateColumnsPhrase() { + return model.columnList().map(this::calculateColumnsPhrase).orElse(""); //$NON-NLS-1$ } private String calculateColumnsPhrase(InsertColumnListModel columnList) { return columnList.columns() .map(SqlColumn::name) - .collect(Collectors.joining(", ", "(", ")")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + .collect(Collectors.joining(", ", " (", ")")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } public static Builder withInsertSelectModel(InsertSelectModel model) { diff --git a/src/main/java/org/mybatis/dynamic/sql/render/RendererFactory.java b/src/main/java/org/mybatis/dynamic/sql/render/RendererFactory.java index 380585358..2b7b2e945 100644 --- a/src/main/java/org/mybatis/dynamic/sql/render/RendererFactory.java +++ b/src/main/java/org/mybatis/dynamic/sql/render/RendererFactory.java @@ -115,6 +115,14 @@ static Renderer createSubQueryRenderer( .render(); } + static Renderer createSubQueryRenderer(SelectModel selectModel, + String prefix, String suffix) { + return renderingContext -> SubQueryRenderer.withSelectModel(selectModel) + .withRenderingContext(renderingContext) + .build() + .render(prefix, suffix); + } + static Renderer createUpdateRenderer(UpdateModel updateModel) { return renderingStrategy -> UpdateRenderer.withUpdateModel(updateModel) .withRenderingStrategy(renderingStrategy) diff --git a/src/main/java/org/mybatis/dynamic/sql/select/SelectModel.java b/src/main/java/org/mybatis/dynamic/sql/select/SelectModel.java index ae9e9027f..14225147f 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/SelectModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/SelectModel.java @@ -22,10 +22,8 @@ import org.jetbrains.annotations.NotNull; import org.mybatis.dynamic.sql.render.RendererFactory; -import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.render.RenderingStrategy; import org.mybatis.dynamic.sql.select.render.SelectStatementProvider; -import org.mybatis.dynamic.sql.util.FragmentAndParameters; import org.mybatis.dynamic.sql.util.Validator; public class SelectModel extends AbstractSelectModel { @@ -46,17 +44,6 @@ public SelectStatementProvider render(RenderingStrategy renderingStrategy) { return RendererFactory.createSelectRenderer(this).render(renderingStrategy); } - /** - * This version is for rendering sub-queries, union queries, etc. - * - * @param renderingContext the rendering context - * @return a rendered select statement and parameters - */ - @NotNull - public FragmentAndParameters renderSubQuery(RenderingContext renderingContext) { - return RendererFactory.createSubQueryRenderer(this).render(renderingContext); - } - public static Builder withQueryExpressions(List queryExpressions) { return new Builder().withQueryExpressions(queryExpressions); } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/MultiSelectRenderer.java b/src/main/java/org/mybatis/dynamic/sql/select/render/MultiSelectRenderer.java index b90c8d6cb..4fe0b7e92 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/render/MultiSelectRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/render/MultiSelectRenderer.java @@ -21,6 +21,7 @@ import org.mybatis.dynamic.sql.common.OrderByModel; import org.mybatis.dynamic.sql.common.OrderByRenderer; +import org.mybatis.dynamic.sql.render.RendererFactory; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.render.RenderingStrategy; import org.mybatis.dynamic.sql.select.MultiSelectModel; @@ -64,13 +65,17 @@ private SelectStatementProvider toSelectStatementProvider(FragmentCollector frag } private FragmentAndParameters renderSelect(SelectModel selectModel) { - return selectModel.renderSubQuery(renderingContext) - .mapFragment(f -> "(" + f + ")"); //$NON-NLS-1$ //$NON-NLS-2$ + return RendererFactory.createSubQueryRenderer(selectModel, + "(", //$NON-NLS-1$ + ")") //$NON-NLS-1$ + .render(renderingContext); } private FragmentAndParameters renderSelect(UnionQuery unionQuery) { - return unionQuery.selectModel().renderSubQuery(renderingContext) - .mapFragment(f -> unionQuery.connector() + " (" + f + ")"); //$NON-NLS-1$ //$NON-NLS-2$ + return RendererFactory.createSubQueryRenderer(unionQuery.selectModel(), + unionQuery.connector() + " (", //$NON-NLS-1$ + ")") //$NON-NLS-1$ + .render(renderingContext); } private Optional renderOrderBy() { diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/SubQueryRenderer.java b/src/main/java/org/mybatis/dynamic/sql/select/render/SubQueryRenderer.java index 013cae505..5e95886c5 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/render/SubQueryRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/render/SubQueryRenderer.java @@ -26,6 +26,7 @@ import java.util.Objects; import java.util.Optional; +import java.util.stream.Collector; import java.util.stream.Collectors; public class SubQueryRenderer { @@ -38,6 +39,16 @@ private SubQueryRenderer(Builder builder) { } public FragmentAndParameters render() { + var collector = Collectors.joining(" "); //$NON-NLS-1$ + return render(collector); + } + + public FragmentAndParameters render(String prefix, String suffix) { + var collector = Collectors.joining(" ", prefix, suffix); //$NON-NLS-1$ + return render(collector); + } + + private FragmentAndParameters render(Collector collector) { FragmentCollector fragmentCollector = selectModel .queryExpressions() .map(this::renderQueryExpression) @@ -46,7 +57,7 @@ public FragmentAndParameters render() { renderOrderBy().ifPresent(fragmentCollector::add); renderPagingModel().ifPresent(fragmentCollector::add); - return fragmentCollector.toFragmentAndParameters(Collectors.joining(" ")); //$NON-NLS-1$ + return fragmentCollector.toFragmentAndParameters(collector); } private FragmentAndParameters renderQueryExpression(QueryExpressionModel queryExpressionModel) { diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/TableExpressionRenderer.java b/src/main/java/org/mybatis/dynamic/sql/select/render/TableExpressionRenderer.java index 0448a2396..ede734ece 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/render/TableExpressionRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/render/TableExpressionRenderer.java @@ -15,12 +15,11 @@ */ package org.mybatis.dynamic.sql.select.render; -import static org.mybatis.dynamic.sql.util.StringUtilities.spaceBefore; - import java.util.Objects; import org.mybatis.dynamic.sql.SqlTable; import org.mybatis.dynamic.sql.TableExpressionVisitor; +import org.mybatis.dynamic.sql.render.RendererFactory; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.select.SubQuery; import org.mybatis.dynamic.sql.util.FragmentAndParameters; @@ -39,14 +38,11 @@ public FragmentAndParameters visit(SqlTable table) { @Override public FragmentAndParameters visit(SubQuery subQuery) { - return subQuery.selectModel().renderSubQuery(renderingContext) - .mapFragment(f -> applyAlias("(" + f + ")", subQuery)); //$NON-NLS-1$ //$NON-NLS-2$ - } + String suffix = subQuery.alias().map(a -> ") " + a) //$NON-NLS-1$ + .orElse(")"); //$NON-NLS-1$ - private String applyAlias(String fragment, SubQuery subQuery) { - return subQuery.alias() - .map(a -> fragment + spaceBefore(a)) - .orElse(fragment); + return RendererFactory.createSubQueryRenderer(subQuery.selectModel(), "(", suffix) //$NON-NLS-1$ + .render(renderingContext); } public static class Builder { diff --git a/src/main/java/org/mybatis/dynamic/sql/update/render/SetPhraseVisitor.java b/src/main/java/org/mybatis/dynamic/sql/update/render/SetPhraseVisitor.java index dd3d6ed78..f44c036dc 100644 --- a/src/main/java/org/mybatis/dynamic/sql/update/render/SetPhraseVisitor.java +++ b/src/main/java/org/mybatis/dynamic/sql/update/render/SetPhraseVisitor.java @@ -19,6 +19,7 @@ import java.util.Optional; import org.mybatis.dynamic.sql.render.RenderedParameterInfo; +import org.mybatis.dynamic.sql.render.RendererFactory; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.util.AbstractColumnMapping; import org.mybatis.dynamic.sql.util.ColumnToColumnMapping; @@ -83,9 +84,12 @@ public Optional visit(ValueWhenPresentMapping mapp @Override public Optional visit(SelectMapping mapping) { - return Optional.of(mapping.selectModel().renderSubQuery(renderingContext) - .mapFragment(f -> renderingContext.aliasedColumnName(mapping.column()) - + " = (" + f + ")")); //$NON-NLS-1$ //$NON-NLS-2$ + FragmentAndParameters fragmentAndParameters = RendererFactory.createSubQueryRenderer(mapping.selectModel(), + renderingContext.aliasedColumnName(mapping.column()) + " = (", //$NON-NLS-1$ + ")") //$NON-NLS-1$ + .render(renderingContext); + + return Optional.of(fragmentAndParameters); } @Override diff --git a/src/main/java/org/mybatis/dynamic/sql/where/render/CriterionRenderer.java b/src/main/java/org/mybatis/dynamic/sql/where/render/CriterionRenderer.java index f19a6b340..6935b8b54 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/render/CriterionRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/render/CriterionRenderer.java @@ -29,6 +29,7 @@ import org.mybatis.dynamic.sql.NotCriterion; import org.mybatis.dynamic.sql.SqlCriterion; import org.mybatis.dynamic.sql.SqlCriterionVisitor; +import org.mybatis.dynamic.sql.render.RendererFactory; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.util.FragmentAndParameters; import org.mybatis.dynamic.sql.util.FragmentCollector; @@ -118,9 +119,10 @@ private Optional renderColumnAndCondition(ColumnAndCo private FragmentAndParameters renderExists(ExistsCriterion criterion) { ExistsPredicate existsPredicate = criterion.existsPredicate(); - - return existsPredicate.selectModelBuilder().build().renderSubQuery(renderingContext) - .mapFragment(f -> existsPredicate.operator() + " (" + f + ")"); //$NON-NLS-1$ //$NON-NLS-2$ + return RendererFactory.createSubQueryRenderer(existsPredicate.selectModelBuilder().build(), + existsPredicate.operator() + " (", //$NON-NLS-1$ + ")") //$NON-NLS-1$ + .render(renderingContext); } private List renderSubCriteria(List subCriteria) { diff --git a/src/main/java/org/mybatis/dynamic/sql/where/render/DefaultConditionVisitor.java b/src/main/java/org/mybatis/dynamic/sql/where/render/DefaultConditionVisitor.java index debb4d9c8..c13633b1d 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/render/DefaultConditionVisitor.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/render/DefaultConditionVisitor.java @@ -29,6 +29,7 @@ import org.mybatis.dynamic.sql.BindableColumn; import org.mybatis.dynamic.sql.ConditionVisitor; import org.mybatis.dynamic.sql.render.RenderedParameterInfo; +import org.mybatis.dynamic.sql.render.RendererFactory; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.util.FragmentAndParameters; import org.mybatis.dynamic.sql.util.FragmentCollector; @@ -94,8 +95,10 @@ public FragmentAndParameters visit(AbstractTwoValueCondition condition) { @Override public FragmentAndParameters visit(AbstractSubselectCondition condition) { - return condition.selectModel().renderSubQuery(renderingContext) - .mapFragment(f -> condition.operator() + " (" + f + ")"); //$NON-NLS-1$ //$NON-NLS-2$ + return RendererFactory.createSubQueryRenderer(condition.selectModel(), + condition.operator() + " (", //$NON-NLS-1$ + ")") //$NON-NLS-1$ + .render(renderingContext); } @Override From 7dd88a3c3930691f91f621dffc161f2ed4b7ca11 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Fri, 22 Nov 2024 14:41:46 -0500 Subject: [PATCH 120/289] Make the SelectRenderer work for sub-queries --- .../dynamic/sql/render/RendererFactory.java | 26 ++-- .../sql/select/render/SelectRenderer.java | 66 ++++++++--- .../sql/select/render/SubQueryRenderer.java | 112 ------------------ 3 files changed, 64 insertions(+), 140 deletions(-) delete mode 100644 src/main/java/org/mybatis/dynamic/sql/select/render/SubQueryRenderer.java diff --git a/src/main/java/org/mybatis/dynamic/sql/render/RendererFactory.java b/src/main/java/org/mybatis/dynamic/sql/render/RendererFactory.java index 2b7b2e945..d43ddd6f8 100644 --- a/src/main/java/org/mybatis/dynamic/sql/render/RendererFactory.java +++ b/src/main/java/org/mybatis/dynamic/sql/render/RendererFactory.java @@ -35,10 +35,10 @@ import org.mybatis.dynamic.sql.insert.render.MultiRowInsertStatementProvider; import org.mybatis.dynamic.sql.select.MultiSelectModel; import org.mybatis.dynamic.sql.select.SelectModel; +import org.mybatis.dynamic.sql.select.render.DefaultSelectStatementProvider; import org.mybatis.dynamic.sql.select.render.MultiSelectRenderer; import org.mybatis.dynamic.sql.select.render.SelectRenderer; import org.mybatis.dynamic.sql.select.render.SelectStatementProvider; -import org.mybatis.dynamic.sql.select.render.SubQueryRenderer; import org.mybatis.dynamic.sql.update.UpdateModel; import org.mybatis.dynamic.sql.update.render.UpdateRenderer; import org.mybatis.dynamic.sql.update.render.UpdateStatementProvider; @@ -102,22 +102,24 @@ static Renderer createMultiSelectRen } static Renderer createSelectRenderer(SelectModel selectModel) { - return renderingStrategy -> SelectRenderer.withSelectModel(selectModel) - .withRenderingStrategy(renderingStrategy) - .build() - .render(); - } + return renderingStrategy -> { + RenderingContext renderingContext = RenderingContext.withRenderingStrategy(renderingStrategy) + .withStatementConfiguration(selectModel.statementConfiguration()) + .build(); - static Renderer createSubQueryRenderer(SelectModel selectModel) { - return renderingContext -> SubQueryRenderer.withSelectModel(selectModel) - .withRenderingContext(renderingContext) - .build() - .render(); + FragmentAndParameters fragmentAndParameters = createSubQueryRenderer(selectModel, + "", "") //$NON-NLS-1$ //$NON-NLS-2$ + .render(renderingContext); + + return DefaultSelectStatementProvider.withSelectStatement(fragmentAndParameters.fragment()) + .withParameters(fragmentAndParameters.parameters()) + .build(); + }; } static Renderer createSubQueryRenderer(SelectModel selectModel, String prefix, String suffix) { - return renderingContext -> SubQueryRenderer.withSelectModel(selectModel) + return renderingContext -> SelectRenderer.withSelectModel(selectModel) .withRenderingContext(renderingContext) .build() .render(prefix, suffix); diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/SelectRenderer.java b/src/main/java/org/mybatis/dynamic/sql/select/render/SelectRenderer.java index 76617f038..64725710b 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/render/SelectRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/render/SelectRenderer.java @@ -15,13 +15,18 @@ */ package org.mybatis.dynamic.sql.select.render; -import java.util.Objects; - -import org.mybatis.dynamic.sql.render.RendererFactory; +import org.mybatis.dynamic.sql.common.OrderByModel; +import org.mybatis.dynamic.sql.common.OrderByRenderer; import org.mybatis.dynamic.sql.render.RenderingContext; -import org.mybatis.dynamic.sql.render.RenderingStrategy; +import org.mybatis.dynamic.sql.select.PagingModel; +import org.mybatis.dynamic.sql.select.QueryExpressionModel; import org.mybatis.dynamic.sql.select.SelectModel; import org.mybatis.dynamic.sql.util.FragmentAndParameters; +import org.mybatis.dynamic.sql.util.FragmentCollector; + +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; public class SelectRenderer { private final SelectModel selectModel; @@ -29,17 +34,46 @@ public class SelectRenderer { private SelectRenderer(Builder builder) { selectModel = Objects.requireNonNull(builder.selectModel); - renderingContext = RenderingContext.withRenderingStrategy(builder.renderingStrategy) - .withStatementConfiguration(selectModel.statementConfiguration()) - .build(); + renderingContext = Objects.requireNonNull(builder.renderingContext); + } + + public FragmentAndParameters render(String prefix, String suffix) { + FragmentCollector fragmentCollector = selectModel + .queryExpressions() + .map(this::renderQueryExpression) + .collect(FragmentCollector.collect()); + + renderOrderBy().ifPresent(fragmentCollector::add); + renderPagingModel().ifPresent(fragmentCollector::add); + + return fragmentCollector.toFragmentAndParameters(Collectors.joining(" ", prefix, suffix)); //$NON-NLS-1$ + } + + private FragmentAndParameters renderQueryExpression(QueryExpressionModel queryExpressionModel) { + return QueryExpressionRenderer.withQueryExpression(queryExpressionModel) + .withRenderingContext(renderingContext) + .build() + .render(); + } + + private Optional renderOrderBy() { + return selectModel.orderByModel().map(this::renderOrderBy); + } + + private FragmentAndParameters renderOrderBy(OrderByModel orderByModel) { + return new OrderByRenderer(renderingContext).render(orderByModel); + } + + private Optional renderPagingModel() { + return selectModel.pagingModel().map(this::renderPagingModel); } - public SelectStatementProvider render() { - FragmentAndParameters fragmentAndParameters = RendererFactory.createSubQueryRenderer(selectModel) - .render(renderingContext); - return DefaultSelectStatementProvider.withSelectStatement(fragmentAndParameters.fragment()) - .withParameters(fragmentAndParameters.parameters()) - .build(); + private FragmentAndParameters renderPagingModel(PagingModel pagingModel) { + return new PagingModelRenderer.Builder() + .withPagingModel(pagingModel) + .withRenderingContext(renderingContext) + .build() + .render(); } public static Builder withSelectModel(SelectModel selectModel) { @@ -48,10 +82,10 @@ public static Builder withSelectModel(SelectModel selectModel) { public static class Builder { private SelectModel selectModel; - private RenderingStrategy renderingStrategy; + private RenderingContext renderingContext; - public Builder withRenderingStrategy(RenderingStrategy renderingStrategy) { - this.renderingStrategy = renderingStrategy; + public Builder withRenderingContext(RenderingContext renderingContext) { + this.renderingContext = renderingContext; return this; } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/SubQueryRenderer.java b/src/main/java/org/mybatis/dynamic/sql/select/render/SubQueryRenderer.java deleted file mode 100644 index 5e95886c5..000000000 --- a/src/main/java/org/mybatis/dynamic/sql/select/render/SubQueryRenderer.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright 2016-2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.mybatis.dynamic.sql.select.render; - -import org.mybatis.dynamic.sql.common.OrderByModel; -import org.mybatis.dynamic.sql.common.OrderByRenderer; -import org.mybatis.dynamic.sql.render.RenderingContext; -import org.mybatis.dynamic.sql.select.PagingModel; -import org.mybatis.dynamic.sql.select.QueryExpressionModel; -import org.mybatis.dynamic.sql.select.SelectModel; -import org.mybatis.dynamic.sql.util.FragmentAndParameters; -import org.mybatis.dynamic.sql.util.FragmentCollector; - -import java.util.Objects; -import java.util.Optional; -import java.util.stream.Collector; -import java.util.stream.Collectors; - -public class SubQueryRenderer { - private final SelectModel selectModel; - private final RenderingContext renderingContext; - - private SubQueryRenderer(Builder builder) { - selectModel = Objects.requireNonNull(builder.selectModel); - renderingContext = Objects.requireNonNull(builder.renderingContext); - } - - public FragmentAndParameters render() { - var collector = Collectors.joining(" "); //$NON-NLS-1$ - return render(collector); - } - - public FragmentAndParameters render(String prefix, String suffix) { - var collector = Collectors.joining(" ", prefix, suffix); //$NON-NLS-1$ - return render(collector); - } - - private FragmentAndParameters render(Collector collector) { - FragmentCollector fragmentCollector = selectModel - .queryExpressions() - .map(this::renderQueryExpression) - .collect(FragmentCollector.collect()); - - renderOrderBy().ifPresent(fragmentCollector::add); - renderPagingModel().ifPresent(fragmentCollector::add); - - return fragmentCollector.toFragmentAndParameters(collector); - } - - private FragmentAndParameters renderQueryExpression(QueryExpressionModel queryExpressionModel) { - return QueryExpressionRenderer.withQueryExpression(queryExpressionModel) - .withRenderingContext(renderingContext) - .build() - .render(); - } - - private Optional renderOrderBy() { - return selectModel.orderByModel().map(this::renderOrderBy); - } - - private FragmentAndParameters renderOrderBy(OrderByModel orderByModel) { - return new OrderByRenderer(renderingContext).render(orderByModel); - } - - private Optional renderPagingModel() { - return selectModel.pagingModel().map(this::renderPagingModel); - } - - private FragmentAndParameters renderPagingModel(PagingModel pagingModel) { - return new PagingModelRenderer.Builder() - .withPagingModel(pagingModel) - .withRenderingContext(renderingContext) - .build() - .render(); - } - - public static Builder withSelectModel(SelectModel selectModel) { - return new Builder().withSelectModel(selectModel); - } - - public static class Builder { - private SelectModel selectModel; - private RenderingContext renderingContext; - - public Builder withRenderingContext(RenderingContext renderingContext) { - this.renderingContext = renderingContext; - return this; - } - - public Builder withSelectModel(SelectModel selectModel) { - this.selectModel = selectModel; - return this; - } - - public SubQueryRenderer build() { - return new SubQueryRenderer(this); - } - } -} From 4da1e6dbcce1320121b2a532389c765f5fee40f5 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Fri, 22 Nov 2024 14:42:52 -0500 Subject: [PATCH 121/289] Checkstyle --- .../mybatis/dynamic/sql/select/render/SelectRenderer.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/SelectRenderer.java b/src/main/java/org/mybatis/dynamic/sql/select/render/SelectRenderer.java index 64725710b..cd390d088 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/render/SelectRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/render/SelectRenderer.java @@ -15,6 +15,10 @@ */ package org.mybatis.dynamic.sql.select.render; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; + import org.mybatis.dynamic.sql.common.OrderByModel; import org.mybatis.dynamic.sql.common.OrderByRenderer; import org.mybatis.dynamic.sql.render.RenderingContext; @@ -24,10 +28,6 @@ import org.mybatis.dynamic.sql.util.FragmentAndParameters; import org.mybatis.dynamic.sql.util.FragmentCollector; -import java.util.Objects; -import java.util.Optional; -import java.util.stream.Collectors; - public class SelectRenderer { private final SelectModel selectModel; private final RenderingContext renderingContext; From 63223f35772f6ba8727f7102e46757c5a457b13c Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Fri, 22 Nov 2024 14:49:45 -0500 Subject: [PATCH 122/289] Checkstyle --- .../mybatis/dynamic/sql/update/render/SetPhraseVisitor.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/update/render/SetPhraseVisitor.java b/src/main/java/org/mybatis/dynamic/sql/update/render/SetPhraseVisitor.java index f44c036dc..5464a253f 100644 --- a/src/main/java/org/mybatis/dynamic/sql/update/render/SetPhraseVisitor.java +++ b/src/main/java/org/mybatis/dynamic/sql/update/render/SetPhraseVisitor.java @@ -88,14 +88,14 @@ public Optional visit(SelectMapping mapping) { renderingContext.aliasedColumnName(mapping.column()) + " = (", //$NON-NLS-1$ ")") //$NON-NLS-1$ .render(renderingContext); - return Optional.of(fragmentAndParameters); } @Override public Optional visit(ColumnToColumnMapping mapping) { - return Optional.of(mapping.rightColumn().render(renderingContext) - .mapFragment(f -> renderingContext.aliasedColumnName(mapping.column()) + " = " + f)); //$NON-NLS-1$ + FragmentAndParameters fragmentAndParameters = mapping.rightColumn().render(renderingContext) + .mapFragment(f -> renderingContext.aliasedColumnName(mapping.column()) + " = " + f); //$NON-NLS-1$ + return Optional.of(fragmentAndParameters); } private Optional buildValueFragment(AbstractColumnMapping mapping, T value) { From 99669aba99d734c4d368e9709f9a55811a7e113c Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Fri, 22 Nov 2024 15:02:06 -0500 Subject: [PATCH 123/289] Back to explicit subquery renderer --- .../dynamic/sql/render/RendererFactory.java | 21 ++-- .../sql/select/render/SelectRenderer.java | 62 +++-------- .../sql/select/render/SubQueryRenderer.java | 101 ++++++++++++++++++ 3 files changed, 122 insertions(+), 62 deletions(-) create mode 100644 src/main/java/org/mybatis/dynamic/sql/select/render/SubQueryRenderer.java diff --git a/src/main/java/org/mybatis/dynamic/sql/render/RendererFactory.java b/src/main/java/org/mybatis/dynamic/sql/render/RendererFactory.java index d43ddd6f8..48d495bd3 100644 --- a/src/main/java/org/mybatis/dynamic/sql/render/RendererFactory.java +++ b/src/main/java/org/mybatis/dynamic/sql/render/RendererFactory.java @@ -35,10 +35,10 @@ import org.mybatis.dynamic.sql.insert.render.MultiRowInsertStatementProvider; import org.mybatis.dynamic.sql.select.MultiSelectModel; import org.mybatis.dynamic.sql.select.SelectModel; -import org.mybatis.dynamic.sql.select.render.DefaultSelectStatementProvider; import org.mybatis.dynamic.sql.select.render.MultiSelectRenderer; import org.mybatis.dynamic.sql.select.render.SelectRenderer; import org.mybatis.dynamic.sql.select.render.SelectStatementProvider; +import org.mybatis.dynamic.sql.select.render.SubQueryRenderer; import org.mybatis.dynamic.sql.update.UpdateModel; import org.mybatis.dynamic.sql.update.render.UpdateRenderer; import org.mybatis.dynamic.sql.update.render.UpdateStatementProvider; @@ -102,24 +102,15 @@ static Renderer createMultiSelectRen } static Renderer createSelectRenderer(SelectModel selectModel) { - return renderingStrategy -> { - RenderingContext renderingContext = RenderingContext.withRenderingStrategy(renderingStrategy) - .withStatementConfiguration(selectModel.statementConfiguration()) - .build(); - - FragmentAndParameters fragmentAndParameters = createSubQueryRenderer(selectModel, - "", "") //$NON-NLS-1$ //$NON-NLS-2$ - .render(renderingContext); - - return DefaultSelectStatementProvider.withSelectStatement(fragmentAndParameters.fragment()) - .withParameters(fragmentAndParameters.parameters()) - .build(); - }; + return renderingStrategy -> SelectRenderer.withSelectModel(selectModel) + .withRenderingStrategy(renderingStrategy) + .build() + .render(); } static Renderer createSubQueryRenderer(SelectModel selectModel, String prefix, String suffix) { - return renderingContext -> SelectRenderer.withSelectModel(selectModel) + return renderingContext -> SubQueryRenderer.withSelectModel(selectModel) .withRenderingContext(renderingContext) .build() .render(prefix, suffix); diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/SelectRenderer.java b/src/main/java/org/mybatis/dynamic/sql/select/render/SelectRenderer.java index cd390d088..5789b0298 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/render/SelectRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/render/SelectRenderer.java @@ -16,17 +16,12 @@ package org.mybatis.dynamic.sql.select.render; import java.util.Objects; -import java.util.Optional; -import java.util.stream.Collectors; -import org.mybatis.dynamic.sql.common.OrderByModel; -import org.mybatis.dynamic.sql.common.OrderByRenderer; +import org.mybatis.dynamic.sql.render.RendererFactory; import org.mybatis.dynamic.sql.render.RenderingContext; -import org.mybatis.dynamic.sql.select.PagingModel; -import org.mybatis.dynamic.sql.select.QueryExpressionModel; +import org.mybatis.dynamic.sql.render.RenderingStrategy; import org.mybatis.dynamic.sql.select.SelectModel; import org.mybatis.dynamic.sql.util.FragmentAndParameters; -import org.mybatis.dynamic.sql.util.FragmentCollector; public class SelectRenderer { private final SelectModel selectModel; @@ -34,46 +29,19 @@ public class SelectRenderer { private SelectRenderer(Builder builder) { selectModel = Objects.requireNonNull(builder.selectModel); - renderingContext = Objects.requireNonNull(builder.renderingContext); + renderingContext = RenderingContext.withRenderingStrategy(builder.renderingStrategy) + .withStatementConfiguration(selectModel.statementConfiguration()) + .build(); } - public FragmentAndParameters render(String prefix, String suffix) { - FragmentCollector fragmentCollector = selectModel - .queryExpressions() - .map(this::renderQueryExpression) - .collect(FragmentCollector.collect()); + public SelectStatementProvider render() { + FragmentAndParameters fragmentAndParameters = RendererFactory.createSubQueryRenderer(selectModel, + "", "") //$NON-NLS-1$ //$NON-NLS-2$ + .render(renderingContext); - renderOrderBy().ifPresent(fragmentCollector::add); - renderPagingModel().ifPresent(fragmentCollector::add); - - return fragmentCollector.toFragmentAndParameters(Collectors.joining(" ", prefix, suffix)); //$NON-NLS-1$ - } - - private FragmentAndParameters renderQueryExpression(QueryExpressionModel queryExpressionModel) { - return QueryExpressionRenderer.withQueryExpression(queryExpressionModel) - .withRenderingContext(renderingContext) - .build() - .render(); - } - - private Optional renderOrderBy() { - return selectModel.orderByModel().map(this::renderOrderBy); - } - - private FragmentAndParameters renderOrderBy(OrderByModel orderByModel) { - return new OrderByRenderer(renderingContext).render(orderByModel); - } - - private Optional renderPagingModel() { - return selectModel.pagingModel().map(this::renderPagingModel); - } - - private FragmentAndParameters renderPagingModel(PagingModel pagingModel) { - return new PagingModelRenderer.Builder() - .withPagingModel(pagingModel) - .withRenderingContext(renderingContext) - .build() - .render(); + return DefaultSelectStatementProvider.withSelectStatement(fragmentAndParameters.fragment()) + .withParameters(fragmentAndParameters.parameters()) + .build(); } public static Builder withSelectModel(SelectModel selectModel) { @@ -82,10 +50,10 @@ public static Builder withSelectModel(SelectModel selectModel) { public static class Builder { private SelectModel selectModel; - private RenderingContext renderingContext; + private RenderingStrategy renderingStrategy; - public Builder withRenderingContext(RenderingContext renderingContext) { - this.renderingContext = renderingContext; + public Builder withRenderingStrategy(RenderingStrategy renderingStrategy) { + this.renderingStrategy = renderingStrategy; return this; } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/SubQueryRenderer.java b/src/main/java/org/mybatis/dynamic/sql/select/render/SubQueryRenderer.java new file mode 100644 index 000000000..1f97f5e7d --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/select/render/SubQueryRenderer.java @@ -0,0 +1,101 @@ +/* + * Copyright 2016-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mybatis.dynamic.sql.select.render; + +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; + +import org.mybatis.dynamic.sql.common.OrderByModel; +import org.mybatis.dynamic.sql.common.OrderByRenderer; +import org.mybatis.dynamic.sql.render.RenderingContext; +import org.mybatis.dynamic.sql.select.PagingModel; +import org.mybatis.dynamic.sql.select.QueryExpressionModel; +import org.mybatis.dynamic.sql.select.SelectModel; +import org.mybatis.dynamic.sql.util.FragmentAndParameters; +import org.mybatis.dynamic.sql.util.FragmentCollector; + +public class SubQueryRenderer { + private final SelectModel selectModel; + private final RenderingContext renderingContext; + + private SubQueryRenderer(Builder builder) { + selectModel = Objects.requireNonNull(builder.selectModel); + renderingContext = Objects.requireNonNull(builder.renderingContext); + } + + public FragmentAndParameters render(String prefix, String suffix) { + FragmentCollector fragmentCollector = selectModel + .queryExpressions() + .map(this::renderQueryExpression) + .collect(FragmentCollector.collect()); + + renderOrderBy().ifPresent(fragmentCollector::add); + renderPagingModel().ifPresent(fragmentCollector::add); + + return fragmentCollector.toFragmentAndParameters(Collectors.joining(" ", prefix, suffix)); //$NON-NLS-1$ + } + + private FragmentAndParameters renderQueryExpression(QueryExpressionModel queryExpressionModel) { + return QueryExpressionRenderer.withQueryExpression(queryExpressionModel) + .withRenderingContext(renderingContext) + .build() + .render(); + } + + private Optional renderOrderBy() { + return selectModel.orderByModel().map(this::renderOrderBy); + } + + private FragmentAndParameters renderOrderBy(OrderByModel orderByModel) { + return new OrderByRenderer(renderingContext).render(orderByModel); + } + + private Optional renderPagingModel() { + return selectModel.pagingModel().map(this::renderPagingModel); + } + + private FragmentAndParameters renderPagingModel(PagingModel pagingModel) { + return new PagingModelRenderer.Builder() + .withPagingModel(pagingModel) + .withRenderingContext(renderingContext) + .build() + .render(); + } + + public static Builder withSelectModel(SelectModel selectModel) { + return new Builder().withSelectModel(selectModel); + } + + public static class Builder { + private SelectModel selectModel; + private RenderingContext renderingContext; + + public Builder withRenderingContext(RenderingContext renderingContext) { + this.renderingContext = renderingContext; + return this; + } + + public Builder withSelectModel(SelectModel selectModel) { + this.selectModel = selectModel; + return this; + } + + public SubQueryRenderer build() { + return new SubQueryRenderer(this); + } + } +} From 8db58a8f861200b0fec01e1b50cb2dd1b35cc761 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Sat, 23 Nov 2024 15:32:23 -0500 Subject: [PATCH 124/289] Remove renderer factory It didn't reduce the Sonar cycles, and added unnecessary complexity --- .../dynamic/sql/delete/DeleteModel.java | 8 +- .../dynamic/sql/insert/BatchInsertModel.java | 8 +- .../sql/insert/GeneralInsertModel.java | 8 +- .../dynamic/sql/insert/InsertModel.java | 8 +- .../dynamic/sql/insert/InsertSelectModel.java | 8 +- .../sql/insert/MultiRowInsertModel.java | 8 +- .../insert/render/InsertSelectRenderer.java | 10 +- .../mybatis/dynamic/sql/render/Renderer.java | 21 --- .../dynamic/sql/render/RendererFactory.java | 125 ------------------ .../dynamic/sql/select/MultiSelectModel.java | 8 +- .../dynamic/sql/select/SelectModel.java | 7 +- .../select/render/MultiSelectRenderer.java | 25 ++-- .../sql/select/render/SelectRenderer.java | 18 +-- .../sql/select/render/SubQueryRenderer.java | 18 ++- .../render/TableExpressionRenderer.java | 9 +- .../dynamic/sql/update/UpdateModel.java | 8 +- .../sql/update/render/SetPhraseVisitor.java | 15 ++- .../sql/where/render/CriterionRenderer.java | 12 +- .../where/render/DefaultConditionVisitor.java | 12 +- 19 files changed, 124 insertions(+), 212 deletions(-) delete mode 100644 src/main/java/org/mybatis/dynamic/sql/render/Renderer.java delete mode 100644 src/main/java/org/mybatis/dynamic/sql/render/RendererFactory.java diff --git a/src/main/java/org/mybatis/dynamic/sql/delete/DeleteModel.java b/src/main/java/org/mybatis/dynamic/sql/delete/DeleteModel.java index 581d2250a..4519b1002 100644 --- a/src/main/java/org/mybatis/dynamic/sql/delete/DeleteModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/delete/DeleteModel.java @@ -23,8 +23,8 @@ import org.mybatis.dynamic.sql.common.CommonBuilder; import org.mybatis.dynamic.sql.common.OrderByModel; import org.mybatis.dynamic.sql.configuration.StatementConfiguration; +import org.mybatis.dynamic.sql.delete.render.DeleteRenderer; import org.mybatis.dynamic.sql.delete.render.DeleteStatementProvider; -import org.mybatis.dynamic.sql.render.RendererFactory; import org.mybatis.dynamic.sql.render.RenderingStrategy; import org.mybatis.dynamic.sql.where.EmbeddedWhereModel; @@ -71,8 +71,10 @@ public StatementConfiguration statementConfiguration() { @NotNull public DeleteStatementProvider render(RenderingStrategy renderingStrategy) { - return RendererFactory.createDeleteRenderer(this) - .render(renderingStrategy); + return DeleteRenderer.withDeleteModel(this) + .withRenderingStrategy(renderingStrategy) + .build() + .render(); } public static Builder withTable(SqlTable table) { diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/BatchInsertModel.java b/src/main/java/org/mybatis/dynamic/sql/insert/BatchInsertModel.java index 5e48e9035..b591753a2 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/BatchInsertModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/BatchInsertModel.java @@ -19,7 +19,7 @@ import org.jetbrains.annotations.NotNull; import org.mybatis.dynamic.sql.insert.render.BatchInsert; -import org.mybatis.dynamic.sql.render.RendererFactory; +import org.mybatis.dynamic.sql.insert.render.BatchInsertRenderer; import org.mybatis.dynamic.sql.render.RenderingStrategy; import org.mybatis.dynamic.sql.util.Validator; @@ -33,8 +33,10 @@ private BatchInsertModel(Builder builder) { @NotNull public BatchInsert render(RenderingStrategy renderingStrategy) { - return RendererFactory.createBatchInsertRenderer(this) - .render(renderingStrategy); + return BatchInsertRenderer.withBatchInsertModel(this) + .withRenderingStrategy(renderingStrategy) + .build() + .render(); } public static Builder withRecords(Collection records) { diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/GeneralInsertModel.java b/src/main/java/org/mybatis/dynamic/sql/insert/GeneralInsertModel.java index 955d5fe7c..1fe845090 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/GeneralInsertModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/GeneralInsertModel.java @@ -23,8 +23,8 @@ import org.jetbrains.annotations.NotNull; import org.mybatis.dynamic.sql.SqlTable; import org.mybatis.dynamic.sql.configuration.StatementConfiguration; +import org.mybatis.dynamic.sql.insert.render.GeneralInsertRenderer; import org.mybatis.dynamic.sql.insert.render.GeneralInsertStatementProvider; -import org.mybatis.dynamic.sql.render.RendererFactory; import org.mybatis.dynamic.sql.render.RenderingStrategy; import org.mybatis.dynamic.sql.util.AbstractColumnMapping; import org.mybatis.dynamic.sql.util.Validator; @@ -56,8 +56,10 @@ public StatementConfiguration statementConfiguration() { @NotNull public GeneralInsertStatementProvider render(RenderingStrategy renderingStrategy) { - return RendererFactory.createGeneralInsertRenderer(this) - .render(renderingStrategy); + return GeneralInsertRenderer.withInsertModel(this) + .withRenderingStrategy(renderingStrategy) + .build() + .render(); } public static class Builder { diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/InsertModel.java b/src/main/java/org/mybatis/dynamic/sql/insert/InsertModel.java index 07fac79ed..7f740051e 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/InsertModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/InsertModel.java @@ -22,8 +22,8 @@ import org.jetbrains.annotations.NotNull; import org.mybatis.dynamic.sql.SqlTable; +import org.mybatis.dynamic.sql.insert.render.InsertRenderer; import org.mybatis.dynamic.sql.insert.render.InsertStatementProvider; -import org.mybatis.dynamic.sql.render.RendererFactory; import org.mybatis.dynamic.sql.render.RenderingStrategy; import org.mybatis.dynamic.sql.util.AbstractColumnMapping; import org.mybatis.dynamic.sql.util.Validator; @@ -54,8 +54,10 @@ public SqlTable table() { @NotNull public InsertStatementProvider render(RenderingStrategy renderingStrategy) { - return RendererFactory.createInsertRenderer(this) - .render(renderingStrategy); + return InsertRenderer.withInsertModel(this) + .withRenderingStrategy(renderingStrategy) + .build() + .render(); } public static Builder withRow(T row) { diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/InsertSelectModel.java b/src/main/java/org/mybatis/dynamic/sql/insert/InsertSelectModel.java index 37df5e10e..3d9580942 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/InsertSelectModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/InsertSelectModel.java @@ -21,8 +21,8 @@ import org.jetbrains.annotations.NotNull; import org.mybatis.dynamic.sql.SqlTable; import org.mybatis.dynamic.sql.configuration.StatementConfiguration; +import org.mybatis.dynamic.sql.insert.render.InsertSelectRenderer; import org.mybatis.dynamic.sql.insert.render.InsertSelectStatementProvider; -import org.mybatis.dynamic.sql.render.RendererFactory; import org.mybatis.dynamic.sql.render.RenderingStrategy; import org.mybatis.dynamic.sql.select.SelectModel; @@ -57,8 +57,10 @@ public StatementConfiguration statementConfiguration() { @NotNull public InsertSelectStatementProvider render(RenderingStrategy renderingStrategy) { - return RendererFactory.createInsertSelectRenderer(this) - .render(renderingStrategy); + return InsertSelectRenderer.withInsertSelectModel(this) + .withRenderingStrategy(renderingStrategy) + .build() + .render(); } public static Builder withTable(SqlTable table) { diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/MultiRowInsertModel.java b/src/main/java/org/mybatis/dynamic/sql/insert/MultiRowInsertModel.java index d5d7f478d..406c02b7a 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/MultiRowInsertModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/MultiRowInsertModel.java @@ -18,8 +18,8 @@ import java.util.Collection; import org.jetbrains.annotations.NotNull; +import org.mybatis.dynamic.sql.insert.render.MultiRowInsertRenderer; import org.mybatis.dynamic.sql.insert.render.MultiRowInsertStatementProvider; -import org.mybatis.dynamic.sql.render.RendererFactory; import org.mybatis.dynamic.sql.render.RenderingStrategy; import org.mybatis.dynamic.sql.util.Validator; @@ -33,8 +33,10 @@ private MultiRowInsertModel(Builder builder) { @NotNull public MultiRowInsertStatementProvider render(RenderingStrategy renderingStrategy) { - return RendererFactory.createMultiRowInsertRenderer(this) - .render(renderingStrategy); + return MultiRowInsertRenderer.withMultiRowInsertModel(this) + .withRenderingStrategy(renderingStrategy) + .build() + .render(); } public static Builder withRecords(Collection records) { diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/render/InsertSelectRenderer.java b/src/main/java/org/mybatis/dynamic/sql/insert/render/InsertSelectRenderer.java index fb3b37503..cd052f45d 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/render/InsertSelectRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/render/InsertSelectRenderer.java @@ -23,9 +23,9 @@ import org.mybatis.dynamic.sql.SqlColumn; import org.mybatis.dynamic.sql.insert.InsertColumnListModel; import org.mybatis.dynamic.sql.insert.InsertSelectModel; -import org.mybatis.dynamic.sql.render.RendererFactory; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.render.RenderingStrategy; +import org.mybatis.dynamic.sql.select.render.SubQueryRenderer; import org.mybatis.dynamic.sql.util.FragmentAndParameters; public class InsertSelectRenderer { @@ -45,9 +45,11 @@ public InsertSelectStatementProvider render() { String columnsPhrase = calculateColumnsPhrase(); String prefix = statementStart + spaceAfter(columnsPhrase); - FragmentAndParameters fragmentAndParameters = RendererFactory.createSubQueryRenderer(model.selectModel(), - prefix, "") //$NON-NLS-1$ - .render(renderingContext); + FragmentAndParameters fragmentAndParameters = SubQueryRenderer.withSelectModel(model.selectModel()) + .withRenderingContext(renderingContext) + .withPrefix(prefix) + .build() + .render(); return DefaultGeneralInsertStatementProvider.withInsertStatement(fragmentAndParameters.fragment()) .withParameters(fragmentAndParameters.parameters()) diff --git a/src/main/java/org/mybatis/dynamic/sql/render/Renderer.java b/src/main/java/org/mybatis/dynamic/sql/render/Renderer.java deleted file mode 100644 index acb84a98f..000000000 --- a/src/main/java/org/mybatis/dynamic/sql/render/Renderer.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2016-2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.mybatis.dynamic.sql.render; - -@FunctionalInterface -public interface Renderer { - R render(T t); -} diff --git a/src/main/java/org/mybatis/dynamic/sql/render/RendererFactory.java b/src/main/java/org/mybatis/dynamic/sql/render/RendererFactory.java deleted file mode 100644 index 48d495bd3..000000000 --- a/src/main/java/org/mybatis/dynamic/sql/render/RendererFactory.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright 2016-2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.mybatis.dynamic.sql.render; - -import org.mybatis.dynamic.sql.delete.DeleteModel; -import org.mybatis.dynamic.sql.delete.render.DeleteRenderer; -import org.mybatis.dynamic.sql.delete.render.DeleteStatementProvider; -import org.mybatis.dynamic.sql.insert.BatchInsertModel; -import org.mybatis.dynamic.sql.insert.GeneralInsertModel; -import org.mybatis.dynamic.sql.insert.InsertModel; -import org.mybatis.dynamic.sql.insert.InsertSelectModel; -import org.mybatis.dynamic.sql.insert.MultiRowInsertModel; -import org.mybatis.dynamic.sql.insert.render.BatchInsert; -import org.mybatis.dynamic.sql.insert.render.BatchInsertRenderer; -import org.mybatis.dynamic.sql.insert.render.GeneralInsertRenderer; -import org.mybatis.dynamic.sql.insert.render.GeneralInsertStatementProvider; -import org.mybatis.dynamic.sql.insert.render.InsertRenderer; -import org.mybatis.dynamic.sql.insert.render.InsertSelectRenderer; -import org.mybatis.dynamic.sql.insert.render.InsertSelectStatementProvider; -import org.mybatis.dynamic.sql.insert.render.InsertStatementProvider; -import org.mybatis.dynamic.sql.insert.render.MultiRowInsertRenderer; -import org.mybatis.dynamic.sql.insert.render.MultiRowInsertStatementProvider; -import org.mybatis.dynamic.sql.select.MultiSelectModel; -import org.mybatis.dynamic.sql.select.SelectModel; -import org.mybatis.dynamic.sql.select.render.MultiSelectRenderer; -import org.mybatis.dynamic.sql.select.render.SelectRenderer; -import org.mybatis.dynamic.sql.select.render.SelectStatementProvider; -import org.mybatis.dynamic.sql.select.render.SubQueryRenderer; -import org.mybatis.dynamic.sql.update.UpdateModel; -import org.mybatis.dynamic.sql.update.render.UpdateRenderer; -import org.mybatis.dynamic.sql.update.render.UpdateStatementProvider; -import org.mybatis.dynamic.sql.util.FragmentAndParameters; - -public interface RendererFactory { - static Renderer createDeleteRenderer(DeleteModel deleteModel) { - return renderingStrategy -> DeleteRenderer.withDeleteModel(deleteModel) - .withRenderingStrategy(renderingStrategy) - .build() - .render(); - } - - static Renderer> createBatchInsertRenderer( - BatchInsertModel batchInsertModel) { - return renderingStrategy -> BatchInsertRenderer.withBatchInsertModel(batchInsertModel) - .withRenderingStrategy(renderingStrategy) - .build() - .render(); - } - - static Renderer createGeneralInsertRenderer( - GeneralInsertModel generalInsertModel) { - return renderingStrategy -> GeneralInsertRenderer.withInsertModel(generalInsertModel) - .withRenderingStrategy(renderingStrategy) - .build() - .render(); - } - - static Renderer> createInsertRenderer( - InsertModel insertModel) { - return renderingStrategy -> InsertRenderer.withInsertModel(insertModel) - .withRenderingStrategy(renderingStrategy) - .build() - .render(); - } - - static Renderer createInsertSelectRenderer( - InsertSelectModel insertSelectModel) { - return renderingStrategy -> InsertSelectRenderer.withInsertSelectModel(insertSelectModel) - .withRenderingStrategy(renderingStrategy) - .build() - .render(); - } - - static Renderer> createMultiRowInsertRenderer( - MultiRowInsertModel multiRowInsertModel) { - return renderingStrategy -> MultiRowInsertRenderer.withMultiRowInsertModel(multiRowInsertModel) - .withRenderingStrategy(renderingStrategy) - .build() - .render(); - } - - static Renderer createMultiSelectRenderer( - MultiSelectModel multiSelectModel) { - return renderingStrategy -> new MultiSelectRenderer.Builder() - .withMultiSelectModel(multiSelectModel) - .withRenderingStrategy(renderingStrategy) - .build() - .render(); - } - - static Renderer createSelectRenderer(SelectModel selectModel) { - return renderingStrategy -> SelectRenderer.withSelectModel(selectModel) - .withRenderingStrategy(renderingStrategy) - .build() - .render(); - } - - static Renderer createSubQueryRenderer(SelectModel selectModel, - String prefix, String suffix) { - return renderingContext -> SubQueryRenderer.withSelectModel(selectModel) - .withRenderingContext(renderingContext) - .build() - .render(prefix, suffix); - } - - static Renderer createUpdateRenderer(UpdateModel updateModel) { - return renderingStrategy -> UpdateRenderer.withUpdateModel(updateModel) - .withRenderingStrategy(renderingStrategy) - .build() - .render(); - } -} diff --git a/src/main/java/org/mybatis/dynamic/sql/select/MultiSelectModel.java b/src/main/java/org/mybatis/dynamic/sql/select/MultiSelectModel.java index 443a42c56..60539c660 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/MultiSelectModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/MultiSelectModel.java @@ -21,8 +21,8 @@ import java.util.stream.Stream; import org.jetbrains.annotations.NotNull; -import org.mybatis.dynamic.sql.render.RendererFactory; import org.mybatis.dynamic.sql.render.RenderingStrategy; +import org.mybatis.dynamic.sql.select.render.MultiSelectRenderer; import org.mybatis.dynamic.sql.select.render.SelectStatementProvider; import org.mybatis.dynamic.sql.util.Validator; @@ -47,8 +47,10 @@ public Stream unionQueries() { @NotNull public SelectStatementProvider render(RenderingStrategy renderingStrategy) { - return RendererFactory.createMultiSelectRenderer(this) - .render(renderingStrategy); + return MultiSelectRenderer.withMultiSelectModel(this) + .withRenderingStrategy(renderingStrategy) + .build() + .render(); } public static class Builder extends AbstractBuilder { diff --git a/src/main/java/org/mybatis/dynamic/sql/select/SelectModel.java b/src/main/java/org/mybatis/dynamic/sql/select/SelectModel.java index 14225147f..da01d09b5 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/SelectModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/SelectModel.java @@ -21,8 +21,8 @@ import java.util.stream.Stream; import org.jetbrains.annotations.NotNull; -import org.mybatis.dynamic.sql.render.RendererFactory; import org.mybatis.dynamic.sql.render.RenderingStrategy; +import org.mybatis.dynamic.sql.select.render.SelectRenderer; import org.mybatis.dynamic.sql.select.render.SelectStatementProvider; import org.mybatis.dynamic.sql.util.Validator; @@ -41,7 +41,10 @@ public Stream queryExpressions() { @NotNull public SelectStatementProvider render(RenderingStrategy renderingStrategy) { - return RendererFactory.createSelectRenderer(this).render(renderingStrategy); + return SelectRenderer.withSelectModel(this) + .withRenderingStrategy(renderingStrategy) + .build() + .render(); } public static Builder withQueryExpressions(List queryExpressions) { diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/MultiSelectRenderer.java b/src/main/java/org/mybatis/dynamic/sql/select/render/MultiSelectRenderer.java index 4fe0b7e92..634896ad2 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/render/MultiSelectRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/render/MultiSelectRenderer.java @@ -21,7 +21,6 @@ import org.mybatis.dynamic.sql.common.OrderByModel; import org.mybatis.dynamic.sql.common.OrderByRenderer; -import org.mybatis.dynamic.sql.render.RendererFactory; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.render.RenderingStrategy; import org.mybatis.dynamic.sql.select.MultiSelectModel; @@ -65,17 +64,21 @@ private SelectStatementProvider toSelectStatementProvider(FragmentCollector frag } private FragmentAndParameters renderSelect(SelectModel selectModel) { - return RendererFactory.createSubQueryRenderer(selectModel, - "(", //$NON-NLS-1$ - ")") //$NON-NLS-1$ - .render(renderingContext); + return SubQueryRenderer.withSelectModel(selectModel) + .withRenderingContext(renderingContext) + .withPrefix("(") //$NON-NLS-1$ + .withSuffix(")") //$NON-NLS-1$ + .build() + .render(); } private FragmentAndParameters renderSelect(UnionQuery unionQuery) { - return RendererFactory.createSubQueryRenderer(unionQuery.selectModel(), - unionQuery.connector() + " (", //$NON-NLS-1$ - ")") //$NON-NLS-1$ - .render(renderingContext); + return SubQueryRenderer.withSelectModel(unionQuery.selectModel()) + .withRenderingContext(renderingContext) + .withPrefix(unionQuery.connector() + " (") //$NON-NLS-1$ + .withSuffix(")") //$NON-NLS-1$ + .build() + .render(); } private Optional renderOrderBy() { @@ -98,6 +101,10 @@ private FragmentAndParameters renderPagingModel(PagingModel pagingModel) { .render(); } + public static Builder withMultiSelectModel(MultiSelectModel multiSelectModel) { + return new Builder().withMultiSelectModel(multiSelectModel); + } + public static class Builder { private RenderingStrategy renderingStrategy; private MultiSelectModel multiSelectModel; diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/SelectRenderer.java b/src/main/java/org/mybatis/dynamic/sql/select/render/SelectRenderer.java index 5789b0298..6284b0b49 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/render/SelectRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/render/SelectRenderer.java @@ -17,7 +17,6 @@ import java.util.Objects; -import org.mybatis.dynamic.sql.render.RendererFactory; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.render.RenderingStrategy; import org.mybatis.dynamic.sql.select.SelectModel; @@ -25,19 +24,22 @@ public class SelectRenderer { private final SelectModel selectModel; - private final RenderingContext renderingContext; + private final RenderingStrategy renderingStrategy; private SelectRenderer(Builder builder) { selectModel = Objects.requireNonNull(builder.selectModel); - renderingContext = RenderingContext.withRenderingStrategy(builder.renderingStrategy) - .withStatementConfiguration(selectModel.statementConfiguration()) - .build(); + renderingStrategy = Objects.requireNonNull(builder.renderingStrategy); } public SelectStatementProvider render() { - FragmentAndParameters fragmentAndParameters = RendererFactory.createSubQueryRenderer(selectModel, - "", "") //$NON-NLS-1$ //$NON-NLS-2$ - .render(renderingContext); + RenderingContext renderingContext = RenderingContext.withRenderingStrategy(renderingStrategy) + .withStatementConfiguration(selectModel.statementConfiguration()) + .build(); + + FragmentAndParameters fragmentAndParameters = SubQueryRenderer.withSelectModel(selectModel) + .withRenderingContext(renderingContext) + .build() + .render(); return DefaultSelectStatementProvider.withSelectStatement(fragmentAndParameters.fragment()) .withParameters(fragmentAndParameters.parameters()) diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/SubQueryRenderer.java b/src/main/java/org/mybatis/dynamic/sql/select/render/SubQueryRenderer.java index 1f97f5e7d..b1d6c28ce 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/render/SubQueryRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/render/SubQueryRenderer.java @@ -31,13 +31,17 @@ public class SubQueryRenderer { private final SelectModel selectModel; private final RenderingContext renderingContext; + private final String prefix; + private final String suffix; private SubQueryRenderer(Builder builder) { selectModel = Objects.requireNonNull(builder.selectModel); renderingContext = Objects.requireNonNull(builder.renderingContext); + prefix = builder.prefix == null ? "" : builder.prefix; //$NON-NLS-1$ + suffix = builder.suffix == null ? "" : builder.suffix; //$NON-NLS-1$ } - public FragmentAndParameters render(String prefix, String suffix) { + public FragmentAndParameters render() { FragmentCollector fragmentCollector = selectModel .queryExpressions() .map(this::renderQueryExpression) @@ -83,6 +87,8 @@ public static Builder withSelectModel(SelectModel selectModel) { public static class Builder { private SelectModel selectModel; private RenderingContext renderingContext; + private String prefix; + private String suffix; public Builder withRenderingContext(RenderingContext renderingContext) { this.renderingContext = renderingContext; @@ -94,6 +100,16 @@ public Builder withSelectModel(SelectModel selectModel) { return this; } + public Builder withPrefix(String prefix) { + this.prefix = prefix; + return this; + } + + public Builder withSuffix(String suffix) { + this.suffix = suffix; + return this; + } + public SubQueryRenderer build() { return new SubQueryRenderer(this); } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/TableExpressionRenderer.java b/src/main/java/org/mybatis/dynamic/sql/select/render/TableExpressionRenderer.java index ede734ece..24dfb190f 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/render/TableExpressionRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/render/TableExpressionRenderer.java @@ -19,7 +19,6 @@ import org.mybatis.dynamic.sql.SqlTable; import org.mybatis.dynamic.sql.TableExpressionVisitor; -import org.mybatis.dynamic.sql.render.RendererFactory; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.select.SubQuery; import org.mybatis.dynamic.sql.util.FragmentAndParameters; @@ -41,8 +40,12 @@ public FragmentAndParameters visit(SubQuery subQuery) { String suffix = subQuery.alias().map(a -> ") " + a) //$NON-NLS-1$ .orElse(")"); //$NON-NLS-1$ - return RendererFactory.createSubQueryRenderer(subQuery.selectModel(), "(", suffix) //$NON-NLS-1$ - .render(renderingContext); + return SubQueryRenderer.withSelectModel(subQuery.selectModel()) + .withRenderingContext(renderingContext) + .withPrefix("(")//$NON-NLS-1$ + .withSuffix(suffix) + .build() + .render(); } public static class Builder { diff --git a/src/main/java/org/mybatis/dynamic/sql/update/UpdateModel.java b/src/main/java/org/mybatis/dynamic/sql/update/UpdateModel.java index f4ad201e5..2c828da91 100644 --- a/src/main/java/org/mybatis/dynamic/sql/update/UpdateModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/update/UpdateModel.java @@ -26,8 +26,8 @@ import org.mybatis.dynamic.sql.common.CommonBuilder; import org.mybatis.dynamic.sql.common.OrderByModel; import org.mybatis.dynamic.sql.configuration.StatementConfiguration; -import org.mybatis.dynamic.sql.render.RendererFactory; import org.mybatis.dynamic.sql.render.RenderingStrategy; +import org.mybatis.dynamic.sql.update.render.UpdateRenderer; import org.mybatis.dynamic.sql.update.render.UpdateStatementProvider; import org.mybatis.dynamic.sql.util.AbstractColumnMapping; import org.mybatis.dynamic.sql.util.Validator; @@ -83,8 +83,10 @@ public StatementConfiguration statementConfiguration() { @NotNull public UpdateStatementProvider render(RenderingStrategy renderingStrategy) { - return RendererFactory.createUpdateRenderer(this) - .render(renderingStrategy); + return UpdateRenderer.withUpdateModel(this) + .withRenderingStrategy(renderingStrategy) + .build() + .render(); } public static Builder withTable(SqlTable table) { diff --git a/src/main/java/org/mybatis/dynamic/sql/update/render/SetPhraseVisitor.java b/src/main/java/org/mybatis/dynamic/sql/update/render/SetPhraseVisitor.java index 5464a253f..7bbe575fc 100644 --- a/src/main/java/org/mybatis/dynamic/sql/update/render/SetPhraseVisitor.java +++ b/src/main/java/org/mybatis/dynamic/sql/update/render/SetPhraseVisitor.java @@ -19,8 +19,8 @@ import java.util.Optional; import org.mybatis.dynamic.sql.render.RenderedParameterInfo; -import org.mybatis.dynamic.sql.render.RendererFactory; import org.mybatis.dynamic.sql.render.RenderingContext; +import org.mybatis.dynamic.sql.select.render.SubQueryRenderer; import org.mybatis.dynamic.sql.util.AbstractColumnMapping; import org.mybatis.dynamic.sql.util.ColumnToColumnMapping; import org.mybatis.dynamic.sql.util.ConstantMapping; @@ -84,10 +84,15 @@ public Optional visit(ValueWhenPresentMapping mapp @Override public Optional visit(SelectMapping mapping) { - FragmentAndParameters fragmentAndParameters = RendererFactory.createSubQueryRenderer(mapping.selectModel(), - renderingContext.aliasedColumnName(mapping.column()) + " = (", //$NON-NLS-1$ - ")") //$NON-NLS-1$ - .render(renderingContext); + String prefix = renderingContext.aliasedColumnName(mapping.column()) + " = ("; //$NON-NLS-1$ + + FragmentAndParameters fragmentAndParameters = SubQueryRenderer.withSelectModel(mapping.selectModel()) + .withRenderingContext(renderingContext) + .withPrefix(prefix) + .withSuffix(")") //$NON-NLS-1$ + .build() + .render(); + return Optional.of(fragmentAndParameters); } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/render/CriterionRenderer.java b/src/main/java/org/mybatis/dynamic/sql/where/render/CriterionRenderer.java index 6935b8b54..7e29a10d3 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/render/CriterionRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/render/CriterionRenderer.java @@ -29,8 +29,8 @@ import org.mybatis.dynamic.sql.NotCriterion; import org.mybatis.dynamic.sql.SqlCriterion; import org.mybatis.dynamic.sql.SqlCriterionVisitor; -import org.mybatis.dynamic.sql.render.RendererFactory; import org.mybatis.dynamic.sql.render.RenderingContext; +import org.mybatis.dynamic.sql.select.render.SubQueryRenderer; import org.mybatis.dynamic.sql.util.FragmentAndParameters; import org.mybatis.dynamic.sql.util.FragmentCollector; @@ -119,10 +119,12 @@ private Optional renderColumnAndCondition(ColumnAndCo private FragmentAndParameters renderExists(ExistsCriterion criterion) { ExistsPredicate existsPredicate = criterion.existsPredicate(); - return RendererFactory.createSubQueryRenderer(existsPredicate.selectModelBuilder().build(), - existsPredicate.operator() + " (", //$NON-NLS-1$ - ")") //$NON-NLS-1$ - .render(renderingContext); + return SubQueryRenderer.withSelectModel(existsPredicate.selectModelBuilder().build()) + .withRenderingContext(renderingContext) + .withPrefix(existsPredicate.operator() + " (") //$NON-NLS-1$ + .withSuffix(")") //$NON-NLS-1$ + .build() + .render(); } private List renderSubCriteria(List subCriteria) { diff --git a/src/main/java/org/mybatis/dynamic/sql/where/render/DefaultConditionVisitor.java b/src/main/java/org/mybatis/dynamic/sql/where/render/DefaultConditionVisitor.java index c13633b1d..d5cdc0dd2 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/render/DefaultConditionVisitor.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/render/DefaultConditionVisitor.java @@ -29,8 +29,8 @@ import org.mybatis.dynamic.sql.BindableColumn; import org.mybatis.dynamic.sql.ConditionVisitor; import org.mybatis.dynamic.sql.render.RenderedParameterInfo; -import org.mybatis.dynamic.sql.render.RendererFactory; import org.mybatis.dynamic.sql.render.RenderingContext; +import org.mybatis.dynamic.sql.select.render.SubQueryRenderer; import org.mybatis.dynamic.sql.util.FragmentAndParameters; import org.mybatis.dynamic.sql.util.FragmentCollector; @@ -95,10 +95,12 @@ public FragmentAndParameters visit(AbstractTwoValueCondition condition) { @Override public FragmentAndParameters visit(AbstractSubselectCondition condition) { - return RendererFactory.createSubQueryRenderer(condition.selectModel(), - condition.operator() + " (", //$NON-NLS-1$ - ")") //$NON-NLS-1$ - .render(renderingContext); + return SubQueryRenderer.withSelectModel(condition.selectModel()) + .withRenderingContext(renderingContext) + .withPrefix(condition.operator() + " (") //$NON-NLS-1$ + .withSuffix(")") //$NON-NLS-1$ + .build() + .render(); } @Override From 1a374f81b4f139d2e5b3894e271918f1d299a60b Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 25 Nov 2024 13:31:36 -0500 Subject: [PATCH 125/289] Save some garbage in the providers --- .../DefaultDeleteStatementProvider.java | 2 +- ...DefaultGeneralInsertStatementProvider.java | 4 +- .../DefaultUpdateStatementProvider.java | 4 +- .../sql/util/FragmentAndParameters.java | 3 +- .../mybatis/dynamic/sql/where/WhereModel.java | 3 +- .../render/DefaultWhereClauseProvider.java | 63 +++++++++++++++++++ .../sql/where/render/WhereClauseProvider.java | 44 +------------ 7 files changed, 75 insertions(+), 48 deletions(-) create mode 100644 src/main/java/org/mybatis/dynamic/sql/where/render/DefaultWhereClauseProvider.java diff --git a/src/main/java/org/mybatis/dynamic/sql/delete/render/DefaultDeleteStatementProvider.java b/src/main/java/org/mybatis/dynamic/sql/delete/render/DefaultDeleteStatementProvider.java index 89b72333b..ef2ade7f0 100644 --- a/src/main/java/org/mybatis/dynamic/sql/delete/render/DefaultDeleteStatementProvider.java +++ b/src/main/java/org/mybatis/dynamic/sql/delete/render/DefaultDeleteStatementProvider.java @@ -25,7 +25,7 @@ public class DefaultDeleteStatementProvider implements DeleteStatementProvider { private DefaultDeleteStatementProvider(Builder builder) { deleteStatement = Objects.requireNonNull(builder.deleteStatement); - parameters = Objects.requireNonNull(builder.parameters); + parameters = builder.parameters; } @Override diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/render/DefaultGeneralInsertStatementProvider.java b/src/main/java/org/mybatis/dynamic/sql/insert/render/DefaultGeneralInsertStatementProvider.java index de1c41266..5cd4144d6 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/render/DefaultGeneralInsertStatementProvider.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/render/DefaultGeneralInsertStatementProvider.java @@ -22,11 +22,11 @@ public class DefaultGeneralInsertStatementProvider implements GeneralInsertStatementProvider, InsertSelectStatementProvider { private final String insertStatement; - private final Map parameters = new HashMap<>(); + private final Map parameters; private DefaultGeneralInsertStatementProvider(Builder builder) { insertStatement = Objects.requireNonNull(builder.insertStatement); - parameters.putAll(builder.parameters); + parameters = builder.parameters; } @Override diff --git a/src/main/java/org/mybatis/dynamic/sql/update/render/DefaultUpdateStatementProvider.java b/src/main/java/org/mybatis/dynamic/sql/update/render/DefaultUpdateStatementProvider.java index a103bd604..c2f14fbd6 100644 --- a/src/main/java/org/mybatis/dynamic/sql/update/render/DefaultUpdateStatementProvider.java +++ b/src/main/java/org/mybatis/dynamic/sql/update/render/DefaultUpdateStatementProvider.java @@ -21,11 +21,11 @@ public class DefaultUpdateStatementProvider implements UpdateStatementProvider { private final String updateStatement; - private final Map parameters = new HashMap<>(); + private final Map parameters; private DefaultUpdateStatementProvider(Builder builder) { updateStatement = Objects.requireNonNull(builder.updateStatement); - parameters.putAll(builder.parameters); + parameters = builder.parameters; } @Override diff --git a/src/main/java/org/mybatis/dynamic/sql/util/FragmentAndParameters.java b/src/main/java/org/mybatis/dynamic/sql/util/FragmentAndParameters.java index 4c240120c..8f2b58aae 100644 --- a/src/main/java/org/mybatis/dynamic/sql/util/FragmentAndParameters.java +++ b/src/main/java/org/mybatis/dynamic/sql/util/FragmentAndParameters.java @@ -15,6 +15,7 @@ */ package org.mybatis.dynamic.sql.util; +import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Objects; @@ -28,7 +29,7 @@ public class FragmentAndParameters { private FragmentAndParameters(Builder builder) { fragment = Objects.requireNonNull(builder.fragment); - parameters = Objects.requireNonNull(builder.parameters); + parameters = Collections.unmodifiableMap(builder.parameters); } public String fragment() { diff --git a/src/main/java/org/mybatis/dynamic/sql/where/WhereModel.java b/src/main/java/org/mybatis/dynamic/sql/where/WhereModel.java index 8db761223..5c99d68ff 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/WhereModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/WhereModel.java @@ -24,6 +24,7 @@ import org.mybatis.dynamic.sql.render.RenderingStrategy; import org.mybatis.dynamic.sql.render.TableAliasCalculator; import org.mybatis.dynamic.sql.util.FragmentAndParameters; +import org.mybatis.dynamic.sql.where.render.DefaultWhereClauseProvider; import org.mybatis.dynamic.sql.where.render.WhereClauseProvider; import org.mybatis.dynamic.sql.where.render.WhereRenderer; @@ -92,7 +93,7 @@ private Optional render(RenderingContext renderingContext) } private WhereClauseProvider toWhereClauseProvider(FragmentAndParameters fragmentAndParameters) { - return WhereClauseProvider.withWhereClause(fragmentAndParameters.fragment()) + return DefaultWhereClauseProvider.withWhereClause(fragmentAndParameters.fragment()) .withParameters(fragmentAndParameters.parameters()) .build(); } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/render/DefaultWhereClauseProvider.java b/src/main/java/org/mybatis/dynamic/sql/where/render/DefaultWhereClauseProvider.java new file mode 100644 index 000000000..bf68eb7cf --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/where/render/DefaultWhereClauseProvider.java @@ -0,0 +1,63 @@ +/* + * Copyright 2016-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mybatis.dynamic.sql.where.render; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +public class DefaultWhereClauseProvider implements WhereClauseProvider { + private final String whereClause; + private final Map parameters; + + private DefaultWhereClauseProvider(Builder builder) { + whereClause = Objects.requireNonNull(builder.whereClause); + parameters = builder.parameters; + } + + @Override + public Map getParameters() { + return parameters; + } + + @Override + public String getWhereClause() { + return whereClause; + } + + public static Builder withWhereClause(String whereClause) { + return new Builder().withWhereClause(whereClause); + } + + public static class Builder { + private String whereClause; + private final Map parameters = new HashMap<>(); + + public Builder withWhereClause(String whereClause) { + this.whereClause = whereClause; + return this; + } + + public Builder withParameters(Map parameters) { + this.parameters.putAll(parameters); + return this; + } + + public DefaultWhereClauseProvider build() { + return new DefaultWhereClauseProvider(this); + } + } +} diff --git a/src/main/java/org/mybatis/dynamic/sql/where/render/WhereClauseProvider.java b/src/main/java/org/mybatis/dynamic/sql/where/render/WhereClauseProvider.java index 37d051e81..1e8d16be5 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/render/WhereClauseProvider.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/render/WhereClauseProvider.java @@ -15,48 +15,10 @@ */ package org.mybatis.dynamic.sql.where.render; -import java.util.Collections; -import java.util.HashMap; import java.util.Map; -import java.util.Objects; -public class WhereClauseProvider { - private final String whereClause; - private final Map parameters; +public interface WhereClauseProvider { + Map getParameters(); - private WhereClauseProvider(Builder builder) { - whereClause = Objects.requireNonNull(builder.whereClause); - parameters = Objects.requireNonNull(builder.parameters); - } - - public Map getParameters() { - return Collections.unmodifiableMap(parameters); - } - - public String getWhereClause() { - return whereClause; - } - - public static Builder withWhereClause(String whereClause) { - return new Builder().withWhereClause(whereClause); - } - - public static class Builder { - private String whereClause; - private final Map parameters = new HashMap<>(); - - public Builder withWhereClause(String whereClause) { - this.whereClause = whereClause; - return this; - } - - public Builder withParameters(Map parameters) { - this.parameters.putAll(parameters); - return this; - } - - public WhereClauseProvider build() { - return new WhereClauseProvider(this); - } - } + String getWhereClause(); } From 42d5a4318f0e92d8772c3c0622863de7e08debb5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 27 Nov 2024 13:30:19 +0000 Subject: [PATCH 126/289] Update dependency org.mybatis:mybatis to v3.5.17 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d914073b2..e35633113 100644 --- a/pom.xml +++ b/pom.xml @@ -103,7 +103,7 @@ org.mybatis mybatis - 3.5.16 + 3.5.17 provided true From 38f264c913453a5d7a60952455f423e56c074023 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 27 Nov 2024 15:10:00 +0000 Subject: [PATCH 127/289] Update dependency org.jetbrains.kotlin:kotlin-stdlib-jdk8 to v2.1.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d914073b2..fa76960a3 100644 --- a/pom.xml +++ b/pom.xml @@ -69,7 +69,7 @@ org.mybatis.dynamic.sql - 2.0.21 + 2.1.0 17 2.0 2.0 From 1c4c5b68515f211e18fc4404ab911487c769abfa Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 3 Dec 2024 01:25:47 +0000 Subject: [PATCH 128/289] Update dependency org.mybatis:mybatis-parent to v46 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index abf481499..9ca71d163 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ org.mybatis mybatis-parent - 45 + 46 org.mybatis.dynamic-sql From 621dd7354da03320c208490efe136a8362a32d49 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 12 Dec 2024 11:52:17 +0000 Subject: [PATCH 129/289] Update dependency org.springframework:spring-jdbc to v6.2.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9ca71d163..7ced7af99 100644 --- a/pom.xml +++ b/pom.xml @@ -96,7 +96,7 @@ org.springframework spring-jdbc - 6.2.0 + 6.2.1 provided true From df22341467ebb54c6279301e1a49957ed878d8dd Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 16 Dec 2024 15:20:10 +0000 Subject: [PATCH 130/289] Update junit5 monorepo to v5.11.4 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 7ced7af99..ccdf57319 100644 --- a/pom.xml +++ b/pom.xml @@ -60,7 +60,7 @@ 17 17 17 - 5.11.3 + 5.11.4 5.2.0 checkstyle-override.xml From 2182ef4c07e9f8c82dec72de303ab18c954ea2fa Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 18 Dec 2024 18:11:29 +0000 Subject: [PATCH 131/289] Update dependency ch.qos.logback:logback-classic to v1.5.13 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ccdf57319..fc9d6dc18 100644 --- a/pom.xml +++ b/pom.xml @@ -165,7 +165,7 @@ ch.qos.logback logback-classic - 1.5.12 + 1.5.13 test From 072d705215fd5d840c58520b56bb4934c3f03521 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 18 Dec 2024 21:35:33 +0000 Subject: [PATCH 132/289] Update dependency org.springframework.batch:spring-batch-test to v5.2.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ccdf57319..e0cc3e5f5 100644 --- a/pom.xml +++ b/pom.xml @@ -61,7 +61,7 @@ 17 17 5.11.4 - 5.2.0 + 5.2.1 checkstyle-override.xml From 3ae60d76b4c0f2dcc0cc30d214cd4216c3769aa5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 19 Dec 2024 17:22:26 +0000 Subject: [PATCH 133/289] Update dependency ch.qos.logback:logback-classic to v1.5.14 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 4bb813b97..d94583b26 100644 --- a/pom.xml +++ b/pom.xml @@ -165,7 +165,7 @@ ch.qos.logback logback-classic - 1.5.13 + 1.5.14 test From b17ad1585815c1bed9ce50821d6f7293106fd0d8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 19 Dec 2024 20:55:07 +0000 Subject: [PATCH 134/289] Update dependency org.assertj:assertj-core to v3.27.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d94583b26..d21f27850 100644 --- a/pom.xml +++ b/pom.xml @@ -129,7 +129,7 @@ org.assertj assertj-core - 3.26.3 + 3.27.0 test From 9c192a14fa1b87753a0b5a4d9417f2ad8afc2192 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 21 Dec 2024 19:40:19 +0000 Subject: [PATCH 135/289] Update dependency ch.qos.logback:logback-classic to v1.5.15 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d21f27850..23bd4575a 100644 --- a/pom.xml +++ b/pom.xml @@ -165,7 +165,7 @@ ch.qos.logback logback-classic - 1.5.14 + 1.5.15 test From 7dd495f0cc40f3a5fe03fd9a1d493b6aa0e6db0d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 27 Dec 2024 21:44:39 +0000 Subject: [PATCH 136/289] Update dependency org.mybatis:mybatis-parent to v48 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 23bd4575a..e57313231 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ org.mybatis mybatis-parent - 46 + 48 org.mybatis.dynamic-sql From 961e37b0aa1b67ba259a4ae8a6c421213b5bf41b Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Sat, 28 Dec 2024 09:20:47 -0500 Subject: [PATCH 137/289] Update Java Matrix --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 5a6947c02..7f41206e9 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -9,7 +9,7 @@ jobs: matrix: cache: [maven] distribution: [temurin] - java: [17, 21, 22, 23-ea] + java: [17, 21, 23, 24-ea, 25-ea] os: [ubuntu-latest] fail-fast: false max-parallel: 4 From 17ac0c06d3885967ebb039417566c6d2aa850c60 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Sat, 28 Dec 2024 09:29:26 -0500 Subject: [PATCH 138/289] Update Java Matrix and test containers versions --- .github/workflows/ci.yaml | 2 +- src/test/java/config/TestContainersConfiguration.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 7f41206e9..e89bd81b6 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -9,7 +9,7 @@ jobs: matrix: cache: [maven] distribution: [temurin] - java: [17, 21, 23, 24-ea, 25-ea] + java: [17, 21, 23, 24-ea] os: [ubuntu-latest] fail-fast: false max-parallel: 4 diff --git a/src/test/java/config/TestContainersConfiguration.java b/src/test/java/config/TestContainersConfiguration.java index fc6607dbb..1919fc0f9 100644 --- a/src/test/java/config/TestContainersConfiguration.java +++ b/src/test/java/config/TestContainersConfiguration.java @@ -21,6 +21,6 @@ * Utility interface to hold Docker image tags for the test containers we use */ public interface TestContainersConfiguration { - DockerImageName POSTGRES_LATEST = DockerImageName.parse("postgres:17.0"); - DockerImageName MARIADB_LATEST = DockerImageName.parse("mariadb:11.5.2"); + DockerImageName POSTGRES_LATEST = DockerImageName.parse("postgres:17.2"); + DockerImageName MARIADB_LATEST = DockerImageName.parse("mariadb:11.6.2"); } From d9093f95156dfae23d06ccf371aa7f89a674c7b7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 1 Jan 2025 06:04:55 +0000 Subject: [PATCH 139/289] Update dependency org.mybatis:mybatis to v3.5.18 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e57313231..dafe341c8 100644 --- a/pom.xml +++ b/pom.xml @@ -103,7 +103,7 @@ org.mybatis mybatis - 3.5.17 + 3.5.18 provided true From 876201b0deb33642a9b6c2686fcd508c293a981b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 1 Jan 2025 19:17:27 +0000 Subject: [PATCH 140/289] Update dependency org.assertj:assertj-core to v3.27.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index dafe341c8..9ffb9a9cc 100644 --- a/pom.xml +++ b/pom.xml @@ -129,7 +129,7 @@ org.assertj assertj-core - 3.27.0 + 3.27.1 test From 1994eaaed7ffd3b001ee0a202e909c7eccb305b2 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Wed, 1 Jan 2025 14:17:36 -0500 Subject: [PATCH 141/289] Update Copyright for 2025 --- .mvn/extensions.xml | 2 +- .mvn/settings.xml | 2 +- checkstyle-override.xml | 2 +- pom.xml | 2 +- .../mybatis/dynamic/sql/AbstractColumnComparisonCondition.java | 2 +- .../org/mybatis/dynamic/sql/AbstractListValueCondition.java | 2 +- .../java/org/mybatis/dynamic/sql/AbstractNoValueCondition.java | 2 +- .../org/mybatis/dynamic/sql/AbstractSingleValueCondition.java | 2 +- .../org/mybatis/dynamic/sql/AbstractSubselectCondition.java | 2 +- .../java/org/mybatis/dynamic/sql/AbstractTwoValueCondition.java | 2 +- src/main/java/org/mybatis/dynamic/sql/AliasableSqlTable.java | 2 +- src/main/java/org/mybatis/dynamic/sql/AndOrCriteriaGroup.java | 2 +- src/main/java/org/mybatis/dynamic/sql/BasicColumn.java | 2 +- src/main/java/org/mybatis/dynamic/sql/BindableColumn.java | 2 +- src/main/java/org/mybatis/dynamic/sql/BoundValue.java | 2 +- .../org/mybatis/dynamic/sql/ColumnAndConditionCriterion.java | 2 +- src/main/java/org/mybatis/dynamic/sql/ConditionVisitor.java | 2 +- src/main/java/org/mybatis/dynamic/sql/Constant.java | 2 +- src/main/java/org/mybatis/dynamic/sql/CriteriaGroup.java | 2 +- src/main/java/org/mybatis/dynamic/sql/DerivedColumn.java | 2 +- src/main/java/org/mybatis/dynamic/sql/ExistsCriterion.java | 2 +- src/main/java/org/mybatis/dynamic/sql/ExistsPredicate.java | 2 +- src/main/java/org/mybatis/dynamic/sql/NotCriterion.java | 2 +- .../java/org/mybatis/dynamic/sql/ParameterTypeConverter.java | 2 +- src/main/java/org/mybatis/dynamic/sql/SortSpecification.java | 2 +- src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java | 2 +- src/main/java/org/mybatis/dynamic/sql/SqlColumn.java | 2 +- src/main/java/org/mybatis/dynamic/sql/SqlCriterion.java | 2 +- src/main/java/org/mybatis/dynamic/sql/SqlCriterionVisitor.java | 2 +- src/main/java/org/mybatis/dynamic/sql/SqlTable.java | 2 +- src/main/java/org/mybatis/dynamic/sql/StringConstant.java | 2 +- src/main/java/org/mybatis/dynamic/sql/TableExpression.java | 2 +- .../java/org/mybatis/dynamic/sql/TableExpressionVisitor.java | 2 +- src/main/java/org/mybatis/dynamic/sql/VisitableCondition.java | 2 +- .../dynamic/sql/common/AbstractBooleanExpressionDSL.java | 2 +- .../dynamic/sql/common/AbstractBooleanExpressionModel.java | 2 +- .../dynamic/sql/common/AbstractBooleanExpressionRenderer.java | 2 +- src/main/java/org/mybatis/dynamic/sql/common/CommonBuilder.java | 2 +- src/main/java/org/mybatis/dynamic/sql/common/OrderByModel.java | 2 +- .../java/org/mybatis/dynamic/sql/common/OrderByRenderer.java | 2 +- .../mybatis/dynamic/sql/configuration/GlobalConfiguration.java | 2 +- .../org/mybatis/dynamic/sql/configuration/GlobalContext.java | 2 +- .../dynamic/sql/configuration/StatementConfiguration.java | 2 +- src/main/java/org/mybatis/dynamic/sql/delete/DeleteDSL.java | 2 +- .../java/org/mybatis/dynamic/sql/delete/DeleteDSLCompleter.java | 2 +- src/main/java/org/mybatis/dynamic/sql/delete/DeleteModel.java | 2 +- .../sql/delete/render/DefaultDeleteStatementProvider.java | 2 +- .../org/mybatis/dynamic/sql/delete/render/DeleteRenderer.java | 2 +- .../dynamic/sql/delete/render/DeleteStatementProvider.java | 2 +- .../dynamic/sql/exception/DuplicateTableAliasException.java | 2 +- .../org/mybatis/dynamic/sql/exception/DynamicSqlException.java | 2 +- .../org/mybatis/dynamic/sql/exception/InvalidSqlException.java | 2 +- .../dynamic/sql/exception/NonRenderingWhereClauseException.java | 2 +- .../mybatis/dynamic/sql/insert/AbstractMultiRowInsertModel.java | 2 +- .../java/org/mybatis/dynamic/sql/insert/BatchInsertDSL.java | 2 +- .../java/org/mybatis/dynamic/sql/insert/BatchInsertModel.java | 2 +- .../java/org/mybatis/dynamic/sql/insert/GeneralInsertDSL.java | 2 +- .../java/org/mybatis/dynamic/sql/insert/GeneralInsertModel.java | 2 +- .../org/mybatis/dynamic/sql/insert/InsertColumnListModel.java | 2 +- src/main/java/org/mybatis/dynamic/sql/insert/InsertDSL.java | 2 +- src/main/java/org/mybatis/dynamic/sql/insert/InsertModel.java | 2 +- .../java/org/mybatis/dynamic/sql/insert/InsertSelectDSL.java | 2 +- .../java/org/mybatis/dynamic/sql/insert/InsertSelectModel.java | 2 +- .../java/org/mybatis/dynamic/sql/insert/MultiRowInsertDSL.java | 2 +- .../org/mybatis/dynamic/sql/insert/MultiRowInsertModel.java | 2 +- .../java/org/mybatis/dynamic/sql/insert/render/BatchInsert.java | 2 +- .../mybatis/dynamic/sql/insert/render/BatchInsertRenderer.java | 2 +- .../insert/render/DefaultGeneralInsertStatementProvider.java | 2 +- .../sql/insert/render/DefaultInsertStatementProvider.java | 2 +- .../insert/render/DefaultMultiRowInsertStatementProvider.java | 2 +- .../dynamic/sql/insert/render/FieldAndValueAndParameters.java | 2 +- .../dynamic/sql/insert/render/FieldAndValueCollector.java | 2 +- .../dynamic/sql/insert/render/GeneralInsertRenderer.java | 2 +- .../sql/insert/render/GeneralInsertStatementProvider.java | 2 +- .../sql/insert/render/GeneralInsertValuePhraseVisitor.java | 2 +- .../org/mybatis/dynamic/sql/insert/render/InsertRenderer.java | 2 +- .../dynamic/sql/insert/render/InsertRenderingUtilities.java | 2 +- .../mybatis/dynamic/sql/insert/render/InsertSelectRenderer.java | 2 +- .../sql/insert/render/InsertSelectStatementProvider.java | 2 +- .../dynamic/sql/insert/render/InsertStatementProvider.java | 2 +- .../dynamic/sql/insert/render/MultiRowInsertRenderer.java | 2 +- .../sql/insert/render/MultiRowInsertStatementProvider.java | 2 +- .../dynamic/sql/insert/render/MultiRowValuePhraseVisitor.java | 2 +- .../mybatis/dynamic/sql/insert/render/ValuePhraseVisitor.java | 2 +- .../dynamic/sql/render/ExplicitTableAliasCalculator.java | 2 +- .../dynamic/sql/render/GuaranteedTableAliasCalculator.java | 2 +- .../mybatis/dynamic/sql/render/MyBatis3RenderingStrategy.java | 2 +- .../org/mybatis/dynamic/sql/render/RenderedParameterInfo.java | 2 +- .../java/org/mybatis/dynamic/sql/render/RenderingContext.java | 2 +- .../org/mybatis/dynamic/sql/render/RenderingStrategies.java | 2 +- .../java/org/mybatis/dynamic/sql/render/RenderingStrategy.java | 2 +- .../sql/render/SpringNamedParameterRenderingStrategy.java | 2 +- .../org/mybatis/dynamic/sql/render/TableAliasCalculator.java | 2 +- .../dynamic/sql/render/TableAliasCalculatorWithParent.java | 2 +- .../org/mybatis/dynamic/sql/select/AbstractHavingFinisher.java | 2 +- .../org/mybatis/dynamic/sql/select/AbstractHavingStarter.java | 2 +- .../mybatis/dynamic/sql/select/AbstractQueryExpressionDSL.java | 2 +- .../org/mybatis/dynamic/sql/select/AbstractSelectModel.java | 2 +- .../org/mybatis/dynamic/sql/select/ColumnSortSpecification.java | 2 +- src/main/java/org/mybatis/dynamic/sql/select/CountDSL.java | 2 +- .../java/org/mybatis/dynamic/sql/select/CountDSLCompleter.java | 2 +- src/main/java/org/mybatis/dynamic/sql/select/GroupByModel.java | 2 +- src/main/java/org/mybatis/dynamic/sql/select/HavingApplier.java | 2 +- src/main/java/org/mybatis/dynamic/sql/select/HavingDSL.java | 2 +- src/main/java/org/mybatis/dynamic/sql/select/HavingModel.java | 2 +- .../java/org/mybatis/dynamic/sql/select/MultiSelectDSL.java | 2 +- .../java/org/mybatis/dynamic/sql/select/MultiSelectModel.java | 2 +- src/main/java/org/mybatis/dynamic/sql/select/PagingDSL.java | 2 +- src/main/java/org/mybatis/dynamic/sql/select/PagingModel.java | 2 +- .../java/org/mybatis/dynamic/sql/select/QueryExpressionDSL.java | 2 +- .../org/mybatis/dynamic/sql/select/QueryExpressionModel.java | 2 +- src/main/java/org/mybatis/dynamic/sql/select/SelectDSL.java | 2 +- .../java/org/mybatis/dynamic/sql/select/SelectDSLCompleter.java | 2 +- src/main/java/org/mybatis/dynamic/sql/select/SelectModel.java | 2 +- .../org/mybatis/dynamic/sql/select/SimpleSortSpecification.java | 2 +- src/main/java/org/mybatis/dynamic/sql/select/SubQuery.java | 2 +- src/main/java/org/mybatis/dynamic/sql/select/UnionQuery.java | 2 +- .../org/mybatis/dynamic/sql/select/aggregate/AbstractCount.java | 2 +- src/main/java/org/mybatis/dynamic/sql/select/aggregate/Avg.java | 2 +- .../java/org/mybatis/dynamic/sql/select/aggregate/Count.java | 2 +- .../java/org/mybatis/dynamic/sql/select/aggregate/CountAll.java | 2 +- .../org/mybatis/dynamic/sql/select/aggregate/CountDistinct.java | 2 +- src/main/java/org/mybatis/dynamic/sql/select/aggregate/Max.java | 2 +- src/main/java/org/mybatis/dynamic/sql/select/aggregate/Min.java | 2 +- src/main/java/org/mybatis/dynamic/sql/select/aggregate/Sum.java | 2 +- .../dynamic/sql/select/caseexpression/BasicWhenCondition.java | 2 +- .../sql/select/caseexpression/ConditionBasedWhenCondition.java | 2 +- .../org/mybatis/dynamic/sql/select/caseexpression/ElseDSL.java | 2 +- .../dynamic/sql/select/caseexpression/SearchedCaseDSL.java | 2 +- .../dynamic/sql/select/caseexpression/SearchedCaseModel.java | 2 +- .../sql/select/caseexpression/SearchedCaseWhenCondition.java | 2 +- .../dynamic/sql/select/caseexpression/SimpleCaseDSL.java | 2 +- .../dynamic/sql/select/caseexpression/SimpleCaseModel.java | 2 +- .../sql/select/caseexpression/SimpleCaseWhenCondition.java | 2 +- .../select/caseexpression/SimpleCaseWhenConditionVisitor.java | 2 +- .../org/mybatis/dynamic/sql/select/caseexpression/ThenDSL.java | 2 +- .../sql/select/function/AbstractTypeConvertingFunction.java | 2 +- .../dynamic/sql/select/function/AbstractUniTypeFunction.java | 2 +- src/main/java/org/mybatis/dynamic/sql/select/function/Add.java | 2 +- src/main/java/org/mybatis/dynamic/sql/select/function/Cast.java | 2 +- .../java/org/mybatis/dynamic/sql/select/function/Concat.java | 2 +- .../org/mybatis/dynamic/sql/select/function/Concatenate.java | 2 +- .../java/org/mybatis/dynamic/sql/select/function/Divide.java | 2 +- .../java/org/mybatis/dynamic/sql/select/function/Lower.java | 2 +- .../java/org/mybatis/dynamic/sql/select/function/Multiply.java | 2 +- .../mybatis/dynamic/sql/select/function/OperatorFunction.java | 2 +- .../java/org/mybatis/dynamic/sql/select/function/Substring.java | 2 +- .../java/org/mybatis/dynamic/sql/select/function/Subtract.java | 2 +- .../java/org/mybatis/dynamic/sql/select/function/Upper.java | 2 +- .../java/org/mybatis/dynamic/sql/select/join/JoinModel.java | 2 +- .../org/mybatis/dynamic/sql/select/join/JoinSpecification.java | 2 +- src/main/java/org/mybatis/dynamic/sql/select/join/JoinType.java | 2 +- .../sql/select/render/DefaultSelectStatementProvider.java | 2 +- .../sql/select/render/FetchFirstPagingModelRenderer.java | 2 +- .../org/mybatis/dynamic/sql/select/render/HavingRenderer.java | 2 +- .../org/mybatis/dynamic/sql/select/render/JoinRenderer.java | 2 +- .../dynamic/sql/select/render/JoinSpecificationRenderer.java | 2 +- .../sql/select/render/LimitAndOffsetPagingModelRenderer.java | 2 +- .../mybatis/dynamic/sql/select/render/MultiSelectRenderer.java | 2 +- .../mybatis/dynamic/sql/select/render/PagingModelRenderer.java | 2 +- .../dynamic/sql/select/render/QueryExpressionRenderer.java | 2 +- .../mybatis/dynamic/sql/select/render/SearchedCaseRenderer.java | 2 +- .../sql/select/render/SearchedCaseWhenConditionRenderer.java | 2 +- .../org/mybatis/dynamic/sql/select/render/SelectRenderer.java | 2 +- .../dynamic/sql/select/render/SelectStatementProvider.java | 2 +- .../mybatis/dynamic/sql/select/render/SimpleCaseRenderer.java | 2 +- .../sql/select/render/SimpleCaseWhenConditionRenderer.java | 2 +- .../org/mybatis/dynamic/sql/select/render/SubQueryRenderer.java | 2 +- .../dynamic/sql/select/render/TableExpressionRenderer.java | 2 +- src/main/java/org/mybatis/dynamic/sql/update/UpdateDSL.java | 2 +- .../java/org/mybatis/dynamic/sql/update/UpdateDSLCompleter.java | 2 +- src/main/java/org/mybatis/dynamic/sql/update/UpdateModel.java | 2 +- .../sql/update/render/DefaultUpdateStatementProvider.java | 2 +- .../org/mybatis/dynamic/sql/update/render/SetPhraseVisitor.java | 2 +- .../org/mybatis/dynamic/sql/update/render/UpdateRenderer.java | 2 +- .../dynamic/sql/update/render/UpdateStatementProvider.java | 2 +- .../org/mybatis/dynamic/sql/util/AbstractColumnMapping.java | 2 +- src/main/java/org/mybatis/dynamic/sql/util/Buildable.java | 2 +- .../java/org/mybatis/dynamic/sql/util/ColumnMappingVisitor.java | 2 +- .../org/mybatis/dynamic/sql/util/ColumnToColumnMapping.java | 2 +- .../org/mybatis/dynamic/sql/util/ConfigurableStatement.java | 2 +- src/main/java/org/mybatis/dynamic/sql/util/ConstantMapping.java | 2 +- .../org/mybatis/dynamic/sql/util/FragmentAndParameters.java | 2 +- .../java/org/mybatis/dynamic/sql/util/FragmentCollector.java | 2 +- .../mybatis/dynamic/sql/util/GeneralInsertMappingVisitor.java | 2 +- .../java/org/mybatis/dynamic/sql/util/InsertMappingVisitor.java | 2 +- src/main/java/org/mybatis/dynamic/sql/util/InternalError.java | 2 +- src/main/java/org/mybatis/dynamic/sql/util/Messages.java | 2 +- .../mybatis/dynamic/sql/util/MultiRowInsertMappingVisitor.java | 2 +- src/main/java/org/mybatis/dynamic/sql/util/NullMapping.java | 2 +- src/main/java/org/mybatis/dynamic/sql/util/Predicates.java | 2 +- src/main/java/org/mybatis/dynamic/sql/util/PropertyMapping.java | 2 +- .../mybatis/dynamic/sql/util/PropertyWhenPresentMapping.java | 2 +- src/main/java/org/mybatis/dynamic/sql/util/RowMapping.java | 2 +- src/main/java/org/mybatis/dynamic/sql/util/SelectMapping.java | 2 +- .../java/org/mybatis/dynamic/sql/util/SqlProviderAdapter.java | 2 +- .../org/mybatis/dynamic/sql/util/StringConstantMapping.java | 2 +- src/main/java/org/mybatis/dynamic/sql/util/StringUtilities.java | 2 +- .../java/org/mybatis/dynamic/sql/util/UpdateMappingVisitor.java | 2 +- src/main/java/org/mybatis/dynamic/sql/util/Utilities.java | 2 +- src/main/java/org/mybatis/dynamic/sql/util/Validator.java | 2 +- src/main/java/org/mybatis/dynamic/sql/util/ValueMapping.java | 2 +- .../java/org/mybatis/dynamic/sql/util/ValueOrNullMapping.java | 2 +- .../org/mybatis/dynamic/sql/util/ValueWhenPresentMapping.java | 2 +- .../mybatis/dynamic/sql/util/mybatis3/CommonCountMapper.java | 2 +- .../mybatis/dynamic/sql/util/mybatis3/CommonDeleteMapper.java | 2 +- .../dynamic/sql/util/mybatis3/CommonGeneralInsertMapper.java | 2 +- .../mybatis/dynamic/sql/util/mybatis3/CommonInsertMapper.java | 2 +- .../mybatis/dynamic/sql/util/mybatis3/CommonSelectMapper.java | 2 +- .../mybatis/dynamic/sql/util/mybatis3/CommonUpdateMapper.java | 2 +- .../org/mybatis/dynamic/sql/util/mybatis3/MyBatis3Utils.java | 2 +- .../org/mybatis/dynamic/sql/util/spring/BatchInsertUtility.java | 2 +- .../sql/util/spring/NamedParameterJdbcTemplateExtensions.java | 2 +- .../SpringBatchPagingItemReaderRenderingStrategy.java | 2 +- .../sql/util/springbatch/SpringBatchProviderAdapter.java | 2 +- .../dynamic/sql/util/springbatch/SpringBatchUtility.java | 2 +- .../org/mybatis/dynamic/sql/where/AbstractWhereFinisher.java | 2 +- .../org/mybatis/dynamic/sql/where/AbstractWhereStarter.java | 2 +- .../java/org/mybatis/dynamic/sql/where/EmbeddedWhereModel.java | 2 +- src/main/java/org/mybatis/dynamic/sql/where/WhereApplier.java | 2 +- src/main/java/org/mybatis/dynamic/sql/where/WhereDSL.java | 2 +- src/main/java/org/mybatis/dynamic/sql/where/WhereModel.java | 2 +- .../org/mybatis/dynamic/sql/where/condition/AndGatherer.java | 2 +- .../sql/where/condition/CaseInsensitiveVisitableCondition.java | 2 +- .../java/org/mybatis/dynamic/sql/where/condition/IsBetween.java | 2 +- .../java/org/mybatis/dynamic/sql/where/condition/IsEqualTo.java | 2 +- .../mybatis/dynamic/sql/where/condition/IsEqualToColumn.java | 2 +- .../dynamic/sql/where/condition/IsEqualToWithSubselect.java | 2 +- .../org/mybatis/dynamic/sql/where/condition/IsGreaterThan.java | 2 +- .../dynamic/sql/where/condition/IsGreaterThanColumn.java | 2 +- .../dynamic/sql/where/condition/IsGreaterThanOrEqualTo.java | 2 +- .../sql/where/condition/IsGreaterThanOrEqualToColumn.java | 2 +- .../where/condition/IsGreaterThanOrEqualToWithSubselect.java | 2 +- .../dynamic/sql/where/condition/IsGreaterThanWithSubselect.java | 2 +- src/main/java/org/mybatis/dynamic/sql/where/condition/IsIn.java | 2 +- .../dynamic/sql/where/condition/IsInCaseInsensitive.java | 2 +- .../sql/where/condition/IsInCaseInsensitiveWhenPresent.java | 2 +- .../mybatis/dynamic/sql/where/condition/IsInWhenPresent.java | 2 +- .../mybatis/dynamic/sql/where/condition/IsInWithSubselect.java | 2 +- .../org/mybatis/dynamic/sql/where/condition/IsLessThan.java | 2 +- .../mybatis/dynamic/sql/where/condition/IsLessThanColumn.java | 2 +- .../dynamic/sql/where/condition/IsLessThanOrEqualTo.java | 2 +- .../dynamic/sql/where/condition/IsLessThanOrEqualToColumn.java | 2 +- .../sql/where/condition/IsLessThanOrEqualToWithSubselect.java | 2 +- .../dynamic/sql/where/condition/IsLessThanWithSubselect.java | 2 +- .../java/org/mybatis/dynamic/sql/where/condition/IsLike.java | 2 +- .../dynamic/sql/where/condition/IsLikeCaseInsensitive.java | 2 +- .../org/mybatis/dynamic/sql/where/condition/IsNotBetween.java | 2 +- .../org/mybatis/dynamic/sql/where/condition/IsNotEqualTo.java | 2 +- .../mybatis/dynamic/sql/where/condition/IsNotEqualToColumn.java | 2 +- .../dynamic/sql/where/condition/IsNotEqualToWithSubselect.java | 2 +- .../java/org/mybatis/dynamic/sql/where/condition/IsNotIn.java | 2 +- .../dynamic/sql/where/condition/IsNotInCaseInsensitive.java | 2 +- .../sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java | 2 +- .../mybatis/dynamic/sql/where/condition/IsNotInWhenPresent.java | 2 +- .../dynamic/sql/where/condition/IsNotInWithSubselect.java | 2 +- .../java/org/mybatis/dynamic/sql/where/condition/IsNotLike.java | 2 +- .../dynamic/sql/where/condition/IsNotLikeCaseInsensitive.java | 2 +- .../java/org/mybatis/dynamic/sql/where/condition/IsNotNull.java | 2 +- .../java/org/mybatis/dynamic/sql/where/condition/IsNull.java | 2 +- .../dynamic/sql/where/render/ColumnAndConditionRenderer.java | 2 +- .../org/mybatis/dynamic/sql/where/render/CriterionRenderer.java | 2 +- .../dynamic/sql/where/render/DefaultConditionVisitor.java | 2 +- .../dynamic/sql/where/render/DefaultWhereClauseProvider.java | 2 +- .../org/mybatis/dynamic/sql/where/render/RenderedCriterion.java | 2 +- .../mybatis/dynamic/sql/where/render/WhereClauseProvider.java | 2 +- .../org/mybatis/dynamic/sql/where/render/WhereRenderer.java | 2 +- .../dynamic/sql/util/kotlin/GroupingCriteriaCollector.kt | 2 +- .../kotlin/org/mybatis/dynamic/sql/util/kotlin/JoinCollector.kt | 2 +- .../org/mybatis/dynamic/sql/util/kotlin/KInvalidSQLException.kt | 2 +- .../kotlin/org/mybatis/dynamic/sql/util/kotlin/KValidator.kt | 2 +- .../org/mybatis/dynamic/sql/util/kotlin/KotlinBaseBuilders.kt | 2 +- .../mybatis/dynamic/sql/util/kotlin/KotlinBatchInsertBuilder.kt | 2 +- .../org/mybatis/dynamic/sql/util/kotlin/KotlinCountBuilder.kt | 2 +- .../org/mybatis/dynamic/sql/util/kotlin/KotlinDeleteBuilder.kt | 2 +- .../dynamic/sql/util/kotlin/KotlinGeneralInsertBuilder.kt | 2 +- .../org/mybatis/dynamic/sql/util/kotlin/KotlinInsertBuilder.kt | 2 +- .../dynamic/sql/util/kotlin/KotlinInsertColumnMapCompleters.kt | 2 +- .../dynamic/sql/util/kotlin/KotlinMultiRowInsertBuilder.kt | 2 +- .../mybatis/dynamic/sql/util/kotlin/KotlinMultiSelectBuilder.kt | 2 +- .../org/mybatis/dynamic/sql/util/kotlin/KotlinPagingDSL.kt | 2 +- .../org/mybatis/dynamic/sql/util/kotlin/KotlinSelectBuilder.kt | 2 +- .../mybatis/dynamic/sql/util/kotlin/KotlinSubQueryBuilders.kt | 2 +- .../org/mybatis/dynamic/sql/util/kotlin/KotlinUnionBuilder.kt | 2 +- .../org/mybatis/dynamic/sql/util/kotlin/KotlinUpdateBuilder.kt | 2 +- .../org/mybatis/dynamic/sql/util/kotlin/elements/CaseDSLs.kt | 2 +- .../org/mybatis/dynamic/sql/util/kotlin/elements/CastDSL.kt | 2 +- .../dynamic/sql/util/kotlin/elements/ColumnExtensions.kt | 2 +- .../org/mybatis/dynamic/sql/util/kotlin/elements/SqlElements.kt | 2 +- .../dynamic/sql/util/kotlin/elements/SqlTableExtensions.kt | 2 +- .../dynamic/sql/util/kotlin/model/ModelBuilderFunctions.kt | 2 +- .../dynamic/sql/util/kotlin/mybatis3/MapperSupportFunctions.kt | 2 +- .../sql/util/kotlin/mybatis3/ProviderBuilderFunctions.kt | 2 +- .../util/kotlin/spring/NamedParameterJdbcTemplateExtensions.kt | 2 +- .../dynamic/sql/util/kotlin/spring/ProviderBuilderFunctions.kt | 2 +- .../resources/org/mybatis/dynamic/sql/util/messages.properties | 2 +- src/site/resources/css/site.css | 2 +- src/site/site.xml | 2 +- src/test/java/config/TestContainersConfiguration.java | 2 +- src/test/java/examples/animal/data/AnimalData.java | 2 +- .../java/examples/animal/data/AnimalDataDynamicSqlSupport.java | 2 +- src/test/java/examples/animal/data/AnimalDataMapper.java | 2 +- src/test/java/examples/animal/data/AnimalDataTest.java | 2 +- src/test/java/examples/animal/data/BindingTest.java | 2 +- src/test/java/examples/animal/data/CaseExpressionTest.java | 2 +- src/test/java/examples/animal/data/CommonSelectMapperTest.java | 2 +- src/test/java/examples/animal/data/FetchFirstTest.java | 2 +- src/test/java/examples/animal/data/Length.java | 2 +- src/test/java/examples/animal/data/LimitAndOffsetTest.java | 2 +- src/test/java/examples/animal/data/MyInCondition.java | 2 +- .../examples/animal/data/OptionalConditionsAnimalDataTest.java | 2 +- .../data/OptionalConditionsWithPredicatesAnimalDataTest.java | 2 +- src/test/java/examples/animal/data/SubQueryTest.java | 2 +- .../java/examples/animal/data/VariousListConditionsTest.java | 2 +- .../animal/data/VariousPagingAndLimitScenariosTest.java | 2 +- src/test/java/examples/array/ArrayTest.java | 2 +- src/test/java/examples/array/NamesRecord.java | 2 +- src/test/java/examples/array/NamesTableDynamicSqlSupport.java | 2 +- src/test/java/examples/array/NamesTableMapper.java | 2 +- src/test/java/examples/array/StringArrayTypeHandler.java | 2 +- .../column/comparison/ColumnComparisonConfiguration.java | 2 +- .../column/comparison/ColumnComparisonDynamicSqlSupport.java | 2 +- .../java/examples/column/comparison/ColumnComparisonMapper.java | 2 +- .../java/examples/column/comparison/ColumnComparisonRecord.java | 2 +- .../java/examples/column/comparison/ColumnComparisonTest.java | 2 +- src/test/java/examples/complexquery/ComplexQueryTest.java | 2 +- src/test/java/examples/complexquery/GroupingTest.java | 2 +- .../java/examples/complexquery/PersonDynamicSqlSupport.java | 2 +- src/test/java/examples/complexquery/SearchUtils.java | 2 +- src/test/java/examples/custom_render/CustomRenderingTest.java | 2 +- src/test/java/examples/custom_render/JsonRenderingStrategy.java | 2 +- .../java/examples/custom_render/JsonTestDynamicSqlSupport.java | 2 +- src/test/java/examples/custom_render/JsonTestMapper.java | 2 +- src/test/java/examples/custom_render/JsonTestRecord.java | 2 +- src/test/java/examples/emptywhere/EmptyWhereTest.java | 2 +- src/test/java/examples/emptywhere/OrderDynamicSqlSupport.java | 2 +- src/test/java/examples/emptywhere/PersonDynamicSqlSupport.java | 2 +- .../java/examples/generated/always/GeneratedAlwaysRecord.java | 2 +- src/test/java/examples/generated/always/PersonRecord.java | 2 +- .../always/mybatis/GeneratedAlwaysDynamicSqlSupport.java | 2 +- .../generated/always/mybatis/GeneratedAlwaysMapper.java | 2 +- .../generated/always/mybatis/GeneratedAlwaysMapperTest.java | 2 +- .../java/examples/generated/always/mybatis/GeneratedKey.java | 2 +- .../examples/generated/always/mybatis/GeneratedKeyList.java | 2 +- .../generated/always/mybatis/PersonDynamicSqlSupport.java | 2 +- .../java/examples/generated/always/mybatis/PersonMapper.java | 2 +- .../examples/generated/always/mybatis/PersonMapperTest.java | 2 +- .../always/spring/GeneratedAlwaysDynamicSqlSupport.java | 2 +- src/test/java/examples/generated/always/spring/SpringTest.java | 2 +- src/test/java/examples/groupby/AddressDynamicSqlSupport.java | 2 +- src/test/java/examples/groupby/GroupByTest.java | 2 +- src/test/java/examples/groupby/Person2DynamicSqlSupport.java | 2 +- src/test/java/examples/groupby/PersonDynamicSqlSupport.java | 2 +- src/test/java/examples/joins/ExistsTest.java | 2 +- src/test/java/examples/joins/ItemMasterDynamicSQLSupport.java | 2 +- src/test/java/examples/joins/JoinMapper.java | 2 +- src/test/java/examples/joins/JoinMapperTest.java | 2 +- src/test/java/examples/joins/JoinSubQueryTest.java | 2 +- src/test/java/examples/joins/OrderDetail.java | 2 +- src/test/java/examples/joins/OrderDetailDynamicSQLSupport.java | 2 +- src/test/java/examples/joins/OrderLineDynamicSQLSupport.java | 2 +- src/test/java/examples/joins/OrderMaster.java | 2 +- src/test/java/examples/joins/OrderMasterDynamicSQLSupport.java | 2 +- src/test/java/examples/joins/User.java | 2 +- src/test/java/examples/joins/UserDynamicSQLSupport.java | 2 +- src/test/java/examples/mariadb/ItemsDynamicSQLSupport.java | 2 +- src/test/java/examples/mariadb/MariaDBTest.java | 2 +- src/test/java/examples/mariadb/NumbersDynamicSQLSupport.java | 2 +- src/test/java/examples/mariadb/OrderByCaseTest.java | 2 +- src/test/java/examples/paging/LimitAndOffsetAdapter.java | 2 +- src/test/java/examples/paging/LimitAndOffsetMapper.java | 2 +- src/test/java/examples/paging/LimitAndOffsetTest.java | 2 +- src/test/java/examples/sharding/ShardedMapper.java | 2 +- src/test/java/examples/sharding/ShardingTest.java | 2 +- .../java/examples/sharding/TableCodesDynamicSqlSupport.java | 2 +- src/test/java/examples/simple/AddressDynamicSqlSupport.java | 2 +- src/test/java/examples/simple/AddressMapper.java | 2 +- src/test/java/examples/simple/AddressRecord.java | 2 +- src/test/java/examples/simple/CompoundKeyDynamicSqlSupport.java | 2 +- src/test/java/examples/simple/CompoundKeyMapper.java | 2 +- src/test/java/examples/simple/CompoundKeyRow.java | 2 +- src/test/java/examples/simple/LastName.java | 2 +- src/test/java/examples/simple/LastNameTypeHandler.java | 2 +- src/test/java/examples/simple/MyBatisMapToRowTest.java | 2 +- src/test/java/examples/simple/PersonDynamicSqlSupport.java | 2 +- src/test/java/examples/simple/PersonMapper.java | 2 +- src/test/java/examples/simple/PersonMapperTest.java | 2 +- src/test/java/examples/simple/PersonRecord.java | 2 +- src/test/java/examples/simple/PersonWithAddress.java | 2 +- src/test/java/examples/simple/PersonWithAddressMapper.java | 2 +- src/test/java/examples/simple/ReusableWhereTest.java | 2 +- src/test/java/examples/simple/YesNoTypeHandler.java | 2 +- src/test/java/examples/spring/AddressDynamicSqlSupport.java | 2 +- src/test/java/examples/spring/AddressRecord.java | 2 +- src/test/java/examples/spring/CompoundKeyDynamicSqlSupport.java | 2 +- src/test/java/examples/spring/CompoundKeyRow.java | 2 +- src/test/java/examples/spring/LastName.java | 2 +- src/test/java/examples/spring/LastNameParameterConverter.java | 2 +- src/test/java/examples/spring/PersonDynamicSqlSupport.java | 2 +- src/test/java/examples/spring/PersonRecord.java | 2 +- src/test/java/examples/spring/PersonTemplateTest.java | 2 +- src/test/java/examples/spring/PersonWithAddress.java | 2 +- src/test/java/examples/spring/ReusableWhereTest.java | 2 +- src/test/java/examples/spring/SpringConfiguration.java | 2 +- src/test/java/examples/spring/SpringMapToRowTest.java | 2 +- src/test/java/examples/spring/YesNoParameterConverter.java | 2 +- .../java/examples/springbatch/SpringBatchRenderingTest.java | 2 +- .../springbatch/bulkinsert/BulkInsertConfiguration.java | 2 +- .../springbatch/bulkinsert/SpringBatchBulkInsertTest.java | 2 +- .../examples/springbatch/bulkinsert/TestRecordGenerator.java | 2 +- src/test/java/examples/springbatch/common/PersonProcessor.java | 2 +- src/test/java/examples/springbatch/common/PersonRecord.java | 2 +- .../examples/springbatch/common/UpdateStatementConvertor.java | 2 +- .../springbatch/cursor/CursorReaderBatchConfiguration.java | 2 +- .../java/examples/springbatch/cursor/SpringBatchCursorTest.java | 2 +- .../examples/springbatch/mapper/PersonDynamicSqlSupport.java | 2 +- src/test/java/examples/springbatch/mapper/PersonMapper.java | 2 +- .../springbatch/paging/PagingReaderBatchConfiguration.java | 2 +- .../java/examples/springbatch/paging/SpringBatchPagingTest.java | 2 +- .../java/examples/type_conversion/MyFilesDynamicSqlSupport.java | 2 +- src/test/java/examples/type_conversion/MyFilesMapper.java | 2 +- src/test/java/examples/type_conversion/ToBase64.java | 2 +- src/test/java/examples/type_conversion/TypeConversionTest.java | 2 +- src/test/java/issues/gh100/FromGroupByTest.java | 2 +- src/test/java/issues/gh100/FromJoinWhereTest.java | 2 +- src/test/java/issues/gh100/Issue100StartAfterJoinTest.java | 2 +- src/test/java/issues/gh100/Issue100Test.java | 2 +- src/test/java/issues/gh100/StudentDynamicSqlSupport.java | 2 +- src/test/java/issues/gh100/StudentRegDynamicSqlSupport.java | 2 +- src/test/java/issues/gh105/Issue105Test.java | 2 +- src/test/java/issues/gh105/PersonDynamicSqlSupport.java | 2 +- src/test/java/issues/gh105/SearchUtils.java | 2 +- src/test/java/issues/gh324/Issue324Test.java | 2 +- src/test/java/issues/gh324/NameRecord.java | 2 +- src/test/java/issues/gh324/NameService.java | 2 +- src/test/java/issues/gh324/NameTableDynamicSqlSupport.java | 2 +- src/test/java/issues/gh324/NameTableMapper.java | 2 +- src/test/java/issues/gh324/ObservableCache.java | 2 +- src/test/java/issues/gh324/TestUtils.java | 2 +- src/test/java/issues/gh324/spring/SpringNameService.java | 2 +- src/test/java/issues/gh324/spring/SpringTransactionTest.java | 2 +- src/test/java/issues/gh324/spring/TestConfiguration.java | 2 +- src/test/java/issues/gh430/NoInitialConditionTest.java | 2 +- src/test/java/issues/gh655/Gh655Test.java | 2 +- src/test/java/issues/lhg142/Issue142Test.java | 2 +- src/test/java/issues/lhg142/MyMarkDynamicSqlSupport.java | 2 +- src/test/java/issues/lhg142/Page.java | 2 +- src/test/java/org/mybatis/dynamic/sql/BindableColumnTest.java | 2 +- src/test/java/org/mybatis/dynamic/sql/InvalidSQLTest.java | 2 +- .../org/mybatis/dynamic/sql/StatementConfigurationTest.java | 2 +- .../dynamic/sql/configuration/GlobalConfigurationTest.java | 2 +- .../org/mybatis/dynamic/sql/delete/DeleteStatementTest.java | 2 +- .../mybatis/dynamic/sql/insert/GeneralInsertStatementTest.java | 2 +- .../org/mybatis/dynamic/sql/insert/InsertStatementTest.java | 2 +- src/test/java/org/mybatis/dynamic/sql/insert/MapToRowTest.java | 2 +- .../dynamic/sql/insert/render/FieldAndValueCollectorTest.java | 2 +- .../org/mybatis/dynamic/sql/mybatis3/CriterionRendererTest.java | 2 +- .../org/mybatis/dynamic/sql/mybatis3/InsertStatementTest.java | 2 +- .../org/mybatis/dynamic/sql/mybatis3/SelectStatementTest.java | 2 +- .../org/mybatis/dynamic/sql/mybatis3/UpdateStatementTest.java | 2 +- .../java/org/mybatis/dynamic/sql/select/HavingModelTest.java | 2 +- .../org/mybatis/dynamic/sql/select/SelectStatementTest.java | 2 +- .../org/mybatis/dynamic/sql/subselect/FooDynamicSqlSupport.java | 2 +- .../java/org/mybatis/dynamic/sql/subselect/SubSelectTest.java | 2 +- .../org/mybatis/dynamic/sql/update/UpdateStatementTest.java | 2 +- .../org/mybatis/dynamic/sql/util/ColumnMappingVisitorTest.java | 2 +- .../org/mybatis/dynamic/sql/util/FragmentCollectorTest.java | 2 +- .../org/mybatis/dynamic/sql/util/SqlProviderAdapterTest.java | 2 +- .../java/org/mybatis/dynamic/sql/util/StringUtilitiesTest.java | 2 +- src/test/java/org/mybatis/dynamic/sql/util/UtilitiesTest.java | 2 +- src/test/java/org/mybatis/dynamic/sql/where/WhereModelTest.java | 2 +- .../mybatis/dynamic/sql/where/condition/FilterAndMapTest.java | 2 +- .../org/mybatis/dynamic/sql/where/condition/SupplierTest.java | 2 +- .../mybatis/dynamic/sql/where/render/CriterionRendererTest.java | 2 +- .../dynamic/sql/where/render/OptionalCriterionRenderTest.java | 2 +- .../mybatis/dynamic/sql/where/render/RenderedCriterionTest.java | 2 +- .../examples/kotlin/animal/data/AnimalDataDynamicSqlSupport.kt | 2 +- .../kotlin/examples/kotlin/animal/data/KCaseExpressionTest.kt | 2 +- src/test/kotlin/examples/kotlin/mybatis3/TestUtils.kt | 2 +- .../kotlin/mybatis3/canonical/AddressDynamicSqlSupport.kt | 2 +- .../kotlin/examples/kotlin/mybatis3/canonical/AddressMapper.kt | 2 +- .../kotlin/examples/kotlin/mybatis3/canonical/AddressRecord.kt | 2 +- .../mybatis3/canonical/GeneratedAlwaysDynamicSqlSupport.kt | 2 +- .../examples/kotlin/mybatis3/canonical/GeneratedAlwaysMapper.kt | 2 +- .../examples/kotlin/mybatis3/canonical/GeneratedAlwaysRecord.kt | 2 +- .../examples/kotlin/mybatis3/canonical/GeneratedAlwaysTest.kt | 2 +- src/test/kotlin/examples/kotlin/mybatis3/canonical/LastName.kt | 2 +- .../examples/kotlin/mybatis3/canonical/LastNameTypeHandler.kt | 2 +- .../kotlin/mybatis3/canonical/PersonDynamicSqlSupport.kt | 2 +- .../kotlin/examples/kotlin/mybatis3/canonical/PersonMapper.kt | 2 +- .../kotlin/mybatis3/canonical/PersonMapperExtensions.kt | 2 +- .../examples/kotlin/mybatis3/canonical/PersonMapperTest.kt | 2 +- .../kotlin/examples/kotlin/mybatis3/canonical/PersonRecord.kt | 2 +- .../examples/kotlin/mybatis3/canonical/PersonWithAddress.kt | 2 +- .../kotlin/mybatis3/canonical/PersonWithAddressMapper.kt | 2 +- .../mybatis3/canonical/PersonWithAddressMapperExtensions.kt | 2 +- .../examples/kotlin/mybatis3/canonical/ReusableWhereTest.kt | 2 +- .../examples/kotlin/mybatis3/canonical/YesNoTypeHandler.kt | 2 +- .../mybatis3/column/comparison/ColumnComparisonConfiguration.kt | 2 +- .../column/comparison/ColumnComparisonDynamicSqlSupport.kt | 2 +- .../kotlin/mybatis3/column/comparison/ColumnComparisonMapper.kt | 2 +- .../kotlin/mybatis3/column/comparison/ColumnComparisonRecord.kt | 2 +- .../kotlin/mybatis3/column/comparison/ColumnComparisonTest.kt | 2 +- .../kotlin/mybatis3/custom/render/KCustomRenderingTest.kt | 2 +- .../kotlin/mybatis3/custom/render/KJsonRenderingStrategy.kt | 2 +- .../kotlin/mybatis3/custom/render/KJsonTestDynamicSqlSupport.kt | 2 +- .../examples/kotlin/mybatis3/custom/render/KJsonTestMapper.kt | 2 +- .../examples/kotlin/mybatis3/custom/render/KJsonTestRecord.kt | 2 +- .../examples/kotlin/mybatis3/general/GeneralKotlinTest.kt | 2 +- .../kotlin/examples/kotlin/mybatis3/general/KGroupingTest.kt | 2 +- .../examples/kotlin/mybatis3/joins/DeprecatedJoinMapperTest.kt | 2 +- src/test/kotlin/examples/kotlin/mybatis3/joins/Domain.kt | 2 +- src/test/kotlin/examples/kotlin/mybatis3/joins/ExistsTest.kt | 2 +- .../kotlin/mybatis3/joins/ItemMasterDynamicSQLSupport.kt | 2 +- src/test/kotlin/examples/kotlin/mybatis3/joins/JoinMapper.kt | 2 +- .../examples/kotlin/mybatis3/joins/JoinMapperNewSyntaxTest.kt | 2 +- .../kotlin/mybatis3/joins/OrderDetailDynamicSQLSupport.kt | 2 +- .../kotlin/mybatis3/joins/OrderLineDynamicSQLSupport.kt | 2 +- .../kotlin/mybatis3/joins/OrderMasterDynamicSQLSupport.kt | 2 +- .../examples/kotlin/mybatis3/joins/UserDynamicSQLSupport.kt | 2 +- .../examples/kotlin/mybatis3/mariadb/KItemsDynamicSQLSupport.kt | 2 +- .../kotlin/examples/kotlin/mybatis3/mariadb/KMariaDBTest.kt | 2 +- .../kotlin/examples/kotlin/mybatis3/sharding/KShardedMapper.kt | 2 +- .../kotlin/examples/kotlin/mybatis3/sharding/KShardingTest.kt | 2 +- .../mybatis3/sharding/KTableCodesTableDynamicSQLSupport.kt | 2 +- .../kotlin/spring/canonical/AddressDynamicSqlSupport.kt | 2 +- .../spring/canonical/CanonicalSpringKotlinTemplateDirectTest.kt | 2 +- .../kotlin/spring/canonical/CanonicalSpringKotlinTest.kt | 2 +- .../kotlin/spring/canonical/CompoundKeyDynamicSqlSupport.kt | 2 +- .../examples/kotlin/spring/canonical/DomainAndConverters.kt | 2 +- .../kotlin/spring/canonical/GeneratedAlwaysDynamicSqlSupport.kt | 2 +- .../examples/kotlin/spring/canonical/InfixElementsTest.kt | 2 +- .../examples/kotlin/spring/canonical/InfixSubQueriesTest.kt | 2 +- .../examples/kotlin/spring/canonical/KotlinElementsTest.kt | 2 +- .../examples/kotlin/spring/canonical/PersonDynamicSqlSupport.kt | 2 +- src/test/kotlin/examples/kotlin/spring/canonical/RowMappers.kt | 2 +- .../examples/kotlin/spring/canonical/SpringConfiguration.kt | 2 +- .../kotlin/spring/canonical/SpringKotlinMapToRowTest.kt | 2 +- .../kotlin/spring/canonical/SpringKotlinSubQueryTest.kt | 2 +- src/test/kotlin/issues/kotlin/gh430/KNoInitialConditionsTest.kt | 2 +- src/test/kotlin/nullability/test/BetweenTest.kt | 2 +- src/test/kotlin/nullability/test/BetweenWhenPresentTest.kt | 2 +- src/test/kotlin/nullability/test/ComparisonTest.kt | 2 +- src/test/kotlin/nullability/test/CompilerUtilities.kt | 2 +- src/test/kotlin/nullability/test/EqualNotEqualTest.kt | 2 +- src/test/kotlin/nullability/test/InTest.kt | 2 +- src/test/kotlin/nullability/test/InWhenPresentTest.kt | 2 +- src/test/kotlin/nullability/test/LikeNotLikeTest.kt | 2 +- src/test/kotlin/nullability/test/NotBetweenTest.kt | 2 +- src/test/kotlin/nullability/test/NotBetweenWhenPresentTest.kt | 2 +- src/test/kotlin/nullability/test/NotInTest.kt | 2 +- src/test/kotlin/nullability/test/NotInWhenPresentTest.kt | 2 +- .../mybatis/dynamic/sql/util/kotlin/model/ModelBuilderTest.kt | 2 +- src/test/resources/defaultTrue.properties | 2 +- src/test/resources/empty.properties | 2 +- src/test/resources/examples/animal/data/CreateAnimalData.sql | 2 +- src/test/resources/examples/array/CreateDB.sql | 2 +- src/test/resources/examples/column/comparison/CreateDB.sql | 2 +- src/test/resources/examples/custom_render/dbInit.sql | 2 +- .../examples/generated/always/CreateGeneratedAlwaysDB.sql | 2 +- src/test/resources/examples/groupby/CreateGroupByDB.sql | 2 +- src/test/resources/examples/joins/CreateJoinDB.sql | 2 +- src/test/resources/examples/joins/JoinMapper.xml | 2 +- src/test/resources/examples/kotlin/mybatis3/CreateSimpleDB.sql | 2 +- .../resources/examples/kotlin/mybatis3/joins/CreateJoinDB.sql | 2 +- .../resources/examples/kotlin/mybatis3/joins/JoinMapper.xml | 2 +- .../examples/kotlin/spring/CreateGeneratedAlwaysDB.sql | 2 +- src/test/resources/examples/kotlin/spring/CreateSimpleDB.sql | 2 +- src/test/resources/examples/mariadb/CreateDB.sql | 2 +- src/test/resources/examples/schema_supplier/CreateDB.sql | 2 +- src/test/resources/examples/sharding/ShardingDB.sql | 2 +- src/test/resources/examples/simple/CreateSimpleDB.sql | 2 +- src/test/resources/examples/springbatch/data.sql | 2 +- src/test/resources/examples/springbatch/schema.sql | 2 +- src/test/resources/examples/type_conversion/CreateDB.sql | 2 +- src/test/resources/issues/gh324/CreateDB.sql | 2 +- src/test/resources/logback.xml | 2 +- src/test/resources/mybatis-dynamic-sql.properties | 2 +- 578 files changed, 578 insertions(+), 578 deletions(-) diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml index 2f7f4c3a1..93acda146 100644 --- a/.mvn/extensions.xml +++ b/.mvn/extensions.xml @@ -1,7 +1,7 @@ From 57a757c59e287f6d129d547c6c74c1972f4cea54 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 21 Feb 2025 15:51:47 +0000 Subject: [PATCH 186/289] Update junit5 monorepo to v5.12.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 53cdace6e..7a741e456 100644 --- a/pom.xml +++ b/pom.xml @@ -60,7 +60,7 @@ 17 17 17 - 5.11.4 + 5.12.0 5.2.1 checkstyle-override.xml From c263366641c018af76cbb753830107db1fccf0d6 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Sat, 22 Feb 2025 13:06:19 -0500 Subject: [PATCH 187/289] Fix Nullability Error A type converter could return null. This was not properly handled by the ValueWhenPresentMapping. --- .../sql/util/ValueWhenPresentMapping.java | 6 ++-- .../spring/LastNameParameterConverter.java | 9 ++++-- .../examples/spring/PersonTemplateTest.java | 28 +++++++++++++++++++ .../examples/simple/CreateSimpleDB.sql | 2 +- 4 files changed, 39 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/util/ValueWhenPresentMapping.java b/src/main/java/org/mybatis/dynamic/sql/util/ValueWhenPresentMapping.java index a9dae6c66..5420c644e 100644 --- a/src/main/java/org/mybatis/dynamic/sql/util/ValueWhenPresentMapping.java +++ b/src/main/java/org/mybatis/dynamic/sql/util/ValueWhenPresentMapping.java @@ -35,11 +35,11 @@ private ValueWhenPresentMapping(SqlColumn column, Supplier<@Nullable T> value } public Optional value() { - return Optional.ofNullable(valueSupplier.get()).map(this::convert); + return Optional.ofNullable(valueSupplier.get()).flatMap(this::convert); } - private @Nullable Object convert(@Nullable T value) { - return localColumn.convertParameterType(value); + private Optional convert(T value) { + return Optional.ofNullable(localColumn.convertParameterType(value)); } @Override diff --git a/src/test/java/examples/spring/LastNameParameterConverter.java b/src/test/java/examples/spring/LastNameParameterConverter.java index 2a45753d7..e8d57d4cd 100644 --- a/src/test/java/examples/spring/LastNameParameterConverter.java +++ b/src/test/java/examples/spring/LastNameParameterConverter.java @@ -16,6 +16,7 @@ package examples.spring; import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.ParameterTypeConverter; import org.springframework.core.convert.converter.Converter; @@ -23,7 +24,11 @@ public class LastNameParameterConverter implements ParameterTypeConverter, Converter { @Override - public String convert(LastName source) { - return source.getName(); + public @Nullable String convert(LastName source) { + if ("Slate".equals(source.getName())) { + return null; + } else { + return source.getName(); + } } } diff --git a/src/test/java/examples/spring/PersonTemplateTest.java b/src/test/java/examples/spring/PersonTemplateTest.java index 3934d3125..8376dcef7 100644 --- a/src/test/java/examples/spring/PersonTemplateTest.java +++ b/src/test/java/examples/spring/PersonTemplateTest.java @@ -31,6 +31,8 @@ import org.mybatis.dynamic.sql.insert.GeneralInsertModel; import org.mybatis.dynamic.sql.insert.InsertModel; import org.mybatis.dynamic.sql.insert.MultiRowInsertModel; +import org.mybatis.dynamic.sql.insert.render.GeneralInsertStatementProvider; +import org.mybatis.dynamic.sql.render.RenderingStrategies; import org.mybatis.dynamic.sql.select.SelectModel; import org.mybatis.dynamic.sql.update.UpdateModel; import org.mybatis.dynamic.sql.util.Buildable; @@ -379,6 +381,32 @@ void testInsertSelective() { assertThat(rows).isEqualTo(1); } + @Test + void testGeneralInsertWhenTypeConverterReturnsNull() { + + GeneralInsertStatementProvider insertStatement = insertInto(person) + .set(id).toValue(100) + .set(firstName).toValue("Joe") + .set(lastName).toValueWhenPresent(LastName.of("Slate")) + .set(birthDate).toValue(new Date()) + .set(employed).toValue(true) + .set(occupation).toValue("Quarry Owner") + .set(addressId).toValue(1) + .build() + .render(RenderingStrategies.SPRING_NAMED_PARAMETER); + + assertThat(insertStatement.getInsertStatement()) + .isEqualTo("insert into Person (id, first_name, birth_date, employed, occupation, address_id) values (:p1, :p2, :p3, :p4, :p5, :p6)"); + int rows = template.generalInsert(insertStatement); + assertThat(rows).isEqualTo(1); + + Buildable selectStatement = select(id, firstName, lastName, birthDate, employed, occupation, addressId) + .from(person) + .where(id, isEqualTo(100)); + Optional newRecord = template.selectOne(selectStatement, personRowMapper); + assertThat(newRecord).hasValueSatisfying(r -> assertThat(r.getLastName().getName()).isNull()); + } + @Test void testUpdateByPrimaryKey() { diff --git a/src/test/resources/examples/simple/CreateSimpleDB.sql b/src/test/resources/examples/simple/CreateSimpleDB.sql index a60c51ef9..c335c4215 100644 --- a/src/test/resources/examples/simple/CreateSimpleDB.sql +++ b/src/test/resources/examples/simple/CreateSimpleDB.sql @@ -30,7 +30,7 @@ create table Address ( create table Person ( id int not null, first_name varchar(30) not null, - last_name varchar(30) not null, + last_name varchar(30) null, birth_date date not null, employed varchar(3) not null, occupation varchar(30) null, From d761dd55b7d000e2305a3b87d15e532fc43dd73c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 25 Feb 2025 22:31:55 +0000 Subject: [PATCH 188/289] Update dependency ch.qos.logback:logback-classic to v1.5.17 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 7a741e456..be8a7a259 100644 --- a/pom.xml +++ b/pom.xml @@ -170,7 +170,7 @@ ch.qos.logback logback-classic - 1.5.16 + 1.5.17 test From 7a283ee9157d6c6ec7687f3730dbc1a8c07b82a6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 4 Mar 2025 23:33:03 +0000 Subject: [PATCH 189/289] Update testcontainers-java monorepo to v1.20.6 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index be8a7a259..584b5daa6 100644 --- a/pom.xml +++ b/pom.xml @@ -78,7 +78,7 @@ src/test/java,src/test/kotlin official - 1.20.5 + 1.20.6 org.mybatis.dynamic.sql.*;version=${project.version};-noimport:=true From 1ae2e43d103aa5f538477530fd7cc9b27304e891 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Wed, 5 Mar 2025 14:29:25 -0500 Subject: [PATCH 190/289] Allow Conditions Increased Control over Rendering --- .../AbstractColumnComparisonCondition.java | 15 +- .../sql/AbstractListValueCondition.java | 30 +++- .../dynamic/sql/AbstractNoValueCondition.java | 13 +- .../sql/AbstractSingleValueCondition.java | 21 ++- .../sql/AbstractSubselectCondition.java | 18 ++- .../sql/AbstractTwoValueCondition.java | 27 +++- .../mybatis/dynamic/sql/ConditionVisitor.java | 30 ---- .../dynamic/sql/VisitableCondition.java | 21 +-- .../SimpleCaseWhenConditionRenderer.java | 8 +- .../CaseInsensitiveVisitableCondition.java | 9 +- .../render/ColumnAndConditionRenderer.java | 15 +- .../where/render/DefaultConditionVisitor.java | 137 ------------------ .../java/examples/mysql/IsLikeEscape.java | 71 +++++++++ src/test/java/examples/mysql/MySQLTest.java | 21 +++ 14 files changed, 198 insertions(+), 238 deletions(-) delete mode 100644 src/main/java/org/mybatis/dynamic/sql/ConditionVisitor.java delete mode 100644 src/main/java/org/mybatis/dynamic/sql/where/render/DefaultConditionVisitor.java create mode 100644 src/test/java/examples/mysql/IsLikeEscape.java diff --git a/src/main/java/org/mybatis/dynamic/sql/AbstractColumnComparisonCondition.java b/src/main/java/org/mybatis/dynamic/sql/AbstractColumnComparisonCondition.java index ff6923ecb..502025401 100644 --- a/src/main/java/org/mybatis/dynamic/sql/AbstractColumnComparisonCondition.java +++ b/src/main/java/org/mybatis/dynamic/sql/AbstractColumnComparisonCondition.java @@ -15,6 +15,11 @@ */ package org.mybatis.dynamic.sql; +import static org.mybatis.dynamic.sql.util.StringUtilities.spaceBefore; + +import org.mybatis.dynamic.sql.render.RenderingContext; +import org.mybatis.dynamic.sql.util.FragmentAndParameters; + public abstract class AbstractColumnComparisonCondition implements VisitableCondition { protected final BasicColumn rightColumn; @@ -23,14 +28,10 @@ protected AbstractColumnComparisonCondition(BasicColumn rightColumn) { this.rightColumn = rightColumn; } - public BasicColumn rightColumn() { - return rightColumn; - } + public abstract String operator(); @Override - public R accept(ConditionVisitor visitor) { - return visitor.visit(this); + public FragmentAndParameters renderCondition(RenderingContext renderingContext, BindableColumn leftColumn) { + return rightColumn.render(renderingContext).mapFragment(f -> operator() + spaceBefore(f)); } - - public abstract String operator(); } diff --git a/src/main/java/org/mybatis/dynamic/sql/AbstractListValueCondition.java b/src/main/java/org/mybatis/dynamic/sql/AbstractListValueCondition.java index 21230c821..eeed434ab 100644 --- a/src/main/java/org/mybatis/dynamic/sql/AbstractListValueCondition.java +++ b/src/main/java/org/mybatis/dynamic/sql/AbstractListValueCondition.java @@ -23,6 +23,11 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import org.mybatis.dynamic.sql.render.RenderedParameterInfo; +import org.mybatis.dynamic.sql.render.RenderingContext; +import org.mybatis.dynamic.sql.util.FragmentAndParameters; +import org.mybatis.dynamic.sql.util.FragmentCollector; + public abstract class AbstractListValueCondition implements VisitableCondition { protected final Collection values; @@ -39,19 +44,14 @@ public boolean isEmpty() { return values.isEmpty(); } - @Override - public R accept(ConditionVisitor visitor) { - return visitor.visit(this); - } - private Collection applyMapper(Function mapper) { Objects.requireNonNull(mapper); - return values.stream().map(mapper).collect(Collectors.toList()); + return values().map(mapper).collect(Collectors.toList()); } private Collection applyFilter(Predicate predicate) { Objects.requireNonNull(predicate); - return values.stream().filter(predicate).toList(); + return values().filter(predicate).toList(); } protected > S filterSupport(Predicate predicate, @@ -84,4 +84,20 @@ protected > S mapSupport(Function filter(Predicate predicate); public abstract String operator(); + + @Override + public FragmentAndParameters renderCondition(RenderingContext renderingContext, BindableColumn leftColumn) { + return values().map(v -> toFragmentAndParameters(v, renderingContext, leftColumn)) + .collect(FragmentCollector.collect()) + .toFragmentAndParameters(Collectors.joining(",", //$NON-NLS-1$ + operator() + " (", ")")); //$NON-NLS-1$ //$NON-NLS-2$ + } + + private FragmentAndParameters toFragmentAndParameters(T value, RenderingContext renderingContext, + BindableColumn leftColumn) { + RenderedParameterInfo parameterInfo = renderingContext.calculateParameterInfo(leftColumn); + return FragmentAndParameters.withFragment(parameterInfo.renderedPlaceHolder()) + .withParameter(parameterInfo.parameterMapKey(), leftColumn.convertParameterType(value)) + .build(); + } } diff --git a/src/main/java/org/mybatis/dynamic/sql/AbstractNoValueCondition.java b/src/main/java/org/mybatis/dynamic/sql/AbstractNoValueCondition.java index a60f2a843..02f6e25f4 100644 --- a/src/main/java/org/mybatis/dynamic/sql/AbstractNoValueCondition.java +++ b/src/main/java/org/mybatis/dynamic/sql/AbstractNoValueCondition.java @@ -18,12 +18,10 @@ import java.util.function.BooleanSupplier; import java.util.function.Supplier; -public abstract class AbstractNoValueCondition implements VisitableCondition { +import org.mybatis.dynamic.sql.render.RenderingContext; +import org.mybatis.dynamic.sql.util.FragmentAndParameters; - @Override - public R accept(ConditionVisitor visitor) { - return visitor.visit(this); - } +public abstract class AbstractNoValueCondition implements VisitableCondition { protected > S filterSupport(BooleanSupplier booleanSupplier, Supplier emptySupplier, S self) { @@ -35,4 +33,9 @@ protected > S filterSupport(BooleanSupplie } public abstract String operator(); + + @Override + public FragmentAndParameters renderCondition(RenderingContext renderingContext, BindableColumn leftColumn) { + return FragmentAndParameters.fromFragment(operator()); + } } diff --git a/src/main/java/org/mybatis/dynamic/sql/AbstractSingleValueCondition.java b/src/main/java/org/mybatis/dynamic/sql/AbstractSingleValueCondition.java index 13d4dc8e1..a361c4ed0 100644 --- a/src/main/java/org/mybatis/dynamic/sql/AbstractSingleValueCondition.java +++ b/src/main/java/org/mybatis/dynamic/sql/AbstractSingleValueCondition.java @@ -15,10 +15,16 @@ */ package org.mybatis.dynamic.sql; +import static org.mybatis.dynamic.sql.util.StringUtilities.spaceBefore; + import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; +import org.mybatis.dynamic.sql.render.RenderedParameterInfo; +import org.mybatis.dynamic.sql.render.RenderingContext; +import org.mybatis.dynamic.sql.util.FragmentAndParameters; + public abstract class AbstractSingleValueCondition implements VisitableCondition { protected final T value; @@ -30,11 +36,6 @@ public T value() { return value; } - @Override - public R accept(ConditionVisitor visitor) { - return visitor.visit(this); - } - protected > S filterSupport(Predicate predicate, Supplier emptySupplier, S self) { if (isEmpty()) { @@ -64,4 +65,14 @@ protected > S mapSupport(Function filter(Predicate predicate); public abstract String operator(); + + @Override + public FragmentAndParameters renderCondition(RenderingContext renderingContext, BindableColumn leftColumn) { + RenderedParameterInfo parameterInfo = renderingContext.calculateParameterInfo(leftColumn); + String finalFragment = operator() + spaceBefore(parameterInfo.renderedPlaceHolder()); + + return FragmentAndParameters.withFragment(finalFragment) + .withParameter(parameterInfo.parameterMapKey(), leftColumn.convertParameterType(value())) + .build(); + } } diff --git a/src/main/java/org/mybatis/dynamic/sql/AbstractSubselectCondition.java b/src/main/java/org/mybatis/dynamic/sql/AbstractSubselectCondition.java index 4408f279c..3254fbd2d 100644 --- a/src/main/java/org/mybatis/dynamic/sql/AbstractSubselectCondition.java +++ b/src/main/java/org/mybatis/dynamic/sql/AbstractSubselectCondition.java @@ -15,8 +15,11 @@ */ package org.mybatis.dynamic.sql; +import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.select.SelectModel; +import org.mybatis.dynamic.sql.select.render.SubQueryRenderer; import org.mybatis.dynamic.sql.util.Buildable; +import org.mybatis.dynamic.sql.util.FragmentAndParameters; public abstract class AbstractSubselectCondition implements VisitableCondition { private final SelectModel selectModel; @@ -25,14 +28,15 @@ protected AbstractSubselectCondition(Buildable selectModelBuilder) this.selectModel = selectModelBuilder.build(); } - public SelectModel selectModel() { - return selectModel; - } + public abstract String operator(); @Override - public R accept(ConditionVisitor visitor) { - return visitor.visit(this); + public FragmentAndParameters renderCondition(RenderingContext renderingContext, BindableColumn leftColumn) { + return SubQueryRenderer.withSelectModel(selectModel) + .withRenderingContext(renderingContext) + .withPrefix(operator() + " (") //$NON-NLS-1$ + .withSuffix(")") //$NON-NLS-1$ + .build() + .render(); } - - public abstract String operator(); } diff --git a/src/main/java/org/mybatis/dynamic/sql/AbstractTwoValueCondition.java b/src/main/java/org/mybatis/dynamic/sql/AbstractTwoValueCondition.java index c36fe186d..fe34333a2 100644 --- a/src/main/java/org/mybatis/dynamic/sql/AbstractTwoValueCondition.java +++ b/src/main/java/org/mybatis/dynamic/sql/AbstractTwoValueCondition.java @@ -15,12 +15,18 @@ */ package org.mybatis.dynamic.sql; +import static org.mybatis.dynamic.sql.util.StringUtilities.spaceBefore; + import java.util.function.BiFunction; import java.util.function.BiPredicate; import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; +import org.mybatis.dynamic.sql.render.RenderedParameterInfo; +import org.mybatis.dynamic.sql.render.RenderingContext; +import org.mybatis.dynamic.sql.util.FragmentAndParameters; + public abstract class AbstractTwoValueCondition implements VisitableCondition { protected final T value1; protected final T value2; @@ -38,11 +44,6 @@ public T value2() { return value2; } - @Override - public R accept(ConditionVisitor visitor) { - return visitor.visit(this); - } - protected > S filterSupport(BiPredicate predicate, Supplier emptySupplier, S self) { if (isEmpty()) { @@ -90,4 +91,20 @@ protected > S mapSupport(Function leftColumn) { + RenderedParameterInfo parameterInfo1 = renderingContext.calculateParameterInfo(leftColumn); + RenderedParameterInfo parameterInfo2 = renderingContext.calculateParameterInfo(leftColumn); + + String finalFragment = operator1() + + spaceBefore(parameterInfo1.renderedPlaceHolder()) + + spaceBefore(operator2()) + + spaceBefore(parameterInfo2.renderedPlaceHolder()); + + return FragmentAndParameters.withFragment(finalFragment) + .withParameter(parameterInfo1.parameterMapKey(), leftColumn.convertParameterType(value1())) + .withParameter(parameterInfo2.parameterMapKey(), leftColumn.convertParameterType(value2())) + .build(); + } } diff --git a/src/main/java/org/mybatis/dynamic/sql/ConditionVisitor.java b/src/main/java/org/mybatis/dynamic/sql/ConditionVisitor.java deleted file mode 100644 index 99a4fd36c..000000000 --- a/src/main/java/org/mybatis/dynamic/sql/ConditionVisitor.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2016-2025 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.mybatis.dynamic.sql; - -public interface ConditionVisitor { - R visit(AbstractListValueCondition condition); - - R visit(AbstractNoValueCondition condition); - - R visit(AbstractSingleValueCondition condition); - - R visit(AbstractTwoValueCondition condition); - - R visit(AbstractSubselectCondition condition); - - R visit(AbstractColumnComparisonCondition condition); -} diff --git a/src/main/java/org/mybatis/dynamic/sql/VisitableCondition.java b/src/main/java/org/mybatis/dynamic/sql/VisitableCondition.java index fc974b932..d201ae4dd 100644 --- a/src/main/java/org/mybatis/dynamic/sql/VisitableCondition.java +++ b/src/main/java/org/mybatis/dynamic/sql/VisitableCondition.java @@ -16,10 +16,17 @@ package org.mybatis.dynamic.sql; import org.mybatis.dynamic.sql.render.RenderingContext; +import org.mybatis.dynamic.sql.util.FragmentAndParameters; @FunctionalInterface public interface VisitableCondition { - R accept(ConditionVisitor visitor); + FragmentAndParameters renderCondition(RenderingContext renderingContext, BindableColumn leftColumn); + + default FragmentAndParameters renderLeftColumn(RenderingContext renderingContext, BindableColumn leftColumn) { + return leftColumn.alias() + .map(FragmentAndParameters::fromFragment) + .orElseGet(() -> leftColumn.render(renderingContext)); + } /** * Subclasses can override this to inform the renderer if the condition should not be included @@ -46,16 +53,4 @@ default boolean isEmpty() { * returns false. */ default void renderingSkipped() {} - - /** - * This method is called during rendering. Its purpose is to allow conditions to change - * the value of the rendered left column. This is primarily used in the case-insensitive conditions - * where we surround the rendered column with "upper(" and ")". - * - * @param renderedLeftColumn the rendered left column - * @return the altered column - by default no change is applied - */ - default String overrideRenderedLeftColumn(String renderedLeftColumn) { - return renderedLeftColumn; - } } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/SimpleCaseWhenConditionRenderer.java b/src/main/java/org/mybatis/dynamic/sql/select/render/SimpleCaseWhenConditionRenderer.java index 702f1a0ad..cb13434d3 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/render/SimpleCaseWhenConditionRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/render/SimpleCaseWhenConditionRenderer.java @@ -28,20 +28,14 @@ import org.mybatis.dynamic.sql.util.FragmentAndParameters; import org.mybatis.dynamic.sql.util.FragmentCollector; import org.mybatis.dynamic.sql.util.Validator; -import org.mybatis.dynamic.sql.where.render.DefaultConditionVisitor; public class SimpleCaseWhenConditionRenderer implements SimpleCaseWhenConditionVisitor { private final RenderingContext renderingContext; private final BindableColumn column; - private final DefaultConditionVisitor conditionVisitor; public SimpleCaseWhenConditionRenderer(RenderingContext renderingContext, BindableColumn column) { this.renderingContext = Objects.requireNonNull(renderingContext); this.column = Objects.requireNonNull(column); - conditionVisitor = new DefaultConditionVisitor.Builder() - .withColumn(column) - .withRenderingContext(renderingContext) - .build(); } @Override @@ -68,7 +62,7 @@ private boolean shouldRender(VisitableCondition condition) { } private FragmentAndParameters renderCondition(VisitableCondition condition) { - return condition.accept(conditionVisitor); + return condition.renderCondition(renderingContext, column); } private FragmentAndParameters renderBasicValue(T value) { diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/CaseInsensitiveVisitableCondition.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/CaseInsensitiveVisitableCondition.java index c0eef325a..9315b68fa 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/CaseInsensitiveVisitableCondition.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/CaseInsensitiveVisitableCondition.java @@ -15,12 +15,17 @@ */ package org.mybatis.dynamic.sql.where.condition; +import org.mybatis.dynamic.sql.BindableColumn; import org.mybatis.dynamic.sql.VisitableCondition; +import org.mybatis.dynamic.sql.render.RenderingContext; +import org.mybatis.dynamic.sql.util.FragmentAndParameters; public interface CaseInsensitiveVisitableCondition extends VisitableCondition { @Override - default String overrideRenderedLeftColumn(String renderedLeftColumn) { - return "upper(" + renderedLeftColumn + ")"; //$NON-NLS-1$ //$NON-NLS-2$ + default FragmentAndParameters renderLeftColumn(RenderingContext renderingContext, + BindableColumn leftColumn) { + return VisitableCondition.super.renderLeftColumn(renderingContext, leftColumn) + .mapFragment(s -> "upper(" + s + ")"); //$NON-NLS-1$ //$NON-NLS-2$ } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/render/ColumnAndConditionRenderer.java b/src/main/java/org/mybatis/dynamic/sql/where/render/ColumnAndConditionRenderer.java index 6035c143b..d640c0796 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/render/ColumnAndConditionRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/render/ColumnAndConditionRenderer.java @@ -29,31 +29,20 @@ public class ColumnAndConditionRenderer { private final BindableColumn column; private final VisitableCondition condition; private final RenderingContext renderingContext; - private final DefaultConditionVisitor visitor; private ColumnAndConditionRenderer(Builder builder) { column = Objects.requireNonNull(builder.column); condition = Objects.requireNonNull(builder.condition); renderingContext = Objects.requireNonNull(builder.renderingContext); - visitor = DefaultConditionVisitor.withColumn(column) - .withRenderingContext(renderingContext) - .build(); } public FragmentAndParameters render() { FragmentCollector fc = new FragmentCollector(); - fc.add(renderLeftColumn()); - fc.add(condition.accept(visitor)); + fc.add(condition.renderLeftColumn(renderingContext, column)); + fc.add(condition.renderCondition(renderingContext, column)); return fc.toFragmentAndParameters(Collectors.joining(" ")); //$NON-NLS-1$ } - private FragmentAndParameters renderLeftColumn() { - return column.alias() - .map(FragmentAndParameters::fromFragment) - .orElseGet(() -> column.render(renderingContext)) - .mapFragment(condition::overrideRenderedLeftColumn); - } - public static class Builder { private @Nullable BindableColumn column; private @Nullable VisitableCondition condition; diff --git a/src/main/java/org/mybatis/dynamic/sql/where/render/DefaultConditionVisitor.java b/src/main/java/org/mybatis/dynamic/sql/where/render/DefaultConditionVisitor.java deleted file mode 100644 index 78bbc81e7..000000000 --- a/src/main/java/org/mybatis/dynamic/sql/where/render/DefaultConditionVisitor.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright 2016-2025 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.mybatis.dynamic.sql.where.render; - -import static org.mybatis.dynamic.sql.util.StringUtilities.spaceBefore; - -import java.util.Objects; -import java.util.stream.Collectors; - -import org.jspecify.annotations.Nullable; -import org.mybatis.dynamic.sql.AbstractColumnComparisonCondition; -import org.mybatis.dynamic.sql.AbstractListValueCondition; -import org.mybatis.dynamic.sql.AbstractNoValueCondition; -import org.mybatis.dynamic.sql.AbstractSingleValueCondition; -import org.mybatis.dynamic.sql.AbstractSubselectCondition; -import org.mybatis.dynamic.sql.AbstractTwoValueCondition; -import org.mybatis.dynamic.sql.BindableColumn; -import org.mybatis.dynamic.sql.ConditionVisitor; -import org.mybatis.dynamic.sql.render.RenderedParameterInfo; -import org.mybatis.dynamic.sql.render.RenderingContext; -import org.mybatis.dynamic.sql.select.render.SubQueryRenderer; -import org.mybatis.dynamic.sql.util.FragmentAndParameters; -import org.mybatis.dynamic.sql.util.FragmentCollector; - -public class DefaultConditionVisitor implements ConditionVisitor { - - private final BindableColumn column; - private final RenderingContext renderingContext; - - private DefaultConditionVisitor(Builder builder) { - column = Objects.requireNonNull(builder.column); - renderingContext = Objects.requireNonNull(builder.renderingContext); - } - - @Override - public FragmentAndParameters visit(AbstractListValueCondition condition) { - return condition.values().map(this::toFragmentAndParameters) - .collect(FragmentCollector.collect()) - .toFragmentAndParameters(Collectors.joining(",", //$NON-NLS-1$ - condition.operator() + " (", ")")); //$NON-NLS-1$ //$NON-NLS-2$ - } - - @Override - public FragmentAndParameters visit(AbstractNoValueCondition condition) { - return FragmentAndParameters.fromFragment(condition.operator()); - } - - @Override - public FragmentAndParameters visit(AbstractSingleValueCondition condition) { - RenderedParameterInfo parameterInfo = renderingContext.calculateParameterInfo(column); - String finalFragment = condition.operator() - + spaceBefore(parameterInfo.renderedPlaceHolder()); - - return FragmentAndParameters.withFragment(finalFragment) - .withParameter(parameterInfo.parameterMapKey(), convertValue(condition.value())) - .build(); - } - - @Override - public FragmentAndParameters visit(AbstractTwoValueCondition condition) { - RenderedParameterInfo parameterInfo1 = renderingContext.calculateParameterInfo(column); - RenderedParameterInfo parameterInfo2 = renderingContext.calculateParameterInfo(column); - - String finalFragment = condition.operator1() - + spaceBefore(parameterInfo1.renderedPlaceHolder()) - + spaceBefore(condition.operator2()) - + spaceBefore(parameterInfo2.renderedPlaceHolder()); - - return FragmentAndParameters.withFragment(finalFragment) - .withParameter(parameterInfo1.parameterMapKey(), convertValue(condition.value1())) - .withParameter(parameterInfo2.parameterMapKey(), convertValue(condition.value2())) - .build(); - } - - @Override - public FragmentAndParameters visit(AbstractSubselectCondition condition) { - return SubQueryRenderer.withSelectModel(condition.selectModel()) - .withRenderingContext(renderingContext) - .withPrefix(condition.operator() + " (") //$NON-NLS-1$ - .withSuffix(")") //$NON-NLS-1$ - .build() - .render(); - } - - @Override - public FragmentAndParameters visit(AbstractColumnComparisonCondition condition) { - return condition.rightColumn().render(renderingContext) - .mapFragment(f -> condition.operator() + spaceBefore(f)); - } - - private @Nullable Object convertValue(T value) { - return column.convertParameterType(value); - } - - private FragmentAndParameters toFragmentAndParameters(T value) { - RenderedParameterInfo parameterInfo = renderingContext.calculateParameterInfo(column); - return FragmentAndParameters.withFragment(parameterInfo.renderedPlaceHolder()) - .withParameter(parameterInfo.parameterMapKey(), convertValue(value)) - .build(); - } - - public static Builder withColumn(BindableColumn column) { - return new Builder().withColumn(column); - } - - public static class Builder { - private @Nullable BindableColumn column; - private @Nullable RenderingContext renderingContext; - - public Builder withColumn(BindableColumn column) { - this.column = column; - return this; - } - - public Builder withRenderingContext(RenderingContext renderingContext) { - this.renderingContext = renderingContext; - return this; - } - - public DefaultConditionVisitor build() { - return new DefaultConditionVisitor<>(this); - } - } -} diff --git a/src/test/java/examples/mysql/IsLikeEscape.java b/src/test/java/examples/mysql/IsLikeEscape.java new file mode 100644 index 000000000..28e3045c2 --- /dev/null +++ b/src/test/java/examples/mysql/IsLikeEscape.java @@ -0,0 +1,71 @@ +/* + * Copyright 2016-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package examples.mysql; + +import java.util.NoSuchElementException; +import java.util.function.Function; + +import org.jspecify.annotations.NullMarked; +import org.mybatis.dynamic.sql.BindableColumn; +import org.mybatis.dynamic.sql.render.RenderingContext; +import org.mybatis.dynamic.sql.util.FragmentAndParameters; +import org.mybatis.dynamic.sql.where.condition.IsLike; + +@NullMarked +public class IsLikeEscape extends IsLike { + private static final IsLikeEscape EMPTY = new IsLikeEscape(-1, "") { + @Override + public Object value() { + throw new NoSuchElementException("No value present"); //$NON-NLS-1$ + } + + @Override + public boolean isEmpty() { + return true; + } + }; + + public static IsLikeEscape empty() { + @SuppressWarnings("unchecked") + IsLikeEscape t = (IsLikeEscape) EMPTY; + return t; + } + + private final String escapeString; + + protected IsLikeEscape(T value, String escapeString) { + super(value); + this.escapeString = escapeString; + } + + @Override + public FragmentAndParameters renderCondition(RenderingContext renderingContext, BindableColumn leftColumn) { + return super.renderCondition(renderingContext, leftColumn).mapFragment(this::addEscape); + } + + private String addEscape(String s) { + return s + " ESCAPE '" + escapeString + "'"; + } + + @Override + public IsLike map(Function mapper) { + return mapSupport(mapper, v -> new IsLikeEscape<>(v, escapeString), IsLikeEscape::empty); + } + + public static IsLikeEscape isLike(T value, String escapeString) { + return new IsLikeEscape<>(value, escapeString); + } +} diff --git a/src/test/java/examples/mysql/MySQLTest.java b/src/test/java/examples/mysql/MySQLTest.java index 54c43c34a..20dd9fd39 100644 --- a/src/test/java/examples/mysql/MySQLTest.java +++ b/src/test/java/examples/mysql/MySQLTest.java @@ -119,4 +119,25 @@ void testMemberOfAsFunction() { assertThat(rows.get(2)).containsOnly(entry("id", 3), entry("inList", 1L)); } } + + @Test + void testIsLikeEscape() { + try (SqlSession session = sqlSessionFactory.openSession()) { + CommonSelectMapper mapper = session.getMapper(CommonSelectMapper.class); + + SelectStatementProvider selectStatement = select(id, description) + .from(items) + .where(description, IsLikeEscape.isLike("Item 1%", "#").map(s -> s)) + .orderBy(id) + .build() + .render(RenderingStrategies.MYBATIS3); + + assertThat(selectStatement.getSelectStatement()) + .isEqualTo("select id, description from items where description like #{parameters.p1,jdbcType=VARCHAR} ESCAPE '#' order by id"); + + List> rows = mapper.selectManyMappedRows(selectStatement); + assertThat(rows).hasSize(11); + assertThat(rows.get(2)).containsOnly(entry("id", 11), entry("description", "Item 11")); + } + } } From 0cfecd75f30a46898b5cab77d566f436830f51b3 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Wed, 5 Mar 2025 15:53:31 -0500 Subject: [PATCH 191/289] Rename VisitableCondition to RenderableCondition Conditions are no longer rendered via a Visitor, so the new name makes more sense --- .../dynamic/sql/RenderableCondition.java | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 src/main/java/org/mybatis/dynamic/sql/RenderableCondition.java diff --git a/src/main/java/org/mybatis/dynamic/sql/RenderableCondition.java b/src/main/java/org/mybatis/dynamic/sql/RenderableCondition.java new file mode 100644 index 000000000..4ca7a17f2 --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/RenderableCondition.java @@ -0,0 +1,56 @@ +/* + * Copyright 2016-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mybatis.dynamic.sql; + +import org.mybatis.dynamic.sql.render.RenderingContext; +import org.mybatis.dynamic.sql.util.FragmentAndParameters; + +@FunctionalInterface +public interface RenderableCondition { + FragmentAndParameters renderCondition(RenderingContext renderingContext, BindableColumn leftColumn); + + default FragmentAndParameters renderLeftColumn(RenderingContext renderingContext, BindableColumn leftColumn) { + return leftColumn.alias() + .map(FragmentAndParameters::fromFragment) + .orElseGet(() -> leftColumn.render(renderingContext)); + } + + /** + * Subclasses can override this to inform the renderer if the condition should not be included + * in the rendered SQL. Typically, conditions will not render if they are empty. + * + * @return true if the condition should render. + */ + default boolean shouldRender(RenderingContext renderingContext) { + return !isEmpty(); + } + + /** + * Subclasses can override this to indicate whether the condition is considered empty. This is primarily used in + * map and filter operations - the map and filter functions will not be applied if the condition is empty. + * + * @return true if the condition is empty. + */ + default boolean isEmpty() { + return false; + } + + /** + * This method will be called during rendering when {@link RenderableCondition#shouldRender(RenderingContext)} + * returns false. + */ + default void renderingSkipped() {} +} From bc4becaebee9ba07ef3f525e9537e6cdf05e9aec Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Wed, 5 Mar 2025 15:54:21 -0500 Subject: [PATCH 192/289] Rename VisitableCondition to RenderableCondition Conditions are no longer rendered via a Visitor, so the new name makes more sense --- CHANGELOG.md | 4 ++ .../AbstractColumnComparisonCondition.java | 2 +- .../sql/AbstractListValueCondition.java | 2 +- .../dynamic/sql/AbstractNoValueCondition.java | 2 +- .../sql/AbstractSingleValueCondition.java | 2 +- .../sql/AbstractSubselectCondition.java | 2 +- .../sql/AbstractTwoValueCondition.java | 2 +- .../sql/ColumnAndConditionCriterion.java | 8 +-- .../org/mybatis/dynamic/sql/SqlBuilder.java | 20 +++---- .../dynamic/sql/VisitableCondition.java | 54 ++++++------------- .../common/AbstractBooleanExpressionDSL.java | 12 ++--- .../sql/select/AbstractHavingStarter.java | 6 +-- .../sql/select/QueryExpressionDSL.java | 11 ++-- .../dynamic/sql/select/aggregate/Sum.java | 6 +-- .../ConditionBasedWhenCondition.java | 8 +-- .../caseexpression/SearchedCaseDSL.java | 6 +-- .../select/caseexpression/SimpleCaseDSL.java | 16 +++--- .../SimpleCaseWhenConditionRenderer.java | 6 +-- .../sql/where/AbstractWhereStarter.java | 6 +-- .../CaseInsensitiveVisitableCondition.java | 6 +-- .../render/ColumnAndConditionRenderer.java | 8 +-- .../util/kotlin/GroupingCriteriaCollector.kt | 4 +- .../dynamic/sql/util/kotlin/JoinCollector.kt | 4 +- .../sql/util/kotlin/elements/CaseDSLs.kt | 4 +- .../sql/util/kotlin/elements/SqlElements.kt | 4 +- 25 files changed, 95 insertions(+), 110 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c12f44da..8b333e3ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -100,6 +100,10 @@ Runtime behavior changes: these concepts for different databases it simply adds known clauses to a generated SQL statement. You should always test to make sure these functions work in your target database. Currently, we support, and test, the options supported by PostgreSQL. +- Rendering for all the conditions (isEqualTo, etc.) has changed. This should be transparent to most users unless you + have coded a direct implementation of `VisitableCondition`. The change makes it easier to code custom conditions that + are not supported by the library out of the box. The statement renderers now call methods `renderCondition` and + `renderLeftColumn` that you can override to implement any rendering you need. ## Release 1.5.2 - June 3, 2024 diff --git a/src/main/java/org/mybatis/dynamic/sql/AbstractColumnComparisonCondition.java b/src/main/java/org/mybatis/dynamic/sql/AbstractColumnComparisonCondition.java index 502025401..65e45aafe 100644 --- a/src/main/java/org/mybatis/dynamic/sql/AbstractColumnComparisonCondition.java +++ b/src/main/java/org/mybatis/dynamic/sql/AbstractColumnComparisonCondition.java @@ -20,7 +20,7 @@ import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.util.FragmentAndParameters; -public abstract class AbstractColumnComparisonCondition implements VisitableCondition { +public abstract class AbstractColumnComparisonCondition implements RenderableCondition { protected final BasicColumn rightColumn; diff --git a/src/main/java/org/mybatis/dynamic/sql/AbstractListValueCondition.java b/src/main/java/org/mybatis/dynamic/sql/AbstractListValueCondition.java index eeed434ab..23f48e6f4 100644 --- a/src/main/java/org/mybatis/dynamic/sql/AbstractListValueCondition.java +++ b/src/main/java/org/mybatis/dynamic/sql/AbstractListValueCondition.java @@ -28,7 +28,7 @@ import org.mybatis.dynamic.sql.util.FragmentAndParameters; import org.mybatis.dynamic.sql.util.FragmentCollector; -public abstract class AbstractListValueCondition implements VisitableCondition { +public abstract class AbstractListValueCondition implements RenderableCondition { protected final Collection values; protected AbstractListValueCondition(Collection values) { diff --git a/src/main/java/org/mybatis/dynamic/sql/AbstractNoValueCondition.java b/src/main/java/org/mybatis/dynamic/sql/AbstractNoValueCondition.java index 02f6e25f4..c0e103baf 100644 --- a/src/main/java/org/mybatis/dynamic/sql/AbstractNoValueCondition.java +++ b/src/main/java/org/mybatis/dynamic/sql/AbstractNoValueCondition.java @@ -21,7 +21,7 @@ import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.util.FragmentAndParameters; -public abstract class AbstractNoValueCondition implements VisitableCondition { +public abstract class AbstractNoValueCondition implements RenderableCondition { protected > S filterSupport(BooleanSupplier booleanSupplier, Supplier emptySupplier, S self) { diff --git a/src/main/java/org/mybatis/dynamic/sql/AbstractSingleValueCondition.java b/src/main/java/org/mybatis/dynamic/sql/AbstractSingleValueCondition.java index a361c4ed0..9c8248d02 100644 --- a/src/main/java/org/mybatis/dynamic/sql/AbstractSingleValueCondition.java +++ b/src/main/java/org/mybatis/dynamic/sql/AbstractSingleValueCondition.java @@ -25,7 +25,7 @@ import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.util.FragmentAndParameters; -public abstract class AbstractSingleValueCondition implements VisitableCondition { +public abstract class AbstractSingleValueCondition implements RenderableCondition { protected final T value; protected AbstractSingleValueCondition(T value) { diff --git a/src/main/java/org/mybatis/dynamic/sql/AbstractSubselectCondition.java b/src/main/java/org/mybatis/dynamic/sql/AbstractSubselectCondition.java index 3254fbd2d..dcfbd4b3c 100644 --- a/src/main/java/org/mybatis/dynamic/sql/AbstractSubselectCondition.java +++ b/src/main/java/org/mybatis/dynamic/sql/AbstractSubselectCondition.java @@ -21,7 +21,7 @@ import org.mybatis.dynamic.sql.util.Buildable; import org.mybatis.dynamic.sql.util.FragmentAndParameters; -public abstract class AbstractSubselectCondition implements VisitableCondition { +public abstract class AbstractSubselectCondition implements RenderableCondition { private final SelectModel selectModel; protected AbstractSubselectCondition(Buildable selectModelBuilder) { diff --git a/src/main/java/org/mybatis/dynamic/sql/AbstractTwoValueCondition.java b/src/main/java/org/mybatis/dynamic/sql/AbstractTwoValueCondition.java index fe34333a2..865f7db0b 100644 --- a/src/main/java/org/mybatis/dynamic/sql/AbstractTwoValueCondition.java +++ b/src/main/java/org/mybatis/dynamic/sql/AbstractTwoValueCondition.java @@ -27,7 +27,7 @@ import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.util.FragmentAndParameters; -public abstract class AbstractTwoValueCondition implements VisitableCondition { +public abstract class AbstractTwoValueCondition implements RenderableCondition { protected final T value1; protected final T value2; diff --git a/src/main/java/org/mybatis/dynamic/sql/ColumnAndConditionCriterion.java b/src/main/java/org/mybatis/dynamic/sql/ColumnAndConditionCriterion.java index 646e695c2..053c18f64 100644 --- a/src/main/java/org/mybatis/dynamic/sql/ColumnAndConditionCriterion.java +++ b/src/main/java/org/mybatis/dynamic/sql/ColumnAndConditionCriterion.java @@ -21,7 +21,7 @@ public class ColumnAndConditionCriterion extends SqlCriterion { private final BindableColumn column; - private final VisitableCondition condition; + private final RenderableCondition condition; private ColumnAndConditionCriterion(Builder builder) { super(builder); @@ -33,7 +33,7 @@ public BindableColumn column() { return column; } - public VisitableCondition condition() { + public RenderableCondition condition() { return condition; } @@ -48,14 +48,14 @@ public static Builder withColumn(BindableColumn column) { public static class Builder extends AbstractBuilder> { private @Nullable BindableColumn column; - private @Nullable VisitableCondition condition; + private @Nullable RenderableCondition condition; public Builder withColumn(BindableColumn column) { this.column = column; return this; } - public Builder withCondition(VisitableCondition condition) { + public Builder withCondition(RenderableCondition condition) { this.condition = condition; return this; } diff --git a/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java b/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java index 8b36417fe..1e27db93d 100644 --- a/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java +++ b/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java @@ -250,7 +250,7 @@ static WhereDSL.StandaloneWhereFinisher where() { return new WhereDSL().where(); } - static WhereDSL.StandaloneWhereFinisher where(BindableColumn column, VisitableCondition condition, + static WhereDSL.StandaloneWhereFinisher where(BindableColumn column, RenderableCondition condition, AndOrCriteriaGroup... subCriteria) { return new WhereDSL().where(column, condition, subCriteria); } @@ -263,7 +263,7 @@ static WhereDSL.StandaloneWhereFinisher where(ExistsPredicate existsPredicate, A return new WhereDSL().where(existsPredicate, subCriteria); } - static HavingDSL.StandaloneHavingFinisher having(BindableColumn column, VisitableCondition condition, + static HavingDSL.StandaloneHavingFinisher having(BindableColumn column, RenderableCondition condition, AndOrCriteriaGroup... subCriteria) { return new HavingDSL().having(column, condition, subCriteria); } @@ -273,12 +273,12 @@ static HavingDSL.StandaloneHavingFinisher having(SqlCriterion initialCriterion, } // where condition connectors - static CriteriaGroup group(BindableColumn column, VisitableCondition condition, + static CriteriaGroup group(BindableColumn column, RenderableCondition condition, AndOrCriteriaGroup... subCriteria) { return group(column, condition, Arrays.asList(subCriteria)); } - static CriteriaGroup group(BindableColumn column, VisitableCondition condition, + static CriteriaGroup group(BindableColumn column, RenderableCondition condition, List subCriteria) { return new CriteriaGroup.Builder() .withInitialCriterion(new ColumnAndConditionCriterion.Builder().withColumn(column) @@ -316,12 +316,12 @@ static CriteriaGroup group(List subCriteria) { .build(); } - static NotCriterion not(BindableColumn column, VisitableCondition condition, + static NotCriterion not(BindableColumn column, RenderableCondition condition, AndOrCriteriaGroup... subCriteria) { return not(column, condition, Arrays.asList(subCriteria)); } - static NotCriterion not(BindableColumn column, VisitableCondition condition, + static NotCriterion not(BindableColumn column, RenderableCondition condition, List subCriteria) { return new NotCriterion.Builder() .withInitialCriterion(new ColumnAndConditionCriterion.Builder().withColumn(column) @@ -359,7 +359,7 @@ static NotCriterion not(List subCriteria) { .build(); } - static AndOrCriteriaGroup or(BindableColumn column, VisitableCondition condition, + static AndOrCriteriaGroup or(BindableColumn column, RenderableCondition condition, AndOrCriteriaGroup... subCriteria) { return new AndOrCriteriaGroup.Builder() .withInitialCriterion(ColumnAndConditionCriterion.withColumn(column) @@ -394,7 +394,7 @@ static AndOrCriteriaGroup or(List subCriteria) { .build(); } - static AndOrCriteriaGroup and(BindableColumn column, VisitableCondition condition, + static AndOrCriteriaGroup and(BindableColumn column, RenderableCondition condition, AndOrCriteriaGroup... subCriteria) { return new AndOrCriteriaGroup.Builder() .withInitialCriterion(ColumnAndConditionCriterion.withColumn(column) @@ -430,7 +430,7 @@ static AndOrCriteriaGroup and(List subCriteria) { } // join support - static ColumnAndConditionCriterion on(BindableColumn joinColumn, VisitableCondition joinCondition) { + static ColumnAndConditionCriterion on(BindableColumn joinColumn, RenderableCondition joinCondition) { return ColumnAndConditionCriterion.withColumn(joinColumn) .withCondition(joinCondition) .build(); @@ -506,7 +506,7 @@ static Sum sum(BasicColumn column) { return Sum.of(column); } - static Sum sum(BindableColumn column, VisitableCondition condition) { + static Sum sum(BindableColumn column, RenderableCondition condition) { return Sum.of(column, condition); } diff --git a/src/main/java/org/mybatis/dynamic/sql/VisitableCondition.java b/src/main/java/org/mybatis/dynamic/sql/VisitableCondition.java index d201ae4dd..9969c3997 100644 --- a/src/main/java/org/mybatis/dynamic/sql/VisitableCondition.java +++ b/src/main/java/org/mybatis/dynamic/sql/VisitableCondition.java @@ -16,41 +16,21 @@ package org.mybatis.dynamic.sql; import org.mybatis.dynamic.sql.render.RenderingContext; -import org.mybatis.dynamic.sql.util.FragmentAndParameters; -@FunctionalInterface -public interface VisitableCondition { - FragmentAndParameters renderCondition(RenderingContext renderingContext, BindableColumn leftColumn); - - default FragmentAndParameters renderLeftColumn(RenderingContext renderingContext, BindableColumn leftColumn) { - return leftColumn.alias() - .map(FragmentAndParameters::fromFragment) - .orElseGet(() -> leftColumn.render(renderingContext)); - } - - /** - * Subclasses can override this to inform the renderer if the condition should not be included - * in the rendered SQL. Typically, conditions will not render if they are empty. - * - * @return true if the condition should render. - */ - default boolean shouldRender(RenderingContext renderingContext) { - return !isEmpty(); - } - - /** - * Subclasses can override this to indicate whether the condition is considered empty. This is primarily used in - * map and filter operations - the map and filter functions will not be applied if the condition is empty. - * - * @return true if the condition is empty. - */ - default boolean isEmpty() { - return false; - } - - /** - * This method will be called during rendering when {@link VisitableCondition#shouldRender(RenderingContext)} - * returns false. - */ - default void renderingSkipped() {} -} +/** + * Deprecated interface. + * + *

Conditions are no longer rendered with a visitor, so the name is misleading. This change makes it far easier + * to implement custom conditions for functionality not supplied out of the box by the library. + * + *

If you created any direct implementations of this interface, you will need to change the rendering functions. + * The library now calls {@link RenderableCondition#renderCondition(RenderingContext, BindableColumn)} and + * {@link RenderableCondition#renderLeftColumn(RenderingContext, BindableColumn)} instead of the previous methods + * like operator, value, etc. Subclasses of the supplied abstract conditions should continue + * to function as before. + * + * @param the Java type related to the column this condition relates to. Used primarily for compiler type checking + * @deprecated since 2.0.0. Please use {@link RenderableCondition} instead. + */ +@Deprecated(since = "2.0.0", forRemoval = true) +public interface VisitableCondition extends RenderableCondition { } diff --git a/src/main/java/org/mybatis/dynamic/sql/common/AbstractBooleanExpressionDSL.java b/src/main/java/org/mybatis/dynamic/sql/common/AbstractBooleanExpressionDSL.java index c671b39a9..2f817fb5f 100644 --- a/src/main/java/org/mybatis/dynamic/sql/common/AbstractBooleanExpressionDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/common/AbstractBooleanExpressionDSL.java @@ -26,20 +26,20 @@ import org.mybatis.dynamic.sql.CriteriaGroup; import org.mybatis.dynamic.sql.ExistsCriterion; import org.mybatis.dynamic.sql.ExistsPredicate; +import org.mybatis.dynamic.sql.RenderableCondition; import org.mybatis.dynamic.sql.SqlCriterion; -import org.mybatis.dynamic.sql.VisitableCondition; import org.mybatis.dynamic.sql.util.Validator; public abstract class AbstractBooleanExpressionDSL> { private @Nullable SqlCriterion initialCriterion; protected final List subCriteria = new ArrayList<>(); - public T and(BindableColumn column, VisitableCondition condition, + public T and(BindableColumn column, RenderableCondition condition, AndOrCriteriaGroup... subCriteria) { return and(column, condition, Arrays.asList(subCriteria)); } - public T and(BindableColumn column, VisitableCondition condition, + public T and(BindableColumn column, RenderableCondition condition, List subCriteria) { addSubCriteria("and", buildCriterion(column, condition), subCriteria); //$NON-NLS-1$ return getThis(); @@ -68,12 +68,12 @@ public T and(List criteria) { return getThis(); } - public T or(BindableColumn column, VisitableCondition condition, + public T or(BindableColumn column, RenderableCondition condition, AndOrCriteriaGroup... subCriteria) { return or(column, condition, Arrays.asList(subCriteria)); } - public T or(BindableColumn column, VisitableCondition condition, + public T or(BindableColumn column, RenderableCondition condition, List subCriteria) { addSubCriteria("or", buildCriterion(column, condition), subCriteria); //$NON-NLS-1$ return getThis(); @@ -102,7 +102,7 @@ public T or(List criteria) { return getThis(); } - private SqlCriterion buildCriterion(BindableColumn column, VisitableCondition condition) { + private SqlCriterion buildCriterion(BindableColumn column, RenderableCondition condition) { return ColumnAndConditionCriterion.withColumn(column).withCondition(condition).build(); } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/AbstractHavingStarter.java b/src/main/java/org/mybatis/dynamic/sql/select/AbstractHavingStarter.java index c8375bbd3..1090fb064 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/AbstractHavingStarter.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/AbstractHavingStarter.java @@ -22,17 +22,17 @@ import org.mybatis.dynamic.sql.BindableColumn; import org.mybatis.dynamic.sql.ColumnAndConditionCriterion; import org.mybatis.dynamic.sql.CriteriaGroup; +import org.mybatis.dynamic.sql.RenderableCondition; import org.mybatis.dynamic.sql.SqlCriterion; -import org.mybatis.dynamic.sql.VisitableCondition; public interface AbstractHavingStarter> { - default F having(BindableColumn column, VisitableCondition condition, + default F having(BindableColumn column, RenderableCondition condition, AndOrCriteriaGroup... subCriteria) { return having(column, condition, Arrays.asList(subCriteria)); } - default F having(BindableColumn column, VisitableCondition condition, + default F having(BindableColumn column, RenderableCondition condition, List subCriteria) { SqlCriterion sqlCriterion = ColumnAndConditionCriterion.withColumn(column) .withCondition(condition) 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 b61f5e98a..70ad2617d 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionDSL.java @@ -28,10 +28,10 @@ import org.mybatis.dynamic.sql.BindableColumn; import org.mybatis.dynamic.sql.ColumnAndConditionCriterion; import org.mybatis.dynamic.sql.CriteriaGroup; +import org.mybatis.dynamic.sql.RenderableCondition; import org.mybatis.dynamic.sql.SortSpecification; import org.mybatis.dynamic.sql.SqlTable; import org.mybatis.dynamic.sql.TableExpression; -import org.mybatis.dynamic.sql.VisitableCondition; import org.mybatis.dynamic.sql.common.AbstractBooleanExpressionDSL; import org.mybatis.dynamic.sql.configuration.StatementConfiguration; import org.mybatis.dynamic.sql.select.join.JoinSpecification; @@ -324,11 +324,11 @@ public JoinSpecificationStarter(TableExpression joinTable, JoinType joinType) { this.joinType = joinType; } - public JoinSpecificationFinisher on(BindableColumn joinColumn, VisitableCondition joinCondition) { + public JoinSpecificationFinisher on(BindableColumn joinColumn, RenderableCondition joinCondition) { return new JoinSpecificationFinisher(joinTable, joinColumn, joinCondition, joinType); } - public JoinSpecificationFinisher on(BindableColumn joinColumn, VisitableCondition onJoinCondition, + public JoinSpecificationFinisher on(BindableColumn joinColumn, RenderableCondition onJoinCondition, AndOrCriteriaGroup... subCriteria) { return new JoinSpecificationFinisher(joinTable, joinColumn, onJoinCondition, joinType, subCriteria); } @@ -343,7 +343,7 @@ public class JoinSpecificationFinisher private final JoinType joinType; public JoinSpecificationFinisher(TableExpression table, BindableColumn joinColumn, - VisitableCondition joinCondition, JoinType joinType) { + RenderableCondition joinCondition, JoinType joinType) { this.table = table; this.joinType = joinType; addJoinSpecificationSupplier(this::buildJoinSpecification); @@ -356,7 +356,8 @@ public JoinSpecificationFinisher(TableExpression table, BindableColumn jo } public JoinSpecificationFinisher(TableExpression table, BindableColumn joinColumn, - VisitableCondition joinCondition, JoinType joinType, AndOrCriteriaGroup... subCriteria) { + RenderableCondition joinCondition, JoinType joinType, + AndOrCriteriaGroup... subCriteria) { this.table = table; this.joinType = joinType; addJoinSpecificationSupplier(this::buildJoinSpecification); diff --git a/src/main/java/org/mybatis/dynamic/sql/select/aggregate/Sum.java b/src/main/java/org/mybatis/dynamic/sql/select/aggregate/Sum.java index 6b9cd657e..7ccfd7854 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/aggregate/Sum.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/aggregate/Sum.java @@ -19,7 +19,7 @@ import org.mybatis.dynamic.sql.BasicColumn; import org.mybatis.dynamic.sql.BindableColumn; -import org.mybatis.dynamic.sql.VisitableCondition; +import org.mybatis.dynamic.sql.RenderableCondition; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.select.function.AbstractUniTypeFunction; import org.mybatis.dynamic.sql.util.FragmentAndParameters; @@ -34,7 +34,7 @@ private Sum(BasicColumn column) { renderer = rc -> column.render(rc).mapFragment(this::applyAggregate); } - private Sum(BindableColumn column, VisitableCondition condition) { + private Sum(BindableColumn column, RenderableCondition condition) { super(column); renderer = rc -> { Validator.assertTrue(condition.shouldRender(rc), "ERROR.37", "sum"); //$NON-NLS-1$ //$NON-NLS-2$ @@ -76,7 +76,7 @@ public static Sum of(BasicColumn column) { return new Sum<>(column); } - public static Sum of(BindableColumn column, VisitableCondition condition) { + public static Sum of(BindableColumn column, RenderableCondition condition) { return new Sum<>(column, condition); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/ConditionBasedWhenCondition.java b/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/ConditionBasedWhenCondition.java index fe3178bff..78f841b1d 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/ConditionBasedWhenCondition.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/ConditionBasedWhenCondition.java @@ -20,17 +20,17 @@ import java.util.stream.Stream; import org.mybatis.dynamic.sql.BasicColumn; -import org.mybatis.dynamic.sql.VisitableCondition; +import org.mybatis.dynamic.sql.RenderableCondition; public class ConditionBasedWhenCondition extends SimpleCaseWhenCondition { - private final List> conditions = new ArrayList<>(); + private final List> conditions = new ArrayList<>(); - public ConditionBasedWhenCondition(List> conditions, BasicColumn thenValue) { + public ConditionBasedWhenCondition(List> conditions, BasicColumn thenValue) { super(thenValue); this.conditions.addAll(conditions); } - public Stream> conditions() { + public Stream> conditions() { return conditions.stream(); } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/SearchedCaseDSL.java b/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/SearchedCaseDSL.java index 0c0c6ea87..c86bf7ff0 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/SearchedCaseDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/SearchedCaseDSL.java @@ -25,20 +25,20 @@ import org.mybatis.dynamic.sql.BindableColumn; import org.mybatis.dynamic.sql.ColumnAndConditionCriterion; import org.mybatis.dynamic.sql.CriteriaGroup; +import org.mybatis.dynamic.sql.RenderableCondition; import org.mybatis.dynamic.sql.SqlCriterion; -import org.mybatis.dynamic.sql.VisitableCondition; import org.mybatis.dynamic.sql.common.AbstractBooleanExpressionDSL; public class SearchedCaseDSL implements ElseDSL { private final List whenConditions = new ArrayList<>(); private @Nullable BasicColumn elseValue; - public WhenDSL when(BindableColumn column, VisitableCondition condition, + public WhenDSL when(BindableColumn column, RenderableCondition condition, AndOrCriteriaGroup... subCriteria) { return when(column, condition, Arrays.asList(subCriteria)); } - public WhenDSL when(BindableColumn column, VisitableCondition condition, + public WhenDSL when(BindableColumn column, RenderableCondition condition, List subCriteria) { SqlCriterion sqlCriterion = ColumnAndConditionCriterion.withColumn(column) .withCondition(condition) diff --git a/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/SimpleCaseDSL.java b/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/SimpleCaseDSL.java index 488f20060..be2e1e908 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/SimpleCaseDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/SimpleCaseDSL.java @@ -23,7 +23,7 @@ import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.BasicColumn; import org.mybatis.dynamic.sql.BindableColumn; -import org.mybatis.dynamic.sql.VisitableCondition; +import org.mybatis.dynamic.sql.RenderableCondition; public class SimpleCaseDSL implements ElseDSL.SimpleCaseEnder> { private final BindableColumn column; @@ -35,13 +35,13 @@ private SimpleCaseDSL(BindableColumn column) { } @SafeVarargs - public final ConditionBasedWhenFinisher when(VisitableCondition condition, - VisitableCondition... subsequentConditions) { + public final ConditionBasedWhenFinisher when(RenderableCondition condition, + RenderableCondition... subsequentConditions) { return when(condition, Arrays.asList(subsequentConditions)); } - public ConditionBasedWhenFinisher when(VisitableCondition condition, - List> subsequentConditions) { + public ConditionBasedWhenFinisher when(RenderableCondition condition, + List> subsequentConditions) { return new ConditionBasedWhenFinisher(condition, subsequentConditions); } @@ -70,10 +70,10 @@ public SimpleCaseModel end() { } public class ConditionBasedWhenFinisher implements ThenDSL> { - private final List> conditions = new ArrayList<>(); + private final List> conditions = new ArrayList<>(); - private ConditionBasedWhenFinisher(VisitableCondition condition, - List> subsequentConditions) { + private ConditionBasedWhenFinisher(RenderableCondition condition, + List> subsequentConditions) { conditions.add(condition); conditions.addAll(subsequentConditions); } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/SimpleCaseWhenConditionRenderer.java b/src/main/java/org/mybatis/dynamic/sql/select/render/SimpleCaseWhenConditionRenderer.java index cb13434d3..1bb6e2adc 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/render/SimpleCaseWhenConditionRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/render/SimpleCaseWhenConditionRenderer.java @@ -19,7 +19,7 @@ import java.util.stream.Collectors; import org.mybatis.dynamic.sql.BindableColumn; -import org.mybatis.dynamic.sql.VisitableCondition; +import org.mybatis.dynamic.sql.RenderableCondition; import org.mybatis.dynamic.sql.render.RenderedParameterInfo; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.select.caseexpression.BasicWhenCondition; @@ -57,11 +57,11 @@ public FragmentAndParameters visit(BasicWhenCondition whenCondition) { .toFragmentAndParameters(Collectors.joining(", ")); //$NON-NLS-1$ } - private boolean shouldRender(VisitableCondition condition) { + private boolean shouldRender(RenderableCondition condition) { return condition.shouldRender(renderingContext); } - private FragmentAndParameters renderCondition(VisitableCondition condition) { + private FragmentAndParameters renderCondition(RenderableCondition condition) { return condition.renderCondition(renderingContext, column); } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/AbstractWhereStarter.java b/src/main/java/org/mybatis/dynamic/sql/where/AbstractWhereStarter.java index 3a037e5e9..17efa091e 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/AbstractWhereStarter.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/AbstractWhereStarter.java @@ -25,8 +25,8 @@ import org.mybatis.dynamic.sql.CriteriaGroup; import org.mybatis.dynamic.sql.ExistsCriterion; import org.mybatis.dynamic.sql.ExistsPredicate; +import org.mybatis.dynamic.sql.RenderableCondition; import org.mybatis.dynamic.sql.SqlCriterion; -import org.mybatis.dynamic.sql.VisitableCondition; import org.mybatis.dynamic.sql.util.ConfigurableStatement; /** @@ -39,11 +39,11 @@ public interface AbstractWhereStarter, D extends AbstractWhereStarter> extends ConfigurableStatement { - default F where(BindableColumn column, VisitableCondition condition, AndOrCriteriaGroup... subCriteria) { + default F where(BindableColumn column, RenderableCondition condition, AndOrCriteriaGroup... subCriteria) { return where(column, condition, Arrays.asList(subCriteria)); } - default F where(BindableColumn column, VisitableCondition condition, + default F where(BindableColumn column, RenderableCondition condition, List subCriteria) { SqlCriterion sqlCriterion = ColumnAndConditionCriterion.withColumn(column) .withCondition(condition) diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/CaseInsensitiveVisitableCondition.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/CaseInsensitiveVisitableCondition.java index 9315b68fa..9224ad594 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/CaseInsensitiveVisitableCondition.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/CaseInsensitiveVisitableCondition.java @@ -16,16 +16,16 @@ package org.mybatis.dynamic.sql.where.condition; import org.mybatis.dynamic.sql.BindableColumn; -import org.mybatis.dynamic.sql.VisitableCondition; +import org.mybatis.dynamic.sql.RenderableCondition; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.util.FragmentAndParameters; -public interface CaseInsensitiveVisitableCondition extends VisitableCondition { +public interface CaseInsensitiveVisitableCondition extends RenderableCondition { @Override default FragmentAndParameters renderLeftColumn(RenderingContext renderingContext, BindableColumn leftColumn) { - return VisitableCondition.super.renderLeftColumn(renderingContext, leftColumn) + return RenderableCondition.super.renderLeftColumn(renderingContext, leftColumn) .mapFragment(s -> "upper(" + s + ")"); //$NON-NLS-1$ //$NON-NLS-2$ } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/render/ColumnAndConditionRenderer.java b/src/main/java/org/mybatis/dynamic/sql/where/render/ColumnAndConditionRenderer.java index d640c0796..c094bca1b 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/render/ColumnAndConditionRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/render/ColumnAndConditionRenderer.java @@ -20,14 +20,14 @@ import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.BindableColumn; -import org.mybatis.dynamic.sql.VisitableCondition; +import org.mybatis.dynamic.sql.RenderableCondition; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.util.FragmentAndParameters; import org.mybatis.dynamic.sql.util.FragmentCollector; public class ColumnAndConditionRenderer { private final BindableColumn column; - private final VisitableCondition condition; + private final RenderableCondition condition; private final RenderingContext renderingContext; private ColumnAndConditionRenderer(Builder builder) { @@ -45,7 +45,7 @@ public FragmentAndParameters render() { public static class Builder { private @Nullable BindableColumn column; - private @Nullable VisitableCondition condition; + private @Nullable RenderableCondition condition; private @Nullable RenderingContext renderingContext; public Builder withColumn(BindableColumn column) { @@ -53,7 +53,7 @@ public Builder withColumn(BindableColumn column) { return this; } - public Builder withCondition(VisitableCondition condition) { + public Builder withCondition(RenderableCondition condition) { this.condition = condition; return this; } diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/GroupingCriteriaCollector.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/GroupingCriteriaCollector.kt index 841539eeb..0aaaff460 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/GroupingCriteriaCollector.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/GroupingCriteriaCollector.kt @@ -22,9 +22,9 @@ import org.mybatis.dynamic.sql.ColumnAndConditionCriterion import org.mybatis.dynamic.sql.CriteriaGroup import org.mybatis.dynamic.sql.ExistsCriterion import org.mybatis.dynamic.sql.NotCriterion +import org.mybatis.dynamic.sql.RenderableCondition import org.mybatis.dynamic.sql.SqlBuilder import org.mybatis.dynamic.sql.SqlCriterion -import org.mybatis.dynamic.sql.VisitableCondition typealias GroupingCriteriaReceiver = GroupingCriteriaCollector.() -> Unit @@ -229,7 +229,7 @@ open class GroupingCriteriaCollector : SubCriteriaCollector() { * * @param condition the condition to be applied to this column, in this scope */ - operator fun BindableColumn.invoke(condition: VisitableCondition) { + operator fun BindableColumn.invoke(condition: RenderableCondition) { initialCriterion = ColumnAndConditionCriterion.withColumn(this) .withCondition(condition) .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 f85927682..c65b37a7a 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 @@ -16,8 +16,8 @@ package org.mybatis.dynamic.sql.util.kotlin import org.mybatis.dynamic.sql.BindableColumn +import org.mybatis.dynamic.sql.RenderableCondition import org.mybatis.dynamic.sql.SqlBuilder -import org.mybatis.dynamic.sql.VisitableCondition typealias JoinReceiver = JoinCollector.() -> Unit @@ -38,7 +38,7 @@ class JoinCollector { } } -class RightColumnCollector(private val joinConditionConsumer: (VisitableCondition) -> Unit) { +class RightColumnCollector(private val joinConditionConsumer: (RenderableCondition) -> Unit) { infix fun equalTo(rightColumn: BindableColumn) = joinConditionConsumer.invoke(SqlBuilder.isEqualTo(rightColumn)) infix fun equalTo(value: T) = joinConditionConsumer.invoke(SqlBuilder.isEqualTo(value)) diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/CaseDSLs.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/CaseDSLs.kt index bc04a992d..ce33f27b7 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/CaseDSLs.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/CaseDSLs.kt @@ -16,7 +16,7 @@ package org.mybatis.dynamic.sql.util.kotlin.elements import org.mybatis.dynamic.sql.BasicColumn -import org.mybatis.dynamic.sql.VisitableCondition +import org.mybatis.dynamic.sql.RenderableCondition import org.mybatis.dynamic.sql.select.caseexpression.BasicWhenCondition import org.mybatis.dynamic.sql.select.caseexpression.ConditionBasedWhenCondition import org.mybatis.dynamic.sql.select.caseexpression.SearchedCaseWhenCondition @@ -67,7 +67,7 @@ class KSimpleCaseDSL : KElseDSL { } internal val whenConditions = mutableListOf>() - fun `when`(vararg conditions: VisitableCondition) = + fun `when`(vararg conditions: RenderableCondition) = SimpleCaseThenGatherer { whenConditions.add(ConditionBasedWhenCondition(conditions.asList(), it)) } fun `when`(vararg values: T) = diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/SqlElements.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/SqlElements.kt index a7fe899d6..536032605 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/SqlElements.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/SqlElements.kt @@ -21,11 +21,11 @@ import org.mybatis.dynamic.sql.BasicColumn import org.mybatis.dynamic.sql.BindableColumn import org.mybatis.dynamic.sql.BoundValue import org.mybatis.dynamic.sql.Constant +import org.mybatis.dynamic.sql.RenderableCondition import org.mybatis.dynamic.sql.SortSpecification import org.mybatis.dynamic.sql.SqlBuilder import org.mybatis.dynamic.sql.SqlColumn import org.mybatis.dynamic.sql.StringConstant -import org.mybatis.dynamic.sql.VisitableCondition import org.mybatis.dynamic.sql.select.caseexpression.SearchedCaseModel import org.mybatis.dynamic.sql.select.caseexpression.SimpleCaseModel import org.mybatis.dynamic.sql.select.aggregate.Avg @@ -139,7 +139,7 @@ fun sum(column: BindableColumn): Sum = SqlBuilder.sum(column) fun sum(column: BasicColumn): Sum<*> = SqlBuilder.sum(column) -fun sum(column: BindableColumn, condition: VisitableCondition): Sum = SqlBuilder.sum(column, condition) +fun sum(column: BindableColumn, condition: RenderableCondition): Sum = SqlBuilder.sum(column, condition) // constants fun constant(constant: String): Constant = SqlBuilder.constant(constant) From fd7d6e8206b69ce292647266c73916aab6d26c08 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Wed, 5 Mar 2025 16:35:34 -0500 Subject: [PATCH 193/289] Documentation --- src/site/markdown/docs/extending.md | 83 +++++++++++++++++++ .../java/examples/mysql/IsLikeEscape.java | 44 +++++++--- src/test/java/examples/mysql/MySQLTest.java | 2 +- 3 files changed, 116 insertions(+), 13 deletions(-) diff --git a/src/site/markdown/docs/extending.md b/src/site/markdown/docs/extending.md index a32dea137..eabee1e03 100644 --- a/src/site/markdown/docs/extending.md +++ b/src/site/markdown/docs/extending.md @@ -292,3 +292,86 @@ it. You can write your own rendering support if you are dissatisfied with the S Writing a custom renderer is quite complex. If you want to undertake that task, we suggest that you take the time to understand how the default renderers work first. Feel free to ask questions about this topic on the MyBatis mailing list. + +## Writing Custom Conditions + +The library supplies a full range of conditions for all the common SQL operators (=, !=, like, between, etc.) Some +databases support extensions to the standard operators. For example, MySQL supports an extension to the "LIKE" +condition - the "ESCAPE" clause. If you need to implement a condition like that, then you will need to code a +custom condition. + +Here's an example of implementing a LIKE condition that supports ESCAPE: + +```java +@NullMarked +public class IsLikeEscape extends AbstractSingleValueCondition { + private static final IsLikeEscape EMPTY = new IsLikeEscape(-1, null) { + @Override + public Object value() { + throw new NoSuchElementException("No value present"); //$NON-NLS-1$ + } + + @Override + public boolean isEmpty() { + return true; + } + }; + + public static IsLikeEscape empty() { + @SuppressWarnings("unchecked") + IsLikeEscape t = (IsLikeEscape) EMPTY; + return t; + } + + private final @Nullable Character escapeCharacter; + + protected IsLikeEscape(T value, @Nullable Character escapeCharacter) { + super(value); + this.escapeCharacter = escapeCharacter; + } + + @Override + public String operator() { + return "like"; + } + + @Override + public FragmentAndParameters renderCondition(RenderingContext renderingContext, BindableColumn leftColumn) { + var fragment = super.renderCondition(renderingContext, leftColumn); + if (escapeCharacter != null) { + fragment = fragment.mapFragment(this::addEscape); + } + + return fragment; + } + + private String addEscape(String s) { + return s + " ESCAPE '" + escapeCharacter + "'"; + } + + @Override + public IsLikeEscape filter(Predicate predicate) { + return filterSupport(predicate, IsLikeEscape::empty, this); + } + + public IsLikeEscape map(Function mapper) { + return mapSupport(mapper, v -> new IsLikeEscape<>(v, escapeCharacter), IsLikeEscape::empty); + } + + public static IsLikeEscape isLike(T value) { + return new IsLikeEscape<>(value, null); + } + + public static IsLikeEscape isLike(T value, Character escapeCharacter) { + return new IsLikeEscape<>(value, escapeCharacter); + } +} +``` + +Important notes: + +1. The class extends `AbstractSingleValueCondition` - which is appropriate for like conditions +2. The class constructor accepts an escape character that will be rendered into an ESCAPE phrase +3. The class overrides `renderCondition` and changes the library generated `FragmentAndParameters` to add the ESCAPE + phrase. **This is the key to what's needed to implement a custom condition.** +4. The class provides `map` and `filter` functions as is expected for any condition in the library diff --git a/src/test/java/examples/mysql/IsLikeEscape.java b/src/test/java/examples/mysql/IsLikeEscape.java index 28e3045c2..19e1a085c 100644 --- a/src/test/java/examples/mysql/IsLikeEscape.java +++ b/src/test/java/examples/mysql/IsLikeEscape.java @@ -17,16 +17,18 @@ import java.util.NoSuchElementException; import java.util.function.Function; +import java.util.function.Predicate; import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; +import org.mybatis.dynamic.sql.AbstractSingleValueCondition; import org.mybatis.dynamic.sql.BindableColumn; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.util.FragmentAndParameters; -import org.mybatis.dynamic.sql.where.condition.IsLike; @NullMarked -public class IsLikeEscape extends IsLike { - private static final IsLikeEscape EMPTY = new IsLikeEscape(-1, "") { +public class IsLikeEscape extends AbstractSingleValueCondition { + private static final IsLikeEscape EMPTY = new IsLikeEscape(-1, null) { @Override public Object value() { throw new NoSuchElementException("No value present"); //$NON-NLS-1$ @@ -44,28 +46,46 @@ public static IsLikeEscape empty() { return t; } - private final String escapeString; + private final @Nullable Character escapeCharacter; - protected IsLikeEscape(T value, String escapeString) { + protected IsLikeEscape(T value, @Nullable Character escapeCharacter) { super(value); - this.escapeString = escapeString; + this.escapeCharacter = escapeCharacter; + } + + @Override + public String operator() { + return "like"; } @Override public FragmentAndParameters renderCondition(RenderingContext renderingContext, BindableColumn leftColumn) { - return super.renderCondition(renderingContext, leftColumn).mapFragment(this::addEscape); + var fragment = super.renderCondition(renderingContext, leftColumn); + if (escapeCharacter != null) { + fragment = fragment.mapFragment(this::addEscape); + } + + return fragment; } private String addEscape(String s) { - return s + " ESCAPE '" + escapeString + "'"; + return s + " ESCAPE '" + escapeCharacter + "'"; } @Override - public IsLike map(Function mapper) { - return mapSupport(mapper, v -> new IsLikeEscape<>(v, escapeString), IsLikeEscape::empty); + public IsLikeEscape filter(Predicate predicate) { + return filterSupport(predicate, IsLikeEscape::empty, this); + } + + public IsLikeEscape map(Function mapper) { + return mapSupport(mapper, v -> new IsLikeEscape<>(v, escapeCharacter), IsLikeEscape::empty); + } + + public static IsLikeEscape isLike(T value) { + return new IsLikeEscape<>(value, null); } - public static IsLikeEscape isLike(T value, String escapeString) { - return new IsLikeEscape<>(value, escapeString); + public static IsLikeEscape isLike(T value, Character escapeCharacter) { + return new IsLikeEscape<>(value, escapeCharacter); } } diff --git a/src/test/java/examples/mysql/MySQLTest.java b/src/test/java/examples/mysql/MySQLTest.java index 20dd9fd39..45c403bd7 100644 --- a/src/test/java/examples/mysql/MySQLTest.java +++ b/src/test/java/examples/mysql/MySQLTest.java @@ -127,7 +127,7 @@ void testIsLikeEscape() { SelectStatementProvider selectStatement = select(id, description) .from(items) - .where(description, IsLikeEscape.isLike("Item 1%", "#").map(s -> s)) + .where(description, IsLikeEscape.isLike("Item 1%", '#').map(s -> s)) .orderBy(id) .build() .render(RenderingStrategies.MYBATIS3); From 7dd08ab95c4a9cbb51ccce39cfc93a0505cf5a2f Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Thu, 6 Mar 2025 09:33:24 -0500 Subject: [PATCH 194/289] Documentation --- .../dynamic/sql/RenderableCondition.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/main/java/org/mybatis/dynamic/sql/RenderableCondition.java b/src/main/java/org/mybatis/dynamic/sql/RenderableCondition.java index 4ca7a17f2..51dc912e8 100644 --- a/src/main/java/org/mybatis/dynamic/sql/RenderableCondition.java +++ b/src/main/java/org/mybatis/dynamic/sql/RenderableCondition.java @@ -20,8 +20,33 @@ @FunctionalInterface public interface RenderableCondition { + /** + * Render a condition - typically a condition in a WHERE clause. + * + *

A rendered condition includes an SQL fragment, and any associated parameters. For example, + * the isEqual condition should be rendered as "= ?" where "?" is a properly formatted + * parameter marker (the parameter marker can be computed from the RenderingContext). + * Note that a rendered condition should NOT include the left side of the phrase - that is rendered + * by the {@link RenderableCondition#renderLeftColumn(RenderingContext, BindableColumn)} method. + * + * @param renderingContext the current rendering context + * @param leftColumn the column related to this condition in a where clause + * @return the rendered condition. Should NOT include the column. + */ FragmentAndParameters renderCondition(RenderingContext renderingContext, BindableColumn leftColumn); + /** + * Render the column in a column and condition phrase - typically in a WHERE clause. + * + *

By default, the column will be rendered as the column alias if it exists, or the column name. + * This can be complicated if the column has a table qualifier, or if the "column" is a function or + * part of a CASE expression. Columns know how to render themselves, so we just call their "render" + * methods. + * + * @param renderingContext the current rendering context + * @param leftColumn the column related to this condition in a where clause + * @return the rendered column + */ default FragmentAndParameters renderLeftColumn(RenderingContext renderingContext, BindableColumn leftColumn) { return leftColumn.alias() .map(FragmentAndParameters::fromFragment) From 13fb0cf5d7bee7781ea85ce24f8c5ff68c223d14 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Thu, 6 Mar 2025 09:33:38 -0500 Subject: [PATCH 195/289] Convert to record --- .../dynamic/sql/render/RenderedParameterInfo.java | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/render/RenderedParameterInfo.java b/src/main/java/org/mybatis/dynamic/sql/render/RenderedParameterInfo.java index c1be974f5..5c8187ef2 100644 --- a/src/main/java/org/mybatis/dynamic/sql/render/RenderedParameterInfo.java +++ b/src/main/java/org/mybatis/dynamic/sql/render/RenderedParameterInfo.java @@ -17,20 +17,9 @@ import java.util.Objects; -public class RenderedParameterInfo { - private final String parameterMapKey; - private final String renderedPlaceHolder; - +public record RenderedParameterInfo(String parameterMapKey, String renderedPlaceHolder) { public RenderedParameterInfo(String parameterMapKey, String renderedPlaceHolder) { this.parameterMapKey = Objects.requireNonNull(parameterMapKey); this.renderedPlaceHolder = Objects.requireNonNull(renderedPlaceHolder); } - - public String parameterMapKey() { - return parameterMapKey; - } - - public String renderedPlaceHolder() { - return renderedPlaceHolder; - } } From 1d4dbe1b5710fa81da865b4411832b8718469631 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Fri, 7 Mar 2025 09:40:55 -0500 Subject: [PATCH 196/289] Kotlin version of a custom condition --- .../kotlin/mybatis3/mariadb/KIsLikeEscape.kt | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 src/test/kotlin/examples/kotlin/mybatis3/mariadb/KIsLikeEscape.kt diff --git a/src/test/kotlin/examples/kotlin/mybatis3/mariadb/KIsLikeEscape.kt b/src/test/kotlin/examples/kotlin/mybatis3/mariadb/KIsLikeEscape.kt new file mode 100644 index 000000000..454f47d96 --- /dev/null +++ b/src/test/kotlin/examples/kotlin/mybatis3/mariadb/KIsLikeEscape.kt @@ -0,0 +1,44 @@ +package examples.kotlin.mybatis3.mariadb + +import org.mybatis.dynamic.sql.AbstractSingleValueCondition +import org.mybatis.dynamic.sql.BindableColumn +import org.mybatis.dynamic.sql.render.RenderingContext +import org.mybatis.dynamic.sql.util.FragmentAndParameters +import java.util.function.Predicate + +open class KIsLikeEscape(value: T, private val escapeCharacter: Char? = null) : AbstractSingleValueCondition(value) { + + override fun operator(): String = "like" + + override fun renderCondition( + renderingContext: RenderingContext, + leftColumn: BindableColumn + ): FragmentAndParameters { + val f = super.renderCondition(renderingContext, leftColumn) + + return escapeCharacter?.let { f.mapFragment{ "$it ESCAPE '$escapeCharacter'"} } ?: f + } + + override fun filter(predicate: Predicate): KIsLikeEscape { + return filterSupport(predicate, ::empty, this) + } + + fun map(mapper : (T) -> R): KIsLikeEscape { + return mapSupport(mapper, { r -> KIsLikeEscape(r, escapeCharacter) }, ::empty) + } + + private class EmptyCondition : KIsLikeEscape(-1) { + override fun isEmpty(): Boolean = true + + override fun value(): Any { + throw NoSuchElementException("No value present") //$NON-NLS-1$ + } + } + + companion object { + private val EMPTY: KIsLikeEscape = EmptyCondition() + + @Suppress("UNCHECKED_CAST") + fun empty(): KIsLikeEscape = EMPTY as KIsLikeEscape + } +} From 90ddb51e93948e90345f128b81e1619aa43efea2 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Fri, 7 Mar 2025 11:00:06 -0500 Subject: [PATCH 197/289] Example of a Custom Condition in Kotlin --- .../kotlin/mybatis3/mariadb/KIsLikeEscape.kt | 46 ++++++----- .../kotlin/mybatis3/mariadb/KMariaDBTest.kt | 77 +++++++++++++++++++ 2 files changed, 105 insertions(+), 18 deletions(-) diff --git a/src/test/kotlin/examples/kotlin/mybatis3/mariadb/KIsLikeEscape.kt b/src/test/kotlin/examples/kotlin/mybatis3/mariadb/KIsLikeEscape.kt index 454f47d96..e018a8329 100644 --- a/src/test/kotlin/examples/kotlin/mybatis3/mariadb/KIsLikeEscape.kt +++ b/src/test/kotlin/examples/kotlin/mybatis3/mariadb/KIsLikeEscape.kt @@ -1,44 +1,54 @@ package examples.kotlin.mybatis3.mariadb +import java.util.function.Predicate +import java.util.function.Function import org.mybatis.dynamic.sql.AbstractSingleValueCondition import org.mybatis.dynamic.sql.BindableColumn import org.mybatis.dynamic.sql.render.RenderingContext import org.mybatis.dynamic.sql.util.FragmentAndParameters -import java.util.function.Predicate -open class KIsLikeEscape(value: T, private val escapeCharacter: Char? = null) : AbstractSingleValueCondition(value) { +sealed class KIsLikeEscape( + value: T, + private val escapeCharacter: Char? = null +) : AbstractSingleValueCondition(value) { override fun operator(): String = "like" override fun renderCondition( renderingContext: RenderingContext, leftColumn: BindableColumn - ): FragmentAndParameters { - val f = super.renderCondition(renderingContext, leftColumn) - - return escapeCharacter?.let { f.mapFragment{ "$it ESCAPE '$escapeCharacter'"} } ?: f + ): FragmentAndParameters = with(super.renderCondition(renderingContext, leftColumn)) { + escapeCharacter?.let { mapFragment { "$it ESCAPE '$escapeCharacter'" } } ?: this } - override fun filter(predicate: Predicate): KIsLikeEscape { - return filterSupport(predicate, ::empty, this) - } + override fun filter(predicate: Predicate): KIsLikeEscape = + filterSupport(predicate, EmptyIsLikeEscape::empty, this) - fun map(mapper : (T) -> R): KIsLikeEscape { - return mapSupport(mapper, { r -> KIsLikeEscape(r, escapeCharacter) }, ::empty) + fun map(mapper : Function): KIsLikeEscape = + mapSupport(mapper, { r -> ConcreteIsLikeEscape(r, escapeCharacter) }, EmptyIsLikeEscape::empty) + + companion object { + fun isLike(value: T, escapeCharacter: Char? = null) : KIsLikeEscape = + ConcreteIsLikeEscape(value, escapeCharacter) } +} + +private class ConcreteIsLikeEscape( + value: T, + escapeCharacter: Char? = null +) : KIsLikeEscape(value, escapeCharacter) - private class EmptyCondition : KIsLikeEscape(-1) { - override fun isEmpty(): Boolean = true +private class EmptyIsLikeEscape : KIsLikeEscape(-1) { + override fun isEmpty(): Boolean = true - override fun value(): Any { - throw NoSuchElementException("No value present") //$NON-NLS-1$ - } + override fun value(): Any { + throw NoSuchElementException("No value present") } companion object { - private val EMPTY: KIsLikeEscape = EmptyCondition() + private val EMPTY: KIsLikeEscape = EmptyIsLikeEscape() @Suppress("UNCHECKED_CAST") - fun empty(): KIsLikeEscape = EMPTY as KIsLikeEscape + internal fun empty(): KIsLikeEscape = EMPTY as KIsLikeEscape } } diff --git a/src/test/kotlin/examples/kotlin/mybatis3/mariadb/KMariaDBTest.kt b/src/test/kotlin/examples/kotlin/mybatis3/mariadb/KMariaDBTest.kt index 8ce870c01..11593f2ac 100644 --- a/src/test/kotlin/examples/kotlin/mybatis3/mariadb/KMariaDBTest.kt +++ b/src/test/kotlin/examples/kotlin/mybatis3/mariadb/KMariaDBTest.kt @@ -38,6 +38,7 @@ import org.mybatis.dynamic.sql.util.mybatis3.CommonUpdateMapper import org.testcontainers.containers.MariaDBContainer import org.testcontainers.junit.jupiter.Container import org.testcontainers.junit.jupiter.Testcontainers +import java.util.* @Testcontainers @TestInstance(TestInstance.Lifecycle.PER_CLASS) @@ -142,6 +143,82 @@ class KMariaDBTest { } } + @Test + fun testIsLikeEscape() { + sqlSessionFactory.openSession().use { session -> + val mapper = session.getMapper(CommonSelectMapper::class.java) + val selectStatement = select(id, description) { + from(items) + where { + description(KIsLikeEscape.isLike("Item 1%", '#')) + } + } + + assertThat(selectStatement.selectStatement).isEqualTo("select id, description from items where description like #{parameters.p1,jdbcType=VARCHAR} ESCAPE '#'") + assertThat(selectStatement.parameters).containsEntry("p1", "Item 1%") + + val rows = mapper.selectManyMappedRows(selectStatement) + assertThat(rows).hasSize(11) + } + } + + @Test + fun testIsLikeEscapeNoEscapeCharacter() { + val selectStatement = select(id, description) { + from(items) + where { + description(KIsLikeEscape.isLike("%fred%")) + } + } + + assertThat(selectStatement.selectStatement).isEqualTo("select id, description from items where description like #{parameters.p1,jdbcType=VARCHAR}") + assertThat(selectStatement.parameters).containsEntry("p1", "%fred%") + } + + @Test + fun testIsLikeEscapeMap() { + val selectStatement = select(id, description) { + from(items) + where { + description(KIsLikeEscape.isLike("%fred%", '#').map { s -> s.uppercase(Locale.getDefault()) }) + } + } + + assertThat(selectStatement.selectStatement).isEqualTo("select id, description from items where description like #{parameters.p1,jdbcType=VARCHAR} ESCAPE '#'") + assertThat(selectStatement.parameters).containsEntry("p1", "%FRED%") + } + + @Test + fun testIsLikeEscapeFilter() { + val selectStatement = select(id, description) { + from(items) + where { + description(KIsLikeEscape.isLike("%fred%", '#').filter { _ -> false }) + } + configureStatement { isNonRenderingWhereClauseAllowed = true } + } + + assertThat(selectStatement.selectStatement).isEqualTo("select id, description from items") + assertThat(selectStatement.parameters).isEmpty() + } + + @Test + fun testIsLikeEscapeFilterMapFilter() { + val selectStatement = select(id, description) { + from(items) + where { + description(KIsLikeEscape.isLike("%fred%", '#') + .filter { _ -> true } + .map { s -> s.uppercase(Locale.getDefault()) } + .filter{_ -> false }) + } + configureStatement { isNonRenderingWhereClauseAllowed = true } + } + + assertThat(selectStatement.selectStatement).isEqualTo("select id, description from items") + assertThat(selectStatement.parameters).isEmpty() + } + companion object { @Container private val mariadb = MariaDBContainer(TestContainersConfiguration.MARIADB_LATEST) From 80e0d64ad0d5ee84dbf4e99579bf02251bbaa8b0 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Fri, 7 Mar 2025 11:03:14 -0500 Subject: [PATCH 198/289] Rename to match the super interface --- ...leCondition.java => CaseInsensitiveRenderableCondition.java} | 2 +- .../dynamic/sql/where/condition/IsInCaseInsensitive.java | 2 +- .../sql/where/condition/IsInCaseInsensitiveWhenPresent.java | 2 +- .../dynamic/sql/where/condition/IsLikeCaseInsensitive.java | 2 +- .../dynamic/sql/where/condition/IsNotInCaseInsensitive.java | 2 +- .../sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java | 2 +- .../dynamic/sql/where/condition/IsNotLikeCaseInsensitive.java | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) rename src/main/java/org/mybatis/dynamic/sql/where/condition/{CaseInsensitiveVisitableCondition.java => CaseInsensitiveRenderableCondition.java} (93%) diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/CaseInsensitiveVisitableCondition.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/CaseInsensitiveRenderableCondition.java similarity index 93% rename from src/main/java/org/mybatis/dynamic/sql/where/condition/CaseInsensitiveVisitableCondition.java rename to src/main/java/org/mybatis/dynamic/sql/where/condition/CaseInsensitiveRenderableCondition.java index 9224ad594..2c837c4c7 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/CaseInsensitiveVisitableCondition.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/CaseInsensitiveRenderableCondition.java @@ -20,7 +20,7 @@ import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.util.FragmentAndParameters; -public interface CaseInsensitiveVisitableCondition extends RenderableCondition { +public interface CaseInsensitiveRenderableCondition extends RenderableCondition { @Override default FragmentAndParameters renderLeftColumn(RenderingContext renderingContext, diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java index 6f14406fa..67f37951e 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java @@ -27,7 +27,7 @@ import org.mybatis.dynamic.sql.util.Validator; public class IsInCaseInsensitive extends AbstractListValueCondition - implements CaseInsensitiveVisitableCondition { + implements CaseInsensitiveRenderableCondition { private static final IsInCaseInsensitive EMPTY = new IsInCaseInsensitive(Collections.emptyList()); public static IsInCaseInsensitive empty() { diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java index d366f0857..cff58415d 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java @@ -27,7 +27,7 @@ import org.mybatis.dynamic.sql.util.Utilities; public class IsInCaseInsensitiveWhenPresent extends AbstractListValueCondition - implements CaseInsensitiveVisitableCondition { + implements CaseInsensitiveRenderableCondition { private static final IsInCaseInsensitiveWhenPresent EMPTY = new IsInCaseInsensitiveWhenPresent(Collections.emptyList()); diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitive.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitive.java index ccf6699ee..4ebdb00fb 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitive.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitive.java @@ -23,7 +23,7 @@ import org.mybatis.dynamic.sql.util.StringUtilities; public class IsLikeCaseInsensitive extends AbstractSingleValueCondition - implements CaseInsensitiveVisitableCondition { + implements CaseInsensitiveRenderableCondition { private static final IsLikeCaseInsensitive EMPTY = new IsLikeCaseInsensitive("") { //$NON-NLS-1$ @Override public String value() { diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java index b4c1e96a7..f5f970c45 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java @@ -27,7 +27,7 @@ import org.mybatis.dynamic.sql.util.Validator; public class IsNotInCaseInsensitive extends AbstractListValueCondition - implements CaseInsensitiveVisitableCondition { + implements CaseInsensitiveRenderableCondition { private static final IsNotInCaseInsensitive EMPTY = new IsNotInCaseInsensitive(Collections.emptyList()); public static IsNotInCaseInsensitive empty() { diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java index 5562b0ff4..a8873a7e4 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java @@ -27,7 +27,7 @@ import org.mybatis.dynamic.sql.util.Utilities; public class IsNotInCaseInsensitiveWhenPresent extends AbstractListValueCondition - implements CaseInsensitiveVisitableCondition { + implements CaseInsensitiveRenderableCondition { private static final IsNotInCaseInsensitiveWhenPresent EMPTY = new IsNotInCaseInsensitiveWhenPresent(Collections.emptyList()); diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitive.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitive.java index 5d9d8c3af..1fb6847c0 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitive.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitive.java @@ -23,7 +23,7 @@ import org.mybatis.dynamic.sql.util.StringUtilities; public class IsNotLikeCaseInsensitive extends AbstractSingleValueCondition - implements CaseInsensitiveVisitableCondition { + implements CaseInsensitiveRenderableCondition { private static final IsNotLikeCaseInsensitive EMPTY = new IsNotLikeCaseInsensitive("") { //$NON-NLS-1$ @Override public String value() { From ff530c6d3dd7014a417289f227564fcc386cf988 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Fri, 7 Mar 2025 11:15:19 -0500 Subject: [PATCH 199/289] Add comment about Kotlin context parameters --- .../kotlin/examples/kotlin/mybatis3/mariadb/KMariaDBTest.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/test/kotlin/examples/kotlin/mybatis3/mariadb/KMariaDBTest.kt b/src/test/kotlin/examples/kotlin/mybatis3/mariadb/KMariaDBTest.kt index 11593f2ac..ee593404c 100644 --- a/src/test/kotlin/examples/kotlin/mybatis3/mariadb/KMariaDBTest.kt +++ b/src/test/kotlin/examples/kotlin/mybatis3/mariadb/KMariaDBTest.kt @@ -143,6 +143,10 @@ class KMariaDBTest { } } + // Note that the following example uses of KIsLikeEscape are a bit awkward and don't look as natural as the + // built-in conditions. We should be able to improve this once Kotlin implements the context parameters + // proposal (https://github.com/Kotlin/KEEP/issues/367) + @Test fun testIsLikeEscape() { sqlSessionFactory.openSession().use { session -> From 6694eba0403e8bacae901be0c2388c6ec7350c97 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Fri, 7 Mar 2025 11:29:26 -0500 Subject: [PATCH 200/289] Add comment about Kotlin context parameters --- .../util/kotlin/GroupingCriteriaCollector.kt | 4 ++-- .../kotlin/mybatis3/mariadb/KMariaDBTest.kt | 22 ++++++++++++------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/GroupingCriteriaCollector.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/GroupingCriteriaCollector.kt index 0aaaff460..be4ba72af 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/GroupingCriteriaCollector.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/GroupingCriteriaCollector.kt @@ -235,8 +235,8 @@ open class GroupingCriteriaCollector : SubCriteriaCollector() { .build() } - // infix functions...we may be able to rewrite these as extension functions once Kotlin solves the multiple - // receivers problem (https://youtrack.jetbrains.com/issue/KT-42435) + // infix functions...we may be able to rewrite these as extension functions once Kotlin implements the context + // parameters proposal (https://github.com/Kotlin/KEEP/issues/367) // conditions for all data types fun BindableColumn<*>.isNull() = invoke(org.mybatis.dynamic.sql.util.kotlin.elements.isNull()) diff --git a/src/test/kotlin/examples/kotlin/mybatis3/mariadb/KMariaDBTest.kt b/src/test/kotlin/examples/kotlin/mybatis3/mariadb/KMariaDBTest.kt index ee593404c..fe1dd2906 100644 --- a/src/test/kotlin/examples/kotlin/mybatis3/mariadb/KMariaDBTest.kt +++ b/src/test/kotlin/examples/kotlin/mybatis3/mariadb/KMariaDBTest.kt @@ -143,9 +143,15 @@ class KMariaDBTest { } } - // Note that the following example uses of KIsLikeEscape are a bit awkward and don't look as natural as the - // built-in conditions. We should be able to improve this once Kotlin implements the context parameters - // proposal (https://github.com/Kotlin/KEEP/issues/367) + + /** + * Shortcut function for KIsLikeEscape + * + * Note that the following example uses of this function are a bit awkward and don't look as natural as the + * built-in conditions. We should be able to improve this once Kotlin implements the context parameters + * proposal (https://github.com/Kotlin/KEEP/issues/367) + */ + fun isLike(value: T, escapeCharacter: Char? = null) = KIsLikeEscape.isLike(value, escapeCharacter) @Test fun testIsLikeEscape() { @@ -154,7 +160,7 @@ class KMariaDBTest { val selectStatement = select(id, description) { from(items) where { - description(KIsLikeEscape.isLike("Item 1%", '#')) + description(isLike("Item 1%", '#')) } } @@ -171,7 +177,7 @@ class KMariaDBTest { val selectStatement = select(id, description) { from(items) where { - description(KIsLikeEscape.isLike("%fred%")) + description(isLike("%fred%")) } } @@ -184,7 +190,7 @@ class KMariaDBTest { val selectStatement = select(id, description) { from(items) where { - description(KIsLikeEscape.isLike("%fred%", '#').map { s -> s.uppercase(Locale.getDefault()) }) + description(isLike("%fred%", '#').map { s -> s.uppercase(Locale.getDefault()) }) } } @@ -197,7 +203,7 @@ class KMariaDBTest { val selectStatement = select(id, description) { from(items) where { - description(KIsLikeEscape.isLike("%fred%", '#').filter { _ -> false }) + description(isLike("%fred%", '#').filter { _ -> false }) } configureStatement { isNonRenderingWhereClauseAllowed = true } } @@ -211,7 +217,7 @@ class KMariaDBTest { val selectStatement = select(id, description) { from(items) where { - description(KIsLikeEscape.isLike("%fred%", '#') + description(isLike("%fred%", '#') .filter { _ -> true } .map { s -> s.uppercase(Locale.getDefault()) } .filter{_ -> false }) From 10fe79dbec366cc984a67610050b69240b44eeed Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Fri, 7 Mar 2025 11:31:06 -0500 Subject: [PATCH 201/289] Star import is not necessary --- .../kotlin/examples/kotlin/mybatis3/mariadb/KMariaDBTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/kotlin/examples/kotlin/mybatis3/mariadb/KMariaDBTest.kt b/src/test/kotlin/examples/kotlin/mybatis3/mariadb/KMariaDBTest.kt index fe1dd2906..28bf98a3b 100644 --- a/src/test/kotlin/examples/kotlin/mybatis3/mariadb/KMariaDBTest.kt +++ b/src/test/kotlin/examples/kotlin/mybatis3/mariadb/KMariaDBTest.kt @@ -38,7 +38,7 @@ import org.mybatis.dynamic.sql.util.mybatis3.CommonUpdateMapper import org.testcontainers.containers.MariaDBContainer import org.testcontainers.junit.jupiter.Container import org.testcontainers.junit.jupiter.Testcontainers -import java.util.* +import java.util.Locale @Testcontainers @TestInstance(TestInstance.Lifecycle.PER_CLASS) From 1da7647981bb2c00bb1cc0075f4b1a66d4aa4d52 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Thu, 13 Mar 2025 09:39:14 -0400 Subject: [PATCH 202/289] Define a map template method for single value --- .../sql/AbstractSingleValueCondition.java | 11 ++++++ .../org/mybatis/dynamic/sql/SqlBuilder.java | 17 +++++---- .../CaseInsensitiveRenderableCondition.java | 4 +- .../sql/where/condition/IsEqualTo.java | 10 +---- .../sql/where/condition/IsGreaterThan.java | 10 +---- .../condition/IsGreaterThanOrEqualTo.java | 10 +---- .../where/condition/IsInCaseInsensitive.java | 2 +- .../IsInCaseInsensitiveWhenPresent.java | 2 +- .../sql/where/condition/IsLessThan.java | 10 +---- .../where/condition/IsLessThanOrEqualTo.java | 10 +---- .../dynamic/sql/where/condition/IsLike.java | 10 +---- .../condition/IsLikeCaseInsensitive.java | 33 +++++++--------- .../sql/where/condition/IsNotEqualTo.java | 10 +---- .../condition/IsNotInCaseInsensitive.java | 2 +- .../IsNotInCaseInsensitiveWhenPresent.java | 2 +- .../sql/where/condition/IsNotLike.java | 13 +------ .../condition/IsNotLikeCaseInsensitive.java | 24 ++++++------ .../sql/util/kotlin/elements/SqlElements.kt | 8 ++-- .../java/examples/mysql/IsLikeEscape.java | 1 + .../sql/where/condition/FilterAndMapTest.java | 38 +++++++++---------- .../kotlin/mybatis3/mariadb/KIsLikeEscape.kt | 2 +- 21 files changed, 86 insertions(+), 143 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/AbstractSingleValueCondition.java b/src/main/java/org/mybatis/dynamic/sql/AbstractSingleValueCondition.java index 9c8248d02..f032d64db 100644 --- a/src/main/java/org/mybatis/dynamic/sql/AbstractSingleValueCondition.java +++ b/src/main/java/org/mybatis/dynamic/sql/AbstractSingleValueCondition.java @@ -64,6 +64,17 @@ protected > S mapSupport(Function filter(Predicate predicate); + /** + * If renderable, apply the mapping to the value and return a new condition with the new value. Else return a + * condition that will not render (this). + * + * @param mapper a mapping function to apply to the value, if renderable + * @param type of the new condition + * @return a new condition with the result of applying the mapper to the value of this condition, + * if renderable, otherwise a condition that will not render. + */ + public abstract AbstractSingleValueCondition map(Function mapper); + public abstract String operator(); @Override diff --git a/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java b/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java index 1e27db93d..8d462c698 100644 --- a/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java +++ b/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java @@ -882,35 +882,36 @@ static IsEqualTo isFalse() { } // conditions for strings only - static IsLikeCaseInsensitive isLikeCaseInsensitive(String value) { + static IsLikeCaseInsensitive isLikeCaseInsensitive(String value) { return IsLikeCaseInsensitive.of(value); } - static IsLikeCaseInsensitive isLikeCaseInsensitive(Supplier valueSupplier) { + static IsLikeCaseInsensitive isLikeCaseInsensitive(Supplier valueSupplier) { return isLikeCaseInsensitive(valueSupplier.get()); } - static IsLikeCaseInsensitive isLikeCaseInsensitiveWhenPresent(@Nullable String value) { + static IsLikeCaseInsensitive isLikeCaseInsensitiveWhenPresent(@Nullable String value) { return value == null ? IsLikeCaseInsensitive.empty() : IsLikeCaseInsensitive.of(value); } - static IsLikeCaseInsensitive isLikeCaseInsensitiveWhenPresent(Supplier<@Nullable String> valueSupplier) { + static IsLikeCaseInsensitive isLikeCaseInsensitiveWhenPresent(Supplier<@Nullable String> valueSupplier) { return isLikeCaseInsensitiveWhenPresent(valueSupplier.get()); } - static IsNotLikeCaseInsensitive isNotLikeCaseInsensitive(String value) { + static IsNotLikeCaseInsensitive isNotLikeCaseInsensitive(String value) { return IsNotLikeCaseInsensitive.of(value); } - static IsNotLikeCaseInsensitive isNotLikeCaseInsensitive(Supplier valueSupplier) { + static IsNotLikeCaseInsensitive isNotLikeCaseInsensitive(Supplier valueSupplier) { return isNotLikeCaseInsensitive(valueSupplier.get()); } - static IsNotLikeCaseInsensitive isNotLikeCaseInsensitiveWhenPresent(@Nullable String value) { + static IsNotLikeCaseInsensitive isNotLikeCaseInsensitiveWhenPresent(@Nullable String value) { return value == null ? IsNotLikeCaseInsensitive.empty() : IsNotLikeCaseInsensitive.of(value); } - static IsNotLikeCaseInsensitive isNotLikeCaseInsensitiveWhenPresent(Supplier<@Nullable String> valueSupplier) { + static IsNotLikeCaseInsensitive isNotLikeCaseInsensitiveWhenPresent( + Supplier<@Nullable String> valueSupplier) { return isNotLikeCaseInsensitiveWhenPresent(valueSupplier.get()); } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/CaseInsensitiveRenderableCondition.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/CaseInsensitiveRenderableCondition.java index 2c837c4c7..977a0090b 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/CaseInsensitiveRenderableCondition.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/CaseInsensitiveRenderableCondition.java @@ -20,11 +20,11 @@ import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.util.FragmentAndParameters; -public interface CaseInsensitiveRenderableCondition extends RenderableCondition { +public interface CaseInsensitiveRenderableCondition extends RenderableCondition { @Override default FragmentAndParameters renderLeftColumn(RenderingContext renderingContext, - BindableColumn leftColumn) { + BindableColumn leftColumn) { return RenderableCondition.super.renderLeftColumn(renderingContext, leftColumn) .mapFragment(s -> "upper(" + s + ")"); //$NON-NLS-1$ //$NON-NLS-2$ } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsEqualTo.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsEqualTo.java index 0a4b19207..17fe9eef1 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsEqualTo.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsEqualTo.java @@ -59,15 +59,7 @@ public IsEqualTo filter(Predicate predicate) { return filterSupport(predicate, IsEqualTo::empty, this); } - /** - * If renderable, apply the mapping to the value and return a new condition with the new value. Else return a - * condition that will not render (this). - * - * @param mapper a mapping function to apply to the value, if renderable - * @param type of the new condition - * @return a new condition with the result of applying the mapper to the value of this condition, - * if renderable, otherwise a condition that will not render. - */ + @Override public IsEqualTo map(Function mapper) { return mapSupport(mapper, IsEqualTo::new, IsEqualTo::empty); } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThan.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThan.java index a0ed1a2bc..2b3162e1a 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThan.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThan.java @@ -58,15 +58,7 @@ public IsGreaterThan filter(Predicate predicate) { return filterSupport(predicate, IsGreaterThan::empty, this); } - /** - * If renderable, apply the mapping to the value and return a new condition with the new value. Else return a - * condition that will not render (this). - * - * @param mapper a mapping function to apply to the value, if renderable - * @param type of the new condition - * @return a new condition with the result of applying the mapper to the value of this condition, - * if renderable, otherwise a condition that will not render. - */ + @Override public IsGreaterThan map(Function mapper) { return mapSupport(mapper, IsGreaterThan::new, IsGreaterThan::empty); } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanOrEqualTo.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanOrEqualTo.java index 59560339b..7439ae4a8 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanOrEqualTo.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanOrEqualTo.java @@ -58,15 +58,7 @@ public IsGreaterThanOrEqualTo filter(Predicate predicate) { return filterSupport(predicate, IsGreaterThanOrEqualTo::empty, this); } - /** - * If renderable, apply the mapping to the value and return a new condition with the new value. Else return a - * condition that will not render (this). - * - * @param mapper a mapping function to apply to the value, if renderable - * @param type of the new condition - * @return a new condition with the result of applying the mapper to the value of this condition, - * if renderable, otherwise a condition that will not render. - */ + @Override public IsGreaterThanOrEqualTo map(Function mapper) { return mapSupport(mapper, IsGreaterThanOrEqualTo::new, IsGreaterThanOrEqualTo::empty); } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java index 67f37951e..8fdf172bd 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java @@ -27,7 +27,7 @@ import org.mybatis.dynamic.sql.util.Validator; public class IsInCaseInsensitive extends AbstractListValueCondition - implements CaseInsensitiveRenderableCondition { + implements CaseInsensitiveRenderableCondition { private static final IsInCaseInsensitive EMPTY = new IsInCaseInsensitive(Collections.emptyList()); public static IsInCaseInsensitive empty() { diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java index cff58415d..91b77901a 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java @@ -27,7 +27,7 @@ import org.mybatis.dynamic.sql.util.Utilities; public class IsInCaseInsensitiveWhenPresent extends AbstractListValueCondition - implements CaseInsensitiveRenderableCondition { + implements CaseInsensitiveRenderableCondition { private static final IsInCaseInsensitiveWhenPresent EMPTY = new IsInCaseInsensitiveWhenPresent(Collections.emptyList()); diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThan.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThan.java index 09e2e7ba6..01614d6dc 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThan.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThan.java @@ -58,15 +58,7 @@ public IsLessThan filter(Predicate predicate) { return filterSupport(predicate, IsLessThan::empty, this); } - /** - * If renderable, apply the mapping to the value and return a new condition with the new value. Else return a - * condition that will not render (this). - * - * @param mapper a mapping function to apply to the value, if renderable - * @param type of the new condition - * @return a new condition with the result of applying the mapper to the value of this condition, - * if renderable, otherwise a condition that will not render. - */ + @Override public IsLessThan map(Function mapper) { return mapSupport(mapper, IsLessThan::new, IsLessThan::empty); } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanOrEqualTo.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanOrEqualTo.java index b11d06c88..20c3ed460 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanOrEqualTo.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanOrEqualTo.java @@ -58,15 +58,7 @@ public IsLessThanOrEqualTo filter(Predicate predicate) { return filterSupport(predicate, IsLessThanOrEqualTo::empty, this); } - /** - * If renderable, apply the mapping to the value and return a new condition with the new value. Else return a - * condition that will not render (this). - * - * @param mapper a mapping function to apply to the value, if renderable - * @param type of the new condition - * @return a new condition with the result of applying the mapper to the value of this condition, - * if renderable, otherwise a condition that will not render. - */ + @Override public IsLessThanOrEqualTo map(Function mapper) { return mapSupport(mapper, IsLessThanOrEqualTo::new, IsLessThanOrEqualTo::empty); } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLike.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLike.java index 9d79bed81..5c7ba967a 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLike.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLike.java @@ -58,15 +58,7 @@ public IsLike filter(Predicate predicate) { return filterSupport(predicate, IsLike::empty, this); } - /** - * If renderable, apply the mapping to the value and return a new condition with the new value. Else return a - * condition that will not render (this). - * - * @param mapper a mapping function to apply to the value, if renderable - * @param type of the new condition - * @return a new condition with the result of applying the mapper to the value of this condition, - * if renderable, otherwise a condition that will not render. - */ + @Override public IsLike map(Function mapper) { return mapSupport(mapper, IsLike::new, IsLike::empty); } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitive.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitive.java index 4ebdb00fb..921903d01 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitive.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitive.java @@ -16,15 +16,15 @@ package org.mybatis.dynamic.sql.where.condition; import java.util.NoSuchElementException; +import java.util.function.Function; import java.util.function.Predicate; -import java.util.function.UnaryOperator; import org.mybatis.dynamic.sql.AbstractSingleValueCondition; import org.mybatis.dynamic.sql.util.StringUtilities; -public class IsLikeCaseInsensitive extends AbstractSingleValueCondition - implements CaseInsensitiveRenderableCondition { - private static final IsLikeCaseInsensitive EMPTY = new IsLikeCaseInsensitive("") { //$NON-NLS-1$ +public class IsLikeCaseInsensitive extends AbstractSingleValueCondition + implements CaseInsensitiveRenderableCondition { + private static final IsLikeCaseInsensitive EMPTY = new IsLikeCaseInsensitive<>("") { //$NON-NLS-1$ @Override public String value() { throw new NoSuchElementException("No value present"); //$NON-NLS-1$ @@ -36,11 +36,13 @@ public boolean isEmpty() { } }; - public static IsLikeCaseInsensitive empty() { - return EMPTY; + public static IsLikeCaseInsensitive empty() { + @SuppressWarnings("unchecked") + IsLikeCaseInsensitive t = (IsLikeCaseInsensitive) EMPTY; + return t; } - protected IsLikeCaseInsensitive(String value) { + protected IsLikeCaseInsensitive(T value) { super(value); } @@ -50,25 +52,18 @@ public String operator() { } @Override - public IsLikeCaseInsensitive filter(Predicate predicate) { + public IsLikeCaseInsensitive filter(Predicate predicate) { return filterSupport(predicate, IsLikeCaseInsensitive::empty, this); } - /** - * If renderable, apply the mapping to the value and return a new condition with the new value. Else return a - * condition that will not render (this). - * - * @param mapper a mapping function to apply to the value, if renderable - * @return a new condition with the result of applying the mapper to the value of this condition, - * if renderable, otherwise a condition that will not render. - */ - public IsLikeCaseInsensitive map(UnaryOperator mapper) { + @Override + public IsLikeCaseInsensitive map(Function mapper) { return mapSupport(mapper, IsLikeCaseInsensitive::new, IsLikeCaseInsensitive::empty); } - public static IsLikeCaseInsensitive of(String value) { + public static IsLikeCaseInsensitive of(String value) { // Keep the null safe upper case utility for backwards compatibility //noinspection DataFlowIssue - return new IsLikeCaseInsensitive(value).map(StringUtilities::safelyUpperCase); + return new IsLikeCaseInsensitive<>(value).map(StringUtilities::safelyUpperCase); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotEqualTo.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotEqualTo.java index 821fd019f..e52ab0385 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotEqualTo.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotEqualTo.java @@ -58,15 +58,7 @@ public IsNotEqualTo filter(Predicate predicate) { return filterSupport(predicate, IsNotEqualTo::empty, this); } - /** - * If renderable, apply the mapping to the value and return a new condition with the new value. Else return a - * condition that will not render (this). - * - * @param mapper a mapping function to apply to the value, if renderable - * @param type of the new condition - * @return a new condition with the result of applying the mapper to the value of this condition, - * if renderable, otherwise a condition that will not render. - */ + @Override public IsNotEqualTo map(Function mapper) { return mapSupport(mapper, IsNotEqualTo::new, IsNotEqualTo::empty); } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java index f5f970c45..473b9077e 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java @@ -27,7 +27,7 @@ import org.mybatis.dynamic.sql.util.Validator; public class IsNotInCaseInsensitive extends AbstractListValueCondition - implements CaseInsensitiveRenderableCondition { + implements CaseInsensitiveRenderableCondition { private static final IsNotInCaseInsensitive EMPTY = new IsNotInCaseInsensitive(Collections.emptyList()); public static IsNotInCaseInsensitive empty() { diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java index a8873a7e4..b2d834f2b 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java @@ -27,7 +27,7 @@ import org.mybatis.dynamic.sql.util.Utilities; public class IsNotInCaseInsensitiveWhenPresent extends AbstractListValueCondition - implements CaseInsensitiveRenderableCondition { + implements CaseInsensitiveRenderableCondition { private static final IsNotInCaseInsensitiveWhenPresent EMPTY = new IsNotInCaseInsensitiveWhenPresent(Collections.emptyList()); diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLike.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLike.java index 7379a316b..a2cf60310 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLike.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLike.java @@ -58,18 +58,7 @@ public IsNotLike filter(Predicate predicate) { return filterSupport(predicate, IsNotLike::empty, this); } - /** - * If renderable, apply the mapping to the value and return a new condition with the new value. Else return a - * condition that will not render (this). - * - * @param mapper - * a mapping function to apply to the value, if renderable - * @param - * type of the new condition - * - * @return a new condition with the result of applying the mapper to the value of this condition, if renderable, - * otherwise a condition that will not render. - */ + @Override public IsNotLike map(Function mapper) { return mapSupport(mapper, IsNotLike::new, IsNotLike::empty); } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitive.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitive.java index 1fb6847c0..4b3604165 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitive.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitive.java @@ -16,15 +16,15 @@ package org.mybatis.dynamic.sql.where.condition; import java.util.NoSuchElementException; +import java.util.function.Function; import java.util.function.Predicate; -import java.util.function.UnaryOperator; import org.mybatis.dynamic.sql.AbstractSingleValueCondition; import org.mybatis.dynamic.sql.util.StringUtilities; -public class IsNotLikeCaseInsensitive extends AbstractSingleValueCondition - implements CaseInsensitiveRenderableCondition { - private static final IsNotLikeCaseInsensitive EMPTY = new IsNotLikeCaseInsensitive("") { //$NON-NLS-1$ +public class IsNotLikeCaseInsensitive extends AbstractSingleValueCondition + implements CaseInsensitiveRenderableCondition { + private static final IsNotLikeCaseInsensitive EMPTY = new IsNotLikeCaseInsensitive<>("") { //$NON-NLS-1$ @Override public String value() { throw new NoSuchElementException("No value present"); //$NON-NLS-1$ @@ -36,11 +36,13 @@ public boolean isEmpty() { } }; - public static IsNotLikeCaseInsensitive empty() { - return EMPTY; + public static IsNotLikeCaseInsensitive empty() { + @SuppressWarnings("unchecked") + IsNotLikeCaseInsensitive t = (IsNotLikeCaseInsensitive) EMPTY; + return t; } - protected IsNotLikeCaseInsensitive(String value) { + protected IsNotLikeCaseInsensitive(T value) { super(value); } @@ -50,7 +52,7 @@ public String operator() { } @Override - public IsNotLikeCaseInsensitive filter(Predicate predicate) { + public IsNotLikeCaseInsensitive filter(Predicate predicate) { return filterSupport(predicate, IsNotLikeCaseInsensitive::empty, this); } @@ -64,13 +66,13 @@ public IsNotLikeCaseInsensitive filter(Predicate predicate) { * @return a new condition with the result of applying the mapper to the value of this condition, if renderable, * otherwise a condition that will not render. */ - public IsNotLikeCaseInsensitive map(UnaryOperator mapper) { + public IsNotLikeCaseInsensitive map(Function mapper) { return mapSupport(mapper, IsNotLikeCaseInsensitive::new, IsNotLikeCaseInsensitive::empty); } - public static IsNotLikeCaseInsensitive of(String value) { + public static IsNotLikeCaseInsensitive of(String value) { // Keep the null safe upper case utility for backwards compatibility //noinspection DataFlowIssue - return new IsNotLikeCaseInsensitive(value).map(StringUtilities::safelyUpperCase); + return new IsNotLikeCaseInsensitive<>(value).map(StringUtilities::safelyUpperCase); } } diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/SqlElements.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/SqlElements.kt index 536032605..0983eaa9c 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/SqlElements.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/SqlElements.kt @@ -324,14 +324,14 @@ fun isTrue(): IsEqualTo = isEqualTo(true) fun isFalse(): IsEqualTo = isEqualTo(false) // conditions for strings only -fun isLikeCaseInsensitive(value: String): IsLikeCaseInsensitive = SqlBuilder.isLikeCaseInsensitive(value) +fun isLikeCaseInsensitive(value: String): IsLikeCaseInsensitive = SqlBuilder.isLikeCaseInsensitive(value) -fun isLikeCaseInsensitiveWhenPresent(value: String?): IsLikeCaseInsensitive = +fun isLikeCaseInsensitiveWhenPresent(value: String?): IsLikeCaseInsensitive = SqlBuilder.isLikeCaseInsensitiveWhenPresent(value) -fun isNotLikeCaseInsensitive(value: String): IsNotLikeCaseInsensitive = SqlBuilder.isNotLikeCaseInsensitive(value) +fun isNotLikeCaseInsensitive(value: String): IsNotLikeCaseInsensitive = SqlBuilder.isNotLikeCaseInsensitive(value) -fun isNotLikeCaseInsensitiveWhenPresent(value: String?): IsNotLikeCaseInsensitive = +fun isNotLikeCaseInsensitiveWhenPresent(value: String?): IsNotLikeCaseInsensitive = SqlBuilder.isNotLikeCaseInsensitiveWhenPresent(value) fun isInCaseInsensitive(vararg values: String): IsInCaseInsensitive = isInCaseInsensitive(values.asList()) diff --git a/src/test/java/examples/mysql/IsLikeEscape.java b/src/test/java/examples/mysql/IsLikeEscape.java index 19e1a085c..21b43fa13 100644 --- a/src/test/java/examples/mysql/IsLikeEscape.java +++ b/src/test/java/examples/mysql/IsLikeEscape.java @@ -77,6 +77,7 @@ public IsLikeEscape filter(Predicate predicate) { return filterSupport(predicate, IsLikeEscape::empty, this); } + @Override public IsLikeEscape map(Function mapper) { return mapSupport(mapper, v -> new IsLikeEscape<>(v, escapeCharacter), IsLikeEscape::empty); } diff --git a/src/test/java/org/mybatis/dynamic/sql/where/condition/FilterAndMapTest.java b/src/test/java/org/mybatis/dynamic/sql/where/condition/FilterAndMapTest.java index bd5f2e2cd..358ec0cd3 100644 --- a/src/test/java/org/mybatis/dynamic/sql/where/condition/FilterAndMapTest.java +++ b/src/test/java/org/mybatis/dynamic/sql/where/condition/FilterAndMapTest.java @@ -28,14 +28,14 @@ class FilterAndMapTest { @Test void testTypeConversion() { - IsEqualTo cond = SqlBuilder.isEqualTo("1").map(Integer::parseInt); + var cond = SqlBuilder.isEqualTo("1").map(Integer::parseInt); assertThat(cond.isEmpty()).isFalse(); assertThat(cond.value()).isEqualTo(1); } @Test void testTypeConversionWithNullThrowsException() { - IsEqualTo cond = SqlBuilder.isEqualTo((String) null); + var cond = SqlBuilder.isEqualTo((String) null); assertThatExceptionOfType(NumberFormatException.class).isThrownBy(() -> cond.map(Integer::parseInt) ); @@ -43,7 +43,7 @@ void testTypeConversionWithNullThrowsException() { @Test void testTypeConversionWithNullAndFilterDoesNotThrowException() { - IsEqualTo cond = SqlBuilder.isEqualTo((String) null).filter(Objects::nonNull).map(Integer::parseInt); + var cond = SqlBuilder.isEqualTo((String) null).filter(Objects::nonNull).map(Integer::parseInt); assertThat(cond.isEmpty()).isTrue(); } @@ -328,8 +328,8 @@ void testIsLikeMapUnRenderableShouldNotThrowNullPointerException() { @Test void testIsLikeCaseInsensitiveRenderableTruePredicateShouldReturnSameObject() { - IsLikeCaseInsensitive cond = SqlBuilder.isLikeCaseInsensitive("Fred"); - IsLikeCaseInsensitive filtered = cond.filter(s -> true); + var cond = SqlBuilder.isLikeCaseInsensitive("Fred"); + var filtered = cond.filter(s -> true); assertThat(filtered.value()).isEqualTo("FRED"); assertThat(filtered.isEmpty()).isFalse(); assertThat(cond).isSameAs(filtered); @@ -337,24 +337,24 @@ void testIsLikeCaseInsensitiveRenderableTruePredicateShouldReturnSameObject() { @Test void testIsLikeCaseInsensitiveRenderableFalsePredicate() { - IsLikeCaseInsensitive cond = SqlBuilder.isLikeCaseInsensitive("Fred"); - IsLikeCaseInsensitive filtered = cond.filter(s -> false); + var cond = SqlBuilder.isLikeCaseInsensitive("Fred"); + var filtered = cond.filter(s -> false); assertThat(cond.isEmpty()).isFalse(); assertThat(filtered.isEmpty()).isTrue(); } @Test void testIsLikeCaseInsensitiveFilterUnRenderableShouldReturnSameObject() { - IsLikeCaseInsensitive cond = SqlBuilder.isLikeCaseInsensitive("Fred").filter(s -> false); - IsLikeCaseInsensitive filtered = cond.filter(s -> true); + var cond = SqlBuilder.isLikeCaseInsensitive("Fred").filter(s -> false); + var filtered = cond.filter(s -> true); assertThat(filtered.isEmpty()).isTrue(); assertThat(cond).isSameAs(filtered); } @Test void testIsLikeCaseInsensitiveMapUnRenderableShouldNotThrowNullPointerException() { - IsLikeCaseInsensitive cond = SqlBuilder.isLikeCaseInsensitive("Fred").filter(s -> false); - IsLikeCaseInsensitive mapped = cond.map(String::toUpperCase); + IsLikeCaseInsensitive cond = SqlBuilder.isLikeCaseInsensitive("Fred").filter(s -> false); + IsLikeCaseInsensitive mapped = cond.map(String::toUpperCase); assertThat(cond.isEmpty()).isTrue(); assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value); assertThat(cond).isSameAs(mapped); @@ -395,8 +395,8 @@ void testIsNotLikeMapUnRenderableShouldNotThrowNullPointerException() { @Test void testIsNotLikeCaseInsensitiveRenderableTruePredicateShouldReturnSameObject() { - IsNotLikeCaseInsensitive cond = SqlBuilder.isNotLikeCaseInsensitive("Fred"); - IsNotLikeCaseInsensitive filtered = cond.filter(s -> true); + var cond = SqlBuilder.isNotLikeCaseInsensitive("Fred"); + var filtered = cond.filter(s -> true); assertThat(filtered.value()).isEqualTo("FRED"); assertThat(filtered.isEmpty()).isFalse(); assertThat(cond).isSameAs(filtered); @@ -404,24 +404,24 @@ void testIsNotLikeCaseInsensitiveRenderableTruePredicateShouldReturnSameObject() @Test void testIsNotLikeCaseInsensitiveRenderableFalsePredicate() { - IsNotLikeCaseInsensitive cond = SqlBuilder.isNotLikeCaseInsensitive("Fred"); - IsNotLikeCaseInsensitive filtered = cond.filter(s -> false); + var cond = SqlBuilder.isNotLikeCaseInsensitive("Fred"); + var filtered = cond.filter(s -> false); assertThat(cond.isEmpty()).isFalse(); assertThat(filtered.isEmpty()).isTrue(); } @Test void testIsNotLikeCaseInsensitiveFilterUnRenderableShouldReturnSameObject() { - IsNotLikeCaseInsensitive cond = SqlBuilder.isNotLikeCaseInsensitive("Fred").filter(s -> false); - IsNotLikeCaseInsensitive filtered = cond.filter(s -> true); + var cond = SqlBuilder.isNotLikeCaseInsensitive("Fred").filter(s -> false); + var filtered = cond.filter(s -> true); assertThat(filtered.isEmpty()).isTrue(); assertThat(cond).isSameAs(filtered); } @Test void testIsNotLikeCaseInsensitiveMapUnRenderableShouldNotThrowNullPointerException() { - IsNotLikeCaseInsensitive cond = SqlBuilder.isNotLikeCaseInsensitive("Fred").filter(s -> false); - IsNotLikeCaseInsensitive mapped = cond.map(String::toUpperCase); + var cond = SqlBuilder.isNotLikeCaseInsensitive("Fred").filter(s -> false); + var mapped = cond.map(String::toUpperCase); assertThat(cond.isEmpty()).isTrue(); assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value); assertThat(cond).isSameAs(mapped); diff --git a/src/test/kotlin/examples/kotlin/mybatis3/mariadb/KIsLikeEscape.kt b/src/test/kotlin/examples/kotlin/mybatis3/mariadb/KIsLikeEscape.kt index e018a8329..06dca6609 100644 --- a/src/test/kotlin/examples/kotlin/mybatis3/mariadb/KIsLikeEscape.kt +++ b/src/test/kotlin/examples/kotlin/mybatis3/mariadb/KIsLikeEscape.kt @@ -24,7 +24,7 @@ sealed class KIsLikeEscape( override fun filter(predicate: Predicate): KIsLikeEscape = filterSupport(predicate, EmptyIsLikeEscape::empty, this) - fun map(mapper : Function): KIsLikeEscape = + override fun map(mapper : Function): KIsLikeEscape = mapSupport(mapper, { r -> ConcreteIsLikeEscape(r, escapeCharacter) }, EmptyIsLikeEscape::empty) companion object { From 1d41ea4ea587141498d3a66b8199e979391cf144 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Thu, 13 Mar 2025 09:48:23 -0400 Subject: [PATCH 203/289] Define a map template method for no value --- .../dynamic/sql/AbstractNoValueCondition.java | 16 +++++++++++++- .../sql/where/condition/IsNotNull.java | 12 +---------- .../dynamic/sql/where/condition/IsNull.java | 12 +---------- .../examples/mysql/MemberOfCondition.java | 21 +++++++++++++++++++ 4 files changed, 38 insertions(+), 23 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/AbstractNoValueCondition.java b/src/main/java/org/mybatis/dynamic/sql/AbstractNoValueCondition.java index c0e103baf..f28073bf2 100644 --- a/src/main/java/org/mybatis/dynamic/sql/AbstractNoValueCondition.java +++ b/src/main/java/org/mybatis/dynamic/sql/AbstractNoValueCondition.java @@ -34,7 +34,21 @@ protected > S filterSupport(BooleanSupplie public abstract String operator(); - @Override + /** + * If renderable and the supplier returns true, returns this condition. Else returns a condition that will not + * render. + * + * @param booleanSupplier + * function that specifies whether the condition should render + * @param + * condition type - not used except for compilation compliance + * + * @return this condition if renderable and the supplier returns true, otherwise a condition that will not render. + */ + public abstract AbstractNoValueCondition filter(BooleanSupplier booleanSupplier); + + + @Override public FragmentAndParameters renderCondition(RenderingContext renderingContext, BindableColumn leftColumn) { return FragmentAndParameters.fromFragment(operator()); } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotNull.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotNull.java index 03d558387..fa13adbaf 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotNull.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotNull.java @@ -42,17 +42,7 @@ public String operator() { return "is not null"; //$NON-NLS-1$ } - /** - * If renderable and the supplier returns true, returns this condition. Else returns a condition that will not - * render. - * - * @param booleanSupplier - * function that specifies whether the condition should render - * @param - * condition type - not used except for compilation compliance - * - * @return this condition if renderable and the supplier returns true, otherwise a condition that will not render. - */ + @Override public IsNotNull filter(BooleanSupplier booleanSupplier) { @SuppressWarnings("unchecked") IsNotNull self = (IsNotNull) this; diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNull.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNull.java index 36c68aa34..befbb9a13 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNull.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNull.java @@ -42,17 +42,7 @@ public String operator() { return "is null"; //$NON-NLS-1$ } - /** - * If renderable and the supplier returns true, returns this condition. Else returns a condition that will not - * render. - * - * @param booleanSupplier - * function that specifies whether the condition should render - * @param - * condition type - not used except for compilation compliance - * - * @return this condition if renderable and the supplier returns true, otherwise a condition that will not render. - */ + @Override public IsNull filter(BooleanSupplier booleanSupplier) { @SuppressWarnings("unchecked") IsNull self = (IsNull) this; diff --git a/src/test/java/examples/mysql/MemberOfCondition.java b/src/test/java/examples/mysql/MemberOfCondition.java index 33b967556..c805b2127 100644 --- a/src/test/java/examples/mysql/MemberOfCondition.java +++ b/src/test/java/examples/mysql/MemberOfCondition.java @@ -16,12 +16,26 @@ package examples.mysql; import java.util.Objects; +import java.util.function.BooleanSupplier; import org.jspecify.annotations.NullMarked; import org.mybatis.dynamic.sql.AbstractNoValueCondition; @NullMarked public class MemberOfCondition extends AbstractNoValueCondition { + private static final MemberOfCondition EMPTY = new MemberOfCondition<>("") { + @Override + public boolean isEmpty() { + return true; + } + }; + + public static MemberOfCondition empty() { + @SuppressWarnings("unchecked") + MemberOfCondition t = (MemberOfCondition) EMPTY; + return t; + } + private final String jsonArray; protected MemberOfCondition(String jsonArray) { @@ -33,6 +47,13 @@ public String operator() { return "member of(" + jsonArray + ")"; } + @Override + public MemberOfCondition filter(BooleanSupplier booleanSupplier) { + @SuppressWarnings("unchecked") + MemberOfCondition self = (MemberOfCondition) this; + return filterSupport(booleanSupplier, MemberOfCondition::empty, self); + } + public static MemberOfCondition memberOf(String jsonArray) { return new MemberOfCondition<>(jsonArray); } From e52fa81434a3dfd1d3b7b62451c6f2f55f066ed2 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Thu, 13 Mar 2025 10:03:42 -0400 Subject: [PATCH 204/289] Define a map template method for list value --- .../sql/AbstractListValueCondition.java | 10 ++++++ .../org/mybatis/dynamic/sql/SqlBuilder.java | 16 ++++----- .../dynamic/sql/where/condition/IsIn.java | 9 +---- .../where/condition/IsInCaseInsensitive.java | 34 ++++++++---------- .../IsInCaseInsensitiveWhenPresent.java | 36 +++++++++---------- .../dynamic/sql/where/condition/IsNotIn.java | 9 +---- .../condition/IsNotInCaseInsensitive.java | 34 ++++++++---------- .../IsNotInCaseInsensitiveWhenPresent.java | 36 +++++++++---------- .../sql/util/kotlin/elements/SqlElements.kt | 27 +++++++------- .../sql/where/condition/FilterAndMapTest.java | 16 ++++----- 10 files changed, 105 insertions(+), 122 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/AbstractListValueCondition.java b/src/main/java/org/mybatis/dynamic/sql/AbstractListValueCondition.java index 23f48e6f4..066012e28 100644 --- a/src/main/java/org/mybatis/dynamic/sql/AbstractListValueCondition.java +++ b/src/main/java/org/mybatis/dynamic/sql/AbstractListValueCondition.java @@ -83,6 +83,16 @@ protected > S mapSupport(Function filter(Predicate predicate); + /** + * If not empty, apply the mapping to each value in the list return a new condition with the mapped values. + * Else return an empty condition (this). + * + * @param mapper a mapping function to apply to the values, if not empty + * @param type of the new condition + * @return a new condition with mapped values if renderable, otherwise an empty condition + */ + public abstract AbstractListValueCondition map(Function mapper); + public abstract String operator(); @Override diff --git a/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java b/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java index 8d462c698..2f365de1e 100644 --- a/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java +++ b/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java @@ -915,36 +915,36 @@ static IsNotLikeCaseInsensitive isNotLikeCaseInsensitiveWhenPresent( return isNotLikeCaseInsensitiveWhenPresent(valueSupplier.get()); } - static IsInCaseInsensitive isInCaseInsensitive(String... values) { + static IsInCaseInsensitive isInCaseInsensitive(String... values) { return IsInCaseInsensitive.of(values); } - static IsInCaseInsensitive isInCaseInsensitive(Collection values) { + static IsInCaseInsensitive isInCaseInsensitive(Collection values) { return IsInCaseInsensitive.of(values); } - static IsInCaseInsensitiveWhenPresent isInCaseInsensitiveWhenPresent(@Nullable String... values) { + static IsInCaseInsensitiveWhenPresent isInCaseInsensitiveWhenPresent(@Nullable String... values) { return IsInCaseInsensitiveWhenPresent.of(values); } - static IsInCaseInsensitiveWhenPresent isInCaseInsensitiveWhenPresent( + static IsInCaseInsensitiveWhenPresent isInCaseInsensitiveWhenPresent( @Nullable Collection<@Nullable String> values) { return values == null ? IsInCaseInsensitiveWhenPresent.empty() : IsInCaseInsensitiveWhenPresent.of(values); } - static IsNotInCaseInsensitive isNotInCaseInsensitive(String... values) { + static IsNotInCaseInsensitive isNotInCaseInsensitive(String... values) { return IsNotInCaseInsensitive.of(values); } - static IsNotInCaseInsensitive isNotInCaseInsensitive(Collection values) { + static IsNotInCaseInsensitive isNotInCaseInsensitive(Collection values) { return IsNotInCaseInsensitive.of(values); } - static IsNotInCaseInsensitiveWhenPresent isNotInCaseInsensitiveWhenPresent(@Nullable String... values) { + static IsNotInCaseInsensitiveWhenPresent isNotInCaseInsensitiveWhenPresent(@Nullable String... values) { return IsNotInCaseInsensitiveWhenPresent.of(values); } - static IsNotInCaseInsensitiveWhenPresent isNotInCaseInsensitiveWhenPresent( + static IsNotInCaseInsensitiveWhenPresent isNotInCaseInsensitiveWhenPresent( @Nullable Collection<@Nullable String> values) { return values == null ? IsNotInCaseInsensitiveWhenPresent.empty() : IsNotInCaseInsensitiveWhenPresent.of(values); diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsIn.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsIn.java index 6ce403717..67b6fff08 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsIn.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsIn.java @@ -54,14 +54,7 @@ public IsIn filter(Predicate predicate) { return filterSupport(predicate, IsIn::new, this, IsIn::empty); } - /** - * If not empty, apply the mapping to each value in the list return a new condition with the mapped values. - * Else return an empty condition (this). - * - * @param mapper a mapping function to apply to the values, if not empty - * @param type of the new condition - * @return a new condition with mapped values if renderable, otherwise an empty condition - */ + @Override public IsIn map(Function mapper) { Function, IsIn> constructor = IsIn::new; return mapSupport(mapper, constructor, IsIn::empty); diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java index 8fdf172bd..6f2313bdb 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java @@ -18,23 +18,25 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.function.Function; import java.util.function.Predicate; -import java.util.function.UnaryOperator; import org.mybatis.dynamic.sql.AbstractListValueCondition; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.util.StringUtilities; import org.mybatis.dynamic.sql.util.Validator; -public class IsInCaseInsensitive extends AbstractListValueCondition - implements CaseInsensitiveRenderableCondition { - private static final IsInCaseInsensitive EMPTY = new IsInCaseInsensitive(Collections.emptyList()); +public class IsInCaseInsensitive extends AbstractListValueCondition + implements CaseInsensitiveRenderableCondition { + private static final IsInCaseInsensitive EMPTY = new IsInCaseInsensitive<>(Collections.emptyList()); - public static IsInCaseInsensitive empty() { - return EMPTY; + public static IsInCaseInsensitive empty() { + @SuppressWarnings("unchecked") + IsInCaseInsensitive t = (IsInCaseInsensitive) EMPTY; + return t; } - protected IsInCaseInsensitive(Collection values) { + protected IsInCaseInsensitive(Collection values) { super(values); } @@ -50,28 +52,22 @@ public String operator() { } @Override - public IsInCaseInsensitive filter(Predicate predicate) { + public IsInCaseInsensitive filter(Predicate predicate) { return filterSupport(predicate, IsInCaseInsensitive::new, this, IsInCaseInsensitive::empty); } - /** - * If not empty, apply the mapping to each value in the list return a new condition with the mapped values. - * Else return an empty condition (this). - * - * @param mapper a mapping function to apply to the values, if not empty - * @return a new condition with mapped values if renderable, otherwise an empty condition - */ - public IsInCaseInsensitive map(UnaryOperator mapper) { + @Override + public IsInCaseInsensitive map(Function mapper) { return mapSupport(mapper, IsInCaseInsensitive::new, IsInCaseInsensitive::empty); } - public static IsInCaseInsensitive of(String... values) { + public static IsInCaseInsensitive of(String... values) { return of(Arrays.asList(values)); } - public static IsInCaseInsensitive of(Collection values) { + public static IsInCaseInsensitive of(Collection values) { // Keep the null safe upper case utility for backwards compatibility //noinspection DataFlowIssue - return new IsInCaseInsensitive(values).map(StringUtilities::safelyUpperCase); + return new IsInCaseInsensitive<>(values).map(StringUtilities::safelyUpperCase); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java index 91b77901a..523b3d732 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java @@ -18,24 +18,26 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.function.Function; import java.util.function.Predicate; -import java.util.function.UnaryOperator; import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.AbstractListValueCondition; import org.mybatis.dynamic.sql.util.StringUtilities; import org.mybatis.dynamic.sql.util.Utilities; -public class IsInCaseInsensitiveWhenPresent extends AbstractListValueCondition - implements CaseInsensitiveRenderableCondition { - private static final IsInCaseInsensitiveWhenPresent EMPTY = - new IsInCaseInsensitiveWhenPresent(Collections.emptyList()); +public class IsInCaseInsensitiveWhenPresent extends AbstractListValueCondition + implements CaseInsensitiveRenderableCondition { + private static final IsInCaseInsensitiveWhenPresent EMPTY = + new IsInCaseInsensitiveWhenPresent<>(Collections.emptyList()); - public static IsInCaseInsensitiveWhenPresent empty() { - return EMPTY; + public static IsInCaseInsensitiveWhenPresent empty() { + @SuppressWarnings("unchecked") + IsInCaseInsensitiveWhenPresent t = (IsInCaseInsensitiveWhenPresent) EMPTY; + return t; } - protected IsInCaseInsensitiveWhenPresent(Collection<@Nullable String> values) { + protected IsInCaseInsensitiveWhenPresent(Collection<@Nullable T> values) { super(Utilities.removeNullElements(values)); } @@ -45,29 +47,23 @@ public String operator() { } @Override - public IsInCaseInsensitiveWhenPresent filter(Predicate predicate) { + public IsInCaseInsensitiveWhenPresent filter(Predicate predicate) { return filterSupport(predicate, IsInCaseInsensitiveWhenPresent::new, this, IsInCaseInsensitiveWhenPresent::empty); } - /** - * If not empty, apply the mapping to each value in the list return a new condition with the mapped values. - * Else return an empty condition (this). - * - * @param mapper a mapping function to apply to the values, if not empty - * @return a new condition with mapped values if renderable, otherwise an empty condition - */ - public IsInCaseInsensitiveWhenPresent map(UnaryOperator mapper) { + @Override + public IsInCaseInsensitiveWhenPresent map(Function mapper) { return mapSupport(mapper, IsInCaseInsensitiveWhenPresent::new, IsInCaseInsensitiveWhenPresent::empty); } - public static IsInCaseInsensitiveWhenPresent of(@Nullable String... values) { + public static IsInCaseInsensitiveWhenPresent of(@Nullable String... values) { return of(Arrays.asList(values)); } - public static IsInCaseInsensitiveWhenPresent of(Collection<@Nullable String> values) { + public static IsInCaseInsensitiveWhenPresent of(Collection<@Nullable String> values) { // Keep the null safe upper case utility for backwards compatibility //noinspection DataFlowIssue - return new IsInCaseInsensitiveWhenPresent(values).map(StringUtilities::safelyUpperCase); + return new IsInCaseInsensitiveWhenPresent<>(values).map(StringUtilities::safelyUpperCase); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotIn.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotIn.java index e1ca07abf..f22c504c8 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotIn.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotIn.java @@ -54,14 +54,7 @@ public IsNotIn filter(Predicate predicate) { return filterSupport(predicate, IsNotIn::new, this, IsNotIn::empty); } - /** - * If not empty, apply the mapping to each value in the list return a new condition with the mapped values. - * Else return an empty condition (this). - * - * @param mapper a mapping function to apply to the values, if not empty - * @param type of the new condition - * @return a new condition with mapped values if renderable, otherwise an empty condition - */ + @Override public IsNotIn map(Function mapper) { Function, IsNotIn> constructor = IsNotIn::new; return mapSupport(mapper, constructor, IsNotIn::empty); diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java index 473b9077e..2687ef9b7 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java @@ -18,23 +18,25 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.function.Function; import java.util.function.Predicate; -import java.util.function.UnaryOperator; import org.mybatis.dynamic.sql.AbstractListValueCondition; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.util.StringUtilities; import org.mybatis.dynamic.sql.util.Validator; -public class IsNotInCaseInsensitive extends AbstractListValueCondition - implements CaseInsensitiveRenderableCondition { - private static final IsNotInCaseInsensitive EMPTY = new IsNotInCaseInsensitive(Collections.emptyList()); +public class IsNotInCaseInsensitive extends AbstractListValueCondition + implements CaseInsensitiveRenderableCondition { + private static final IsNotInCaseInsensitive EMPTY = new IsNotInCaseInsensitive<>(Collections.emptyList()); - public static IsNotInCaseInsensitive empty() { - return EMPTY; + public static IsNotInCaseInsensitive empty() { + @SuppressWarnings("unchecked") + IsNotInCaseInsensitive t = (IsNotInCaseInsensitive) EMPTY; + return t; } - protected IsNotInCaseInsensitive(Collection values) { + protected IsNotInCaseInsensitive(Collection values) { super(values); } @@ -50,28 +52,22 @@ public String operator() { } @Override - public IsNotInCaseInsensitive filter(Predicate predicate) { + public IsNotInCaseInsensitive filter(Predicate predicate) { return filterSupport(predicate, IsNotInCaseInsensitive::new, this, IsNotInCaseInsensitive::empty); } - /** - * If not empty, apply the mapping to each value in the list return a new condition with the mapped values. - * Else return an empty condition (this). - * - * @param mapper a mapping function to apply to the values, if not empty - * @return a new condition with mapped values if renderable, otherwise an empty condition - */ - public IsNotInCaseInsensitive map(UnaryOperator mapper) { + @Override + public IsNotInCaseInsensitive map(Function mapper) { return mapSupport(mapper, IsNotInCaseInsensitive::new, IsNotInCaseInsensitive::empty); } - public static IsNotInCaseInsensitive of(String... values) { + public static IsNotInCaseInsensitive of(String... values) { return of(Arrays.asList(values)); } - public static IsNotInCaseInsensitive of(Collection values) { + public static IsNotInCaseInsensitive of(Collection values) { // Keep the null safe upper case utility for backwards compatibility //noinspection DataFlowIssue - return new IsNotInCaseInsensitive(values).map(StringUtilities::safelyUpperCase); + return new IsNotInCaseInsensitive<>(values).map(StringUtilities::safelyUpperCase); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java index b2d834f2b..143d2a6a2 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java @@ -18,24 +18,26 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.function.Function; import java.util.function.Predicate; -import java.util.function.UnaryOperator; import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.AbstractListValueCondition; import org.mybatis.dynamic.sql.util.StringUtilities; import org.mybatis.dynamic.sql.util.Utilities; -public class IsNotInCaseInsensitiveWhenPresent extends AbstractListValueCondition - implements CaseInsensitiveRenderableCondition { - private static final IsNotInCaseInsensitiveWhenPresent EMPTY = - new IsNotInCaseInsensitiveWhenPresent(Collections.emptyList()); +public class IsNotInCaseInsensitiveWhenPresent extends AbstractListValueCondition + implements CaseInsensitiveRenderableCondition { + private static final IsNotInCaseInsensitiveWhenPresent EMPTY = + new IsNotInCaseInsensitiveWhenPresent<>(Collections.emptyList()); - public static IsNotInCaseInsensitiveWhenPresent empty() { - return EMPTY; + public static IsNotInCaseInsensitiveWhenPresent empty() { + @SuppressWarnings("unchecked") + IsNotInCaseInsensitiveWhenPresent t = (IsNotInCaseInsensitiveWhenPresent) EMPTY; + return t; } - protected IsNotInCaseInsensitiveWhenPresent(Collection<@Nullable String> values) { + protected IsNotInCaseInsensitiveWhenPresent(Collection<@Nullable T> values) { super(Utilities.removeNullElements(values)); } @@ -45,29 +47,23 @@ public String operator() { } @Override - public IsNotInCaseInsensitiveWhenPresent filter(Predicate predicate) { + public IsNotInCaseInsensitiveWhenPresent filter(Predicate predicate) { return filterSupport(predicate, IsNotInCaseInsensitiveWhenPresent::new, this, IsNotInCaseInsensitiveWhenPresent::empty); } - /** - * If not empty, apply the mapping to each value in the list return a new condition with the mapped values. - * Else return an empty condition (this). - * - * @param mapper a mapping function to apply to the values, if not empty - * @return a new condition with mapped values if renderable, otherwise an empty condition - */ - public IsNotInCaseInsensitiveWhenPresent map(UnaryOperator mapper) { + @Override + public IsNotInCaseInsensitiveWhenPresent map(Function mapper) { return mapSupport(mapper, IsNotInCaseInsensitiveWhenPresent::new, IsNotInCaseInsensitiveWhenPresent::empty); } - public static IsNotInCaseInsensitiveWhenPresent of(@Nullable String... values) { + public static IsNotInCaseInsensitiveWhenPresent of(@Nullable String... values) { return of(Arrays.asList(values)); } - public static IsNotInCaseInsensitiveWhenPresent of(Collection<@Nullable String> values) { + public static IsNotInCaseInsensitiveWhenPresent of(Collection<@Nullable String> values) { // Keep the null safe upper case utility for backwards compatibility //noinspection DataFlowIssue - return new IsNotInCaseInsensitiveWhenPresent(values).map(StringUtilities::safelyUpperCase); + return new IsNotInCaseInsensitiveWhenPresent<>(values).map(StringUtilities::safelyUpperCase); } } diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/SqlElements.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/SqlElements.kt index 0983eaa9c..530c962ed 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/SqlElements.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/SqlElements.kt @@ -334,40 +334,43 @@ fun isNotLikeCaseInsensitive(value: String): IsNotLikeCaseInsensitive = fun isNotLikeCaseInsensitiveWhenPresent(value: String?): IsNotLikeCaseInsensitive = SqlBuilder.isNotLikeCaseInsensitiveWhenPresent(value) -fun isInCaseInsensitive(vararg values: String): IsInCaseInsensitive = isInCaseInsensitive(values.asList()) +fun isInCaseInsensitive(vararg values: String): IsInCaseInsensitive = isInCaseInsensitive(values.asList()) @JvmName("isInArrayCaseInsensitive") -fun isInCaseInsensitive(values: Array): IsInCaseInsensitive = SqlBuilder.isInCaseInsensitive(values.asList()) +fun isInCaseInsensitive(values: Array): IsInCaseInsensitive = + SqlBuilder.isInCaseInsensitive(values.asList()) -fun isInCaseInsensitive(values: Collection): IsInCaseInsensitive = SqlBuilder.isInCaseInsensitive(values) +fun isInCaseInsensitive(values: Collection): IsInCaseInsensitive = + SqlBuilder.isInCaseInsensitive(values) -fun isInCaseInsensitiveWhenPresent(vararg values: String?): IsInCaseInsensitiveWhenPresent = +fun isInCaseInsensitiveWhenPresent(vararg values: String?): IsInCaseInsensitiveWhenPresent = isInCaseInsensitiveWhenPresent(values.asList()) @JvmName("isInArrayCaseInsensitiveWhenPresent") -fun isInCaseInsensitiveWhenPresent(values: Array?): IsInCaseInsensitiveWhenPresent = +fun isInCaseInsensitiveWhenPresent(values: Array?): IsInCaseInsensitiveWhenPresent = SqlBuilder.isInCaseInsensitiveWhenPresent(values?.asList()) -fun isInCaseInsensitiveWhenPresent(values: Collection?): IsInCaseInsensitiveWhenPresent = +fun isInCaseInsensitiveWhenPresent(values: Collection?): IsInCaseInsensitiveWhenPresent = SqlBuilder.isInCaseInsensitiveWhenPresent(values) -fun isNotInCaseInsensitive(vararg values: String): IsNotInCaseInsensitive = isNotInCaseInsensitive(values.asList()) +fun isNotInCaseInsensitive(vararg values: String): IsNotInCaseInsensitive = + isNotInCaseInsensitive(values.asList()) @JvmName("isNotInArrayCaseInsensitive") -fun isNotInCaseInsensitive(values: Array): IsNotInCaseInsensitive = +fun isNotInCaseInsensitive(values: Array): IsNotInCaseInsensitive = SqlBuilder.isNotInCaseInsensitive(values.asList()) -fun isNotInCaseInsensitive(values: Collection): IsNotInCaseInsensitive = +fun isNotInCaseInsensitive(values: Collection): IsNotInCaseInsensitive = SqlBuilder.isNotInCaseInsensitive(values) -fun isNotInCaseInsensitiveWhenPresent(vararg values: String?): IsNotInCaseInsensitiveWhenPresent = +fun isNotInCaseInsensitiveWhenPresent(vararg values: String?): IsNotInCaseInsensitiveWhenPresent = isNotInCaseInsensitiveWhenPresent(values.asList()) @JvmName("isNotInArrayCaseInsensitiveWhenPresent") -fun isNotInCaseInsensitiveWhenPresent(values: Array?): IsNotInCaseInsensitiveWhenPresent = +fun isNotInCaseInsensitiveWhenPresent(values: Array?): IsNotInCaseInsensitiveWhenPresent = SqlBuilder.isNotInCaseInsensitiveWhenPresent(values?.asList()) -fun isNotInCaseInsensitiveWhenPresent(values: Collection?): IsNotInCaseInsensitiveWhenPresent = +fun isNotInCaseInsensitiveWhenPresent(values: Collection?): IsNotInCaseInsensitiveWhenPresent = SqlBuilder.isNotInCaseInsensitiveWhenPresent(values) // order by support diff --git a/src/test/java/org/mybatis/dynamic/sql/where/condition/FilterAndMapTest.java b/src/test/java/org/mybatis/dynamic/sql/where/condition/FilterAndMapTest.java index 358ec0cd3..8c8f35eb5 100644 --- a/src/test/java/org/mybatis/dynamic/sql/where/condition/FilterAndMapTest.java +++ b/src/test/java/org/mybatis/dynamic/sql/where/condition/FilterAndMapTest.java @@ -447,25 +447,25 @@ void testIsNotInRenderableMapShouldReturnMappedObject() { @Test void testIsNotInCaseInsensitiveRenderableMapShouldReturnMappedObject() { - IsNotInCaseInsensitive cond = SqlBuilder.isNotInCaseInsensitive("Fred ", "Wilma "); - List values = cond.values().toList(); + var cond = SqlBuilder.isNotInCaseInsensitive("Fred ", "Wilma "); + var values = cond.values().toList(); assertThat(values).containsExactly("FRED ", "WILMA "); assertThat(cond.isEmpty()).isFalse(); - IsNotInCaseInsensitive mapped = cond.map(String::trim); - List mappedValues = mapped.values().toList(); + var mapped = cond.map(String::trim); + var mappedValues = mapped.values().toList(); assertThat(mappedValues).containsExactly("FRED", "WILMA"); } @Test void testIsInCaseInsensitiveRenderableMapShouldReturnMappedObject() { - IsInCaseInsensitive cond = SqlBuilder.isInCaseInsensitive("Fred ", "Wilma "); - List values = cond.values().toList(); + var cond = SqlBuilder.isInCaseInsensitive("Fred ", "Wilma "); + var values = cond.values().toList(); assertThat(values).containsExactly("FRED ", "WILMA "); assertThat(cond.isEmpty()).isFalse(); - IsInCaseInsensitive mapped = cond.map(String::trim); - List mappedValues = mapped.values().toList(); + var mapped = cond.map(String::trim); + var mappedValues = mapped.values().toList(); assertThat(mappedValues).containsExactly("FRED", "WILMA"); } From d73b31b945be5f349cb907e8a78283b87cd14bc0 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Thu, 13 Mar 2025 10:10:28 -0400 Subject: [PATCH 205/289] Define a map template method for two value --- .../sql/AbstractTwoValueCondition.java | 24 +++++++++++++++++++ .../sql/where/condition/IsBetween.java | 21 ++-------------- .../sql/where/condition/IsNotBetween.java | 21 ++-------------- 3 files changed, 28 insertions(+), 38 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/AbstractTwoValueCondition.java b/src/main/java/org/mybatis/dynamic/sql/AbstractTwoValueCondition.java index 865f7db0b..15a5b6ffe 100644 --- a/src/main/java/org/mybatis/dynamic/sql/AbstractTwoValueCondition.java +++ b/src/main/java/org/mybatis/dynamic/sql/AbstractTwoValueCondition.java @@ -88,6 +88,30 @@ protected > S mapSupport(Function filter(Predicate predicate); + /** + * If renderable, apply the mappings to the values and return a new condition with the new values. Else return a + * condition that will not render (this). + * + * @param mapper1 a mapping function to apply to the first value, if renderable + * @param mapper2 a mapping function to apply to the second value, if renderable + * @param type of the new condition + * @return a new condition with the result of applying the mappers to the values of this condition, + * if renderable, otherwise a condition that will not render. + */ + public abstract AbstractTwoValueCondition map(Function mapper1, + Function mapper2); + + /** + * If renderable, apply the mapping to both values and return a new condition with the new values. Else return a + * condition that will not render (this). + * + * @param mapper a mapping function to apply to both values, if renderable + * @param type of the new condition + * @return a new condition with the result of applying the mappers to the values of this condition, + * if renderable, otherwise a condition that will not render. + */ + public abstract AbstractTwoValueCondition map(Function mapper); + public abstract String operator1(); public abstract String operator2(); diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsBetween.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsBetween.java index deeddb4c9..0d554d0fc 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsBetween.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsBetween.java @@ -71,29 +71,12 @@ public IsBetween filter(Predicate predicate) { return filterSupport(predicate, IsBetween::empty, this); } - /** - * If renderable, apply the mappings to the values and return a new condition with the new values. Else return a - * condition that will not render (this). - * - * @param mapper1 a mapping function to apply to the first value, if renderable - * @param mapper2 a mapping function to apply to the second value, if renderable - * @param type of the new condition - * @return a new condition with the result of applying the mappers to the values of this condition, - * if renderable, otherwise a condition that will not render. - */ + @Override public IsBetween map(Function mapper1, Function mapper2) { return mapSupport(mapper1, mapper2, IsBetween::new, IsBetween::empty); } - /** - * If renderable, apply the mapping to both values and return a new condition with the new values. Else return a - * condition that will not render (this). - * - * @param mapper a mapping function to apply to both values, if renderable - * @param type of the new condition - * @return a new condition with the result of applying the mappers to the values of this condition, - * if renderable, otherwise a condition that will not render. - */ + @Override public IsBetween map(Function mapper) { return map(mapper, mapper); } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotBetween.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotBetween.java index 5700de2ac..f7eb98f52 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotBetween.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotBetween.java @@ -71,30 +71,13 @@ public IsNotBetween filter(Predicate predicate) { return filterSupport(predicate, IsNotBetween::empty, this); } - /** - * If renderable, apply the mappings to the values and return a new condition with the new values. Else return a - * condition that will not render (this). - * - * @param mapper1 a mapping function to apply to the first value, if renderable - * @param mapper2 a mapping function to apply to the second value, if renderable - * @param type of the new condition - * @return a new condition with the result of applying the mappers to the values of this condition, - * if renderable, otherwise a condition that will not render. - */ + @Override public IsNotBetween map(Function mapper1, Function mapper2) { return mapSupport(mapper1, mapper2, IsNotBetween::new, IsNotBetween::empty); } - /** - * If renderable, apply the mapping to both values and return a new condition with the new values. Else return a - * condition that will not render (this). - * - * @param mapper a mapping function to apply to both values, if renderable - * @param type of the new condition - * @return a new condition with the result of applying the mappers to the values of this condition, - * if renderable, otherwise a condition that will not render. - */ + @Override public IsNotBetween map(Function mapper) { return map(mapper, mapper); } From 5eda6cb283ae3fa3a09ebd3510277264f3754fe6 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Thu, 13 Mar 2025 17:33:08 -0400 Subject: [PATCH 206/289] Little optimization that creates less garbage --- .../mybatis/dynamic/sql/util/StringUtilities.java | 1 - .../org/mybatis/dynamic/sql/util/Utilities.java | 13 ------------- .../sql/where/condition/IsInCaseInsensitive.java | 5 ++--- .../condition/IsInCaseInsensitiveWhenPresent.java | 12 +++++------- .../sql/where/condition/IsLikeCaseInsensitive.java | 5 ++--- .../sql/where/condition/IsNotInCaseInsensitive.java | 5 ++--- .../IsNotInCaseInsensitiveWhenPresent.java | 12 +++++------- .../where/condition/IsNotLikeCaseInsensitive.java | 5 ++--- 8 files changed, 18 insertions(+), 40 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/util/StringUtilities.java b/src/main/java/org/mybatis/dynamic/sql/util/StringUtilities.java index 3104c2905..2b57c748e 100644 --- a/src/main/java/org/mybatis/dynamic/sql/util/StringUtilities.java +++ b/src/main/java/org/mybatis/dynamic/sql/util/StringUtilities.java @@ -58,6 +58,5 @@ static String toCamelCase(String inputString) { static String formatConstantForSQL(String in) { String escaped = in.replace("'", "''"); //$NON-NLS-1$ //$NON-NLS-2$ return "'" + escaped + "'"; //$NON-NLS-1$ //$NON-NLS-2$ - } } diff --git a/src/main/java/org/mybatis/dynamic/sql/util/Utilities.java b/src/main/java/org/mybatis/dynamic/sql/util/Utilities.java index 87ea18e12..0c3bd188f 100644 --- a/src/main/java/org/mybatis/dynamic/sql/util/Utilities.java +++ b/src/main/java/org/mybatis/dynamic/sql/util/Utilities.java @@ -15,23 +15,10 @@ */ package org.mybatis.dynamic.sql.util; -import java.util.Collection; -import java.util.Objects; -import java.util.stream.Stream; - -import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; public interface Utilities { static long safelyUnbox(@Nullable Long l) { return l == null ? 0 : l; } - - static Stream<@NonNull T> filterNullValues(Stream<@Nullable T> values) { - return values.filter(Objects::nonNull); - } - - static Collection<@NonNull T> removeNullElements(Collection<@Nullable T> values) { - return filterNullValues(values.stream()).toList(); - } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java index 67f37951e..e521d28b2 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java @@ -70,8 +70,7 @@ public static IsInCaseInsensitive of(String... values) { } public static IsInCaseInsensitive of(Collection values) { - // Keep the null safe upper case utility for backwards compatibility - //noinspection DataFlowIssue - return new IsInCaseInsensitive(values).map(StringUtilities::safelyUpperCase); + // Keep the null safe upper case utility for backwards compatibility in case someone passes in a null + return new IsInCaseInsensitive(values.stream().map(StringUtilities::safelyUpperCase).toList()); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java index cff58415d..7d81bba69 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java @@ -18,13 +18,12 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.Objects; import java.util.function.Predicate; import java.util.function.UnaryOperator; import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.AbstractListValueCondition; -import org.mybatis.dynamic.sql.util.StringUtilities; -import org.mybatis.dynamic.sql.util.Utilities; public class IsInCaseInsensitiveWhenPresent extends AbstractListValueCondition implements CaseInsensitiveRenderableCondition { @@ -35,8 +34,8 @@ public static IsInCaseInsensitiveWhenPresent empty() { return EMPTY; } - protected IsInCaseInsensitiveWhenPresent(Collection<@Nullable String> values) { - super(Utilities.removeNullElements(values)); + protected IsInCaseInsensitiveWhenPresent(Collection values) { + super(values); } @Override @@ -66,8 +65,7 @@ public static IsInCaseInsensitiveWhenPresent of(@Nullable String... values) { } public static IsInCaseInsensitiveWhenPresent of(Collection<@Nullable String> values) { - // Keep the null safe upper case utility for backwards compatibility - //noinspection DataFlowIssue - return new IsInCaseInsensitiveWhenPresent(values).map(StringUtilities::safelyUpperCase); + return new IsInCaseInsensitiveWhenPresent( + values.stream().filter(Objects::nonNull).map(String::toUpperCase).toList()); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitive.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitive.java index 4ebdb00fb..de8d72cd0 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitive.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitive.java @@ -67,8 +67,7 @@ public IsLikeCaseInsensitive map(UnaryOperator mapper) { } public static IsLikeCaseInsensitive of(String value) { - // Keep the null safe upper case utility for backwards compatibility - //noinspection DataFlowIssue - return new IsLikeCaseInsensitive(value).map(StringUtilities::safelyUpperCase); + // Keep the null safe upper case utility for backwards compatibility in case someone passes in a null + return new IsLikeCaseInsensitive(StringUtilities.safelyUpperCase(value)); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java index f5f970c45..c956b4d55 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java @@ -70,8 +70,7 @@ public static IsNotInCaseInsensitive of(String... values) { } public static IsNotInCaseInsensitive of(Collection values) { - // Keep the null safe upper case utility for backwards compatibility - //noinspection DataFlowIssue - return new IsNotInCaseInsensitive(values).map(StringUtilities::safelyUpperCase); + // Keep the null safe upper case utility for backwards compatibility in case someone passes in a null + return new IsNotInCaseInsensitive(values.stream().map(StringUtilities::safelyUpperCase).toList()); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java index a8873a7e4..9202a2ad1 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java @@ -18,13 +18,12 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.Objects; import java.util.function.Predicate; import java.util.function.UnaryOperator; import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.AbstractListValueCondition; -import org.mybatis.dynamic.sql.util.StringUtilities; -import org.mybatis.dynamic.sql.util.Utilities; public class IsNotInCaseInsensitiveWhenPresent extends AbstractListValueCondition implements CaseInsensitiveRenderableCondition { @@ -35,8 +34,8 @@ public static IsNotInCaseInsensitiveWhenPresent empty() { return EMPTY; } - protected IsNotInCaseInsensitiveWhenPresent(Collection<@Nullable String> values) { - super(Utilities.removeNullElements(values)); + protected IsNotInCaseInsensitiveWhenPresent(Collection values) { + super(values); } @Override @@ -66,8 +65,7 @@ public static IsNotInCaseInsensitiveWhenPresent of(@Nullable String... values) { } public static IsNotInCaseInsensitiveWhenPresent of(Collection<@Nullable String> values) { - // Keep the null safe upper case utility for backwards compatibility - //noinspection DataFlowIssue - return new IsNotInCaseInsensitiveWhenPresent(values).map(StringUtilities::safelyUpperCase); + return new IsNotInCaseInsensitiveWhenPresent( + values.stream().filter(Objects::nonNull).map(String::toUpperCase).toList()); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitive.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitive.java index 1fb6847c0..c26168e42 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitive.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitive.java @@ -69,8 +69,7 @@ public IsNotLikeCaseInsensitive map(UnaryOperator mapper) { } public static IsNotLikeCaseInsensitive of(String value) { - // Keep the null safe upper case utility for backwards compatibility - //noinspection DataFlowIssue - return new IsNotLikeCaseInsensitive(value).map(StringUtilities::safelyUpperCase); + // Keep the null safe upper case utility for backwards compatibility in case someone passes in a null + return new IsNotLikeCaseInsensitive(StringUtilities.safelyUpperCase(value)); } } From b428bb5fad0041f8abf330c2b63adda3601a5942 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 13 Mar 2025 21:40:52 +0000 Subject: [PATCH 207/289] Update dependency org.springframework:spring-jdbc to v6.2.4 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 584b5daa6..f26ba6481 100644 --- a/pom.xml +++ b/pom.xml @@ -101,7 +101,7 @@ org.springframework spring-jdbc - 6.2.3 + 6.2.4 provided true From f49cf7f28f3f9a48ac8c880895f0e3c19d8175b3 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Thu, 13 Mar 2025 17:50:02 -0400 Subject: [PATCH 208/289] Fixes after merge --- .../sql/where/condition/IsInCaseInsensitiveWhenPresent.java | 2 +- .../sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java index abd6758e0..de17a8394 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java @@ -36,7 +36,7 @@ public static IsInCaseInsensitiveWhenPresent empty() { return t; } - protected IsInCaseInsensitiveWhenPresent(Collection values) { + protected IsInCaseInsensitiveWhenPresent(Collection values) { super(values); } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java index c2784d819..bbff09bbe 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java @@ -36,7 +36,7 @@ public static IsNotInCaseInsensitiveWhenPresent empty() { return t; } - protected IsNotInCaseInsensitiveWhenPresent(Collection values) { + protected IsNotInCaseInsensitiveWhenPresent(Collection values) { super(values); } From 7b426ceb0a3795112a15867670d8007c002240ed Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Fri, 14 Mar 2025 09:40:32 -0400 Subject: [PATCH 209/289] Make filtering optional on no value conditions --- .../dynamic/sql/AbstractNoValueCondition.java | 31 ++++++++++--------- .../sql/where/condition/IsNotNull.java | 2 +- .../dynamic/sql/where/condition/IsNull.java | 2 +- .../examples/mysql/MemberOfCondition.java | 21 ------------- 4 files changed, 18 insertions(+), 38 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/AbstractNoValueCondition.java b/src/main/java/org/mybatis/dynamic/sql/AbstractNoValueCondition.java index f28073bf2..b0c7d9bad 100644 --- a/src/main/java/org/mybatis/dynamic/sql/AbstractNoValueCondition.java +++ b/src/main/java/org/mybatis/dynamic/sql/AbstractNoValueCondition.java @@ -34,22 +34,23 @@ protected > S filterSupport(BooleanSupplie public abstract String operator(); - /** - * If renderable and the supplier returns true, returns this condition. Else returns a condition that will not - * render. - * - * @param booleanSupplier - * function that specifies whether the condition should render - * @param - * condition type - not used except for compilation compliance - * - * @return this condition if renderable and the supplier returns true, otherwise a condition that will not render. - */ - public abstract AbstractNoValueCondition filter(BooleanSupplier booleanSupplier); - - - @Override + @Override public FragmentAndParameters renderCondition(RenderingContext renderingContext, BindableColumn leftColumn) { return FragmentAndParameters.fromFragment(operator()); } + + public interface Filterable { + /** + * If renderable and the supplier returns true, returns this condition. Else returns a condition that will not + * render. + * + * @param booleanSupplier + * function that specifies whether the condition should render + * @param + * condition type - not used except for compilation compliance + * + * @return this condition if renderable and the supplier returns true, otherwise a condition that will not render. + */ + AbstractNoValueCondition filter(BooleanSupplier booleanSupplier); + } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotNull.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotNull.java index fa13adbaf..1c1f3139d 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotNull.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotNull.java @@ -19,7 +19,7 @@ import org.mybatis.dynamic.sql.AbstractNoValueCondition; -public class IsNotNull extends AbstractNoValueCondition { +public class IsNotNull extends AbstractNoValueCondition implements AbstractNoValueCondition.Filterable { private static final IsNotNull EMPTY = new IsNotNull<>() { @Override public boolean isEmpty() { diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNull.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNull.java index befbb9a13..a27b7dc2a 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNull.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNull.java @@ -19,7 +19,7 @@ import org.mybatis.dynamic.sql.AbstractNoValueCondition; -public class IsNull extends AbstractNoValueCondition { +public class IsNull extends AbstractNoValueCondition implements AbstractNoValueCondition.Filterable { private static final IsNull EMPTY = new IsNull<>() { @Override public boolean isEmpty() { diff --git a/src/test/java/examples/mysql/MemberOfCondition.java b/src/test/java/examples/mysql/MemberOfCondition.java index c805b2127..33b967556 100644 --- a/src/test/java/examples/mysql/MemberOfCondition.java +++ b/src/test/java/examples/mysql/MemberOfCondition.java @@ -16,26 +16,12 @@ package examples.mysql; import java.util.Objects; -import java.util.function.BooleanSupplier; import org.jspecify.annotations.NullMarked; import org.mybatis.dynamic.sql.AbstractNoValueCondition; @NullMarked public class MemberOfCondition extends AbstractNoValueCondition { - private static final MemberOfCondition EMPTY = new MemberOfCondition<>("") { - @Override - public boolean isEmpty() { - return true; - } - }; - - public static MemberOfCondition empty() { - @SuppressWarnings("unchecked") - MemberOfCondition t = (MemberOfCondition) EMPTY; - return t; - } - private final String jsonArray; protected MemberOfCondition(String jsonArray) { @@ -47,13 +33,6 @@ public String operator() { return "member of(" + jsonArray + ")"; } - @Override - public MemberOfCondition filter(BooleanSupplier booleanSupplier) { - @SuppressWarnings("unchecked") - MemberOfCondition self = (MemberOfCondition) this; - return filterSupport(booleanSupplier, MemberOfCondition::empty, self); - } - public static MemberOfCondition memberOf(String jsonArray) { return new MemberOfCondition<>(jsonArray); } From 30fc7efdfd868761fc653f4655002d9b2ccb9f82 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Fri, 14 Mar 2025 10:12:56 -0400 Subject: [PATCH 210/289] Make filtering optional on no value conditions --- .../mybatis/dynamic/sql/AbstractNoValueCondition.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/main/java/org/mybatis/dynamic/sql/AbstractNoValueCondition.java b/src/main/java/org/mybatis/dynamic/sql/AbstractNoValueCondition.java index b0c7d9bad..20e6251d6 100644 --- a/src/main/java/org/mybatis/dynamic/sql/AbstractNoValueCondition.java +++ b/src/main/java/org/mybatis/dynamic/sql/AbstractNoValueCondition.java @@ -39,6 +39,17 @@ public FragmentAndParameters renderCondition(RenderingContext renderingContext, return FragmentAndParameters.fromFragment(operator()); } + /** + * Conditions may implement Filterable to add optionality to rendering. + * + *

If a condition is Filterable, then a user may add a filter to the usage of the condition that makes a decision + * whether to render the condition at runtime. Conditions that fail the filter will be dropped from the + * rendered SQL. + * + *

Implementations of Filterable may call + * {@link AbstractNoValueCondition#filterSupport(BooleanSupplier, Supplier, AbstractNoValueCondition)} as + * a common implementation of the filtering algorithm. + */ public interface Filterable { /** * If renderable and the supplier returns true, returns this condition. Else returns a condition that will not From 50944221f6e15df6f95c57887da3c58011212444 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Fri, 14 Mar 2025 10:45:37 -0400 Subject: [PATCH 211/289] Make filter and map optional on single value conditions --- .../sql/AbstractSingleValueCondition.java | 71 +++++++++++++------ .../sql/where/condition/IsEqualTo.java | 3 +- .../sql/where/condition/IsGreaterThan.java | 3 +- .../condition/IsGreaterThanOrEqualTo.java | 3 +- .../sql/where/condition/IsLessThan.java | 4 +- .../where/condition/IsLessThanOrEqualTo.java | 3 +- .../dynamic/sql/where/condition/IsLike.java | 4 +- .../condition/IsLikeCaseInsensitive.java | 3 +- .../sql/where/condition/IsNotEqualTo.java | 3 +- .../sql/where/condition/IsNotLike.java | 3 +- .../condition/IsNotLikeCaseInsensitive.java | 14 +--- .../java/examples/mysql/IsLikeEscape.java | 3 +- .../kotlin/mybatis3/mariadb/KIsLikeEscape.kt | 3 +- 13 files changed, 77 insertions(+), 43 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/AbstractSingleValueCondition.java b/src/main/java/org/mybatis/dynamic/sql/AbstractSingleValueCondition.java index f032d64db..c16dbf08c 100644 --- a/src/main/java/org/mybatis/dynamic/sql/AbstractSingleValueCondition.java +++ b/src/main/java/org/mybatis/dynamic/sql/AbstractSingleValueCondition.java @@ -54,27 +54,6 @@ protected > S mapSupport(Function filter(Predicate predicate); - - /** - * If renderable, apply the mapping to the value and return a new condition with the new value. Else return a - * condition that will not render (this). - * - * @param mapper a mapping function to apply to the value, if renderable - * @param type of the new condition - * @return a new condition with the result of applying the mapper to the value of this condition, - * if renderable, otherwise a condition that will not render. - */ - public abstract AbstractSingleValueCondition map(Function mapper); - public abstract String operator(); @Override @@ -86,4 +65,54 @@ public FragmentAndParameters renderCondition(RenderingContext renderingContext, .withParameter(parameterInfo.parameterMapKey(), leftColumn.convertParameterType(value())) .build(); } + + /** + * Conditions may implement Filterable to add optionality to rendering. + * + *

If a condition is Filterable, then a user may add a filter to the usage of the condition that makes a decision + * whether to render the condition at runtime. Conditions that fail the filter will be dropped from the + * rendered SQL. + * + *

Implementations of Filterable may call + * {@link AbstractSingleValueCondition#filterSupport(Predicate, Supplier, AbstractSingleValueCondition)} as + * a common implementation of the filtering algorithm. + * + * @param the Java type related to the database column type + */ + public interface Filterable { + /** + * If renderable and the value matches the predicate, returns this condition. Else returns a condition + * that will not render. + * + * @param predicate predicate applied to the value, if renderable + * @return this condition if renderable and the value matches the predicate, otherwise a condition + * that will not render. + */ + AbstractSingleValueCondition filter(Predicate predicate); + } + + /** + * Conditions may implement Mappable to alter condition values or types during rendering. + * + *

If a condition is Mappable, then a user may add a mapper to the usage of the condition that can alter the + * values of a condition, or change that datatype. + * + *

Implementations of Mappable may call + * {@link AbstractSingleValueCondition#mapSupport(Function, Function, Supplier)} as + * a common implementation of the mapping algorithm. + * + * @param the Java type related to the database column type + */ + public interface Mappable { + /** + * If renderable, apply the mapping to the value and return a new condition with the new value. Else return a + * condition that will not render (this). + * + * @param mapper a mapping function to apply to the value, if renderable + * @param type of the new condition + * @return a new condition with the result of applying the mapper to the value of this condition, + * if renderable, otherwise a condition that will not render. + */ + AbstractSingleValueCondition map(Function mapper); + } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsEqualTo.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsEqualTo.java index 17fe9eef1..51e6e4d47 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsEqualTo.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsEqualTo.java @@ -21,7 +21,8 @@ import org.mybatis.dynamic.sql.AbstractSingleValueCondition; -public class IsEqualTo extends AbstractSingleValueCondition { +public class IsEqualTo extends AbstractSingleValueCondition + implements AbstractSingleValueCondition.Filterable, AbstractSingleValueCondition.Mappable { private static final IsEqualTo EMPTY = new IsEqualTo(-1) { @Override diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThan.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThan.java index 2b3162e1a..93be70911 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThan.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThan.java @@ -21,7 +21,8 @@ import org.mybatis.dynamic.sql.AbstractSingleValueCondition; -public class IsGreaterThan extends AbstractSingleValueCondition { +public class IsGreaterThan extends AbstractSingleValueCondition + implements AbstractSingleValueCondition.Filterable, AbstractSingleValueCondition.Mappable { private static final IsGreaterThan EMPTY = new IsGreaterThan(-1) { @Override public Object value() { diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanOrEqualTo.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanOrEqualTo.java index 7439ae4a8..8373bf352 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanOrEqualTo.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanOrEqualTo.java @@ -21,7 +21,8 @@ import org.mybatis.dynamic.sql.AbstractSingleValueCondition; -public class IsGreaterThanOrEqualTo extends AbstractSingleValueCondition { +public class IsGreaterThanOrEqualTo extends AbstractSingleValueCondition + implements AbstractSingleValueCondition.Filterable, AbstractSingleValueCondition.Mappable { private static final IsGreaterThanOrEqualTo EMPTY = new IsGreaterThanOrEqualTo(-1) { @Override public Object value() { diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThan.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThan.java index 01614d6dc..3ed383fbd 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThan.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThan.java @@ -21,7 +21,9 @@ import org.mybatis.dynamic.sql.AbstractSingleValueCondition; -public class IsLessThan extends AbstractSingleValueCondition { +public class IsLessThan extends AbstractSingleValueCondition + implements AbstractSingleValueCondition.Filterable, AbstractSingleValueCondition.Mappable { + private static final IsLessThan EMPTY = new IsLessThan(-1) { @Override public Object value() { diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanOrEqualTo.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanOrEqualTo.java index 20c3ed460..1b92e0c40 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanOrEqualTo.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanOrEqualTo.java @@ -21,7 +21,8 @@ import org.mybatis.dynamic.sql.AbstractSingleValueCondition; -public class IsLessThanOrEqualTo extends AbstractSingleValueCondition { +public class IsLessThanOrEqualTo extends AbstractSingleValueCondition + implements AbstractSingleValueCondition.Filterable, AbstractSingleValueCondition.Mappable { private static final IsLessThanOrEqualTo EMPTY = new IsLessThanOrEqualTo(-1) { @Override public Object value() { diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLike.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLike.java index 5c7ba967a..e738bda4c 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLike.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLike.java @@ -21,7 +21,9 @@ import org.mybatis.dynamic.sql.AbstractSingleValueCondition; -public class IsLike extends AbstractSingleValueCondition { +public class IsLike extends AbstractSingleValueCondition + implements AbstractSingleValueCondition.Filterable, AbstractSingleValueCondition.Mappable { + private static final IsLike EMPTY = new IsLike(-1) { @Override public Object value() { diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitive.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitive.java index c7d8deefe..b1675a44d 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitive.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitive.java @@ -23,7 +23,8 @@ import org.mybatis.dynamic.sql.util.StringUtilities; public class IsLikeCaseInsensitive extends AbstractSingleValueCondition - implements CaseInsensitiveRenderableCondition { + implements CaseInsensitiveRenderableCondition, AbstractSingleValueCondition.Filterable, + AbstractSingleValueCondition.Mappable { private static final IsLikeCaseInsensitive EMPTY = new IsLikeCaseInsensitive<>("") { //$NON-NLS-1$ @Override public String value() { diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotEqualTo.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotEqualTo.java index e52ab0385..39070c2e8 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotEqualTo.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotEqualTo.java @@ -21,7 +21,8 @@ import org.mybatis.dynamic.sql.AbstractSingleValueCondition; -public class IsNotEqualTo extends AbstractSingleValueCondition { +public class IsNotEqualTo extends AbstractSingleValueCondition + implements AbstractSingleValueCondition.Filterable, AbstractSingleValueCondition.Mappable { private static final IsNotEqualTo EMPTY = new IsNotEqualTo(-1) { @Override public Object value() { diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLike.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLike.java index a2cf60310..a62dc3e9e 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLike.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLike.java @@ -21,7 +21,8 @@ import org.mybatis.dynamic.sql.AbstractSingleValueCondition; -public class IsNotLike extends AbstractSingleValueCondition { +public class IsNotLike extends AbstractSingleValueCondition + implements AbstractSingleValueCondition.Filterable, AbstractSingleValueCondition.Mappable { private static final IsNotLike EMPTY = new IsNotLike(-1) { @Override public Object value() { diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitive.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitive.java index 8aded422d..5b64ef5f5 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitive.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitive.java @@ -23,7 +23,8 @@ import org.mybatis.dynamic.sql.util.StringUtilities; public class IsNotLikeCaseInsensitive extends AbstractSingleValueCondition - implements CaseInsensitiveRenderableCondition { + implements CaseInsensitiveRenderableCondition, AbstractSingleValueCondition.Filterable, + AbstractSingleValueCondition.Mappable { private static final IsNotLikeCaseInsensitive EMPTY = new IsNotLikeCaseInsensitive<>("") { //$NON-NLS-1$ @Override public String value() { @@ -56,16 +57,7 @@ public IsNotLikeCaseInsensitive filter(Predicate predicate) { return filterSupport(predicate, IsNotLikeCaseInsensitive::empty, this); } - /** - * If renderable, apply the mapping to the value and return a new condition with the new value. Else return a - * condition that will not render (this). - * - * @param mapper - * a mapping function to apply to the value, if renderable - * - * @return a new condition with the result of applying the mapper to the value of this condition, if renderable, - * otherwise a condition that will not render. - */ + @Override public IsNotLikeCaseInsensitive map(Function mapper) { return mapSupport(mapper, IsNotLikeCaseInsensitive::new, IsNotLikeCaseInsensitive::empty); } diff --git a/src/test/java/examples/mysql/IsLikeEscape.java b/src/test/java/examples/mysql/IsLikeEscape.java index 21b43fa13..6b8799abb 100644 --- a/src/test/java/examples/mysql/IsLikeEscape.java +++ b/src/test/java/examples/mysql/IsLikeEscape.java @@ -27,7 +27,8 @@ import org.mybatis.dynamic.sql.util.FragmentAndParameters; @NullMarked -public class IsLikeEscape extends AbstractSingleValueCondition { +public class IsLikeEscape extends AbstractSingleValueCondition + implements AbstractSingleValueCondition.Filterable, AbstractSingleValueCondition.Mappable { private static final IsLikeEscape EMPTY = new IsLikeEscape(-1, null) { @Override public Object value() { diff --git a/src/test/kotlin/examples/kotlin/mybatis3/mariadb/KIsLikeEscape.kt b/src/test/kotlin/examples/kotlin/mybatis3/mariadb/KIsLikeEscape.kt index 06dca6609..b47f09110 100644 --- a/src/test/kotlin/examples/kotlin/mybatis3/mariadb/KIsLikeEscape.kt +++ b/src/test/kotlin/examples/kotlin/mybatis3/mariadb/KIsLikeEscape.kt @@ -10,7 +10,8 @@ import org.mybatis.dynamic.sql.util.FragmentAndParameters sealed class KIsLikeEscape( value: T, private val escapeCharacter: Char? = null -) : AbstractSingleValueCondition(value) { +) : AbstractSingleValueCondition(value), AbstractSingleValueCondition.Filterable, + AbstractSingleValueCondition.Mappable { override fun operator(): String = "like" From 43fdf0651330c71c810e49a730e47efbfc28d9bb Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Fri, 14 Mar 2025 10:53:52 -0400 Subject: [PATCH 212/289] Make filter and map optional on list value conditions --- .../sql/AbstractListValueCondition.java | 70 +++++++++++++------ .../dynamic/sql/where/condition/IsIn.java | 6 +- .../where/condition/IsInCaseInsensitive.java | 3 +- .../IsInCaseInsensitiveWhenPresent.java | 3 +- .../sql/where/condition/IsInWhenPresent.java | 15 ++-- .../dynamic/sql/where/condition/IsNotIn.java | 6 +- .../condition/IsNotInCaseInsensitive.java | 3 +- .../IsNotInCaseInsensitiveWhenPresent.java | 3 +- .../where/condition/IsNotInWhenPresent.java | 15 ++-- 9 files changed, 72 insertions(+), 52 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/AbstractListValueCondition.java b/src/main/java/org/mybatis/dynamic/sql/AbstractListValueCondition.java index 066012e28..41c6a56e2 100644 --- a/src/main/java/org/mybatis/dynamic/sql/AbstractListValueCondition.java +++ b/src/main/java/org/mybatis/dynamic/sql/AbstractListValueCondition.java @@ -73,26 +73,6 @@ protected > S mapSupport(Function filter(Predicate predicate); - - /** - * If not empty, apply the mapping to each value in the list return a new condition with the mapped values. - * Else return an empty condition (this). - * - * @param mapper a mapping function to apply to the values, if not empty - * @param type of the new condition - * @return a new condition with mapped values if renderable, otherwise an empty condition - */ - public abstract AbstractListValueCondition map(Function mapper); - public abstract String operator(); @Override @@ -110,4 +90,54 @@ private FragmentAndParameters toFragmentAndParameters(T value, RenderingContext .withParameter(parameterInfo.parameterMapKey(), leftColumn.convertParameterType(value)) .build(); } + + /** + * Conditions may implement Filterable to add optionality to rendering. + * + *

If a condition is Filterable, then a user may add a filter to the usage of the condition that makes a decision + * whether to render the condition at runtime. Conditions that fail the filter will be dropped from the + * rendered SQL. + * + *

Implementations of Filterable may call + * {@link AbstractListValueCondition#filterSupport(Predicate, Function, AbstractListValueCondition, Supplier)} as + * a common implementation of the filtering algorithm. + * + * @param the Java type related to the database column type + */ + public interface Filterable { + /** + * If renderable and the value matches the predicate, returns this condition. Else returns a condition + * that will not render. + * + * @param predicate predicate applied to the value, if renderable + * @return this condition if renderable and the value matches the predicate, otherwise a condition + * that will not render. + */ + AbstractListValueCondition filter(Predicate predicate); + } + + /** + * Conditions may implement Mappable to alter condition values or types during rendering. + * + *

If a condition is Mappable, then a user may add a mapper to the usage of the condition that can alter the + * values of a condition, or change that datatype. + * + *

Implementations of Mappable may call + * {@link AbstractListValueCondition#mapSupport(Function, Function, Supplier)} as + * a common implementation of the mapping algorithm. + * + * @param the Java type related to the database column type + */ + public interface Mappable { + /** + * If renderable, apply the mapping to the value and return a new condition with the new value. Else return a + * condition that will not render (this). + * + * @param mapper a mapping function to apply to the value, if renderable + * @param type of the new condition + * @return a new condition with the result of applying the mapper to the value of this condition, + * if renderable, otherwise a condition that will not render. + */ + AbstractListValueCondition map(Function mapper); + } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsIn.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsIn.java index 67b6fff08..8beeacc8d 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsIn.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsIn.java @@ -25,7 +25,8 @@ import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.util.Validator; -public class IsIn extends AbstractListValueCondition { +public class IsIn extends AbstractListValueCondition + implements AbstractListValueCondition.Filterable, AbstractListValueCondition.Mappable{ private static final IsIn EMPTY = new IsIn<>(Collections.emptyList()); public static IsIn empty() { @@ -56,8 +57,7 @@ public IsIn filter(Predicate predicate) { @Override public IsIn map(Function mapper) { - Function, IsIn> constructor = IsIn::new; - return mapSupport(mapper, constructor, IsIn::empty); + return mapSupport(mapper, IsIn::new, IsIn::empty); } @SafeVarargs diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java index 6d0219dcd..6ca85d554 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java @@ -27,7 +27,8 @@ import org.mybatis.dynamic.sql.util.Validator; public class IsInCaseInsensitive extends AbstractListValueCondition - implements CaseInsensitiveRenderableCondition { + implements CaseInsensitiveRenderableCondition, AbstractListValueCondition.Filterable, + AbstractListValueCondition.Mappable { private static final IsInCaseInsensitive EMPTY = new IsInCaseInsensitive<>(Collections.emptyList()); public static IsInCaseInsensitive empty() { diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java index de17a8394..6afdb486d 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java @@ -26,7 +26,8 @@ import org.mybatis.dynamic.sql.AbstractListValueCondition; public class IsInCaseInsensitiveWhenPresent extends AbstractListValueCondition - implements CaseInsensitiveRenderableCondition { + implements CaseInsensitiveRenderableCondition, AbstractListValueCondition.Filterable, + AbstractListValueCondition.Mappable { private static final IsInCaseInsensitiveWhenPresent EMPTY = new IsInCaseInsensitiveWhenPresent<>(Collections.emptyList()); diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInWhenPresent.java index ea1bfe509..5c431fea3 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInWhenPresent.java @@ -25,7 +25,8 @@ import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.AbstractListValueCondition; -public class IsInWhenPresent extends AbstractListValueCondition { +public class IsInWhenPresent extends AbstractListValueCondition + implements AbstractListValueCondition.Filterable, AbstractListValueCondition.Mappable{ private static final IsInWhenPresent EMPTY = new IsInWhenPresent<>(Collections.emptyList()); public static IsInWhenPresent empty() { @@ -48,17 +49,9 @@ public IsInWhenPresent filter(Predicate predicate) { return filterSupport(predicate, IsInWhenPresent::new, this, IsInWhenPresent::empty); } - /** - * If not empty, apply the mapping to each value in the list return a new condition with the mapped values. - * Else return an empty condition (this). - * - * @param mapper a mapping function to apply to the values, if not empty - * @param type of the new condition - * @return a new condition with mapped values if renderable, otherwise an empty condition - */ + @Override public IsInWhenPresent map(Function mapper) { - Function, IsInWhenPresent> constructor = IsInWhenPresent::new; - return mapSupport(mapper, constructor, IsInWhenPresent::empty); + return mapSupport(mapper, IsInWhenPresent::new, IsInWhenPresent::empty); } @SafeVarargs diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotIn.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotIn.java index f22c504c8..33f5d14c7 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotIn.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotIn.java @@ -25,7 +25,8 @@ import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.util.Validator; -public class IsNotIn extends AbstractListValueCondition { +public class IsNotIn extends AbstractListValueCondition + implements AbstractListValueCondition.Filterable, AbstractListValueCondition.Mappable{ private static final IsNotIn EMPTY = new IsNotIn<>(Collections.emptyList()); public static IsNotIn empty() { @@ -56,8 +57,7 @@ public IsNotIn filter(Predicate predicate) { @Override public IsNotIn map(Function mapper) { - Function, IsNotIn> constructor = IsNotIn::new; - return mapSupport(mapper, constructor, IsNotIn::empty); + return mapSupport(mapper, IsNotIn::new, IsNotIn::empty); } @SafeVarargs diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java index 3513d022c..7ade40938 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java @@ -27,7 +27,8 @@ import org.mybatis.dynamic.sql.util.Validator; public class IsNotInCaseInsensitive extends AbstractListValueCondition - implements CaseInsensitiveRenderableCondition { + implements CaseInsensitiveRenderableCondition, AbstractListValueCondition.Filterable, + AbstractListValueCondition.Mappable { private static final IsNotInCaseInsensitive EMPTY = new IsNotInCaseInsensitive<>(Collections.emptyList()); public static IsNotInCaseInsensitive empty() { diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java index bbff09bbe..9d57e7623 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java @@ -26,7 +26,8 @@ import org.mybatis.dynamic.sql.AbstractListValueCondition; public class IsNotInCaseInsensitiveWhenPresent extends AbstractListValueCondition - implements CaseInsensitiveRenderableCondition { + implements CaseInsensitiveRenderableCondition, AbstractListValueCondition.Filterable, + AbstractListValueCondition.Mappable { private static final IsNotInCaseInsensitiveWhenPresent EMPTY = new IsNotInCaseInsensitiveWhenPresent<>(Collections.emptyList()); diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInWhenPresent.java index 1c4b570a9..ddc8e5470 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInWhenPresent.java @@ -24,7 +24,8 @@ import org.mybatis.dynamic.sql.AbstractListValueCondition; -public class IsNotInWhenPresent extends AbstractListValueCondition { +public class IsNotInWhenPresent extends AbstractListValueCondition + implements AbstractListValueCondition.Filterable, AbstractListValueCondition.Mappable{ private static final IsNotInWhenPresent EMPTY = new IsNotInWhenPresent<>(Collections.emptyList()); public static IsNotInWhenPresent empty() { @@ -47,17 +48,9 @@ public IsNotInWhenPresent filter(Predicate predicate) { return filterSupport(predicate, IsNotInWhenPresent::new, this, IsNotInWhenPresent::empty); } - /** - * If not empty, apply the mapping to each value in the list return a new condition with the mapped values. - * Else return an empty condition (this). - * - * @param mapper a mapping function to apply to the values, if not empty - * @param type of the new condition - * @return a new condition with mapped values if renderable, otherwise an empty condition - */ + @Override public IsNotInWhenPresent map(Function mapper) { - Function, IsNotInWhenPresent> constructor = IsNotInWhenPresent::new; - return mapSupport(mapper, constructor, IsNotInWhenPresent::empty); + return mapSupport(mapper, IsNotInWhenPresent::new, IsNotInWhenPresent::empty); } @SafeVarargs From 1a2b9189270dd1b2c8f0bb02e1a8bbd6820da5b1 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Fri, 14 Mar 2025 11:08:08 -0400 Subject: [PATCH 213/289] Make filter and map optional on two value conditions --- .../sql/AbstractTwoValueCondition.java | 120 +++++++++++------- .../sql/where/condition/IsBetween.java | 3 +- .../sql/where/condition/IsNotBetween.java | 3 +- 3 files changed, 79 insertions(+), 47 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/AbstractTwoValueCondition.java b/src/main/java/org/mybatis/dynamic/sql/AbstractTwoValueCondition.java index 15a5b6ffe..6cceff16e 100644 --- a/src/main/java/org/mybatis/dynamic/sql/AbstractTwoValueCondition.java +++ b/src/main/java/org/mybatis/dynamic/sql/AbstractTwoValueCondition.java @@ -67,51 +67,6 @@ protected > S mapSupport(Function filter(BiPredicate predicate); - - /** - * If renderable and both values match the predicate, returns this condition. Else returns a condition - * that will not render. This function implements a short-circuiting test. If the - * first value does not match the predicate, then the second value will not be tested. - * - * @param predicate predicate applied to both values, if renderable - * @return this condition if renderable and the values match the predicate, otherwise a condition - * that will not render. - */ - public abstract AbstractTwoValueCondition filter(Predicate predicate); - - /** - * If renderable, apply the mappings to the values and return a new condition with the new values. Else return a - * condition that will not render (this). - * - * @param mapper1 a mapping function to apply to the first value, if renderable - * @param mapper2 a mapping function to apply to the second value, if renderable - * @param type of the new condition - * @return a new condition with the result of applying the mappers to the values of this condition, - * if renderable, otherwise a condition that will not render. - */ - public abstract AbstractTwoValueCondition map(Function mapper1, - Function mapper2); - - /** - * If renderable, apply the mapping to both values and return a new condition with the new values. Else return a - * condition that will not render (this). - * - * @param mapper a mapping function to apply to both values, if renderable - * @param type of the new condition - * @return a new condition with the result of applying the mappers to the values of this condition, - * if renderable, otherwise a condition that will not render. - */ - public abstract AbstractTwoValueCondition map(Function mapper); - public abstract String operator1(); public abstract String operator2(); @@ -131,4 +86,79 @@ public FragmentAndParameters renderCondition(RenderingContext renderingContext, .withParameter(parameterInfo2.parameterMapKey(), leftColumn.convertParameterType(value2())) .build(); } + + /** + * Conditions may implement Filterable to add optionality to rendering. + * + *

If a condition is Filterable, then a user may add a filter to the usage of the condition that makes a decision + * whether to render the condition at runtime. Conditions that fail the filter will be dropped from the + * rendered SQL. + * + *

Implementations of Filterable may call + * {@link AbstractTwoValueCondition#filterSupport(Predicate, Supplier, AbstractTwoValueCondition)} + * or {@link AbstractTwoValueCondition#filterSupport(BiPredicate, Supplier, AbstractTwoValueCondition)} as + * a common implementation of the filtering algorithm. + * + * @param the Java type related to the database column type + */ + public interface Filterable { + /** + * If renderable and the values match the predicate, returns this condition. Else returns a condition + * that will not render. + * + * @param predicate predicate applied to the values, if renderable + * @return this condition if renderable and the values match the predicate, otherwise a condition + * that will not render. + */ + AbstractTwoValueCondition filter(BiPredicate predicate); + + /** + * If renderable and both values match the predicate, returns this condition. Else returns a condition + * that will not render. This function implements a short-circuiting test. If the + * first value does not match the predicate, then the second value will not be tested. + * + * @param predicate predicate applied to both values, if renderable + * @return this condition if renderable and the values match the predicate, otherwise a condition + * that will not render. + */ + AbstractTwoValueCondition filter(Predicate predicate); + } + + /** + * Conditions may implement Mappable to alter condition values or types during rendering. + * + *

If a condition is Mappable, then a user may add a mapper to the usage of the condition that can alter the + * values of a condition, or change that datatype. + * + *

Implementations of Mappable may call + * {@link AbstractTwoValueCondition#mapSupport(Function, Function, BiFunction, Supplier)} as + * a common implementation of the mapping algorithm. + * + * @param the Java type related to the database column type + */ + public interface Mappable { + /** + * If renderable, apply the mappings to the values and return a new condition with the new values. Else return a + * condition that will not render (this). + * + * @param mapper1 a mapping function to apply to the first value, if renderable + * @param mapper2 a mapping function to apply to the second value, if renderable + * @param type of the new condition + * @return a new condition with the result of applying the mappers to the values of this condition, + * if renderable, otherwise a condition that will not render. + */ + AbstractTwoValueCondition map(Function mapper1, + Function mapper2); + + /** + * If renderable, apply the mapping to both values and return a new condition with the new values. Else return a + * condition that will not render (this). + * + * @param mapper a mapping function to apply to both values, if renderable + * @param type of the new condition + * @return a new condition with the result of applying the mappers to the values of this condition, + * if renderable, otherwise a condition that will not render. + */ + AbstractTwoValueCondition map(Function mapper); + } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsBetween.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsBetween.java index 0d554d0fc..0e6700fb0 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsBetween.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsBetween.java @@ -23,7 +23,8 @@ import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.AbstractTwoValueCondition; -public class IsBetween extends AbstractTwoValueCondition { +public class IsBetween extends AbstractTwoValueCondition + implements AbstractTwoValueCondition.Filterable, AbstractTwoValueCondition.Mappable { private static final IsBetween EMPTY = new IsBetween(-1, -1) { @Override public Object value1() { diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotBetween.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotBetween.java index f7eb98f52..6a515d4ac 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotBetween.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotBetween.java @@ -23,7 +23,8 @@ import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.AbstractTwoValueCondition; -public class IsNotBetween extends AbstractTwoValueCondition { +public class IsNotBetween extends AbstractTwoValueCondition + implements AbstractTwoValueCondition.Filterable, AbstractTwoValueCondition.Mappable { private static final IsNotBetween EMPTY = new IsNotBetween(-1, -1) { @Override public Object value1() { From 4594a5f4995f7d76d20eb5366fcca429ce4c412b Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Fri, 14 Mar 2025 11:19:14 -0400 Subject: [PATCH 214/289] Update docs --- src/site/markdown/docs/extending.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/site/markdown/docs/extending.md b/src/site/markdown/docs/extending.md index eabee1e03..a1fee9adb 100644 --- a/src/site/markdown/docs/extending.md +++ b/src/site/markdown/docs/extending.md @@ -304,7 +304,8 @@ Here's an example of implementing a LIKE condition that supports ESCAPE: ```java @NullMarked -public class IsLikeEscape extends AbstractSingleValueCondition { +public class IsLikeEscape extends AbstractSingleValueCondition + implements AbstractSingleValueCondition.Filterable, AbstractSingleValueCondition.Mappable { private static final IsLikeEscape EMPTY = new IsLikeEscape(-1, null) { @Override public Object value() { @@ -354,6 +355,7 @@ public class IsLikeEscape extends AbstractSingleValueCondition { return filterSupport(predicate, IsLikeEscape::empty, this); } + @Override public IsLikeEscape map(Function mapper) { return mapSupport(mapper, v -> new IsLikeEscape<>(v, escapeCharacter), IsLikeEscape::empty); } @@ -374,4 +376,5 @@ Important notes: 2. The class constructor accepts an escape character that will be rendered into an ESCAPE phrase 3. The class overrides `renderCondition` and changes the library generated `FragmentAndParameters` to add the ESCAPE phrase. **This is the key to what's needed to implement a custom condition.** -4. The class provides `map` and `filter` functions as is expected for any condition in the library +4. The class implements `Filterable` and `Mappable` to provide `filter` and `map` functions as is expected for most + conditions in the library From 0acbda7617d41b0a5608beccda8074499fbe436b Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Fri, 14 Mar 2025 12:32:53 -0400 Subject: [PATCH 215/289] Update docs --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b333e3ab..cec9f683f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -103,7 +103,8 @@ Runtime behavior changes: - Rendering for all the conditions (isEqualTo, etc.) has changed. This should be transparent to most users unless you have coded a direct implementation of `VisitableCondition`. The change makes it easier to code custom conditions that are not supported by the library out of the box. The statement renderers now call methods `renderCondition` and - `renderLeftColumn` that you can override to implement any rendering you need. + `renderLeftColumn` that you can override to implement any rendering you need. In addition, we've made `filter` and + `map` support optional if you implement custom conditions ## Release 1.5.2 - June 3, 2024 From 1df401a0c1e7493ea6cb0f37423bee2c4a8668e4 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Fri, 14 Mar 2025 12:54:59 -0400 Subject: [PATCH 216/289] Polishing --- .../sql/where/condition/SupplierTest.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/test/java/org/mybatis/dynamic/sql/where/condition/SupplierTest.java b/src/test/java/org/mybatis/dynamic/sql/where/condition/SupplierTest.java index e1362d48f..b85a7f412 100644 --- a/src/test/java/org/mybatis/dynamic/sql/where/condition/SupplierTest.java +++ b/src/test/java/org/mybatis/dynamic/sql/where/condition/SupplierTest.java @@ -260,28 +260,28 @@ void testIsLikeNull() { @Test void testIsLikeCaseInsensitive() { - IsLikeCaseInsensitive cond = SqlBuilder.isLikeCaseInsensitive(() -> "%f%"); + IsLikeCaseInsensitive cond = SqlBuilder.isLikeCaseInsensitive(() -> "%f%"); assertThat(cond.value()).isEqualTo("%F%"); assertThat(cond.isEmpty()).isFalse(); } @Test void testIsLikeCaseInsensitiveNull() { - IsLikeCaseInsensitive cond = SqlBuilder.isLikeCaseInsensitive(() -> null); + IsLikeCaseInsensitive cond = SqlBuilder.isLikeCaseInsensitive(() -> null); assertThat(cond.value()).isNull(); assertThat(cond.isEmpty()).isFalse(); } @Test void testIsLikeCaseInsensitiveWhenPresent() { - IsLikeCaseInsensitive cond = SqlBuilder.isLikeCaseInsensitiveWhenPresent(() -> "%f%"); + IsLikeCaseInsensitive cond = SqlBuilder.isLikeCaseInsensitiveWhenPresent(() -> "%f%"); assertThat(cond.value()).isEqualTo("%F%"); assertThat(cond.isEmpty()).isFalse(); } @Test void testIsLikeCaseInsensitiveWhenPresentNull() { - IsLikeCaseInsensitive cond = SqlBuilder.isLikeCaseInsensitiveWhenPresent(() -> null); + IsLikeCaseInsensitive cond = SqlBuilder.isLikeCaseInsensitiveWhenPresent(() -> null); assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value); assertThat(cond.isEmpty()).isTrue(); } @@ -330,28 +330,28 @@ void testIsNotLikeWhenPresentNull() { @Test void testIsNotLikeCaseInsensitive() { - IsNotLikeCaseInsensitive cond = SqlBuilder.isNotLikeCaseInsensitive(() -> "%f%"); + IsNotLikeCaseInsensitive cond = SqlBuilder.isNotLikeCaseInsensitive(() -> "%f%"); assertThat(cond.value()).isEqualTo("%F%"); assertThat(cond.isEmpty()).isFalse(); } @Test void testIsNotLikeCaseInsensitiveNull() { - IsNotLikeCaseInsensitive cond = SqlBuilder.isNotLikeCaseInsensitive(() -> null); + IsNotLikeCaseInsensitive cond = SqlBuilder.isNotLikeCaseInsensitive(() -> null); assertThat(cond.value()).isNull(); assertThat(cond.isEmpty()).isFalse(); } @Test void testIsNotLikeCaseInsensitiveWhenPresent() { - IsNotLikeCaseInsensitive cond = SqlBuilder.isNotLikeCaseInsensitiveWhenPresent(() -> "%f%"); + IsNotLikeCaseInsensitive cond = SqlBuilder.isNotLikeCaseInsensitiveWhenPresent(() -> "%f%"); assertThat(cond.value()).isEqualTo("%F%"); assertThat(cond.isEmpty()).isFalse(); } @Test void testIsNotLikeCaseInsensitiveWhenPresentNull() { - IsNotLikeCaseInsensitive cond = SqlBuilder.isNotLikeCaseInsensitiveWhenPresent(() -> null); + IsNotLikeCaseInsensitive cond = SqlBuilder.isNotLikeCaseInsensitiveWhenPresent(() -> null); assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value); assertThat(cond.isEmpty()).isTrue(); } From 60b10b04695e58c5c9c52d6e446e6c5904807e74 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 14 Mar 2025 18:10:39 +0000 Subject: [PATCH 217/289] Update junit5 monorepo to v5.12.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f26ba6481..03b9bc69f 100644 --- a/pom.xml +++ b/pom.xml @@ -60,7 +60,7 @@ 17 17 17 - 5.12.0 + 5.12.1 5.2.1 checkstyle-override.xml From 7cb17bd932f150a6765b0751244917b4c22599c6 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Fri, 14 Mar 2025 16:17:05 -0400 Subject: [PATCH 218/289] Coverage --- .../dynamic/sql/util/StringUtilities.java | 6 +++ .../where/condition/IsInCaseInsensitive.java | 13 +++++++ .../IsInCaseInsensitiveWhenPresent.java | 14 +++++++ .../condition/IsLikeCaseInsensitive.java | 13 +++++++ .../condition/IsNotInCaseInsensitive.java | 13 +++++++ .../IsNotInCaseInsensitiveWhenPresent.java | 14 +++++++ .../condition/IsNotLikeCaseInsensitive.java | 13 +++++++ .../sql/where/condition/FilterAndMapTest.java | 37 +++++++++++++++++++ 8 files changed, 123 insertions(+) diff --git a/src/main/java/org/mybatis/dynamic/sql/util/StringUtilities.java b/src/main/java/org/mybatis/dynamic/sql/util/StringUtilities.java index 2b57c748e..25a7e390c 100644 --- a/src/main/java/org/mybatis/dynamic/sql/util/StringUtilities.java +++ b/src/main/java/org/mybatis/dynamic/sql/util/StringUtilities.java @@ -15,6 +15,8 @@ */ package org.mybatis.dynamic.sql.util; +import java.util.function.Function; + import org.jspecify.annotations.Nullable; public interface StringUtilities { @@ -59,4 +61,8 @@ static String formatConstantForSQL(String in) { String escaped = in.replace("'", "''"); //$NON-NLS-1$ //$NON-NLS-2$ return "'" + escaped + "'"; //$NON-NLS-1$ //$NON-NLS-2$ } + + static Function mapToUpperCase(Function f) { + return f.andThen(String::toUpperCase); + } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java index 6ca85d554..dc3b0f8f1 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java @@ -57,6 +57,19 @@ public IsInCaseInsensitive filter(Predicate predicate) { return filterSupport(predicate, IsInCaseInsensitive::new, this, IsInCaseInsensitive::empty); } + /** + * If renderable, apply the mapping to the value and return a new condition with the new value. Else return a + * condition that will not render (this). + * + *

This function DOES NOT automatically transform values to uppercase, so it potentially creates a + * case-sensitive query. For String conditions you can use {@link StringUtilities#mapToUpperCase(Function)} + * to add an uppercase transform after your mapping function. + * + * @param mapper a mapping function to apply to the value, if renderable + * @param type of the new condition + * @return a new condition with the result of applying the mapper to the value of this condition, + * if renderable, otherwise a condition that will not render. + */ @Override public IsInCaseInsensitive map(Function mapper) { return mapSupport(mapper, IsInCaseInsensitive::new, IsInCaseInsensitive::empty); diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java index 6afdb486d..283e62fc7 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java @@ -24,6 +24,7 @@ import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.AbstractListValueCondition; +import org.mybatis.dynamic.sql.util.StringUtilities; public class IsInCaseInsensitiveWhenPresent extends AbstractListValueCondition implements CaseInsensitiveRenderableCondition, AbstractListValueCondition.Filterable, @@ -52,6 +53,19 @@ public IsInCaseInsensitiveWhenPresent filter(Predicate predicate) IsInCaseInsensitiveWhenPresent::empty); } + /** + * If renderable, apply the mapping to the value and return a new condition with the new value. Else return a + * condition that will not render (this). + * + *

This function DOES NOT automatically transform values to uppercase, so it potentially creates a + * case-sensitive query. For String conditions you can use {@link StringUtilities#mapToUpperCase(Function)} + * to add an uppercase transform after your mapping function. + * + * @param mapper a mapping function to apply to the value, if renderable + * @param type of the new condition + * @return a new condition with the result of applying the mapper to the value of this condition, + * if renderable, otherwise a condition that will not render. + */ @Override public IsInCaseInsensitiveWhenPresent map(Function mapper) { return mapSupport(mapper, IsInCaseInsensitiveWhenPresent::new, IsInCaseInsensitiveWhenPresent::empty); diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitive.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitive.java index b1675a44d..6b569b32d 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitive.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitive.java @@ -57,6 +57,19 @@ public IsLikeCaseInsensitive filter(Predicate predicate) { return filterSupport(predicate, IsLikeCaseInsensitive::empty, this); } + /** + * If renderable, apply the mapping to the value and return a new condition with the new value. Else return a + * condition that will not render (this). + * + *

This function DOES NOT automatically transform values to uppercase, so it potentially creates a + * case-sensitive query. For String conditions you can use {@link StringUtilities#mapToUpperCase(Function)} + * to add an uppercase transform after your mapping function. + * + * @param mapper a mapping function to apply to the value, if renderable + * @param type of the new condition + * @return a new condition with the result of applying the mapper to the value of this condition, + * if renderable, otherwise a condition that will not render. + */ @Override public IsLikeCaseInsensitive map(Function mapper) { return mapSupport(mapper, IsLikeCaseInsensitive::new, IsLikeCaseInsensitive::empty); diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java index 7ade40938..8731d5b64 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java @@ -57,6 +57,19 @@ public IsNotInCaseInsensitive filter(Predicate predicate) { return filterSupport(predicate, IsNotInCaseInsensitive::new, this, IsNotInCaseInsensitive::empty); } + /** + * If renderable, apply the mapping to the value and return a new condition with the new value. Else return a + * condition that will not render (this). + * + *

This function DOES NOT automatically transform values to uppercase, so it potentially creates a + * case-sensitive query. For String conditions you can use {@link StringUtilities#mapToUpperCase(Function)} + * to add an uppercase transform after your mapping function. + * + * @param mapper a mapping function to apply to the value, if renderable + * @param type of the new condition + * @return a new condition with the result of applying the mapper to the value of this condition, + * if renderable, otherwise a condition that will not render. + */ @Override public IsNotInCaseInsensitive map(Function mapper) { return mapSupport(mapper, IsNotInCaseInsensitive::new, IsNotInCaseInsensitive::empty); diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java index 9d57e7623..438e1c5ed 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java @@ -24,6 +24,7 @@ import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.AbstractListValueCondition; +import org.mybatis.dynamic.sql.util.StringUtilities; public class IsNotInCaseInsensitiveWhenPresent extends AbstractListValueCondition implements CaseInsensitiveRenderableCondition, AbstractListValueCondition.Filterable, @@ -52,6 +53,19 @@ public IsNotInCaseInsensitiveWhenPresent filter(Predicate predicat this, IsNotInCaseInsensitiveWhenPresent::empty); } + /** + * If renderable, apply the mapping to the value and return a new condition with the new value. Else return a + * condition that will not render (this). + * + *

This function DOES NOT automatically transform values to uppercase, so it potentially creates a + * case-sensitive query. For String conditions you can use {@link StringUtilities#mapToUpperCase(Function)} + * to add an uppercase transform after your mapping function. + * + * @param mapper a mapping function to apply to the value, if renderable + * @param type of the new condition + * @return a new condition with the result of applying the mapper to the value of this condition, + * if renderable, otherwise a condition that will not render. + */ @Override public IsNotInCaseInsensitiveWhenPresent map(Function mapper) { return mapSupport(mapper, IsNotInCaseInsensitiveWhenPresent::new, IsNotInCaseInsensitiveWhenPresent::empty); diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitive.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitive.java index 5b64ef5f5..8eb65d772 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitive.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitive.java @@ -57,6 +57,19 @@ public IsNotLikeCaseInsensitive filter(Predicate predicate) { return filterSupport(predicate, IsNotLikeCaseInsensitive::empty, this); } + /** + * If renderable, apply the mapping to the value and return a new condition with the new value. Else return a + * condition that will not render (this). + * + *

This function DOES NOT automatically transform values to uppercase, so it potentially creates a + * case-sensitive query. For String conditions you can use {@link StringUtilities#mapToUpperCase(Function)} + * to add an uppercase transform after your mapping function. + * + * @param mapper a mapping function to apply to the value, if renderable + * @param type of the new condition + * @return a new condition with the result of applying the mapper to the value of this condition, + * if renderable, otherwise a condition that will not render. + */ @Override public IsNotLikeCaseInsensitive map(Function mapper) { return mapSupport(mapper, IsNotLikeCaseInsensitive::new, IsNotLikeCaseInsensitive::empty); diff --git a/src/test/java/org/mybatis/dynamic/sql/where/condition/FilterAndMapTest.java b/src/test/java/org/mybatis/dynamic/sql/where/condition/FilterAndMapTest.java index 8c8f35eb5..7d4e4505e 100644 --- a/src/test/java/org/mybatis/dynamic/sql/where/condition/FilterAndMapTest.java +++ b/src/test/java/org/mybatis/dynamic/sql/where/condition/FilterAndMapTest.java @@ -24,6 +24,7 @@ import org.junit.jupiter.api.Test; import org.mybatis.dynamic.sql.SqlBuilder; +import org.mybatis.dynamic.sql.util.StringUtilities; class FilterAndMapTest { @Test @@ -533,4 +534,40 @@ void testNotBetweenMapWithSingleMapper() { assertThat(cond.value2()).isEqualTo(4); } + @Test + void testMappingAnEmptyListCondition() { + var cond = SqlBuilder.isNotIn("Fred", "Wilma"); + var filtered = cond.filter(s -> false); + var mapped = filtered.map(s -> s); + assertThat(mapped.isEmpty()).isTrue(); + assertThat(filtered).isSameAs(mapped); + } + + @Test + void testIsInCaseInsensitiveWhenPresentMap() { + var cond = SqlBuilder.isInCaseInsensitiveWhenPresent("Fred", "Wilma"); + var mapped = cond.map(s -> s + " Flintstone"); + assertThat(mapped.values().toList()).containsExactly("FRED Flintstone", "WILMA Flintstone"); + } + + @Test + void testIsInCaseInsensitiveWhenPresentMapCaseInsensitive() { + var cond = SqlBuilder.isInCaseInsensitiveWhenPresent("Fred", "Wilma"); + var mapped = cond.map(StringUtilities.mapToUpperCase(s -> s + " Flintstone")); + assertThat(mapped.values().toList()).containsExactly("FRED FLINTSTONE", "WILMA FLINTSTONE"); + } + + @Test + void testIsNotInCaseInsensitiveWhenPresentMap() { + var cond = SqlBuilder.isNotInCaseInsensitiveWhenPresent("Fred", "Wilma"); + var mapped = cond.map(s -> s + " Flintstone"); + assertThat(mapped.values().toList()).containsExactly("FRED Flintstone", "WILMA Flintstone"); + } + + @Test + void testIsNotInCaseInsensitiveWhenPresentMapCaseInsensitive() { + var cond = SqlBuilder.isNotInCaseInsensitiveWhenPresent("Fred", "Wilma"); + var mapped = cond.map(StringUtilities.mapToUpperCase(s -> s + " Flintstone")); + assertThat(mapped.values().toList()).containsExactly("FRED FLINTSTONE", "WILMA FLINTSTONE"); + } } From 2a3be8185fae1ecbdb3dc73b33ee4f3be4ef4cb0 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Sat, 15 Mar 2025 09:36:06 -0400 Subject: [PATCH 219/289] Improve Case Insensitive Conditions Make the case-insensitive conditions work as expected. With a map operation, the values will now be upper-cased if possible. --- .../dynamic/sql/util/StringUtilities.java | 12 ++++++++---- .../where/condition/IsInCaseInsensitive.java | 19 +++---------------- .../IsInCaseInsensitiveWhenPresent.java | 18 ++---------------- .../condition/IsLikeCaseInsensitive.java | 18 ++---------------- .../condition/IsNotInCaseInsensitive.java | 18 ++---------------- .../IsNotInCaseInsensitiveWhenPresent.java | 18 ++---------------- .../condition/IsNotLikeCaseInsensitive.java | 18 ++---------------- .../dynamic/sql/util/StringUtilitiesTest.java | 12 ++++++++++++ .../sql/where/condition/FilterAndMapTest.java | 19 ++----------------- 9 files changed, 35 insertions(+), 117 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/util/StringUtilities.java b/src/main/java/org/mybatis/dynamic/sql/util/StringUtilities.java index 25a7e390c..532391856 100644 --- a/src/main/java/org/mybatis/dynamic/sql/util/StringUtilities.java +++ b/src/main/java/org/mybatis/dynamic/sql/util/StringUtilities.java @@ -15,8 +15,6 @@ */ package org.mybatis.dynamic.sql.util; -import java.util.function.Function; - import org.jspecify.annotations.Nullable; public interface StringUtilities { @@ -62,7 +60,13 @@ static String formatConstantForSQL(String in) { return "'" + escaped + "'"; //$NON-NLS-1$ //$NON-NLS-2$ } - static Function mapToUpperCase(Function f) { - return f.andThen(String::toUpperCase); + static T upperCaseIfPossible(T value) { + if (value instanceof String) { + @SuppressWarnings("unchecked") + T t = (T) safelyUpperCase((String) value); + return t; + } + + return value; } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java index dc3b0f8f1..a3777188a 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java @@ -20,6 +20,7 @@ import java.util.Collections; import java.util.function.Function; import java.util.function.Predicate; +import java.util.stream.Collectors; import org.mybatis.dynamic.sql.AbstractListValueCondition; import org.mybatis.dynamic.sql.render.RenderingContext; @@ -38,7 +39,7 @@ public static IsInCaseInsensitive empty() { } protected IsInCaseInsensitive(Collection values) { - super(values); + super(values.stream().map(StringUtilities::upperCaseIfPossible).collect(Collectors.toList())); } @Override @@ -57,19 +58,6 @@ public IsInCaseInsensitive filter(Predicate predicate) { return filterSupport(predicate, IsInCaseInsensitive::new, this, IsInCaseInsensitive::empty); } - /** - * If renderable, apply the mapping to the value and return a new condition with the new value. Else return a - * condition that will not render (this). - * - *

This function DOES NOT automatically transform values to uppercase, so it potentially creates a - * case-sensitive query. For String conditions you can use {@link StringUtilities#mapToUpperCase(Function)} - * to add an uppercase transform after your mapping function. - * - * @param mapper a mapping function to apply to the value, if renderable - * @param type of the new condition - * @return a new condition with the result of applying the mapper to the value of this condition, - * if renderable, otherwise a condition that will not render. - */ @Override public IsInCaseInsensitive map(Function mapper) { return mapSupport(mapper, IsInCaseInsensitive::new, IsInCaseInsensitive::empty); @@ -80,7 +68,6 @@ public static IsInCaseInsensitive of(String... values) { } public static IsInCaseInsensitive of(Collection values) { - // Keep the null safe upper case utility for backwards compatibility in case someone passes in a null - return new IsInCaseInsensitive<>(values.stream().map(StringUtilities::safelyUpperCase).toList()); + return new IsInCaseInsensitive<>(values); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java index 283e62fc7..fee942f7d 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java @@ -39,7 +39,7 @@ public static IsInCaseInsensitiveWhenPresent empty() { } protected IsInCaseInsensitiveWhenPresent(Collection values) { - super(values); + super(values.stream().filter(Objects::nonNull).map(StringUtilities::upperCaseIfPossible).toList()); } @Override @@ -53,19 +53,6 @@ public IsInCaseInsensitiveWhenPresent filter(Predicate predicate) IsInCaseInsensitiveWhenPresent::empty); } - /** - * If renderable, apply the mapping to the value and return a new condition with the new value. Else return a - * condition that will not render (this). - * - *

This function DOES NOT automatically transform values to uppercase, so it potentially creates a - * case-sensitive query. For String conditions you can use {@link StringUtilities#mapToUpperCase(Function)} - * to add an uppercase transform after your mapping function. - * - * @param mapper a mapping function to apply to the value, if renderable - * @param type of the new condition - * @return a new condition with the result of applying the mapper to the value of this condition, - * if renderable, otherwise a condition that will not render. - */ @Override public IsInCaseInsensitiveWhenPresent map(Function mapper) { return mapSupport(mapper, IsInCaseInsensitiveWhenPresent::new, IsInCaseInsensitiveWhenPresent::empty); @@ -76,7 +63,6 @@ public static IsInCaseInsensitiveWhenPresent of(@Nullable String... valu } public static IsInCaseInsensitiveWhenPresent of(Collection<@Nullable String> values) { - return new IsInCaseInsensitiveWhenPresent<>( - values.stream().filter(Objects::nonNull).map(String::toUpperCase).toList()); + return new IsInCaseInsensitiveWhenPresent<>(values); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitive.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitive.java index 6b569b32d..e4d31c126 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitive.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitive.java @@ -44,7 +44,7 @@ public static IsLikeCaseInsensitive empty() { } protected IsLikeCaseInsensitive(T value) { - super(value); + super(StringUtilities.upperCaseIfPossible(value)); } @Override @@ -57,26 +57,12 @@ public IsLikeCaseInsensitive filter(Predicate predicate) { return filterSupport(predicate, IsLikeCaseInsensitive::empty, this); } - /** - * If renderable, apply the mapping to the value and return a new condition with the new value. Else return a - * condition that will not render (this). - * - *

This function DOES NOT automatically transform values to uppercase, so it potentially creates a - * case-sensitive query. For String conditions you can use {@link StringUtilities#mapToUpperCase(Function)} - * to add an uppercase transform after your mapping function. - * - * @param mapper a mapping function to apply to the value, if renderable - * @param type of the new condition - * @return a new condition with the result of applying the mapper to the value of this condition, - * if renderable, otherwise a condition that will not render. - */ @Override public IsLikeCaseInsensitive map(Function mapper) { return mapSupport(mapper, IsLikeCaseInsensitive::new, IsLikeCaseInsensitive::empty); } public static IsLikeCaseInsensitive of(String value) { - // Keep the null safe upper case utility for backwards compatibility in case someone passes in a null - return new IsLikeCaseInsensitive<>(StringUtilities.safelyUpperCase(value)); + return new IsLikeCaseInsensitive<>(value); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java index 8731d5b64..4486d1df7 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java @@ -38,7 +38,7 @@ public static IsNotInCaseInsensitive empty() { } protected IsNotInCaseInsensitive(Collection values) { - super(values); + super(values.stream().map(StringUtilities::upperCaseIfPossible).toList()); } @Override @@ -57,19 +57,6 @@ public IsNotInCaseInsensitive filter(Predicate predicate) { return filterSupport(predicate, IsNotInCaseInsensitive::new, this, IsNotInCaseInsensitive::empty); } - /** - * If renderable, apply the mapping to the value and return a new condition with the new value. Else return a - * condition that will not render (this). - * - *

This function DOES NOT automatically transform values to uppercase, so it potentially creates a - * case-sensitive query. For String conditions you can use {@link StringUtilities#mapToUpperCase(Function)} - * to add an uppercase transform after your mapping function. - * - * @param mapper a mapping function to apply to the value, if renderable - * @param type of the new condition - * @return a new condition with the result of applying the mapper to the value of this condition, - * if renderable, otherwise a condition that will not render. - */ @Override public IsNotInCaseInsensitive map(Function mapper) { return mapSupport(mapper, IsNotInCaseInsensitive::new, IsNotInCaseInsensitive::empty); @@ -80,7 +67,6 @@ public static IsNotInCaseInsensitive of(String... values) { } public static IsNotInCaseInsensitive of(Collection values) { - // Keep the null safe upper case utility for backwards compatibility in case someone passes in a null - return new IsNotInCaseInsensitive<>(values.stream().map(StringUtilities::safelyUpperCase).toList()); + return new IsNotInCaseInsensitive<>(values); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java index 438e1c5ed..992a231eb 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java @@ -39,7 +39,7 @@ public static IsNotInCaseInsensitiveWhenPresent empty() { } protected IsNotInCaseInsensitiveWhenPresent(Collection values) { - super(values); + super(values.stream().filter(Objects::nonNull).map(StringUtilities::upperCaseIfPossible).toList()); } @Override @@ -53,19 +53,6 @@ public IsNotInCaseInsensitiveWhenPresent filter(Predicate predicat this, IsNotInCaseInsensitiveWhenPresent::empty); } - /** - * If renderable, apply the mapping to the value and return a new condition with the new value. Else return a - * condition that will not render (this). - * - *

This function DOES NOT automatically transform values to uppercase, so it potentially creates a - * case-sensitive query. For String conditions you can use {@link StringUtilities#mapToUpperCase(Function)} - * to add an uppercase transform after your mapping function. - * - * @param mapper a mapping function to apply to the value, if renderable - * @param type of the new condition - * @return a new condition with the result of applying the mapper to the value of this condition, - * if renderable, otherwise a condition that will not render. - */ @Override public IsNotInCaseInsensitiveWhenPresent map(Function mapper) { return mapSupport(mapper, IsNotInCaseInsensitiveWhenPresent::new, IsNotInCaseInsensitiveWhenPresent::empty); @@ -76,7 +63,6 @@ public static IsNotInCaseInsensitiveWhenPresent of(@Nullable String... v } public static IsNotInCaseInsensitiveWhenPresent of(Collection<@Nullable String> values) { - return new IsNotInCaseInsensitiveWhenPresent<>( - values.stream().filter(Objects::nonNull).map(String::toUpperCase).toList()); + return new IsNotInCaseInsensitiveWhenPresent<>(values); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitive.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitive.java index 8eb65d772..715a19a8d 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitive.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitive.java @@ -44,7 +44,7 @@ public static IsNotLikeCaseInsensitive empty() { } protected IsNotLikeCaseInsensitive(T value) { - super(value); + super(StringUtilities.upperCaseIfPossible(value)); } @Override @@ -57,26 +57,12 @@ public IsNotLikeCaseInsensitive filter(Predicate predicate) { return filterSupport(predicate, IsNotLikeCaseInsensitive::empty, this); } - /** - * If renderable, apply the mapping to the value and return a new condition with the new value. Else return a - * condition that will not render (this). - * - *

This function DOES NOT automatically transform values to uppercase, so it potentially creates a - * case-sensitive query. For String conditions you can use {@link StringUtilities#mapToUpperCase(Function)} - * to add an uppercase transform after your mapping function. - * - * @param mapper a mapping function to apply to the value, if renderable - * @param type of the new condition - * @return a new condition with the result of applying the mapper to the value of this condition, - * if renderable, otherwise a condition that will not render. - */ @Override public IsNotLikeCaseInsensitive map(Function mapper) { return mapSupport(mapper, IsNotLikeCaseInsensitive::new, IsNotLikeCaseInsensitive::empty); } public static IsNotLikeCaseInsensitive of(String value) { - // Keep the null safe upper case utility for backwards compatibility in case someone passes in a null - return new IsNotLikeCaseInsensitive<>(StringUtilities.safelyUpperCase(value)); + return new IsNotLikeCaseInsensitive<>(value); } } diff --git a/src/test/java/org/mybatis/dynamic/sql/util/StringUtilitiesTest.java b/src/test/java/org/mybatis/dynamic/sql/util/StringUtilitiesTest.java index 1c54cafc9..e1d8c137c 100644 --- a/src/test/java/org/mybatis/dynamic/sql/util/StringUtilitiesTest.java +++ b/src/test/java/org/mybatis/dynamic/sql/util/StringUtilitiesTest.java @@ -38,4 +38,16 @@ void testNumeric() { String input = "USER%NAME%3"; assertThat(StringUtilities.toCamelCase(input)).isEqualTo("userName3"); } + + @Test + void testUpperCaseInteger() { + Integer i = StringUtilities.upperCaseIfPossible(3); + assertThat(i).isEqualTo(3); + } + + @Test + void testUpperCaseString() { + String i = StringUtilities.upperCaseIfPossible("fred"); + assertThat(i).isEqualTo("FRED"); + } } diff --git a/src/test/java/org/mybatis/dynamic/sql/where/condition/FilterAndMapTest.java b/src/test/java/org/mybatis/dynamic/sql/where/condition/FilterAndMapTest.java index 7d4e4505e..bd2e56fbb 100644 --- a/src/test/java/org/mybatis/dynamic/sql/where/condition/FilterAndMapTest.java +++ b/src/test/java/org/mybatis/dynamic/sql/where/condition/FilterAndMapTest.java @@ -24,7 +24,6 @@ import org.junit.jupiter.api.Test; import org.mybatis.dynamic.sql.SqlBuilder; -import org.mybatis.dynamic.sql.util.StringUtilities; class FilterAndMapTest { @Test @@ -543,31 +542,17 @@ void testMappingAnEmptyListCondition() { assertThat(filtered).isSameAs(mapped); } - @Test - void testIsInCaseInsensitiveWhenPresentMap() { - var cond = SqlBuilder.isInCaseInsensitiveWhenPresent("Fred", "Wilma"); - var mapped = cond.map(s -> s + " Flintstone"); - assertThat(mapped.values().toList()).containsExactly("FRED Flintstone", "WILMA Flintstone"); - } - @Test void testIsInCaseInsensitiveWhenPresentMapCaseInsensitive() { var cond = SqlBuilder.isInCaseInsensitiveWhenPresent("Fred", "Wilma"); - var mapped = cond.map(StringUtilities.mapToUpperCase(s -> s + " Flintstone")); - assertThat(mapped.values().toList()).containsExactly("FRED FLINTSTONE", "WILMA FLINTSTONE"); - } - - @Test - void testIsNotInCaseInsensitiveWhenPresentMap() { - var cond = SqlBuilder.isNotInCaseInsensitiveWhenPresent("Fred", "Wilma"); var mapped = cond.map(s -> s + " Flintstone"); - assertThat(mapped.values().toList()).containsExactly("FRED Flintstone", "WILMA Flintstone"); + assertThat(mapped.values().toList()).containsExactly("FRED FLINTSTONE", "WILMA FLINTSTONE"); } @Test void testIsNotInCaseInsensitiveWhenPresentMapCaseInsensitive() { var cond = SqlBuilder.isNotInCaseInsensitiveWhenPresent("Fred", "Wilma"); - var mapped = cond.map(StringUtilities.mapToUpperCase(s -> s + " Flintstone")); + var mapped = cond.map(s -> s + " Flintstone"); assertThat(mapped.values().toList()).containsExactly("FRED FLINTSTONE", "WILMA FLINTSTONE"); } } From 1fdb1c2ad27657f7024fee6b7e409e942c02bdbd Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Sat, 15 Mar 2025 09:40:19 -0400 Subject: [PATCH 220/289] Prefer toList --- .../dynamic/sql/where/condition/IsInCaseInsensitive.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java index a3777188a..bc8bfbdf9 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java @@ -20,7 +20,6 @@ import java.util.Collections; import java.util.function.Function; import java.util.function.Predicate; -import java.util.stream.Collectors; import org.mybatis.dynamic.sql.AbstractListValueCondition; import org.mybatis.dynamic.sql.render.RenderingContext; @@ -39,7 +38,7 @@ public static IsInCaseInsensitive empty() { } protected IsInCaseInsensitive(Collection values) { - super(values.stream().map(StringUtilities::upperCaseIfPossible).collect(Collectors.toList())); + super(values.stream().map(StringUtilities::upperCaseIfPossible).toList()); } @Override From c8480cc97155d2aef10634b0035ffe8bb96a41f2 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Sat, 15 Mar 2025 11:02:59 -0400 Subject: [PATCH 221/289] Coverage --- .../org/mybatis/dynamic/sql/util/StringUtilities.java | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/util/StringUtilities.java b/src/main/java/org/mybatis/dynamic/sql/util/StringUtilities.java index 532391856..aad161f0c 100644 --- a/src/main/java/org/mybatis/dynamic/sql/util/StringUtilities.java +++ b/src/main/java/org/mybatis/dynamic/sql/util/StringUtilities.java @@ -15,8 +15,6 @@ */ package org.mybatis.dynamic.sql.util; -import org.jspecify.annotations.Nullable; - public interface StringUtilities { static String spaceAfter(String in) { @@ -27,10 +25,6 @@ static String spaceBefore(String in) { return " " + in; //$NON-NLS-1$ } - static @Nullable String safelyUpperCase(@Nullable String s) { - return s == null ? null : s.toUpperCase(); - } - static String toCamelCase(String inputString) { StringBuilder sb = new StringBuilder(); @@ -63,7 +57,7 @@ static String formatConstantForSQL(String in) { static T upperCaseIfPossible(T value) { if (value instanceof String) { @SuppressWarnings("unchecked") - T t = (T) safelyUpperCase((String) value); + T t = (T) ((String) value).toUpperCase(); return t; } From 43f8e8b75ed3243598d2abd6abb3ec9c8db7dab6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 18 Mar 2025 15:59:39 +0000 Subject: [PATCH 222/289] Update dependency ch.qos.logback:logback-classic to v1.5.18 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 03b9bc69f..637e0eff1 100644 --- a/pom.xml +++ b/pom.xml @@ -170,7 +170,7 @@ ch.qos.logback logback-classic - 1.5.17 + 1.5.18 test From e476b7b0df661c04fc972d43bd3e100c38f84923 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 19 Mar 2025 19:00:30 +0000 Subject: [PATCH 223/289] Update spring batch to v5.2.2 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 637e0eff1..8efe27229 100644 --- a/pom.xml +++ b/pom.xml @@ -61,7 +61,7 @@ 17 17 5.12.1 - 5.2.1 + 5.2.2 checkstyle-override.xml From 07668533d4665197ec4ae0f9e0b50e307593f935 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 19 Mar 2025 22:35:33 +0000 Subject: [PATCH 224/289] Update dependency org.springframework:spring-jdbc to v6.2.5 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 637e0eff1..372b41021 100644 --- a/pom.xml +++ b/pom.xml @@ -101,7 +101,7 @@ org.springframework spring-jdbc - 6.2.4 + 6.2.5 provided true From 05bf2d5176762d1d7bfc2f8eae0fbb9858b9c459 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 20 Mar 2025 09:56:44 +0000 Subject: [PATCH 225/289] Update kotlin monorepo to v2.1.20 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 575738922..cad1ea0b9 100644 --- a/pom.xml +++ b/pom.xml @@ -69,7 +69,7 @@ org.mybatis.dynamic.sql - 2.1.10 + 2.1.20 17 2.0 2.0 From 99becd9d915231cdbba7c8a3e1ddf6c3bdae2958 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 27 Mar 2025 08:26:56 +0000 Subject: [PATCH 226/289] Update dependency org.mariadb.jdbc:mariadb-java-client to v3.5.3 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index cad1ea0b9..f5b9b21c7 100644 --- a/pom.xml +++ b/pom.xml @@ -200,7 +200,7 @@ org.mariadb.jdbc mariadb-java-client - 3.5.2 + 3.5.3 test From 6380d6fce809f17328f45f53dc6b7a29c0869c09 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Wed, 2 Apr 2025 11:02:37 -0400 Subject: [PATCH 227/289] Another round of misc. code cleanup --- .../dynamic/sql/select/UnionQuery.java | 13 +- .../examples/complexquery/GroupingTest.java | 6 +- .../examples/emptywhere/EmptyWhereTest.java | 123 ++++++++---------- .../emptywhere/OrderDynamicSqlSupport.java | 10 +- .../emptywhere/PersonDynamicSqlSupport.java | 14 +- .../examples/spring/PersonTemplateTest.java | 2 +- .../examples/spring/SpringMapToRowTest.java | 2 +- .../springbatch/common/PersonProcessor.java | 2 +- .../mapper/PersonDynamicSqlSupport.java | 18 +-- .../sql/insert/InsertStatementTest.java | 56 ++------ .../dynamic/sql/insert/MapToRowTest.java | 10 +- .../sql/util/ColumnMappingVisitorTest.java | 4 +- .../mybatis3/joins/JoinMapperNewSyntaxTest.kt | 24 ++-- .../GeneratedAlwaysDynamicSqlSupport.kt | 2 +- .../sql/util/kotlin/model/ModelBuilderTest.kt | 5 +- 15 files changed, 107 insertions(+), 184 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/select/UnionQuery.java b/src/main/java/org/mybatis/dynamic/sql/select/UnionQuery.java index 9beb85b46..6806d4791 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/UnionQuery.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/UnionQuery.java @@ -17,20 +17,9 @@ import java.util.Objects; -public class UnionQuery { - private final String connector; - private final SelectModel selectModel; - +public record UnionQuery(String connector, SelectModel selectModel) { public UnionQuery(String connector, SelectModel selectModel) { this.connector = Objects.requireNonNull(connector); this.selectModel = Objects.requireNonNull(selectModel); } - - public String connector() { - return connector; - } - - public SelectModel selectModel() { - return selectModel; - } } diff --git a/src/test/java/examples/complexquery/GroupingTest.java b/src/test/java/examples/complexquery/GroupingTest.java index 1d3f631f6..b6552b3cb 100644 --- a/src/test/java/examples/complexquery/GroupingTest.java +++ b/src/test/java/examples/complexquery/GroupingTest.java @@ -33,9 +33,9 @@ class GroupingTest { private static class Foo extends SqlTable { - public SqlColumn columnA = column("A"); - public SqlColumn columnB = column("B"); - public SqlColumn columnC = column("C"); + public final SqlColumn columnA = column("A"); + public final SqlColumn columnB = column("B"); + public final SqlColumn columnC = column("C"); public Foo() { super("Foo"); diff --git a/src/test/java/examples/emptywhere/EmptyWhereTest.java b/src/test/java/examples/emptywhere/EmptyWhereTest.java index 4c02f4f66..f20a81a9a 100644 --- a/src/test/java/examples/emptywhere/EmptyWhereTest.java +++ b/src/test/java/examples/emptywhere/EmptyWhereTest.java @@ -20,9 +20,11 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mybatis.dynamic.sql.SqlBuilder.*; -import java.util.*; +import java.util.Optional; import java.util.stream.Stream; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; @@ -39,62 +41,63 @@ import org.mybatis.dynamic.sql.where.WhereDSL; import org.mybatis.dynamic.sql.where.render.WhereClauseProvider; +@NullMarked class EmptyWhereTest { + private static final String FIRST_NAME = "Fred"; + private static final String LAST_NAME = "Flintstone"; - static List baseVariations() { - String firstName = "Fred"; - String lastName = "Flintstone"; - - Variation v1 = new Variation(firstName, lastName, + static Stream whereVariations() { + Variation v1 = new Variation(FIRST_NAME, LAST_NAME, "where first_name = #{parameters.p1} or last_name = #{parameters.p2}"); - Variation v2 = new Variation(null, lastName, + Variation v2 = new Variation(null, LAST_NAME, "where last_name = #{parameters.p1}"); - Variation v3 = new Variation(firstName, null, + Variation v3 = new Variation(FIRST_NAME, null, "where first_name = #{parameters.p1}"); Variation v4 = new Variation(null, null, ""); - return List.of(v1, v2, v3, v4); - } - - static Stream whereVariations() { - return baseVariations().stream(); + return Stream.of(v1, v2, v3, v4); } static Stream joinWhereVariations() { - List baseVariations = baseVariations(); + Variation v1 = new Variation(FIRST_NAME, LAST_NAME, + "where person.first_name = #{parameters.p1} or person.last_name = #{parameters.p2}"); - baseVariations.get(0).whereClause = - "where person.first_name = #{parameters.p1} or person.last_name = #{parameters.p2}"; - baseVariations.get(1).whereClause = "where person.last_name = #{parameters.p1}"; - baseVariations.get(2).whereClause = "where person.first_name = #{parameters.p1}"; + Variation v2 = new Variation(null, LAST_NAME, + "where person.last_name = #{parameters.p1}"); - return baseVariations.stream(); + Variation v3 = new Variation(FIRST_NAME, null, + "where person.first_name = #{parameters.p1}"); + + Variation v4 = new Variation(null, null, ""); + + return Stream.of(v1, v2, v3, v4); } static Stream updateWhereVariations() { - List baseVariations = baseVariations(); + Variation v1 = new Variation(FIRST_NAME, LAST_NAME, + "where first_name = #{parameters.p2} or last_name = #{parameters.p3}"); - baseVariations.get(0).whereClause = - "where first_name = #{parameters.p2} or last_name = #{parameters.p3}"; - baseVariations.get(1).whereClause ="where last_name = #{parameters.p2}"; - baseVariations.get(2).whereClause = "where first_name = #{parameters.p2}"; + Variation v2 = new Variation(null, LAST_NAME, + "where last_name = #{parameters.p2}"); - return baseVariations.stream(); + Variation v3 = new Variation(FIRST_NAME, null, + "where first_name = #{parameters.p2}"); + + Variation v4 = new Variation(null, null, ""); + + return Stream.of(v1, v2, v3, v4); } @Test void testDeleteThreeConditions() { - String fName = "Fred"; - String lName = "Flintstone"; - DeleteDSL.DeleteWhereBuilder builder = deleteFrom(person) .where(id, isEqualTo(3)); - builder.and(firstName, isEqualTo(fName).filter(Objects::nonNull)); - builder.and(PersonDynamicSqlSupport.lastName, isEqualTo(lName).filter(Objects::nonNull)); + builder.and(firstName, isEqualTo(FIRST_NAME)); + builder.and(PersonDynamicSqlSupport.lastName, isEqualTo(LAST_NAME)); DeleteStatementProvider deleteStatement = builder.build().render(RenderingStrategies.MYBATIS3); @@ -112,8 +115,8 @@ void testDeleteVariations(Variation variation) { DeleteDSL.DeleteWhereBuilder builder = deleteFrom(person) .where(); - builder.and(firstName, isEqualTo(variation.firstName).filter(Objects::nonNull)); - builder.or(PersonDynamicSqlSupport.lastName, isEqualTo(variation.lastName).filter(Objects::nonNull)); + builder.and(firstName, isEqualToWhenPresent(variation.firstName)); + builder.or(PersonDynamicSqlSupport.lastName, isEqualToWhenPresent(variation.lastName)); builder.configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)); DeleteStatementProvider deleteStatement = builder.build().render(RenderingStrategies.MYBATIS3); @@ -125,15 +128,12 @@ void testDeleteVariations(Variation variation) { @Test void testSelectThreeConditions() { - String fName = "Fred"; - String lName = "Flintstone"; - QueryExpressionDSL.QueryExpressionWhereBuilder builder = select(id, firstName, PersonDynamicSqlSupport.lastName) .from(person) .where(id, isEqualTo(3)); - builder.and(firstName, isEqualTo(fName).filter(Objects::nonNull)); - builder.and(PersonDynamicSqlSupport.lastName, isEqualTo(lName).filter(Objects::nonNull)); + builder.and(firstName, isEqualTo(FIRST_NAME)); + builder.and(PersonDynamicSqlSupport.lastName, isEqualTo(LAST_NAME)); SelectStatementProvider selectStatement = builder.build().render(RenderingStrategies.MYBATIS3); @@ -153,8 +153,8 @@ void testSelectVariations(Variation variation) { .from(person) .where(); - builder.and(firstName, isEqualTo(variation.firstName).filter(Objects::nonNull)); - builder.or(PersonDynamicSqlSupport.lastName, isEqualTo(variation.lastName).filter(Objects::nonNull)); + builder.and(firstName, isEqualToWhenPresent(variation.firstName)); + builder.or(PersonDynamicSqlSupport.lastName, isEqualToWhenPresent(variation.lastName)); builder.configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)); SelectStatementProvider selectStatement = builder.build().render(RenderingStrategies.MYBATIS3); @@ -166,15 +166,12 @@ void testSelectVariations(Variation variation) { @Test void testJoinThreeConditions() { - String fName = "Fred"; - String lName = "Flintstone"; - QueryExpressionDSL.QueryExpressionWhereBuilder builder = select(id, firstName, PersonDynamicSqlSupport.lastName, orderDate) .from(person).join(order).on(person.id, isEqualTo(order.personId)) .where(id, isEqualTo(3)); - builder.and(firstName, isEqualTo(fName).filter(Objects::nonNull)); - builder.and(PersonDynamicSqlSupport.lastName, isEqualTo(lName).filter(Objects::nonNull)); + builder.and(firstName, isEqualTo(FIRST_NAME)); + builder.and(PersonDynamicSqlSupport.lastName, isEqualTo(LAST_NAME)); SelectStatementProvider selectStatement = builder.build().render(RenderingStrategies.MYBATIS3); @@ -195,8 +192,8 @@ void testJoinVariations(Variation variation) { .from(person).join(order).on(person.id, isEqualTo(order.personId)) .where(); - builder.and(firstName, isEqualTo(variation.firstName).filter(Objects::nonNull)); - builder.or(PersonDynamicSqlSupport.lastName, isEqualTo(variation.lastName).filter(Objects::nonNull)); + builder.and(firstName, isEqualToWhenPresent(variation.firstName)); + builder.or(PersonDynamicSqlSupport.lastName, isEqualToWhenPresent(variation.lastName)); builder.configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)); SelectStatementProvider selectStatement = builder.build().render(RenderingStrategies.MYBATIS3); @@ -211,15 +208,12 @@ void testJoinVariations(Variation variation) { @Test void testUpdateThreeConditions() { - String fName = "Fred"; - String lName = "Flintstone"; - UpdateDSL.UpdateWhereBuilder builder = update(person) .set(id).equalTo(3) .where(id, isEqualTo(3)); - builder.and(firstName, isEqualTo(fName).filter(Objects::nonNull)); - builder.and(PersonDynamicSqlSupport.lastName, isEqualTo(lName).filter(Objects::nonNull)); + builder.and(firstName, isEqualTo(FIRST_NAME)); + builder.and(PersonDynamicSqlSupport.lastName, isEqualTo(LAST_NAME)); UpdateStatementProvider updateStatement = builder.build().render(RenderingStrategies.MYBATIS3); @@ -239,8 +233,8 @@ void testUpdateVariations(Variation variation) { .set(id).equalTo(3) .where(); - builder.and(firstName, isEqualTo(variation.firstName).filter(Objects::nonNull)); - builder.or(PersonDynamicSqlSupport.lastName, isEqualTo(variation.lastName).filter(Objects::nonNull)); + builder.and(firstName, isEqualToWhenPresent(variation.firstName)); + builder.or(PersonDynamicSqlSupport.lastName, isEqualToWhenPresent(variation.lastName)); builder.configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)); UpdateStatementProvider updateStatement = builder.build().render(RenderingStrategies.MYBATIS3); @@ -254,13 +248,10 @@ void testUpdateVariations(Variation variation) { @Test void testWhereThreeConditions() { - String fName = "Fred"; - String lName = "Flintstone"; - WhereDSL.StandaloneWhereFinisher builder = where(id, isEqualTo(3)); - builder.and(firstName, isEqualTo(fName).filter(Objects::nonNull)); - builder.and(PersonDynamicSqlSupport.lastName, isEqualTo(lName).filter(Objects::nonNull)); + builder.and(firstName, isEqualTo(FIRST_NAME)); + builder.and(PersonDynamicSqlSupport.lastName, isEqualTo(LAST_NAME)); Optional whereClause = builder.build().render(RenderingStrategies.MYBATIS3); @@ -278,8 +269,8 @@ void testWhereThreeConditions() { void testWhereVariations(Variation variation) { WhereDSL.StandaloneWhereFinisher builder = where(); - builder.and(firstName, isEqualTo(variation.firstName).filter(Objects::nonNull)); - builder.or(PersonDynamicSqlSupport.lastName, isEqualTo(variation.lastName).filter(Objects::nonNull)); + builder.and(firstName, isEqualToWhenPresent(variation.firstName)); + builder.or(PersonDynamicSqlSupport.lastName, isEqualToWhenPresent(variation.lastName)); builder.configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)); Optional whereClause = builder.build().render(RenderingStrategies.MYBATIS3); @@ -293,15 +284,5 @@ void testWhereVariations(Variation variation) { } } - private static class Variation { - String firstName; - String lastName; - String whereClause; - - public Variation(String firstName, String lastName, String whereClause) { - this.firstName = firstName; - this.lastName = lastName; - this.whereClause = whereClause; - } - } + private record Variation (@Nullable String firstName, @Nullable String lastName, String whereClause) {} } diff --git a/src/test/java/examples/emptywhere/OrderDynamicSqlSupport.java b/src/test/java/examples/emptywhere/OrderDynamicSqlSupport.java index 4664e2b21..41cab1031 100644 --- a/src/test/java/examples/emptywhere/OrderDynamicSqlSupport.java +++ b/src/test/java/examples/emptywhere/OrderDynamicSqlSupport.java @@ -22,13 +22,13 @@ public class OrderDynamicSqlSupport { - public static Order order = new Order(); - public static SqlColumn personId = order.personId; - public static SqlColumn orderDate = order.orderDate; + public static final Order order = new Order(); + public static final SqlColumn personId = order.personId; + public static final SqlColumn orderDate = order.orderDate; public static class Order extends SqlTable { - public SqlColumn personId = column("person_id"); - public SqlColumn orderDate = column("order_date"); + public final SqlColumn personId = column("person_id"); + public final SqlColumn orderDate = column("order_date"); public Order() { super("order"); diff --git a/src/test/java/examples/emptywhere/PersonDynamicSqlSupport.java b/src/test/java/examples/emptywhere/PersonDynamicSqlSupport.java index 0a8d791fe..9a7d83a81 100644 --- a/src/test/java/examples/emptywhere/PersonDynamicSqlSupport.java +++ b/src/test/java/examples/emptywhere/PersonDynamicSqlSupport.java @@ -20,15 +20,15 @@ public class PersonDynamicSqlSupport { - public static Person person = new Person(); - public static SqlColumn id = person.id; - public static SqlColumn firstName = person.firstName; - public static SqlColumn lastName = person.lastName; + public static final Person person = new Person(); + public static final SqlColumn id = person.id; + public static final SqlColumn firstName = person.firstName; + public static final SqlColumn lastName = person.lastName; public static class Person extends SqlTable { - public SqlColumn id = column("id"); - public SqlColumn firstName = column("first_name"); - public SqlColumn lastName = column("last_name"); + public final SqlColumn id = column("id"); + public final SqlColumn firstName = column("first_name"); + public final SqlColumn lastName = column("last_name"); public Person() { super("person"); diff --git a/src/test/java/examples/spring/PersonTemplateTest.java b/src/test/java/examples/spring/PersonTemplateTest.java index 8376dcef7..1f5f8548a 100644 --- a/src/test/java/examples/spring/PersonTemplateTest.java +++ b/src/test/java/examples/spring/PersonTemplateTest.java @@ -779,7 +779,7 @@ void testJoinCountWithSubCriteria() { }; - static RowMapper personRowMapper = + static final RowMapper personRowMapper = (rs, i) -> { PersonRecord row = new PersonRecord(); row.setId(rs.getInt(1)); diff --git a/src/test/java/examples/spring/SpringMapToRowTest.java b/src/test/java/examples/spring/SpringMapToRowTest.java index 7c40f03d8..cf9b52258 100644 --- a/src/test/java/examples/spring/SpringMapToRowTest.java +++ b/src/test/java/examples/spring/SpringMapToRowTest.java @@ -122,7 +122,7 @@ void testInsertBatch() { assertThat(records).hasSize(3); } - static RowMapper rowMapper = + static final RowMapper rowMapper = (rs, i) -> { CompoundKeyRow answer = new CompoundKeyRow(); answer.setId1(rs.getInt("ID1")); diff --git a/src/test/java/examples/springbatch/common/PersonProcessor.java b/src/test/java/examples/springbatch/common/PersonProcessor.java index ad7492f4e..2a4939cdb 100644 --- a/src/test/java/examples/springbatch/common/PersonProcessor.java +++ b/src/test/java/examples/springbatch/common/PersonProcessor.java @@ -29,7 +29,7 @@ public class PersonProcessor implements ItemProcessor id = person.id; - public static SqlColumn firstName = person.firstName; - public static SqlColumn lastName = person.lastName; - public static SqlColumn forPagingTest = person.forPagingTest; + public static final Person person = new Person(); + public static final SqlColumn id = person.id; + public static final SqlColumn firstName = person.firstName; + public static final SqlColumn lastName = person.lastName; + public static final SqlColumn forPagingTest = person.forPagingTest; public static class Person extends SqlTable { - public SqlColumn id = column("id", JDBCType.INTEGER); - public SqlColumn firstName = column("first_name", JDBCType.VARCHAR); - public SqlColumn lastName = column("last_name", JDBCType.VARCHAR); - public SqlColumn forPagingTest = column("for_paging_test", JDBCType.BOOLEAN); + public final SqlColumn id = column("id", JDBCType.INTEGER); + public final SqlColumn firstName = column("first_name", JDBCType.VARCHAR); + public final SqlColumn lastName = column("last_name", JDBCType.VARCHAR); + public final SqlColumn forPagingTest = column("for_paging_test", JDBCType.BOOLEAN); public Person() { super("person"); diff --git a/src/test/java/org/mybatis/dynamic/sql/insert/InsertStatementTest.java b/src/test/java/org/mybatis/dynamic/sql/insert/InsertStatementTest.java index e991bef02..29249317b 100644 --- a/src/test/java/org/mybatis/dynamic/sql/insert/InsertStatementTest.java +++ b/src/test/java/org/mybatis/dynamic/sql/insert/InsertStatementTest.java @@ -20,6 +20,7 @@ import java.sql.JDBCType; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.mybatis.dynamic.sql.SqlColumn; import org.mybatis.dynamic.sql.SqlTable; @@ -37,9 +38,7 @@ class InsertStatementTest { @Test void testFullInsertStatementBuilder() { - TestRecord row = new TestRecord(); - row.setLastName("jones"); - row.setOccupation("dino driver"); + TestRecord row = new TestRecord(null, null, "jones", "dino driver"); InsertStatementProvider insertStatement = insert(row) .into(foo) @@ -97,16 +96,14 @@ void testInsertStatementBuilderWithConstants() { @Test void testSelectiveInsertStatementBuilder() { - TestRecord row = new TestRecord(); - row.setLastName("jones"); - row.setOccupation("dino driver"); + TestRecord row = new TestRecord(null, null, "jones", "dino driver"); InsertStatementProvider insertStatement = insert(row) .into(foo) - .map(id).toPropertyWhenPresent("id", row::getId) - .map(firstName).toPropertyWhenPresent("firstName", row::getFirstName) - .map(lastName).toPropertyWhenPresent("lastName", row::getLastName) - .map(occupation).toPropertyWhenPresent("occupation", row::getOccupation) + .map(id).toPropertyWhenPresent("id", row::id) + .map(firstName).toPropertyWhenPresent("firstName", row::firstName) + .map(lastName).toPropertyWhenPresent("lastName", row::lastName) + .map(occupation).toPropertyWhenPresent("occupation", row::occupation) .build() .render(RenderingStrategies.MYBATIS3); @@ -115,42 +112,9 @@ void testSelectiveInsertStatementBuilder() { assertThat(insertStatement.getInsertStatement()).isEqualTo(expected); } - static class TestRecord { - private Integer id; - private String firstName; - private String lastName; - private String occupation; - - Integer getId() { - return id; - } - - void setId(Integer id) { - this.id = id; - } - - String getFirstName() { - return firstName; - } - - void setFirstName(String firstName) { - this.firstName = firstName; - } - - String getLastName() { - return lastName; - } - - void setLastName(String lastName) { - this.lastName = lastName; - } - - String getOccupation() { - return occupation; - } - - void setOccupation(String occupation) { - this.occupation = occupation; + record TestRecord (@Nullable Integer id, @Nullable String firstName, @Nullable String lastName, @Nullable String occupation) { + TestRecord() { + this(null, null, null, null); } } } diff --git a/src/test/java/org/mybatis/dynamic/sql/insert/MapToRowTest.java b/src/test/java/org/mybatis/dynamic/sql/insert/MapToRowTest.java index eb0ff2657..d17811fe1 100644 --- a/src/test/java/org/mybatis/dynamic/sql/insert/MapToRowTest.java +++ b/src/test/java/org/mybatis/dynamic/sql/insert/MapToRowTest.java @@ -166,13 +166,5 @@ void testBatchInsertRowMappingWithSpring() { assertThat(batchInsert.getInsertStatementSQL()).isEqualTo(expected); } - static class Record { - public Record(Integer id1, Integer id2) { - this.id1 = id1; - this.id2 = id2; - } - - public Integer id1; - public Integer id2; - } + record Record(Integer id1, Integer id2) { } } diff --git a/src/test/java/org/mybatis/dynamic/sql/util/ColumnMappingVisitorTest.java b/src/test/java/org/mybatis/dynamic/sql/util/ColumnMappingVisitorTest.java index f75be43f6..2f17910b2 100644 --- a/src/test/java/org/mybatis/dynamic/sql/util/ColumnMappingVisitorTest.java +++ b/src/test/java/org/mybatis/dynamic/sql/util/ColumnMappingVisitorTest.java @@ -205,8 +205,8 @@ void testThatUpdateVisitorErrorsForRowMapping() { } private static class TestTable extends SqlTable { - public SqlColumn id; - public SqlColumn description; + public final SqlColumn id; + public final SqlColumn description; public TestTable() { super("Test"); diff --git a/src/test/kotlin/examples/kotlin/mybatis3/joins/JoinMapperNewSyntaxTest.kt b/src/test/kotlin/examples/kotlin/mybatis3/joins/JoinMapperNewSyntaxTest.kt index 2d74a5784..1ad6d71c2 100644 --- a/src/test/kotlin/examples/kotlin/mybatis3/joins/JoinMapperNewSyntaxTest.kt +++ b/src/test/kotlin/examples/kotlin/mybatis3/joins/JoinMapperNewSyntaxTest.kt @@ -477,14 +477,12 @@ class JoinMapperNewSyntaxTest { join(orderLine, "ol") on { orderMaster.orderId isEqualTo orderLine.orderId } - leftJoin( - { - select(itemMaster.allColumns()) { - from(itemMaster) - } - + "im" + leftJoin { + select(itemMaster.allColumns()) { + from(itemMaster) } - ) on { + +"im" + } on { orderLine.itemId isEqualTo "im"(itemMaster.itemId) } orderBy(orderLine.orderId, itemMaster.itemId) @@ -614,14 +612,12 @@ class JoinMapperNewSyntaxTest { join(orderLine, "ol") on { orderMaster.orderId isEqualTo orderLine.orderId } - rightJoin( - { - select(itemMaster.allColumns()) { - from(itemMaster) - } - + "im" + rightJoin { + select(itemMaster.allColumns()) { + from(itemMaster) } - ) on { + +"im" + } on { orderLine.itemId isEqualTo "im"(itemMaster.itemId) } orderBy(orderLine.orderId, itemMaster.itemId) diff --git a/src/test/kotlin/examples/kotlin/spring/canonical/GeneratedAlwaysDynamicSqlSupport.kt b/src/test/kotlin/examples/kotlin/spring/canonical/GeneratedAlwaysDynamicSqlSupport.kt index db4067c5a..0c388bdb6 100644 --- a/src/test/kotlin/examples/kotlin/spring/canonical/GeneratedAlwaysDynamicSqlSupport.kt +++ b/src/test/kotlin/examples/kotlin/spring/canonical/GeneratedAlwaysDynamicSqlSupport.kt @@ -26,7 +26,7 @@ object GeneratedAlwaysDynamicSqlSupport { val fullName = generatedAlways.fullName class GeneratedAlways : SqlTable("GeneratedAlways") { - val id = column("id") + val id = column(name = "id") val firstName = column(name = "first_name") val lastName = column(name = "last_name") val fullName = column(name = "full_name") diff --git a/src/test/kotlin/org/mybatis/dynamic/sql/util/kotlin/model/ModelBuilderTest.kt b/src/test/kotlin/org/mybatis/dynamic/sql/util/kotlin/model/ModelBuilderTest.kt index d4394a500..a4a4b9e3f 100644 --- a/src/test/kotlin/org/mybatis/dynamic/sql/util/kotlin/model/ModelBuilderTest.kt +++ b/src/test/kotlin/org/mybatis/dynamic/sql/util/kotlin/model/ModelBuilderTest.kt @@ -19,13 +19,14 @@ import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test import org.mybatis.dynamic.sql.SqlTable import org.mybatis.dynamic.sql.render.RenderingStrategies +import org.mybatis.dynamic.sql.util.kotlin.elements.column class ModelBuilderTest { class Table : SqlTable("Table") val table = Table() - val id = table.column("id") - val description = table.column("description") + val id = table.column(name = "id") + val description = table.column(name = "description") @Test fun testSelectBuilder() { From c0d769c5b5e34843a47c581a86fcc1ff464279fd Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Thu, 3 Apr 2025 11:32:22 -0400 Subject: [PATCH 228/289] Checkstyle --- src/test/java/examples/animal/data/AnimalDataTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/examples/animal/data/AnimalDataTest.java b/src/test/java/examples/animal/data/AnimalDataTest.java index a883b4bd2..90c247116 100644 --- a/src/test/java/examples/animal/data/AnimalDataTest.java +++ b/src/test/java/examples/animal/data/AnimalDataTest.java @@ -792,7 +792,7 @@ void testNotInCaseSensitiveConditionWithNull() { SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(animalName, isNotInCaseInsensitive((String)null)) + .where(animalName, isNotInCaseInsensitive((String) null)) .build() .render(RenderingStrategies.MYBATIS3); From 65d0c77b47ddc8051bcbbe4ca47169fa524095a1 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Thu, 3 Apr 2025 11:45:30 -0400 Subject: [PATCH 229/289] Convert to records in the Spring example --- .../java/examples/spring/AddressRecord.java | 39 +-- src/test/java/examples/spring/LastName.java | 40 +-- .../spring/LastNameParameterConverter.java | 6 +- .../java/examples/spring/PersonRecord.java | 73 +--- .../examples/spring/PersonTemplateTest.java | 317 +++++++----------- .../examples/spring/PersonWithAddress.java | 67 +--- .../spring/YesNoParameterConverter.java | 2 - .../java/examples/spring/package-info.java | 19 ++ 8 files changed, 164 insertions(+), 399 deletions(-) create mode 100644 src/test/java/examples/spring/package-info.java diff --git a/src/test/java/examples/spring/AddressRecord.java b/src/test/java/examples/spring/AddressRecord.java index a8f56e426..3987285ab 100644 --- a/src/test/java/examples/spring/AddressRecord.java +++ b/src/test/java/examples/spring/AddressRecord.java @@ -15,41 +15,4 @@ */ package examples.spring; -public class AddressRecord { - private Integer id; - private String streetAddress; - private String city; - private String state; - - public Integer getId() { - return id; - } - - public void setId(Integer id) { - this.id = id; - } - - public String getStreetAddress() { - return streetAddress; - } - - public void setStreetAddress(String streetAddress) { - this.streetAddress = streetAddress; - } - - public String getCity() { - return city; - } - - public void setCity(String city) { - this.city = city; - } - - public String getState() { - return state; - } - - public void setState(String state) { - this.state = state; - } -} +public record AddressRecord (Integer id, String streetAddress, String city, String state) { } diff --git a/src/test/java/examples/spring/LastName.java b/src/test/java/examples/spring/LastName.java index 2bda4c7cc..e6e9d93dd 100644 --- a/src/test/java/examples/spring/LastName.java +++ b/src/test/java/examples/spring/LastName.java @@ -15,42 +15,6 @@ */ package examples.spring; -public class LastName { - private String name; +import org.jspecify.annotations.Nullable; - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public static LastName of(String name) { - LastName lastName = new LastName(); - lastName.setName(name); - return lastName; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((name == null) ? 0 : name.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - LastName other = (LastName) obj; - if (name == null) { - return other.name == null; - } else return name.equals(other.name); - } -} +public record LastName(@Nullable String name) { } diff --git a/src/test/java/examples/spring/LastNameParameterConverter.java b/src/test/java/examples/spring/LastNameParameterConverter.java index e8d57d4cd..413aea7cb 100644 --- a/src/test/java/examples/spring/LastNameParameterConverter.java +++ b/src/test/java/examples/spring/LastNameParameterConverter.java @@ -15,20 +15,18 @@ */ package examples.spring; -import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.ParameterTypeConverter; import org.springframework.core.convert.converter.Converter; -@NullMarked public class LastNameParameterConverter implements ParameterTypeConverter, Converter { @Override public @Nullable String convert(LastName source) { - if ("Slate".equals(source.getName())) { + if ("Slate".equals(source.name())) { return null; } else { - return source.getName(); + return source.name(); } } } diff --git a/src/test/java/examples/spring/PersonRecord.java b/src/test/java/examples/spring/PersonRecord.java index 138f853d1..73417e5c6 100644 --- a/src/test/java/examples/spring/PersonRecord.java +++ b/src/test/java/examples/spring/PersonRecord.java @@ -15,78 +15,23 @@ */ package examples.spring; -import java.util.Date; - -public class PersonRecord { - private Integer id; - private String firstName; - private LastName lastName; - private Date birthDate; - private Boolean employed; - private String occupation; - private Integer addressId; - - public Integer getId() { - return id; - } - - public void setId(Integer id) { - this.id = id; - } - - public String getFirstName() { - return firstName; - } - - public void setFirstName(String firstName) { - this.firstName = firstName; - } - - public LastName getLastName() { - return lastName; - } - - public String getLastNameAsString() { - return lastName == null ? null : lastName.getName(); - } +import org.jspecify.annotations.Nullable; - public void setLastName(LastName lastName) { - this.lastName = lastName; - } - - public Date getBirthDate() { - return birthDate; - } - - public void setBirthDate(Date birthDate) { - this.birthDate = birthDate; - } - - public String getOccupation() { - return occupation; - } +import java.util.Date; - public void setOccupation(String occupation) { - this.occupation = occupation; - } +public record PersonRecord (Integer id, @Nullable String firstName, @Nullable LastName lastName, + @Nullable Date birthDate, @Nullable Boolean employed, + @Nullable String occupation, @Nullable Integer addressId) { - public Boolean getEmployed() { - return employed; + public @Nullable String getLastNameAsString() { + return lastName == null ? null : lastName.name(); } public String getEmployedAsString() { return employed == null ? "No" : employed ? "Yes" : "No"; } - public void setEmployed(Boolean employed) { - this.employed = employed; - } - - public Integer getAddressId() { - return addressId; - } - - public void setAddressId(Integer addressId) { - this.addressId = addressId; + public PersonRecord withOccupation(String occupation) { + return new PersonRecord(id, firstName, lastName, birthDate, employed, occupation, addressId); } } diff --git a/src/test/java/examples/spring/PersonTemplateTest.java b/src/test/java/examples/spring/PersonTemplateTest.java index 1f5f8548a..b92c03a50 100644 --- a/src/test/java/examples/spring/PersonTemplateTest.java +++ b/src/test/java/examples/spring/PersonTemplateTest.java @@ -20,7 +20,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mybatis.dynamic.sql.SqlBuilder.*; -import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Optional; @@ -38,7 +37,7 @@ import org.mybatis.dynamic.sql.util.Buildable; import org.mybatis.dynamic.sql.util.spring.NamedParameterJdbcTemplateExtensions; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.jdbc.core.BeanPropertyRowMapper; +import org.springframework.jdbc.core.DataClassRowMapper; import org.springframework.jdbc.core.RowMapper; import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; import org.springframework.transaction.annotation.Transactional; @@ -70,8 +69,8 @@ void testSelectAll() { List rows = template.selectList(selectStatement, personRowMapper); assertThat(rows).hasSize(6); - assertThat(rows.get(0).getId()).isEqualTo(1); - assertThat(rows.get(5).getId()).isEqualTo(6); + assertThat(rows.get(0).id()).isEqualTo(1); + assertThat(rows.get(5).id()).isEqualTo(6); } @@ -84,8 +83,8 @@ void testSelectAllOrdered() { List rows = template.selectList(selectStatement, personRowMapper); assertThat(rows).hasSize(6); - assertThat(rows.get(0).getId()).isEqualTo(5); - assertThat(rows.get(5).getId()).isEqualTo(1); + assertThat(rows.get(0).id()).isEqualTo(5); + assertThat(rows.get(5).id()).isEqualTo(1); } @@ -151,36 +150,36 @@ void testSelectWithTypeHandler() { List rows = template.selectList(selectStatement, personRowMapper); assertThat(rows).hasSize(2); - assertThat(rows.get(0).getId()).isEqualTo(3); - assertThat(rows.get(1).getId()).isEqualTo(6); + assertThat(rows.get(0).id()).isEqualTo(3); + assertThat(rows.get(1).id()).isEqualTo(6); } @Test void testSelectBetweenWithTypeHandler() { Buildable selectStatement = select(id, firstName, lastName, birthDate, employed, occupation, addressId) .from(person) - .where(lastName, isBetween(LastName.of("Adams")).and(LastName.of("Jones"))) + .where(lastName, isBetween(new LastName("Adams")).and(new LastName("Jones"))) .orderBy(id); List rows = template.selectList(selectStatement, personRowMapper); assertThat(rows).hasSize(3); - assertThat(rows.get(0).getId()).isEqualTo(1); - assertThat(rows.get(1).getId()).isEqualTo(2); + assertThat(rows.get(0).id()).isEqualTo(1); + assertThat(rows.get(1).id()).isEqualTo(2); } @Test void testSelectListWithTypeHandler() { Buildable selectStatement = select(id, firstName, lastName, birthDate, employed, occupation, addressId) .from(person) - .where(lastName, isIn(LastName.of("Flintstone"), LastName.of("Rubble"))) + .where(lastName, isIn(new LastName("Flintstone"), new LastName("Rubble"))) .orderBy(id); List rows = template.selectList(selectStatement, personRowMapper); assertThat(rows).hasSize(6); - assertThat(rows.get(0).getId()).isEqualTo(1); - assertThat(rows.get(1).getId()).isEqualTo(2); + assertThat(rows.get(0).id()).isEqualTo(1); + assertThat(rows.get(1).id()).isEqualTo(2); } @Test @@ -203,8 +202,15 @@ void testFirstNameIn() { List rows = template.selectList(selectStatement, personRowMapper); assertThat(rows).hasSize(2); - assertThat(rows.get(0).getLastName().getName()).isEqualTo("Flintstone"); - assertThat(rows.get(1).getLastName().getName()).isEqualTo("Rubble"); + + assertThat(rows).satisfiesExactly( + person1 -> assertThat(person1).isNotNull() + .extracting("lastName").isNotNull() + .extracting("name").isEqualTo("Flintstone"), + person2 -> assertThat(person2).isNotNull() + .extracting("lastName").isNotNull() + .extracting("name").isEqualTo("Rubble") + ); } @Test @@ -238,14 +244,7 @@ void testDeleteByPrimaryKey() { @Test void testInsert() { - PersonRecord row = new PersonRecord(); - row.setId(100); - row.setFirstName("Joe"); - row.setLastName(LastName.of("Jones")); - row.setBirthDate(new Date()); - row.setEmployed(true); - row.setOccupation("Developer"); - row.setAddressId(1); + PersonRecord row = new PersonRecord(100, "Joe", new LastName("Jones"), new Date(), true, "Developer", 1); Buildable> insertStatement = insert(row).into(person) .map(id).toProperty("id") @@ -266,7 +265,7 @@ void testGeneralInsert() { Buildable insertStatement = insertInto(person) .set(id).toValue(100) .set(firstName).toValue("Joe") - .set(lastName).toValue(LastName.of("Jones")) + .set(lastName).toValue(new LastName("Jones")) .set(birthDate).toValue(new Date()) .set(employed).toValue(true) .set(occupation).toValue("Developer") @@ -280,27 +279,9 @@ void testGeneralInsert() { @Test void testInsertMultiple() { - List records = new ArrayList<>(); - - PersonRecord row = new PersonRecord(); - row.setId(100); - row.setFirstName("Joe"); - row.setLastName(LastName.of("Jones")); - row.setBirthDate(new Date()); - row.setEmployed(true); - row.setOccupation("Developer"); - row.setAddressId(1); - records.add(row); - - row = new PersonRecord(); - row.setId(101); - row.setFirstName("Sarah"); - row.setLastName(LastName.of("Smith")); - row.setBirthDate(new Date()); - row.setEmployed(true); - row.setOccupation("Architect"); - row.setAddressId(2); - records.add(row); + List records = List.of( + new PersonRecord(100, "Joe", new LastName("Jones"), new Date(), true, "Developer", 1), + new PersonRecord(101, "Sarah", new LastName("Smith"), new Date(), true, "Architect", 2)); Buildable> insertStatement = insertMultiple(records).into(person) .map(id).toProperty("id") @@ -319,27 +300,9 @@ void testInsertMultiple() { @Test void testInsertBatch() { - List records = new ArrayList<>(); - - PersonRecord row = new PersonRecord(); - row.setId(100); - row.setFirstName("Joe"); - row.setLastName(LastName.of("Jones")); - row.setBirthDate(new Date()); - row.setEmployed(true); - row.setOccupation("Developer"); - row.setAddressId(1); - records.add(row); - - row = new PersonRecord(); - row.setId(101); - row.setFirstName("Sarah"); - row.setLastName(LastName.of("Smith")); - row.setBirthDate(new Date()); - row.setEmployed(true); - row.setOccupation("Architect"); - row.setAddressId(2); - records.add(row); + List records = List.of( + new PersonRecord(100, "Joe", new LastName("Jones"), new Date(), true, "Developer", 1), + new PersonRecord(101, "Sarah", new LastName("Smith"), new Date(), true, "Architect", 2)); Buildable> insertStatement = insertBatch(records).into(person) .map(id).toProperty("id") @@ -359,22 +322,16 @@ void testInsertBatch() { @Test void testInsertSelective() { - PersonRecord row = new PersonRecord(); - row.setId(100); - row.setFirstName("Joe"); - row.setLastName(LastName.of("Jones")); - row.setBirthDate(new Date()); - row.setEmployed(false); - row.setAddressId(1); + PersonRecord row = new PersonRecord(100, "Joe", new LastName("Jones"), new Date(), false, null, 1); Buildable> insertStatement = insert(row).into(person) - .map(id).toPropertyWhenPresent("id", row::getId) - .map(firstName).toPropertyWhenPresent("firstName", row::getFirstName) + .map(id).toPropertyWhenPresent("id", row::id) + .map(firstName).toPropertyWhenPresent("firstName", row::firstName) .map(lastName).toPropertyWhenPresent("lastNameAsString", row::getLastNameAsString) - .map(birthDate).toPropertyWhenPresent("birthDate", row::getBirthDate) + .map(birthDate).toPropertyWhenPresent("birthDate", row::birthDate) .map(employed).toPropertyWhenPresent("employedAsString", row::getEmployedAsString) - .map(occupation).toPropertyWhenPresent("occupation", row::getOccupation) - .map(addressId).toPropertyWhenPresent("addressId", row::getAddressId); + .map(occupation).toPropertyWhenPresent("occupation", row::occupation) + .map(addressId).toPropertyWhenPresent("addressId", row::addressId); int rows = template.insert(insertStatement); @@ -387,7 +344,7 @@ void testGeneralInsertWhenTypeConverterReturnsNull() { GeneralInsertStatementProvider insertStatement = insertInto(person) .set(id).toValue(100) .set(firstName).toValue("Joe") - .set(lastName).toValueWhenPresent(LastName.of("Slate")) + .set(lastName).toValueWhenPresent(new LastName("Slate")) .set(birthDate).toValue(new Date()) .set(employed).toValue(true) .set(occupation).toValue("Quarry Owner") @@ -404,7 +361,9 @@ void testGeneralInsertWhenTypeConverterReturnsNull() { .from(person) .where(id, isEqualTo(100)); Optional newRecord = template.selectOne(selectStatement, personRowMapper); - assertThat(newRecord).hasValueSatisfying(r -> assertThat(r.getLastName().getName()).isNull()); + assertThat(newRecord).hasValueSatisfying( + r -> assertThat(r).isNotNull().extracting("lastName").isNotNull().extracting("name").isNull() + ); } @Test @@ -413,7 +372,7 @@ void testUpdateByPrimaryKey() { Buildable insertStatement = insertInto(person) .set(id).toValue(100) .set(firstName).toValue("Joe") - .set(lastName).toValue(LastName.of("Jones")) + .set(lastName).toValue(new LastName("Jones")) .set(birthDate).toValue(new Date()) .set(employed).toValue(true) .set(occupation).toValue("Developer") @@ -433,7 +392,7 @@ void testUpdateByPrimaryKey() { .from(person) .where(id, isEqualTo(100)); Optional newRecord = template.selectOne(selectStatement, personRowMapper); - assertThat(newRecord).hasValueSatisfying(r -> assertThat(r.getOccupation()).isEqualTo("Programmer")); + assertThat(newRecord).hasValueSatisfying(r -> assertThat(r.occupation()).isEqualTo("Programmer")); } @Test @@ -442,7 +401,7 @@ void testUpdateByPrimaryKeyWithTypeHandler() { Buildable insertStatement = insertInto(person) .set(id).toValue(100) .set(firstName).toValue("Joe") - .set(lastName).toValue(LastName.of("Jones")) + .set(lastName).toValue(new LastName("Jones")) .set(birthDate).toValue(new Date()) .set(employed).toValue(true) .set(occupation).toValue("Developer") @@ -452,7 +411,7 @@ void testUpdateByPrimaryKeyWithTypeHandler() { assertThat(rows).isEqualTo(1); Buildable updateStatement = update(person) - .set(lastName).equalTo(LastName.of("Smith")) + .set(lastName).equalTo(new LastName("Smith")) .where(id, isEqualTo(100)); rows = template.update(updateStatement); @@ -462,8 +421,10 @@ void testUpdateByPrimaryKeyWithTypeHandler() { .from(person) .where(id, isEqualTo(100)); Optional newRecord = template.selectOne(selectStatement, personRowMapper); - assertThat(newRecord).hasValueSatisfying(r -> - assertThat(r.getLastName().getName()).isEqualTo("Smith")); + assertThat(newRecord).hasValueSatisfying(r -> assertThat(r).isNotNull() + .extracting("lastName").isNotNull() + .extracting("name").isEqualTo("Smith") + ); } @Test @@ -471,7 +432,7 @@ void testUpdateByPrimaryKeySelective() { Buildable insertStatement = insertInto(person) .set(id).toValue(100) .set(firstName).toValue("Joe") - .set(lastName).toValue(LastName.of("Jones")) + .set(lastName).toValue(new LastName("Jones")) .set(birthDate).toValue(new Date()) .set(employed).toValue(true) .set(occupation).toValue("Developer") @@ -480,18 +441,16 @@ void testUpdateByPrimaryKeySelective() { int rows = template.generalInsert(insertStatement); assertThat(rows).isEqualTo(1); - PersonRecord updateRecord = new PersonRecord(); - updateRecord.setId(100); - updateRecord.setOccupation("Programmer"); + PersonRecord updateRecord = new PersonRecord(100, null, null, null, null, "Programmer", null); Buildable updateStatement = update(person) - .set(firstName).equalToWhenPresent(updateRecord::getFirstName) - .set(lastName).equalToWhenPresent(updateRecord::getLastName) - .set(birthDate).equalToWhenPresent(updateRecord::getBirthDate) - .set(employed).equalToWhenPresent(updateRecord::getEmployed) - .set(occupation).equalToWhenPresent(updateRecord::getOccupation) - .set(addressId).equalToWhenPresent(updateRecord::getAddressId) - .where(id, isEqualTo(updateRecord::getId)); + .set(firstName).equalToWhenPresent(updateRecord::firstName) + .set(lastName).equalToWhenPresent(updateRecord::lastName) + .set(birthDate).equalToWhenPresent(updateRecord::birthDate) + .set(employed).equalToWhenPresent(updateRecord::employed) + .set(occupation).equalToWhenPresent(updateRecord::occupation) + .set(addressId).equalToWhenPresent(updateRecord::addressId) + .where(id, isEqualTo(updateRecord::id)); rows = template.update(updateStatement); assertThat(rows).isEqualTo(1); @@ -501,21 +460,14 @@ void testUpdateByPrimaryKeySelective() { .where(id, isEqualTo(100)); Optional newRecord = template.selectOne(selectStatement, personRowMapper); assertThat(newRecord).hasValueSatisfying(r -> { - assertThat(r.getOccupation()).isEqualTo("Programmer"); - assertThat(r.getFirstName()).isEqualTo("Joe"); + assertThat(r.occupation()).isEqualTo("Programmer"); + assertThat(r.firstName()).isEqualTo("Joe"); }); } @Test void testUpdate() { - PersonRecord row = new PersonRecord(); - row.setId(100); - row.setFirstName("Joe"); - row.setLastName(LastName.of("Jones")); - row.setBirthDate(new Date()); - row.setEmployed(true); - row.setOccupation("Developer"); - row.setAddressId(1); + PersonRecord row = new PersonRecord(100, "Joe", new LastName("Jones"), new Date(), true, "Developer", 1); Buildable> insertStatement = insert(row).into(person) .map(id).toProperty("id") @@ -529,16 +481,16 @@ void testUpdate() { int rows = template.insert(insertStatement); assertThat(rows).isEqualTo(1); - row.setOccupation("Programmer"); + row = row.withOccupation("Programmer"); Buildable updateStatement = update(person) - .set(firstName).equalTo(row::getFirstName) - .set(lastName).equalTo(row::getLastName) - .set(birthDate).equalTo(row::getBirthDate) - .set(employed).equalTo(row::getEmployed) - .set(occupation).equalTo(row::getOccupation) - .set(addressId).equalTo(row::getAddressId) - .where(id, isEqualTo(row::getId)); + .set(firstName).equalToWhenPresent(row::firstName) + .set(lastName).equalToWhenPresent(row::lastName) + .set(birthDate).equalToWhenPresent(row::birthDate) + .set(employed).equalToWhenPresent(row::employed) + .set(occupation).equalToWhenPresent(row::occupation) + .set(addressId).equalToWhenPresent(row::addressId) + .where(id, isEqualTo(row::id)); rows = template.update(updateStatement); assertThat(rows).isEqualTo(1); @@ -548,8 +500,8 @@ void testUpdate() { .where(id, isEqualTo(100)); Optional newRecord = template.selectOne(selectStatement, personRowMapper); assertThat(newRecord).hasValueSatisfying(r -> { - assertThat(r.getOccupation()).isEqualTo("Programmer"); - assertThat(r.getFirstName()).isEqualTo("Joe"); + assertThat(r.occupation()).isEqualTo("Programmer"); + assertThat(r.firstName()).isEqualTo("Joe"); }); } @@ -558,7 +510,7 @@ void testUpdateAll() { Buildable insertStatement = insertInto(person) .set(id).toValue(100) .set(firstName).toValue("Joe") - .set(lastName).toValue(LastName.of("Jones")) + .set(lastName).toValue(new LastName("Jones")) .set(birthDate).toValue(new Date()) .set(employed).toValue(true) .set(occupation).toValue("Developer") @@ -578,7 +530,7 @@ void testUpdateAll() { .where(id, isEqualTo(100)); Optional newRecord = template.selectOne(selectStatement, personRowMapper); - assertThat(newRecord).hasValueSatisfying(r -> assertThat(r.getOccupation()).isEqualTo("Programmer")); + assertThat(newRecord).hasValueSatisfying(r -> assertThat(r.occupation()).isEqualTo("Programmer")); } @Test @@ -618,25 +570,25 @@ void testCountDistinctLastName() { void testTypeHandledLike() { Buildable selectStatement = select(id, firstName, lastName, birthDate, employed, occupation, addressId) .from(person) - .where(lastName, isLike(LastName.of("Fl%"))) + .where(lastName, isLike(new LastName("Fl%"))) .orderBy(id); List rows = template.selectList(selectStatement, personRowMapper); assertThat(rows).hasSize(3); - assertThat(rows.get(0).getFirstName()).isEqualTo("Fred"); + assertThat(rows.get(0).firstName()).isEqualTo("Fred"); } @Test void testTypeHandledNotLike() { Buildable selectStatement = select(id, firstName, lastName, birthDate, employed, occupation, addressId) .from(person) - .where(lastName, isNotLike(LastName.of("Fl%"))) + .where(lastName, isNotLike(new LastName("Fl%"))) .orderBy(id); List rows = template.selectList(selectStatement, personRowMapper); assertThat(rows).hasSize(3); - assertThat(rows.get(0).getFirstName()).isEqualTo("Barney"); + assertThat(rows.get(0).firstName()).isEqualTo("Barney"); } @Test @@ -646,14 +598,15 @@ void testAutoMapping() { .from(address) .orderBy(address.id); + List records = template.selectList(selectStatement, - BeanPropertyRowMapper.newInstance(AddressRecord.class)); + DataClassRowMapper.newInstance(AddressRecord.class)); assertThat(records).hasSize(2); - assertThat(records.get(0).getId()).isEqualTo(1); - assertThat(records.get(0).getStreetAddress()).isEqualTo("123 Main Street"); - assertThat(records.get(0).getCity()).isEqualTo("Bedrock"); - assertThat(records.get(0).getState()).isEqualTo("IN"); + assertThat(records.get(0).id()).isEqualTo(1); + assertThat(records.get(0).streetAddress()).isEqualTo("123 Main Street"); + assertThat(records.get(0).city()).isEqualTo("Bedrock"); + assertThat(records.get(0).state()).isEqualTo("IN"); } @Test @@ -667,16 +620,16 @@ void testJoinAllRows() { List records = template.selectList(selectStatement, personWithAddressRowMapper); assertThat(records).hasSize(6); - assertThat(records.get(0).getId()).isEqualTo(1); - assertThat(records.get(0).getEmployed()).isTrue(); - assertThat(records.get(0).getFirstName()).isEqualTo("Fred"); - assertThat(records.get(0).getLastName()).isEqualTo(LastName.of("Flintstone")); - assertThat(records.get(0).getOccupation()).isEqualTo("Brontosaurus Operator"); - assertThat(records.get(0).getBirthDate()).isNotNull(); - assertThat(records.get(0).getAddress().getId()).isEqualTo(1); - assertThat(records.get(0).getAddress().getStreetAddress()).isEqualTo("123 Main Street"); - assertThat(records.get(0).getAddress().getCity()).isEqualTo("Bedrock"); - assertThat(records.get(0).getAddress().getState()).isEqualTo("IN"); + assertThat(records.get(0).id()).isEqualTo(1); + assertThat(records.get(0).employed()).isTrue(); + assertThat(records.get(0).firstName()).isEqualTo("Fred"); + assertThat(records.get(0).lastName()).isEqualTo(new LastName("Flintstone")); + assertThat(records.get(0).occupation()).isEqualTo("Brontosaurus Operator"); + assertThat(records.get(0).birthDate()).isNotNull(); + assertThat(records.get(0).address().id()).isEqualTo(1); + assertThat(records.get(0).address().streetAddress()).isEqualTo("123 Main Street"); + assertThat(records.get(0).address().city()).isEqualTo("Bedrock"); + assertThat(records.get(0).address().state()).isEqualTo("IN"); } @Test @@ -690,16 +643,16 @@ void testJoinOneRow() { List records = template.selectList(selectStatement, personWithAddressRowMapper); assertThat(records).hasSize(1); - assertThat(records.get(0).getId()).isEqualTo(1); - assertThat(records.get(0).getEmployed()).isTrue(); - assertThat(records.get(0).getFirstName()).isEqualTo("Fred"); - assertThat(records.get(0).getLastName()).isEqualTo(LastName.of("Flintstone")); - assertThat(records.get(0).getOccupation()).isEqualTo("Brontosaurus Operator"); - assertThat(records.get(0).getBirthDate()).isNotNull(); - assertThat(records.get(0).getAddress().getId()).isEqualTo(1); - assertThat(records.get(0).getAddress().getStreetAddress()).isEqualTo("123 Main Street"); - assertThat(records.get(0).getAddress().getCity()).isEqualTo("Bedrock"); - assertThat(records.get(0).getAddress().getState()).isEqualTo("IN"); + assertThat(records.get(0).id()).isEqualTo(1); + assertThat(records.get(0).employed()).isTrue(); + assertThat(records.get(0).firstName()).isEqualTo("Fred"); + assertThat(records.get(0).lastName()).isEqualTo(new LastName("Flintstone")); + assertThat(records.get(0).occupation()).isEqualTo("Brontosaurus Operator"); + assertThat(records.get(0).birthDate()).isNotNull(); + assertThat(records.get(0).address().id()).isEqualTo(1); + assertThat(records.get(0).address().streetAddress()).isEqualTo("123 Main Street"); + assertThat(records.get(0).address().city()).isEqualTo("Bedrock"); + assertThat(records.get(0).address().state()).isEqualTo("IN"); } @Test @@ -713,16 +666,16 @@ void testJoinPrimaryKey() { Optional row = template.selectOne(selectStatement, personWithAddressRowMapper); assertThat(row).hasValueSatisfying(r -> { - assertThat(r.getId()).isEqualTo(1); - assertThat(r.getEmployed()).isTrue(); - assertThat(r.getFirstName()).isEqualTo("Fred"); - assertThat(r.getLastName()).isEqualTo(LastName.of("Flintstone")); - assertThat(r.getOccupation()).isEqualTo("Brontosaurus Operator"); - assertThat(r.getBirthDate()).isNotNull(); - assertThat(r.getAddress().getId()).isEqualTo(1); - assertThat(r.getAddress().getStreetAddress()).isEqualTo("123 Main Street"); - assertThat(r.getAddress().getCity()).isEqualTo("Bedrock"); - assertThat(r.getAddress().getState()).isEqualTo("IN"); + assertThat(r.id()).isEqualTo(1); + assertThat(r.employed()).isTrue(); + assertThat(r.firstName()).isEqualTo("Fred"); + assertThat(r.lastName()).isEqualTo(new LastName("Flintstone")); + assertThat(r.occupation()).isEqualTo("Brontosaurus Operator"); + assertThat(r.birthDate()).isNotNull(); + assertThat(r.address().id()).isEqualTo(1); + assertThat(r.address().streetAddress()).isEqualTo("123 Main Street"); + assertThat(r.address().city()).isEqualTo("Bedrock"); + assertThat(r.address().state()).isEqualTo("IN"); }); } @@ -759,36 +712,24 @@ void testJoinCountWithSubCriteria() { } private final RowMapper personWithAddressRowMapper = - (rs, i) -> { - PersonWithAddress row = new PersonWithAddress(); - row.setId(rs.getInt(1)); - row.setFirstName(rs.getString(2)); - row.setLastName(LastName.of(rs.getString(3))); - row.setBirthDate(rs.getTimestamp(4)); - row.setEmployed("Yes".equals(rs.getString(5))); - row.setOccupation(rs.getString(6)); - - AddressRecord address = new AddressRecord(); - row.setAddress(address); - address.setId(rs.getInt(7)); - address.setStreetAddress(rs.getString(8)); - address.setCity(rs.getString(9)); - address.setState(rs.getString(10)); - - return row; - }; + (rs, i) -> new PersonWithAddress(rs.getInt(1), + rs.getString(2), + new LastName(rs.getString(3)), + rs.getTimestamp(4), + "Yes".equals(rs.getString(5)), + rs.getString(6), + new AddressRecord(rs.getInt(7), + rs.getString(8), + rs.getString(9), + rs.getString(10))); static final RowMapper personRowMapper = - (rs, i) -> { - PersonRecord row = new PersonRecord(); - row.setId(rs.getInt(1)); - row.setFirstName(rs.getString(2)); - row.setLastName(LastName.of(rs.getString(3))); - row.setBirthDate(rs.getTimestamp(4)); - row.setEmployed("Yes".equals(rs.getString(5))); - row.setOccupation(rs.getString(6)); - row.setAddressId(rs.getInt(7)); - return row; - }; + (rs, i) -> new PersonRecord(rs.getInt(1), + rs.getString(2), + new LastName(rs.getString(3)), + rs.getTimestamp(4), + "Yes".equals(rs.getString(5)), + rs.getString(6), + rs.getInt(7)); } diff --git a/src/test/java/examples/spring/PersonWithAddress.java b/src/test/java/examples/spring/PersonWithAddress.java index 7dd143e6f..7cf524553 100644 --- a/src/test/java/examples/spring/PersonWithAddress.java +++ b/src/test/java/examples/spring/PersonWithAddress.java @@ -17,68 +17,5 @@ import java.util.Date; -public class PersonWithAddress { - private Integer id; - private String firstName; - private LastName lastName; - private Date birthDate; - private Boolean employed; - private String occupation; - private AddressRecord address; - - public Integer getId() { - return id; - } - - public void setId(Integer id) { - this.id = id; - } - - public String getFirstName() { - return firstName; - } - - public void setFirstName(String firstName) { - this.firstName = firstName; - } - - public LastName getLastName() { - return lastName; - } - - public void setLastName(LastName lastName) { - this.lastName = lastName; - } - - public Date getBirthDate() { - return birthDate; - } - - public void setBirthDate(Date birthDate) { - this.birthDate = birthDate; - } - - public String getOccupation() { - return occupation; - } - - public void setOccupation(String occupation) { - this.occupation = occupation; - } - - public Boolean getEmployed() { - return employed; - } - - public void setEmployed(Boolean employed) { - this.employed = employed; - } - - public AddressRecord getAddress() { - return address; - } - - public void setAddress(AddressRecord address) { - this.address = address; - } -} +public record PersonWithAddress(Integer id, String firstName, LastName lastName, Date birthDate, Boolean employed, + String occupation, AddressRecord address) { } diff --git a/src/test/java/examples/spring/YesNoParameterConverter.java b/src/test/java/examples/spring/YesNoParameterConverter.java index f86cc7b0f..9801fe1ae 100644 --- a/src/test/java/examples/spring/YesNoParameterConverter.java +++ b/src/test/java/examples/spring/YesNoParameterConverter.java @@ -15,10 +15,8 @@ */ package examples.spring; -import org.jspecify.annotations.NullMarked; import org.mybatis.dynamic.sql.ParameterTypeConverter; -@NullMarked public class YesNoParameterConverter implements ParameterTypeConverter { @Override diff --git a/src/test/java/examples/spring/package-info.java b/src/test/java/examples/spring/package-info.java new file mode 100644 index 000000000..27fa1f118 --- /dev/null +++ b/src/test/java/examples/spring/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright 2016-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@NullMarked +package examples.spring; + +import org.jspecify.annotations.NullMarked; From 27e82d114ead76e4bf391b46834f9024a6b9838f Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Fri, 4 Apr 2025 09:05:52 -0400 Subject: [PATCH 230/289] Convert to records in the Animal Data example --- .../java/examples/animal/data/AnimalData.java | 39 +---- .../animal/data/AnimalDataMapper.java | 44 +++-- .../examples/animal/data/AnimalDataTest.java | 103 +++++------ .../animal/data/CommonSelectMapperTest.java | 37 ++-- .../examples/animal/data/FetchFirstTest.java | 12 +- .../animal/data/LimitAndOffsetTest.java | 18 +- .../examples/animal/data/MyInCondition.java | 5 +- .../OptionalConditionsAnimalDataTest.java | 100 +++++------ ...onditionsWithPredicatesAnimalDataTest.java | 161 +++++++++--------- .../examples/animal/data/package-info.java | 19 +++ .../examples/paging/LimitAndOffsetMapper.java | 13 +- .../examples/paging/LimitAndOffsetTest.java | 2 +- .../java/examples/paging/package-info.java | 19 +++ 13 files changed, 279 insertions(+), 293 deletions(-) create mode 100644 src/test/java/examples/animal/data/package-info.java create mode 100644 src/test/java/examples/paging/package-info.java diff --git a/src/test/java/examples/animal/data/AnimalData.java b/src/test/java/examples/animal/data/AnimalData.java index aff740d2f..0c4a49321 100644 --- a/src/test/java/examples/animal/data/AnimalData.java +++ b/src/test/java/examples/animal/data/AnimalData.java @@ -15,41 +15,4 @@ */ package examples.animal.data; -public class AnimalData { - private int id; - private String animalName; - private double brainWeight; - private double bodyWeight; - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - public String getAnimalName() { - return animalName; - } - - public void setAnimalName(String animalName) { - this.animalName = animalName; - } - - public double getBrainWeight() { - return brainWeight; - } - - public void setBrainWeight(double brainWeight) { - this.brainWeight = brainWeight; - } - - public double getBodyWeight() { - return bodyWeight; - } - - public void setBodyWeight(double bodyWeight) { - this.bodyWeight = bodyWeight; - } -} +public record AnimalData(int id, String animalName, double brainWeight, double bodyWeight) {} diff --git a/src/test/java/examples/animal/data/AnimalDataMapper.java b/src/test/java/examples/animal/data/AnimalDataMapper.java index 39fcd1875..26a2cbac2 100644 --- a/src/test/java/examples/animal/data/AnimalDataMapper.java +++ b/src/test/java/examples/animal/data/AnimalDataMapper.java @@ -17,10 +17,8 @@ import java.util.List; +import org.apache.ibatis.annotations.Arg; import org.apache.ibatis.annotations.Param; -import org.apache.ibatis.annotations.Result; -import org.apache.ibatis.annotations.ResultMap; -import org.apache.ibatis.annotations.Results; import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.SelectProvider; import org.apache.ibatis.session.RowBounds; @@ -34,20 +32,24 @@ public interface AnimalDataMapper extends CommonDeleteMapper, CommonInsertMapper, CommonUpdateMapper { @SelectProvider(type=SqlProviderAdapter.class, method="select") - @Results(id="AnimalDataResult", value={ - @Result(column="id", property="id", id=true), - @Result(column="animal_name", property="animalName"), - @Result(column="brain_weight", property="brainWeight"), - @Result(column="body_weight", property="bodyWeight") - }) + @Arg(column = "id", javaType = int.class, id = true) + @Arg(column = "animal_name", javaType = String.class) + @Arg(column = "brain_weight", javaType = double.class) + @Arg(column = "body_weight", javaType = double.class) List selectMany(SelectStatementProvider selectStatement); @SelectProvider(type = SqlProviderAdapter.class, method = "select") - @ResultMap("AnimalDataResult") + @Arg(column = "id", javaType = int.class, id = true) + @Arg(column = "animal_name", javaType = String.class) + @Arg(column = "brain_weight", javaType = double.class) + @Arg(column = "body_weight", javaType = double.class) List selectManyWithRowBounds(SelectStatementProvider selectStatement, RowBounds rowBounds); @SelectProvider(type = SqlProviderAdapter.class, method = "select") - @ResultMap("AnimalDataResult") + @Arg(column = "id", javaType = int.class, id = true) + @Arg(column = "animal_name", javaType = String.class) + @Arg(column = "brain_weight", javaType = double.class) + @Arg(column = "body_weight", javaType = double.class) AnimalData selectOne(SelectStatementProvider selectStatement); @Select({ @@ -55,7 +57,10 @@ public interface AnimalDataMapper extends CommonDeleteMapper, CommonInsertMapper "from AnimalData", "${whereClause}" }) - @ResultMap("AnimalDataResult") + @Arg(column = "id", javaType = int.class, id = true) + @Arg(column = "animal_name", javaType = String.class) + @Arg(column = "brain_weight", javaType = double.class) + @Arg(column = "body_weight", javaType = double.class) List selectWithWhereClause(WhereClauseProvider whereClause); @Select({ @@ -63,7 +68,10 @@ public interface AnimalDataMapper extends CommonDeleteMapper, CommonInsertMapper "from AnimalData a", "${whereClause}" }) - @ResultMap("AnimalDataResult") + @Arg(column = "id", javaType = int.class, id = true) + @Arg(column = "animal_name", javaType = String.class) + @Arg(column = "brain_weight", javaType = double.class) + @Arg(column = "body_weight", javaType = double.class) List selectWithWhereClauseAndAlias(WhereClauseProvider whereClause); @Select({ @@ -73,7 +81,10 @@ public interface AnimalDataMapper extends CommonDeleteMapper, CommonInsertMapper "order by id", "OFFSET #{offset,jdbcType=INTEGER} LIMIT #{limit,jdbcType=INTEGER}" }) - @ResultMap("AnimalDataResult") + @Arg(column = "id", javaType = int.class, id = true) + @Arg(column = "animal_name", javaType = String.class) + @Arg(column = "brain_weight", javaType = double.class) + @Arg(column = "body_weight", javaType = double.class) List selectWithWhereClauseLimitAndOffset(@Param("whereClauseProvider") WhereClauseProvider whereClause, @Param("limit") int limit, @Param("offset") int offset); @@ -84,7 +95,10 @@ List selectWithWhereClauseLimitAndOffset(@Param("whereClauseProvider "order by id", "OFFSET #{offset,jdbcType=INTEGER} LIMIT #{limit,jdbcType=INTEGER}" }) - @ResultMap("AnimalDataResult") + @Arg(column = "id", javaType = int.class, id = true) + @Arg(column = "animal_name", javaType = String.class) + @Arg(column = "brain_weight", javaType = double.class) + @Arg(column = "body_weight", javaType = double.class) List selectWithWhereClauseAliasLimitAndOffset(@Param("whereClauseProvider") WhereClauseProvider whereClause, @Param("limit") int limit, @Param("offset") int offset); } diff --git a/src/test/java/examples/animal/data/AnimalDataTest.java b/src/test/java/examples/animal/data/AnimalDataTest.java index 90c247116..df53051f1 100644 --- a/src/test/java/examples/animal/data/AnimalDataTest.java +++ b/src/test/java/examples/animal/data/AnimalDataTest.java @@ -46,6 +46,7 @@ import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mybatis.dynamic.sql.BasicColumn; @@ -103,7 +104,7 @@ void testSelectAllRows() { assertAll( () -> assertThat(animals).hasSize(65), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -121,7 +122,7 @@ void testSelectAllRowsWithNullLimit() { assertAll( () -> assertThat(animals).hasSize(65), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -140,7 +141,7 @@ void testSelectAllRowsWithRowBounds() { List animals = mapper.selectManyWithRowBounds(selectStatement, rowBounds); assertAll( () -> assertThat(animals).hasSize(6), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(5) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(5) ); } } @@ -157,7 +158,7 @@ void testSelectAllRowsWithOrder() { List animals = mapper.selectMany(selectStatement); assertAll( () -> assertThat(animals).hasSize(65), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(65) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(65) ); } } @@ -196,7 +197,7 @@ void testSelectAllRowsAllColumnsWithOrder() { () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select * from AnimalData order by id DESC"), () -> assertThat(animals).hasSize(65), () -> assertThat(animals).first().isNotNull() - .extracting(AnimalData::getId).isEqualTo(65) + .extracting(AnimalData::id).isEqualTo(65) ); } } @@ -214,7 +215,7 @@ void testSelectAllRowsAllColumnsWithOrderAndAlias() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select ad.* from AnimalData ad order by id DESC"), () -> assertThat(animals).hasSize(65), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(65) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(65) ); } } @@ -380,7 +381,7 @@ void testSelectRowsNotBetweenWithStandaloneWhereClauseLimitAndOffset() { assertThat(whereClause).hasValueSatisfying(wc -> { List animals = mapper.selectWithWhereClauseLimitAndOffset(wc, 5, 15); assertThat(animals).hasSize(5); - assertThat(animals.get(0).getId()).isEqualTo(16); + assertThat(animals.get(0).id()).isEqualTo(16); }); } } @@ -398,7 +399,7 @@ void testSelectRowsNotBetweenWithStandaloneWhereClauseAliasLimitAndOffset() { assertThat(whereClause).hasValueSatisfying(wc -> { List animals = mapper.selectWithWhereClauseAliasLimitAndOffset(wc, 3, 24); assertThat(animals).hasSize(3); - assertThat(animals.get(0).getId()).isEqualTo(25); + assertThat(animals.get(0).id()).isEqualTo(25); }); } @@ -710,14 +711,14 @@ void testInConditionWithEventuallyEmptyList() { @Test void testInConditionWithEventuallyEmptyListForceRendering() { - List inValues = new ArrayList<>(); + List<@Nullable Integer> inValues = new ArrayList<>(); inValues.add(null); inValues.add(22); inValues.add(null); SelectModel selectModel = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isInWhenPresent(inValues).filter(Objects::nonNull).filter(i -> i != 22)) + .where(id, isInWhenPresent(inValues).filter(i -> i != 22)) .build(); assertThatExceptionOfType(NonRenderingWhereClauseException.class).isThrownBy(() -> @@ -864,8 +865,8 @@ void testLikeCaseInsensitive() { assertAll( () -> assertThat(animals).hasSize(2), - () -> assertThat(animals).element(0).isNotNull().extracting(AnimalData::getAnimalName).isEqualTo("Ground squirrel"), - () -> assertThat(animals).element(1).isNotNull().extracting(AnimalData::getAnimalName).isEqualTo("Artic ground squirrel") + () -> assertThat(animals).element(0).isNotNull().extracting(AnimalData::animalName).isEqualTo("Ground squirrel"), + () -> assertThat(animals).element(1).isNotNull().extracting(AnimalData::animalName).isEqualTo("Artic ground squirrel") ); } } @@ -1587,11 +1588,9 @@ void testComplexCondition() { void testUpdate() { try (SqlSession sqlSession = sqlSessionFactory.openSession()) { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); - AnimalData row = new AnimalData(); - row.setBodyWeight(2.6); UpdateStatementProvider updateStatement = update(animalData) - .set(bodyWeight).equalTo(row.getBodyWeight()) + .set(bodyWeight).equalTo(2.6) .set(animalName).equalToNull() .where(id, isIn(1, 5, 7)) .or(id, isIn(2, 6, 8), and(animalName, isLike("%bat"))) @@ -1645,11 +1644,7 @@ void testUpdateValueOrNullWithNull() { void testInsert() { try (SqlSession sqlSession = sqlSessionFactory.openSession()) { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); - AnimalData row = new AnimalData(); - row.setId(100); - row.setAnimalName("Old Shep"); - row.setBodyWeight(22.5); - row.setBrainWeight(1.2); + AnimalData row = new AnimalData(100, "Old Shep", 22.5, 1.2); InsertStatementProvider insertStatement = insert(row) .into(animalData) @@ -1669,11 +1664,7 @@ void testInsert() { void testInsertNull() { try (SqlSession sqlSession = sqlSessionFactory.openSession()) { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); - AnimalData row = new AnimalData(); - row.setId(100); - row.setAnimalName("Old Shep"); - row.setBodyWeight(22.5); - row.setBrainWeight(1.2); + AnimalData row = new AnimalData(100, "Old Shep", 22.5, 1.2); InsertStatementProvider insertStatement = insert(row) .into(animalData) @@ -1693,18 +1684,10 @@ void testInsertNull() { void testBulkInsert() { try (SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH)) { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); - List records = new ArrayList<>(); - AnimalData row = new AnimalData(); - row.setId(100); - row.setAnimalName("Old Shep"); - row.setBodyWeight(22.5); - records.add(row); - - row = new AnimalData(); - row.setId(101); - row.setAnimalName("Old Dan"); - row.setBodyWeight(22.5); - records.add(row); + List records = List.of( + new AnimalData(100, "Old Shep", 0.0, 22.5), + new AnimalData(101, "Old Dan", 0.0, 22.5) + ); BatchInsert batchInsert = insertBatch(records) .into(animalData) @@ -1730,10 +1713,10 @@ void testBulkInsert() { assertAll( () -> assertThat(animals).hasSize(2), () -> assertThat(animals).element(0).isNotNull() - .extracting(AnimalData::getId, AnimalData::getBrainWeight, AnimalData::getAnimalName) + .extracting(AnimalData::id, AnimalData::brainWeight, AnimalData::animalName) .containsExactly(100, 1.2, null), () -> assertThat(animals).element(1).isNotNull() - .extracting(AnimalData::getId, AnimalData::getBrainWeight, AnimalData::getAnimalName) + .extracting(AnimalData::id, AnimalData::brainWeight, AnimalData::animalName) .containsExactly(101, 1.2, null) ); } @@ -1743,18 +1726,10 @@ void testBulkInsert() { void testBulkInsert2() { try (SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH)) { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); - List records = new ArrayList<>(); - AnimalData row = new AnimalData(); - row.setId(100); - row.setAnimalName("Old Shep"); - row.setBodyWeight(22.5); - records.add(row); - - row = new AnimalData(); - row.setId(101); - row.setAnimalName("Old Dan"); - row.setBodyWeight(22.5); - records.add(row); + List records = List.of( + new AnimalData(100, "Old Shep", 0.0, 22.5), + new AnimalData(101, "Old Dan", 0.0, 22.5) + ); BatchInsert batchInsert = insertBatch(records) .into(animalData) @@ -1780,10 +1755,10 @@ void testBulkInsert2() { assertAll( () -> assertThat(animals).hasSize(2), () -> assertThat(animals).element(0).isNotNull() - .extracting(AnimalData::getId, AnimalData::getBrainWeight, AnimalData::getAnimalName) + .extracting(AnimalData::id, AnimalData::brainWeight, AnimalData::animalName) .containsExactly(100, 1.2, "Old Fred"), () -> assertThat(animals).element(1).isNotNull() - .extracting(AnimalData::getId, AnimalData::getBrainWeight, AnimalData::getAnimalName) + .extracting(AnimalData::id, AnimalData::brainWeight, AnimalData::animalName) .containsExactly(101, 1.2, "Old Fred") ); } @@ -1806,7 +1781,7 @@ void testOrderByAndDistinct() { assertAll( () -> assertThat(rows).hasSize(14), - () -> assertThat(rows).first().isNotNull().extracting(AnimalData::getId).isEqualTo(65) + () -> assertThat(rows).first().isNotNull().extracting(AnimalData::id).isEqualTo(65) ); } } @@ -1828,7 +1803,7 @@ void testOrderByWithFullClause() { assertAll( () -> assertThat(rows).hasSize(14), - () -> assertThat(rows).first().isNotNull().extracting(AnimalData::getId).isEqualTo(65) + () -> assertThat(rows).first().isNotNull().extracting(AnimalData::id).isEqualTo(65) ); } } @@ -1944,7 +1919,7 @@ void testMaxSubselect() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select a.id, a.animal_name, a.body_weight, a.brain_weight from AnimalData a where a.brain_weight = (select max(b.brain_weight) from AnimalData b)"), () -> assertThat(records).hasSize(1), - () -> assertThat(records).first().isNotNull().extracting(AnimalData::getAnimalName).isEqualTo("Brachiosaurus") + () -> assertThat(records).first().isNotNull().extracting(AnimalData::animalName).isEqualTo("Brachiosaurus") ); } } @@ -2004,7 +1979,7 @@ void testMinSubselect() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select a.id, a.animal_name, a.body_weight, a.brain_weight from AnimalData a where a.brain_weight <> (select min(b.brain_weight) from AnimalData b) order by animal_name"), () -> assertThat(records).hasSize(64), - () -> assertThat(records).first().isNotNull().extracting(AnimalData::getAnimalName).isEqualTo("African elephant") + () -> assertThat(records).first().isNotNull().extracting(AnimalData::animalName).isEqualTo("African elephant") ); } } @@ -2026,7 +2001,7 @@ void testMinSubselectNoAlias() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where brain_weight <> (select min(brain_weight) from AnimalData) order by animal_name"), () -> assertThat(records).hasSize(64), - () -> assertThat(records).first().isNotNull().extracting(AnimalData::getAnimalName).isEqualTo("African elephant") + () -> assertThat(records).first().isNotNull().extracting(AnimalData::animalName).isEqualTo("African elephant") ); } } @@ -2335,13 +2310,13 @@ void testUpdateWithAddAndSubtract() { assertThat(rows).isEqualTo(1); AnimalData row = MyBatis3Utils.selectOne(mapper::selectOne, - BasicColumn.columnList(id, bodyWeight, brainWeight), + BasicColumn.columnList(id, animalName, bodyWeight, brainWeight), animalData, c -> c.where(id, isEqualTo(1)) ); - assertThat(row.getBodyWeight()).isEqualTo(-2.86); - assertThat(row.getBrainWeight()).isEqualTo(2.005); + assertThat(row.bodyWeight()).isEqualTo(-2.86); + assertThat(row.brainWeight()).isEqualTo(2.005); } } @@ -2368,13 +2343,13 @@ void testUpdateWithMultiplyAndDivide() { assertThat(rows).isEqualTo(1); AnimalData row = MyBatis3Utils.selectOne(mapper::selectOne, - BasicColumn.columnList(id, bodyWeight, brainWeight), + BasicColumn.columnList(id, animalName, bodyWeight, brainWeight), animalData, c -> c.where(id, isEqualTo(1)) ); - assertThat(row.getBodyWeight()).isEqualTo(0.42, within(.001)); - assertThat(row.getBrainWeight()).isEqualTo(.0025); + assertThat(row.bodyWeight()).isEqualTo(0.42, within(.001)); + assertThat(row.brainWeight()).isEqualTo(.0025); } } } diff --git a/src/test/java/examples/animal/data/CommonSelectMapperTest.java b/src/test/java/examples/animal/data/CommonSelectMapperTest.java index 863df85e6..e90f4cec7 100644 --- a/src/test/java/examples/animal/data/CommonSelectMapperTest.java +++ b/src/test/java/examples/animal/data/CommonSelectMapperTest.java @@ -69,14 +69,11 @@ void setup() throws Exception { sqlSessionFactory = new SqlSessionFactoryBuilder().build(config); } - private final Function, AnimalData> rowMapper = map -> { - AnimalData ad = new AnimalData(); - ad.setId((Integer) map.get("ID")); - ad.setAnimalName((String) map.get("ANIMAL_NAME")); - ad.setBodyWeight((Double) map.get("BODY_WEIGHT")); - ad.setBrainWeight((Double) map.get("BRAIN_WEIGHT")); - return ad; - }; + private final Function, AnimalData> rowMapper = map -> new AnimalData( + (Integer) map.get("ID"), + (String) map.get("ANIMAL_NAME"), + (Double) map.get("BRAIN_WEIGHT"), + (Double) map.get("BODY_WEIGHT")); @Test void testGeneralSelectOne() { @@ -106,10 +103,10 @@ void testGeneralSelectOneWithRowMapper() { AnimalData animal = mapper.selectOne(selectStatement, rowMapper); - assertThat(animal.getId()).isEqualTo(1); - assertThat(animal.getAnimalName()).isEqualTo("Lesser short-tailed shrew"); - assertThat(animal.getBodyWeight()).isEqualTo(0.14); - assertThat(animal.getBrainWeight()).isEqualTo(0.005); + assertThat(animal.id()).isEqualTo(1); + assertThat(animal.animalName()).isEqualTo("Lesser short-tailed shrew"); + assertThat(animal.bodyWeight()).isEqualTo(0.14); + assertThat(animal.brainWeight()).isEqualTo(0.005); } } @@ -148,14 +145,14 @@ void testGeneralSelectManyWithRowMapper() { assertThat(rows).hasSize(2); - assertThat(rows.get(0).getId()).isEqualTo(1); - assertThat(rows.get(0).getAnimalName()).isEqualTo("Lesser short-tailed shrew"); - assertThat(rows.get(0).getBodyWeight()).isEqualTo(0.14); - assertThat(rows.get(0).getBrainWeight()).isEqualTo(0.005); - assertThat(rows.get(1).getId()).isEqualTo(2); - assertThat(rows.get(1).getAnimalName()).isEqualTo("Little brown bat"); - assertThat(rows.get(1).getBodyWeight()).isEqualTo(0.25); - assertThat(rows.get(1).getBrainWeight()).isEqualTo(0.01); + assertThat(rows.get(0).id()).isEqualTo(1); + assertThat(rows.get(0).animalName()).isEqualTo("Lesser short-tailed shrew"); + assertThat(rows.get(0).bodyWeight()).isEqualTo(0.14); + assertThat(rows.get(0).brainWeight()).isEqualTo(0.005); + assertThat(rows.get(1).id()).isEqualTo(2); + assertThat(rows.get(1).animalName()).isEqualTo("Little brown bat"); + assertThat(rows.get(1).bodyWeight()).isEqualTo(0.25); + assertThat(rows.get(1).brainWeight()).isEqualTo(0.01); } } diff --git a/src/test/java/examples/animal/data/FetchFirstTest.java b/src/test/java/examples/animal/data/FetchFirstTest.java index 1c73532f1..9a1a10c00 100644 --- a/src/test/java/examples/animal/data/FetchFirstTest.java +++ b/src/test/java/examples/animal/data/FetchFirstTest.java @@ -80,7 +80,7 @@ void testOffsetAndFetchFirstAfterFrom() { assertAll( () -> assertThat(records).hasSize(3), - () -> assertThat(records).first().isNotNull().extracting(AnimalData::getId).isEqualTo(23), + () -> assertThat(records).first().isNotNull().extracting(AnimalData::id).isEqualTo(23), () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select * from AnimalData offset #{parameters.p1} rows fetch first #{parameters.p2} rows only"), () -> assertThat(selectStatement.getParameters()).containsEntry("p2", 3L), () -> assertThat(selectStatement.getParameters()).containsEntry("p1", 22L) @@ -102,7 +102,7 @@ void testFetchFirstOnlyAfterFrom() { assertAll( () -> assertThat(records).hasSize(3), - () -> assertThat(records).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1), + () -> assertThat(records).first().isNotNull().extracting(AnimalData::id).isEqualTo(1), () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select * from AnimalData fetch first #{parameters.p1} rows only"), () -> assertThat(selectStatement.getParameters()).containsEntry("p1", 3L) ); @@ -126,7 +126,7 @@ void testOffsetAndFetchFirstAfterWhere() { assertAll( () -> assertThat(records).hasSize(3), - () -> assertThat(records).first().isNotNull().extracting(AnimalData::getId).isEqualTo(45), + () -> assertThat(records).first().isNotNull().extracting(AnimalData::id).isEqualTo(45), () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select * from AnimalData where id < #{parameters.p1,jdbcType=INTEGER} and id > #{parameters.p2,jdbcType=INTEGER} offset #{parameters.p3} rows fetch first #{parameters.p4} rows only"), () -> assertThat(selectStatement.getParameters()).contains(entry("p4", 3L), entry("p3", 22L)) ); @@ -148,7 +148,7 @@ void testFetchFirstOnlyAfterWhere() { assertAll( () -> assertThat(records).hasSize(3), - () -> assertThat(records).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1), + () -> assertThat(records).first().isNotNull().extracting(AnimalData::id).isEqualTo(1), () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select * from AnimalData where id < #{parameters.p1,jdbcType=INTEGER} fetch first #{parameters.p2} rows only"), () -> assertThat(selectStatement.getParameters()).containsEntry("p2", 3L) ); @@ -171,7 +171,7 @@ void testOffsetAndFetchFirstAfterOrderBy() { assertAll( () -> assertThat(records).hasSize(3), - () -> assertThat(records).first().isNotNull().extracting(AnimalData::getId).isEqualTo(23), + () -> assertThat(records).first().isNotNull().extracting(AnimalData::id).isEqualTo(23), () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select * from AnimalData order by id offset #{parameters.p1} rows fetch first #{parameters.p2} rows only"), () -> assertThat(selectStatement) .extracting(SelectStatementProvider::getParameters) @@ -196,7 +196,7 @@ void testLimitOnlyAfterOrderBy() { assertAll( () -> assertThat(records).hasSize(3), - () -> assertThat(records).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1), + () -> assertThat(records).first().isNotNull().extracting(AnimalData::id).isEqualTo(1), () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select * from AnimalData order by id fetch first #{parameters.p1} rows only"), () -> assertThat(selectStatement.getParameters()).containsEntry("p1", 3L) ); diff --git a/src/test/java/examples/animal/data/LimitAndOffsetTest.java b/src/test/java/examples/animal/data/LimitAndOffsetTest.java index a5ffc67e5..9569d0751 100644 --- a/src/test/java/examples/animal/data/LimitAndOffsetTest.java +++ b/src/test/java/examples/animal/data/LimitAndOffsetTest.java @@ -79,7 +79,7 @@ void testLimitAndOffsetAfterFrom() { assertAll( () -> assertThat(records).hasSize(3), - () -> assertThat(records).first().isNotNull().extracting(AnimalData::getId).isEqualTo(23), + () -> assertThat(records).first().isNotNull().extracting(AnimalData::id).isEqualTo(23), () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select * from AnimalData limit #{parameters.p1} offset #{parameters.p2}"), () -> assertThat(selectStatement.getParameters()).containsEntry("p1", 3L), () -> assertThat(selectStatement.getParameters()).containsEntry("p2", 22L) @@ -101,7 +101,7 @@ void testLimitOnlyAfterFrom() { assertAll( () -> assertThat(records).hasSize(3), - () -> assertThat(records).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1), + () -> assertThat(records).first().isNotNull().extracting(AnimalData::id).isEqualTo(1), () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select * from AnimalData limit #{parameters.p1}"), () -> assertThat(selectStatement.getParameters()).containsEntry("p1", 3L) ); @@ -122,7 +122,7 @@ void testOffsetOnlyAfterFrom() { assertAll( () -> assertThat(records).hasSize(43), - () -> assertThat(records).first().isNotNull().extracting(AnimalData::getId).isEqualTo(23), + () -> assertThat(records).first().isNotNull().extracting(AnimalData::id).isEqualTo(23), () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select * from AnimalData offset #{parameters.p1} rows"), () -> assertThat(selectStatement.getParameters()).containsEntry("p1", 22L) ); @@ -146,7 +146,7 @@ void testLimitAndOffsetAfterWhere() { assertAll( () -> assertThat(records).hasSize(3), - () -> assertThat(records).first().isNotNull().extracting(AnimalData::getId).isEqualTo(45), + () -> assertThat(records).first().isNotNull().extracting(AnimalData::id).isEqualTo(45), () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select * from AnimalData where id < #{parameters.p1,jdbcType=INTEGER} and id > #{parameters.p2,jdbcType=INTEGER} limit #{parameters.p3} offset #{parameters.p4}"), () -> assertThat(selectStatement.getParameters()).containsEntry("p3", 3L), () -> assertThat(selectStatement.getParameters()).containsEntry("p4", 22L) @@ -169,7 +169,7 @@ void testLimitOnlyAfterWhere() { assertAll( () -> assertThat(records).hasSize(3), - () -> assertThat(records).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1), + () -> assertThat(records).first().isNotNull().extracting(AnimalData::id).isEqualTo(1), () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select * from AnimalData where id < #{parameters.p1,jdbcType=INTEGER} limit #{parameters.p2}"), () -> assertThat(selectStatement.getParameters()).containsEntry("p2", 3L) ); @@ -191,7 +191,7 @@ void testOffsetOnlyAfterWhere() { assertAll( () -> assertThat(records).hasSize(27), - () -> assertThat(records).first().isNotNull().extracting(AnimalData::getId).isEqualTo(23), + () -> assertThat(records).first().isNotNull().extracting(AnimalData::id).isEqualTo(23), () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select * from AnimalData where id < #{parameters.p1,jdbcType=INTEGER} offset #{parameters.p2} rows"), () -> assertThat(selectStatement.getParameters()).containsEntry("p2", 22L) ); @@ -214,7 +214,7 @@ void testLimitAndOffsetAfterOrderBy() { assertAll( () -> assertThat(records).hasSize(3), - () -> assertThat(records).first().isNotNull().extracting(AnimalData::getId).isEqualTo(23), + () -> assertThat(records).first().isNotNull().extracting(AnimalData::id).isEqualTo(23), () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select * from AnimalData order by id limit #{parameters.p1} offset #{parameters.p2}"), () -> assertThat(selectStatement.getParameters()).containsEntry("p1", 3L), () -> assertThat(selectStatement.getParameters()).containsEntry("p2", 22L) @@ -237,7 +237,7 @@ void testLimitOnlyAfterOrderBy() { assertAll( () -> assertThat(records).hasSize(3), - () -> assertThat(records).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1), + () -> assertThat(records).first().isNotNull().extracting(AnimalData::id).isEqualTo(1), () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select * from AnimalData order by id limit #{parameters.p1}"), () -> assertThat(selectStatement.getParameters()).containsEntry("p1", 3L) ); @@ -259,7 +259,7 @@ void testOffsetOnlyAfterOrderBy() { assertAll( () -> assertThat(records).hasSize(43), - () -> assertThat(records).first().isNotNull().extracting(AnimalData::getId).isEqualTo(23), + () -> assertThat(records).first().isNotNull().extracting(AnimalData::id).isEqualTo(23), () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select * from AnimalData order by id offset #{parameters.p1} rows"), () -> assertThat(selectStatement.getParameters()).containsEntry("p1", 22L) ); diff --git a/src/test/java/examples/animal/data/MyInCondition.java b/src/test/java/examples/animal/data/MyInCondition.java index e31782dbc..7203e4fb5 100644 --- a/src/test/java/examples/animal/data/MyInCondition.java +++ b/src/test/java/examples/animal/data/MyInCondition.java @@ -19,14 +19,15 @@ import java.util.Objects; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.SqlBuilder; import org.mybatis.dynamic.sql.where.condition.IsIn; public class MyInCondition { - public static IsIn isIn(String...values) { + public static IsIn isIn(@Nullable String...values) { return SqlBuilder.isIn(values) .filter(Objects::nonNull) - .map((String::trim)) + .map(String::trim) .filter(not(String::isEmpty)); } } diff --git a/src/test/java/examples/animal/data/OptionalConditionsAnimalDataTest.java b/src/test/java/examples/animal/data/OptionalConditionsAnimalDataTest.java index f09c2544e..166c21a05 100644 --- a/src/test/java/examples/animal/data/OptionalConditionsAnimalDataTest.java +++ b/src/test/java/examples/animal/data/OptionalConditionsAnimalDataTest.java @@ -80,8 +80,8 @@ void testAllIgnored() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData order by id"), () -> assertThat(animals).hasSize(65), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1), - () -> assertThat(animals).element(1).isNotNull().extracting(AnimalData::getId).isEqualTo(2) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1), + () -> assertThat(animals).element(1).isNotNull().extracting(AnimalData::id).isEqualTo(2) ); } } @@ -102,8 +102,8 @@ void testIgnoredBetweenRendered() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id = #{parameters.p1,jdbcType=INTEGER} or id = #{parameters.p2,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(2), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(3), - () -> assertThat(animals).element(1).isNotNull().extracting(AnimalData::getId).isEqualTo(4) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(3), + () -> assertThat(animals).element(1).isNotNull().extracting(AnimalData::id).isEqualTo(4) ); } } @@ -124,8 +124,8 @@ void testIgnoredInWhere() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id = #{parameters.p1,jdbcType=INTEGER} or id = #{parameters.p2,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(2), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(3), - () -> assertThat(animals).element(1).isNotNull().extracting(AnimalData::getId).isEqualTo(4) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(3), + () -> assertThat(animals).element(1).isNotNull().extracting(AnimalData::id).isEqualTo(4) ); } } @@ -147,8 +147,8 @@ void testManyIgnored() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id = #{parameters.p1,jdbcType=INTEGER} or id = #{parameters.p2,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(2), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(3), - () -> assertThat(animals).element(1).isNotNull().extracting(AnimalData::getId).isEqualTo(4) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(3), + () -> assertThat(animals).element(1).isNotNull().extracting(AnimalData::id).isEqualTo(4) ); } } @@ -168,8 +168,8 @@ void testIgnoredInitialWhere() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id = #{parameters.p1,jdbcType=INTEGER} or id = #{parameters.p2,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(2), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(3), - () -> assertThat(animals).element(1).isNotNull().extracting(AnimalData::getId).isEqualTo(4) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(3), + () -> assertThat(animals).element(1).isNotNull().extracting(AnimalData::id).isEqualTo(4) ); } } @@ -188,7 +188,7 @@ void testEqualWhenPresentWithValue() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id = #{parameters.p1,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(1), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(4) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(4) ); } } @@ -208,7 +208,7 @@ void testEqualWhenPresentWithoutValue() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id <= #{parameters.p1,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(10), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -228,7 +228,7 @@ void testNotEqualWhenPresentWithValue() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id <> #{parameters.p1,jdbcType=INTEGER} and id <= #{parameters.p2,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(9), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -248,7 +248,7 @@ void testNotEqualWhenPresentWithoutValue() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id <= #{parameters.p1,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(10), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -268,7 +268,7 @@ void testGreaterThanWhenPresentWithValue() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id > #{parameters.p1,jdbcType=INTEGER} and id <= #{parameters.p2,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(6), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(5) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(5) ); } } @@ -288,7 +288,7 @@ void testGreaterThanWhenPresentWithoutValue() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id <= #{parameters.p1,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(10), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -308,7 +308,7 @@ void testGreaterThanOrEqualToWhenPresentWithValue() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id >= #{parameters.p1,jdbcType=INTEGER} and id <= #{parameters.p2,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(7), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(4) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(4) ); } } @@ -328,7 +328,7 @@ void testGreaterThanOrEqualToWhenPresentWithoutValue() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id <= #{parameters.p1,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(10), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -347,7 +347,7 @@ void testLessThanWhenPresentWithValue() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id < #{parameters.p1,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(3), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -367,7 +367,7 @@ void testLessThanWhenPresentWithoutValue() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id <= #{parameters.p1,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(10), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -386,7 +386,7 @@ void testLessThanOrEqualToWhenPresentWithValue() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id <= #{parameters.p1,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(4), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -406,7 +406,7 @@ void testLessThanOrEqualToWhenPresentWithoutValue() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id <= #{parameters.p1,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(10), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -425,7 +425,7 @@ void testIsInWhenPresentWithValue() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id in (#{parameters.p1,jdbcType=INTEGER},#{parameters.p2,jdbcType=INTEGER},#{parameters.p3,jdbcType=INTEGER}) order by id"), () -> assertThat(animals).hasSize(3), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(4) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(4) ); } } @@ -444,7 +444,7 @@ void testIsInWhenPresentWithSomeValues() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id in (#{parameters.p1,jdbcType=INTEGER},#{parameters.p2,jdbcType=INTEGER}) order by id"), () -> assertThat(animals).hasSize(2), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(3) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(3) ); } } @@ -464,7 +464,7 @@ void testIsInWhenPresentWithNoValues() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id <= #{parameters.p1,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(10), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -483,7 +483,7 @@ void testIsInCaseInsensitiveWhenPresentWithValue() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where upper(animal_name) in (#{parameters.p1,jdbcType=VARCHAR},#{parameters.p2,jdbcType=VARCHAR}) order by id"), () -> assertThat(animals).hasSize(2), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(4) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(4) ); } } @@ -502,7 +502,7 @@ void testIsInCaseInsensitiveWhenPresentWithSomeValues() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where upper(animal_name) in (#{parameters.p1,jdbcType=VARCHAR},#{parameters.p2,jdbcType=VARCHAR}) order by id"), () -> assertThat(animals).hasSize(2), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(4) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(4) ); } } @@ -522,7 +522,7 @@ void testIsInCaseInsensitiveWhenPresentWithNoValues() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id <= #{parameters.p1,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(10), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -542,7 +542,7 @@ void testIsNotInWhenPresentWithValue() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id not in (#{parameters.p1,jdbcType=INTEGER},#{parameters.p2,jdbcType=INTEGER},#{parameters.p3,jdbcType=INTEGER}) and id <= #{parameters.p4,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(7), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -562,7 +562,7 @@ void testIsNotInWhenPresentWithSomeValues() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id not in (#{parameters.p1,jdbcType=INTEGER},#{parameters.p2,jdbcType=INTEGER}) and id <= #{parameters.p3,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(8), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -582,7 +582,7 @@ void testIsNotInWhenPresentWithNoValues() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id <= #{parameters.p1,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(10), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -602,7 +602,7 @@ void testIsNotInCaseInsensitiveWhenPresentWithValue() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where upper(animal_name) not in (#{parameters.p1,jdbcType=VARCHAR},#{parameters.p2,jdbcType=VARCHAR}) and id <= #{parameters.p3,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(8), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -622,7 +622,7 @@ void testIsNotInCaseInsensitiveWhenPresentWithSomeValues() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where upper(animal_name) not in (#{parameters.p1,jdbcType=VARCHAR},#{parameters.p2,jdbcType=VARCHAR}) and id <= #{parameters.p3,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(8), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -642,7 +642,7 @@ void testIsNotInCaseInsensitiveWhenPresentWithNoValues() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id <= #{parameters.p1,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(10), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -661,7 +661,7 @@ void testIsBetweenWhenPresentWithValues() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id between #{parameters.p1,jdbcType=INTEGER} and #{parameters.p2,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(4), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(3) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(3) ); } } @@ -681,7 +681,7 @@ void testIsBetweenWhenPresentWithFirstMissing() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id <= #{parameters.p1,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(10), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -701,7 +701,7 @@ void testIsBetweenWhenPresentWithSecondMissing() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id <= #{parameters.p1,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(10), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -721,7 +721,7 @@ void testIsBetweenWhenPresentWithBothMissing() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id <= #{parameters.p1,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(10), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -741,7 +741,7 @@ void testIsNotBetweenWhenPresentWithValues() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id not between #{parameters.p1,jdbcType=INTEGER} and #{parameters.p2,jdbcType=INTEGER} and id <= #{parameters.p3,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(6), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -761,7 +761,7 @@ void testIsNotBetweenWhenPresentWithFirstMissing() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id <= #{parameters.p1,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(10), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -781,7 +781,7 @@ void testIsNotBetweenWhenPresentWithSecondMissing() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id <= #{parameters.p1,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(10), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -801,7 +801,7 @@ void testIsNotBetweenWhenPresentWithBothMissing() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id <= #{parameters.p1,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(10), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -821,7 +821,7 @@ void testIsLikeWhenPresentWithValue() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where animal_name like #{parameters.p1,jdbcType=VARCHAR} and id <= #{parameters.p2,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(2), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(6) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(6) ); } } @@ -841,7 +841,7 @@ void testIsLikeWhenPresentWithoutValue() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id <= #{parameters.p1,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(10), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -861,7 +861,7 @@ void testIsLikeCaseInsensitiveWhenPresentWithValue() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where upper(animal_name) like #{parameters.p1,jdbcType=VARCHAR} and id <= #{parameters.p2,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(2), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(6) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(6) ); } } @@ -881,7 +881,7 @@ void testIsLikeCaseInsensitiveWhenPresentWithoutValue() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id <= #{parameters.p1,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(10), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -901,7 +901,7 @@ void testIsNotLikeWhenPresentWithValue() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where animal_name not like #{parameters.p1,jdbcType=VARCHAR} and id <= #{parameters.p2,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(8), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -921,7 +921,7 @@ void testIsNotLikeWhenPresentWithoutValue() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id <= #{parameters.p1,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(10), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -941,7 +941,7 @@ void testIsNotLikeCaseInsensitiveWhenPresentWithValue() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where upper(animal_name) not like #{parameters.p1,jdbcType=VARCHAR} and id <= #{parameters.p2,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(8), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -961,7 +961,7 @@ void testIsNotLikeCaseInsensitiveWhenPresentWithoutValue() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id <= #{parameters.p1,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(10), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } diff --git a/src/test/java/examples/animal/data/OptionalConditionsWithPredicatesAnimalDataTest.java b/src/test/java/examples/animal/data/OptionalConditionsWithPredicatesAnimalDataTest.java index a46190941..2ed08cad7 100644 --- a/src/test/java/examples/animal/data/OptionalConditionsWithPredicatesAnimalDataTest.java +++ b/src/test/java/examples/animal/data/OptionalConditionsWithPredicatesAnimalDataTest.java @@ -40,6 +40,7 @@ import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mybatis.dynamic.sql.render.RenderingStrategies; @@ -50,7 +51,7 @@ class OptionalConditionsWithPredicatesAnimalDataTest { private static final String JDBC_URL = "jdbc:hsqldb:mem:aname"; private static final String JDBC_DRIVER = "org.hsqldb.jdbcDriver"; - private static final Integer NULL_INTEGER = null; + private static final @Nullable Integer NULL_INTEGER = null; private SqlSessionFactory sqlSessionFactory; @@ -78,7 +79,7 @@ void testAllIgnored() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isGreaterThan(NULL_INTEGER).filter(Objects::nonNull)) // the where clause should not render + .where(id, isGreaterThanWhenPresent(NULL_INTEGER)) // the where clause should not render .orderBy(id) .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) .build() @@ -87,8 +88,8 @@ void testAllIgnored() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData order by id"), () -> assertThat(animals).hasSize(65), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1), - () -> assertThat(animals).element(1).isNotNull().extracting(AnimalData::getId).isEqualTo(2) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1), + () -> assertThat(animals).element(1).isNotNull().extracting(AnimalData::id).isEqualTo(2) ); } } @@ -120,7 +121,7 @@ void testIgnoredBetweenRendered() { SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) .where(id, isEqualTo(3)) - .and(id, isNotEqualTo(NULL_INTEGER).filter(Objects::nonNull)) + .and(id, isNotEqualToWhenPresent(NULL_INTEGER)) .or(id, isEqualTo(4).filter(Objects::nonNull)) .orderBy(id) .build() @@ -129,8 +130,8 @@ void testIgnoredBetweenRendered() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id = #{parameters.p1,jdbcType=INTEGER} or id = #{parameters.p2,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(2), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(3), - () -> assertThat(animals).element(1).isNotNull().extracting(AnimalData::getId).isEqualTo(4) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(3), + () -> assertThat(animals).element(1).isNotNull().extracting(AnimalData::id).isEqualTo(4) ); } } @@ -141,7 +142,7 @@ void testIgnoredInWhere() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isLessThan(NULL_INTEGER).filter(Objects::nonNull)) + .where(id, isLessThanWhenPresent(NULL_INTEGER)) .and(id, isEqualTo(3).filter(Objects::nonNull)) .or(id, isEqualTo(4).filter(Objects::nonNull)) .orderBy(id) @@ -151,8 +152,8 @@ void testIgnoredInWhere() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id = #{parameters.p1,jdbcType=INTEGER} or id = #{parameters.p2,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(2), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(3), - () -> assertThat(animals).element(1).isNotNull().extracting(AnimalData::getId).isEqualTo(4) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(3), + () -> assertThat(animals).element(1).isNotNull().extracting(AnimalData::id).isEqualTo(4) ); } } @@ -163,10 +164,10 @@ void testManyIgnored() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isLessThan(NULL_INTEGER).filter(Objects::nonNull), and(id, isGreaterThanOrEqualTo(NULL_INTEGER).filter(Objects::nonNull))) - .and(id, isEqualTo(NULL_INTEGER).filter(Objects::nonNull), or(id, isEqualTo(3), and(id, isLessThan(NULL_INTEGER).filter(Objects::nonNull)))) - .or(id, isEqualTo(4).filter(Objects::nonNull), and(id, isGreaterThanOrEqualTo(NULL_INTEGER).filter(Objects::nonNull))) - .and(id, isNotEqualTo(NULL_INTEGER).filter(Objects::nonNull)) + .where(id, isLessThanWhenPresent(NULL_INTEGER), and(id, isGreaterThanOrEqualToWhenPresent(NULL_INTEGER))) + .and(id, isEqualToWhenPresent(NULL_INTEGER), or(id, isEqualTo(3), and(id, isLessThanWhenPresent(NULL_INTEGER)))) + .or(id, isEqualToWhenPresent(4), and(id, isGreaterThanOrEqualToWhenPresent(NULL_INTEGER))) + .and(id, isNotEqualToWhenPresent(NULL_INTEGER)) .orderBy(id) .build() .render(RenderingStrategies.MYBATIS3); @@ -174,8 +175,8 @@ void testManyIgnored() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id = #{parameters.p1,jdbcType=INTEGER} or id = #{parameters.p2,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(2), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(3), - () -> assertThat(animals).element(1).isNotNull().extracting(AnimalData::getId).isEqualTo(4) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(3), + () -> assertThat(animals).element(1).isNotNull().extracting(AnimalData::id).isEqualTo(4) ); } } @@ -186,7 +187,7 @@ void testIgnoredInitialWhere() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isLessThan(NULL_INTEGER).filter(Objects::nonNull), and(id, isEqualTo(3).filter(Objects::nonNull))) + .where(id, isLessThanWhenPresent(NULL_INTEGER), and(id, isEqualTo(3).filter(Objects::nonNull))) .or(id, isEqualTo(4).filter(Objects::nonNull)) .orderBy(id) .build() @@ -195,8 +196,8 @@ void testIgnoredInitialWhere() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id = #{parameters.p1,jdbcType=INTEGER} or id = #{parameters.p2,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(2), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(3), - () -> assertThat(animals).element(1).isNotNull().extracting(AnimalData::getId).isEqualTo(4) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(3), + () -> assertThat(animals).element(1).isNotNull().extracting(AnimalData::id).isEqualTo(4) ); } } @@ -215,7 +216,7 @@ void testEqualWhenWithValue() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id = #{parameters.p1,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(1), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(4) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(4) ); } } @@ -226,7 +227,7 @@ void testEqualWhenWithoutValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isEqualTo(NULL_INTEGER).filter(Objects::nonNull)) + .where(id, isEqualToWhenPresent(NULL_INTEGER)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -235,7 +236,7 @@ void testEqualWhenWithoutValue() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id <= #{parameters.p1,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(10), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -255,7 +256,7 @@ void testNotEqualWhenWithValue() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id <> #{parameters.p1,jdbcType=INTEGER} and id <= #{parameters.p2,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(9), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -266,7 +267,7 @@ void testNotEqualWhenWithoutValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isNotEqualTo(NULL_INTEGER).filter(Objects::nonNull)) + .where(id, isNotEqualToWhenPresent(NULL_INTEGER)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -275,7 +276,7 @@ void testNotEqualWhenWithoutValue() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id <= #{parameters.p1,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(10), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -295,7 +296,7 @@ void testGreaterThanWhenWithValue() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id > #{parameters.p1,jdbcType=INTEGER} and id <= #{parameters.p2,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(6), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(5) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(5) ); } } @@ -306,7 +307,7 @@ void testGreaterThanWhenWithoutValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isGreaterThan(NULL_INTEGER).filter(Objects::nonNull)) + .where(id, isGreaterThanWhenPresent(NULL_INTEGER)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -315,7 +316,7 @@ void testGreaterThanWhenWithoutValue() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id <= #{parameters.p1,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(10), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -335,7 +336,7 @@ void testGreaterThanOrEqualToWhenWithValue() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id >= #{parameters.p1,jdbcType=INTEGER} and id <= #{parameters.p2,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(7), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(4) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(4) ); } } @@ -346,7 +347,7 @@ void testGreaterThanOrEqualToWhenWithoutValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isGreaterThanOrEqualTo(NULL_INTEGER).filter(Objects::nonNull)) + .where(id, isGreaterThanOrEqualToWhenPresent(NULL_INTEGER)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -355,7 +356,7 @@ void testGreaterThanOrEqualToWhenWithoutValue() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id <= #{parameters.p1,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(10), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -374,7 +375,7 @@ void testLessThanWhenWithValue() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id < #{parameters.p1,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(3), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -385,7 +386,7 @@ void testLessThanWhenWithoutValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isLessThan(NULL_INTEGER).filter(Objects::nonNull)) + .where(id, isLessThanWhenPresent(NULL_INTEGER)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -394,7 +395,7 @@ void testLessThanWhenWithoutValue() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id <= #{parameters.p1,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(10), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -413,7 +414,7 @@ void testLessThanOrEqualToWhenWithValue() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id <= #{parameters.p1,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(4), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -424,7 +425,7 @@ void testLessThanOrEqualToWhenWithoutValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isLessThanOrEqualTo(NULL_INTEGER).filter(Objects::nonNull)) + .where(id, isLessThanOrEqualToWhenPresent(NULL_INTEGER)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -433,7 +434,7 @@ void testLessThanOrEqualToWhenWithoutValue() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id <= #{parameters.p1,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(10), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -452,7 +453,7 @@ void testIsInWhenWithValue() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id in (#{parameters.p1,jdbcType=INTEGER},#{parameters.p2,jdbcType=INTEGER},#{parameters.p3,jdbcType=INTEGER}) order by id"), () -> assertThat(animals).hasSize(3), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(4) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(4) ); } } @@ -463,7 +464,7 @@ void testIsInWhenWithSomeValues() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isIn(3, NULL_INTEGER, 5).filter(Objects::nonNull).map(i -> i + 3)) + .where(id, isInWhenPresent(3, NULL_INTEGER, 5).map(i -> i + 3)) .orderBy(id) .build() .render(RenderingStrategies.MYBATIS3); @@ -471,8 +472,8 @@ void testIsInWhenWithSomeValues() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id in (#{parameters.p1,jdbcType=INTEGER},#{parameters.p2,jdbcType=INTEGER}) order by id"), () -> assertThat(animals).hasSize(2), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(6), - () -> assertThat(animals).element(1).isNotNull().extracting(AnimalData::getId).isEqualTo(8) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(6), + () -> assertThat(animals).element(1).isNotNull().extracting(AnimalData::id).isEqualTo(8) ); } } @@ -491,7 +492,7 @@ void testIsInCaseInsensitiveWhenWithValue() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where upper(animal_name) in (#{parameters.p1,jdbcType=VARCHAR},#{parameters.p2,jdbcType=VARCHAR}) order by id"), () -> assertThat(animals).hasSize(2), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(4) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(4) ); } } @@ -504,8 +505,8 @@ void testValueStreamTransformer() { .from(animalData) .where(animalName, isIn(" Mouse", " ", null, "", "Musk shrew ") .filter(Objects::nonNull) - .map(String::trim) - .filter(not(String::isEmpty))) + .map(String::trim) + .filter(not(String::isEmpty))) .orderBy(id) .build() .render(RenderingStrategies.MYBATIS3); @@ -513,7 +514,7 @@ void testValueStreamTransformer() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where animal_name in (#{parameters.p1,jdbcType=VARCHAR},#{parameters.p2,jdbcType=VARCHAR}) order by id"), () -> assertThat(animals).hasSize(2), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(4) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(4) ); } } @@ -532,7 +533,7 @@ void testValueStreamTransformerWithCustomCondition() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where animal_name in (#{parameters.p1,jdbcType=VARCHAR},#{parameters.p2,jdbcType=VARCHAR}) order by id"), () -> assertThat(animals).hasSize(2), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(4) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(4) ); } } @@ -552,7 +553,7 @@ void testIsInCaseInsensitiveWhenWithNoValues() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id <= #{parameters.p1,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(10), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -572,7 +573,7 @@ void testIsNotInWhenWithValue() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id not in (#{parameters.p1,jdbcType=INTEGER},#{parameters.p2,jdbcType=INTEGER},#{parameters.p3,jdbcType=INTEGER}) and id <= #{parameters.p4,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(7), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -583,7 +584,7 @@ void testIsNotInWhenWithSomeValues() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isNotIn(3, NULL_INTEGER, 5).filter(Objects::nonNull)) + .where(id, isNotInWhenPresent(3, NULL_INTEGER, 5)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -592,7 +593,7 @@ void testIsNotInWhenWithSomeValues() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id not in (#{parameters.p1,jdbcType=INTEGER},#{parameters.p2,jdbcType=INTEGER}) and id <= #{parameters.p3,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(8), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -612,7 +613,7 @@ void testIsNotInCaseInsensitiveWhenWithValue() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where upper(animal_name) not in (#{parameters.p1,jdbcType=VARCHAR},#{parameters.p2,jdbcType=VARCHAR}) and id <= #{parameters.p3,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(8), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -632,7 +633,7 @@ void testIsNotInCaseInsensitiveWhenWithNoValues() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id <= #{parameters.p1,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(10), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -651,7 +652,7 @@ void testIsBetweenWhenWithValues() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id between #{parameters.p1,jdbcType=INTEGER} and #{parameters.p2,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(4), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(3) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(3) ); } } @@ -662,7 +663,7 @@ void testIsBetweenWhenWithFirstMissing() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isBetween(NULL_INTEGER).and(6).filter(Predicates.bothPresent())) + .where(id, isBetweenWhenPresent(NULL_INTEGER).and(6)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -671,7 +672,7 @@ void testIsBetweenWhenWithFirstMissing() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id <= #{parameters.p1,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(10), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -682,7 +683,7 @@ void testIsBetweenWhenWithSecondMissing() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isBetween(3).and(NULL_INTEGER).filter(Predicates.bothPresent())) + .where(id, isBetweenWhenPresent(3).and(NULL_INTEGER)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -691,7 +692,7 @@ void testIsBetweenWhenWithSecondMissing() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id <= #{parameters.p1,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(10), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -702,7 +703,7 @@ void testIsBetweenWhenWithBothMissing() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isBetween(NULL_INTEGER).and(NULL_INTEGER).filter(Predicates.bothPresent())) + .where(id, isBetweenWhenPresent(NULL_INTEGER).and(NULL_INTEGER)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -711,7 +712,7 @@ void testIsBetweenWhenWithBothMissing() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id <= #{parameters.p1,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(10), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -731,7 +732,7 @@ void testIsNotBetweenWhenWithValues() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id not between #{parameters.p1,jdbcType=INTEGER} and #{parameters.p2,jdbcType=INTEGER} and id <= #{parameters.p3,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(6), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -742,7 +743,7 @@ void testIsNotBetweenWhenWithFirstMissing() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isNotBetween(NULL_INTEGER).and(6).filter(Predicates.bothPresent())) + .where(id, isNotBetweenWhenPresent(NULL_INTEGER).and(6)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -751,7 +752,7 @@ void testIsNotBetweenWhenWithFirstMissing() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id <= #{parameters.p1,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(10), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -762,7 +763,7 @@ void testIsNotBetweenWhenWithSecondMissing() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isNotBetween(3).and(NULL_INTEGER).filter(Predicates.bothPresent())) + .where(id, isNotBetweenWhenPresent(3).and(NULL_INTEGER)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -771,7 +772,7 @@ void testIsNotBetweenWhenWithSecondMissing() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id <= #{parameters.p1,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(10), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -782,7 +783,7 @@ void testIsNotBetweenWhenWithBothMissing() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isNotBetween(NULL_INTEGER).and(NULL_INTEGER).filter(Predicates.bothPresent())) + .where(id, isNotBetweenWhenPresent(NULL_INTEGER).and(NULL_INTEGER)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -791,7 +792,7 @@ void testIsNotBetweenWhenWithBothMissing() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id <= #{parameters.p1,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(10), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -811,7 +812,7 @@ void testIsLikeWhenWithValue() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where animal_name like #{parameters.p1,jdbcType=VARCHAR} and id <= #{parameters.p2,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(2), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(6) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(6) ); } } @@ -822,7 +823,7 @@ void testIsLikeWhenWithoutValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(animalName, isLike((String) null).filter(Objects::nonNull)) + .where(animalName, isLikeWhenPresent((String) null)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -831,7 +832,7 @@ void testIsLikeWhenWithoutValue() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id <= #{parameters.p1,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(10), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -842,7 +843,7 @@ void testIsLikeCaseInsensitiveWhenWithValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(animalName, isLikeCaseInsensitive("%MoLe").filter(Objects::nonNull)) + .where(animalName, isLikeCaseInsensitive("%MoLe")) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -851,7 +852,7 @@ void testIsLikeCaseInsensitiveWhenWithValue() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where upper(animal_name) like #{parameters.p1,jdbcType=VARCHAR} and id <= #{parameters.p2,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(2), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(6) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(6) ); } } @@ -862,7 +863,7 @@ void testIsLikeCaseInsensitiveWhenWithoutValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(animalName, isLikeCaseInsensitive((String) null).filter(Objects::nonNull)) + .where(animalName, isLikeCaseInsensitiveWhenPresent((String) null)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -871,7 +872,7 @@ void testIsLikeCaseInsensitiveWhenWithoutValue() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id <= #{parameters.p1,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(10), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -891,7 +892,7 @@ void testIsNotLikeWhenWithValue() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where animal_name not like #{parameters.p1,jdbcType=VARCHAR} and id <= #{parameters.p2,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(8), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -902,7 +903,7 @@ void testIsNotLikeWhenWithoutValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(animalName, isNotLike((String) null).filter(Objects::nonNull)) + .where(animalName, isNotLikeWhenPresent((String) null)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -911,7 +912,7 @@ void testIsNotLikeWhenWithoutValue() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id <= #{parameters.p1,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(10), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -922,7 +923,7 @@ void testIsNotLikeCaseInsensitiveWhenWithValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(animalName, isNotLikeCaseInsensitive("%MoLe").filter(Objects::nonNull)) + .where(animalName, isNotLikeCaseInsensitive("%MoLe")) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -931,7 +932,7 @@ void testIsNotLikeCaseInsensitiveWhenWithValue() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where upper(animal_name) not like #{parameters.p1,jdbcType=VARCHAR} and id <= #{parameters.p2,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(8), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } @@ -942,7 +943,7 @@ void testIsNotLikeCaseInsensitiveWhenWithoutValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(animalName, isNotLikeCaseInsensitive((String) null).filter(Objects::nonNull)) + .where(animalName, isNotLikeCaseInsensitiveWhenPresent((String) null)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -951,7 +952,7 @@ void testIsNotLikeCaseInsensitiveWhenWithoutValue() { assertAll( () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id <= #{parameters.p1,jdbcType=INTEGER} order by id"), () -> assertThat(animals).hasSize(10), - () -> assertThat(animals).first().isNotNull().extracting(AnimalData::getId).isEqualTo(1) + () -> assertThat(animals).first().isNotNull().extracting(AnimalData::id).isEqualTo(1) ); } } diff --git a/src/test/java/examples/animal/data/package-info.java b/src/test/java/examples/animal/data/package-info.java new file mode 100644 index 000000000..0b0ff393f --- /dev/null +++ b/src/test/java/examples/animal/data/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright 2016-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@NullMarked +package examples.animal.data; + +import org.jspecify.annotations.NullMarked; diff --git a/src/test/java/examples/paging/LimitAndOffsetMapper.java b/src/test/java/examples/paging/LimitAndOffsetMapper.java index 84146d8b9..14bd2d8b0 100644 --- a/src/test/java/examples/paging/LimitAndOffsetMapper.java +++ b/src/test/java/examples/paging/LimitAndOffsetMapper.java @@ -19,8 +19,7 @@ import java.util.List; -import org.apache.ibatis.annotations.Result; -import org.apache.ibatis.annotations.Results; +import org.apache.ibatis.annotations.Arg; import org.apache.ibatis.annotations.SelectProvider; import org.mybatis.dynamic.sql.select.QueryExpressionDSL; import org.mybatis.dynamic.sql.select.SelectDSL; @@ -32,12 +31,10 @@ public interface LimitAndOffsetMapper { @SelectProvider(type=SqlProviderAdapter.class, method="select") - @Results(id="AnimalDataResult", value={ - @Result(column="id", property="id", id=true), - @Result(column="animal_name", property="animalName"), - @Result(column="brain_weight", property="brainWeight"), - @Result(column="body_weight", property="bodyWeight") - }) + @Arg(column = "id", javaType = int.class, id = true) + @Arg(column = "animal_name", javaType = String.class) + @Arg(column = "brain_weight", javaType = double.class) + @Arg(column = "body_weight", javaType = double.class) List selectMany(SelectStatementProvider selectStatement); default QueryExpressionDSL>> selectWithLimitAndOffset(int limit, int offset) { diff --git a/src/test/java/examples/paging/LimitAndOffsetTest.java b/src/test/java/examples/paging/LimitAndOffsetTest.java index e145568d4..6e8d68ae1 100644 --- a/src/test/java/examples/paging/LimitAndOffsetTest.java +++ b/src/test/java/examples/paging/LimitAndOffsetTest.java @@ -73,7 +73,7 @@ void testLimitAndOffset() { .execute(); assertThat(rows).hasSize(5); - assertThat(rows.get(0).getId()).isEqualTo(4); + assertThat(rows.get(0).id()).isEqualTo(4); } } } diff --git a/src/test/java/examples/paging/package-info.java b/src/test/java/examples/paging/package-info.java new file mode 100644 index 000000000..c8f8f4390 --- /dev/null +++ b/src/test/java/examples/paging/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright 2016-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@NullMarked +package examples.paging; + +import org.jspecify.annotations.NullMarked; From a2fec6a935acb1bc04f00d1364ac41b40bedfc99 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Sun, 6 Apr 2025 18:16:55 -0400 Subject: [PATCH 231/289] Properly handle nullability in the when present conditions --- .../org/mybatis/dynamic/sql/SqlBuilder.java | 108 +++-- .../sql/where/condition/AndGatherer.java | 4 +- .../sql/where/condition/IsBetween.java | 20 - .../where/condition/IsBetweenWhenPresent.java | 108 +++++ .../where/condition/IsEqualToWhenPresent.java | 72 +++ .../IsGreaterThanOrEqualToWhenPresent.java | 71 +++ .../condition/IsGreaterThanWhenPresent.java | 71 +++ .../where/condition/IsInCaseInsensitive.java | 5 +- .../IsInCaseInsensitiveWhenPresent.java | 13 +- .../sql/where/condition/IsInWhenPresent.java | 12 +- .../IsLessThanOrEqualToWhenPresent.java | 71 +++ .../condition/IsLessThanWhenPresent.java | 72 +++ .../condition/IsLikeCaseInsensitive.java | 2 +- .../IsLikeCaseInsensitiveWhenPresent.java | 73 +++ .../where/condition/IsLikeWhenPresent.java | 72 +++ .../sql/where/condition/IsNotBetween.java | 21 - .../condition/IsNotBetweenWhenPresent.java | 109 +++++ .../condition/IsNotEqualToWhenPresent.java | 71 +++ .../condition/IsNotInCaseInsensitive.java | 5 +- .../IsNotInCaseInsensitiveWhenPresent.java | 13 +- .../where/condition/IsNotInWhenPresent.java | 13 +- .../condition/IsNotLikeCaseInsensitive.java | 2 +- .../IsNotLikeCaseInsensitiveWhenPresent.java | 73 +++ .../where/condition/IsNotLikeWhenPresent.java | 71 +++ .../sql/util/kotlin/elements/SqlElements.kt | 38 +- .../sql/where/condition/NullContractTest.java | 441 ++++++++++++++++++ .../sql/where/condition/SupplierTest.java | 48 +- 27 files changed, 1532 insertions(+), 147 deletions(-) create mode 100644 src/main/java/org/mybatis/dynamic/sql/where/condition/IsBetweenWhenPresent.java create mode 100644 src/main/java/org/mybatis/dynamic/sql/where/condition/IsEqualToWhenPresent.java create mode 100644 src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanOrEqualToWhenPresent.java create mode 100644 src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanWhenPresent.java create mode 100644 src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanOrEqualToWhenPresent.java create mode 100644 src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanWhenPresent.java create mode 100644 src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitiveWhenPresent.java create mode 100644 src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeWhenPresent.java create mode 100644 src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotBetweenWhenPresent.java create mode 100644 src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotEqualToWhenPresent.java create mode 100644 src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitiveWhenPresent.java create mode 100644 src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeWhenPresent.java create mode 100644 src/test/java/org/mybatis/dynamic/sql/where/condition/NullContractTest.java diff --git a/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java b/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java index 2f365de1e..9790633b0 100644 --- a/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java +++ b/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java @@ -21,6 +21,7 @@ import java.util.Objects; import java.util.function.Supplier; +import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.delete.DeleteDSL; import org.mybatis.dynamic.sql.delete.DeleteModel; @@ -62,14 +63,18 @@ import org.mybatis.dynamic.sql.util.Buildable; import org.mybatis.dynamic.sql.where.WhereDSL; import org.mybatis.dynamic.sql.where.condition.IsBetween; +import org.mybatis.dynamic.sql.where.condition.IsBetweenWhenPresent; import org.mybatis.dynamic.sql.where.condition.IsEqualTo; import org.mybatis.dynamic.sql.where.condition.IsEqualToColumn; +import org.mybatis.dynamic.sql.where.condition.IsEqualToWhenPresent; import org.mybatis.dynamic.sql.where.condition.IsEqualToWithSubselect; import org.mybatis.dynamic.sql.where.condition.IsGreaterThan; import org.mybatis.dynamic.sql.where.condition.IsGreaterThanColumn; import org.mybatis.dynamic.sql.where.condition.IsGreaterThanOrEqualTo; import org.mybatis.dynamic.sql.where.condition.IsGreaterThanOrEqualToColumn; +import org.mybatis.dynamic.sql.where.condition.IsGreaterThanOrEqualToWhenPresent; import org.mybatis.dynamic.sql.where.condition.IsGreaterThanOrEqualToWithSubselect; +import org.mybatis.dynamic.sql.where.condition.IsGreaterThanWhenPresent; import org.mybatis.dynamic.sql.where.condition.IsGreaterThanWithSubselect; import org.mybatis.dynamic.sql.where.condition.IsIn; import org.mybatis.dynamic.sql.where.condition.IsInCaseInsensitive; @@ -80,13 +85,19 @@ import org.mybatis.dynamic.sql.where.condition.IsLessThanColumn; import org.mybatis.dynamic.sql.where.condition.IsLessThanOrEqualTo; import org.mybatis.dynamic.sql.where.condition.IsLessThanOrEqualToColumn; +import org.mybatis.dynamic.sql.where.condition.IsLessThanOrEqualToWhenPresent; import org.mybatis.dynamic.sql.where.condition.IsLessThanOrEqualToWithSubselect; +import org.mybatis.dynamic.sql.where.condition.IsLessThanWhenPresent; import org.mybatis.dynamic.sql.where.condition.IsLessThanWithSubselect; import org.mybatis.dynamic.sql.where.condition.IsLike; import org.mybatis.dynamic.sql.where.condition.IsLikeCaseInsensitive; +import org.mybatis.dynamic.sql.where.condition.IsLikeCaseInsensitiveWhenPresent; +import org.mybatis.dynamic.sql.where.condition.IsLikeWhenPresent; import org.mybatis.dynamic.sql.where.condition.IsNotBetween; +import org.mybatis.dynamic.sql.where.condition.IsNotBetweenWhenPresent; import org.mybatis.dynamic.sql.where.condition.IsNotEqualTo; import org.mybatis.dynamic.sql.where.condition.IsNotEqualToColumn; +import org.mybatis.dynamic.sql.where.condition.IsNotEqualToWhenPresent; import org.mybatis.dynamic.sql.where.condition.IsNotEqualToWithSubselect; import org.mybatis.dynamic.sql.where.condition.IsNotIn; import org.mybatis.dynamic.sql.where.condition.IsNotInCaseInsensitive; @@ -95,6 +106,8 @@ import org.mybatis.dynamic.sql.where.condition.IsNotInWithSubselect; import org.mybatis.dynamic.sql.where.condition.IsNotLike; import org.mybatis.dynamic.sql.where.condition.IsNotLikeCaseInsensitive; +import org.mybatis.dynamic.sql.where.condition.IsNotLikeCaseInsensitiveWhenPresent; +import org.mybatis.dynamic.sql.where.condition.IsNotLikeWhenPresent; import org.mybatis.dynamic.sql.where.condition.IsNotNull; import org.mybatis.dynamic.sql.where.condition.IsNull; @@ -634,11 +647,11 @@ static IsEqualToColumn isEqualTo(BasicColumn column) { return IsEqualToColumn.of(column); } - static IsEqualTo isEqualToWhenPresent(@Nullable T value) { - return value == null ? IsEqualTo.empty() : IsEqualTo.of(value); + static IsEqualToWhenPresent isEqualToWhenPresent(@Nullable T value) { + return IsEqualToWhenPresent.of(value); } - static IsEqualTo isEqualToWhenPresent(Supplier<@Nullable T> valueSupplier) { + static IsEqualToWhenPresent isEqualToWhenPresent(Supplier<@Nullable T> valueSupplier) { return isEqualToWhenPresent(valueSupplier.get()); } @@ -658,11 +671,11 @@ static IsNotEqualToColumn isNotEqualTo(BasicColumn column) { return IsNotEqualToColumn.of(column); } - static IsNotEqualTo isNotEqualToWhenPresent(@Nullable T value) { - return value == null ? IsNotEqualTo.empty() : IsNotEqualTo.of(value); + static IsNotEqualToWhenPresent isNotEqualToWhenPresent(@Nullable T value) { + return IsNotEqualToWhenPresent.of(value); } - static IsNotEqualTo isNotEqualToWhenPresent(Supplier<@Nullable T> valueSupplier) { + static IsNotEqualToWhenPresent isNotEqualToWhenPresent(Supplier<@Nullable T> valueSupplier) { return isNotEqualToWhenPresent(valueSupplier.get()); } @@ -682,11 +695,11 @@ static IsGreaterThanColumn isGreaterThan(BasicColumn column) { return IsGreaterThanColumn.of(column); } - static IsGreaterThan isGreaterThanWhenPresent(@Nullable T value) { - return value == null ? IsGreaterThan.empty() : IsGreaterThan.of(value); + static IsGreaterThanWhenPresent isGreaterThanWhenPresent(@Nullable T value) { + return IsGreaterThanWhenPresent.of(value); } - static IsGreaterThan isGreaterThanWhenPresent(Supplier<@Nullable T> valueSupplier) { + static IsGreaterThanWhenPresent isGreaterThanWhenPresent(Supplier<@Nullable T> valueSupplier) { return isGreaterThanWhenPresent(valueSupplier.get()); } @@ -707,11 +720,12 @@ static IsGreaterThanOrEqualToColumn isGreaterThanOrEqualTo(BasicColumn co return IsGreaterThanOrEqualToColumn.of(column); } - static IsGreaterThanOrEqualTo isGreaterThanOrEqualToWhenPresent(@Nullable T value) { - return value == null ? IsGreaterThanOrEqualTo.empty() : IsGreaterThanOrEqualTo.of(value); + static IsGreaterThanOrEqualToWhenPresent isGreaterThanOrEqualToWhenPresent(@Nullable T value) { + return IsGreaterThanOrEqualToWhenPresent.of(value); } - static IsGreaterThanOrEqualTo isGreaterThanOrEqualToWhenPresent(Supplier<@Nullable T> valueSupplier) { + static IsGreaterThanOrEqualToWhenPresent isGreaterThanOrEqualToWhenPresent( + Supplier<@Nullable T> valueSupplier) { return isGreaterThanOrEqualToWhenPresent(valueSupplier.get()); } @@ -731,11 +745,11 @@ static IsLessThanColumn isLessThan(BasicColumn column) { return IsLessThanColumn.of(column); } - static IsLessThan isLessThanWhenPresent(@Nullable T value) { - return value == null ? IsLessThan.empty() : IsLessThan.of(value); + static IsLessThanWhenPresent isLessThanWhenPresent(@Nullable T value) { + return IsLessThanWhenPresent.of(value); } - static IsLessThan isLessThanWhenPresent(Supplier<@Nullable T> valueSupplier) { + static IsLessThanWhenPresent isLessThanWhenPresent(Supplier<@Nullable T> valueSupplier) { return isLessThanWhenPresent(valueSupplier.get()); } @@ -755,20 +769,20 @@ static IsLessThanOrEqualToColumn isLessThanOrEqualTo(BasicColumn column) return IsLessThanOrEqualToColumn.of(column); } - static IsLessThanOrEqualTo isLessThanOrEqualToWhenPresent(@Nullable T value) { - return value == null ? IsLessThanOrEqualTo.empty() : IsLessThanOrEqualTo.of(value); + static IsLessThanOrEqualToWhenPresent isLessThanOrEqualToWhenPresent(@Nullable T value) { + return IsLessThanOrEqualToWhenPresent.of(value); } - static IsLessThanOrEqualTo isLessThanOrEqualToWhenPresent(Supplier<@Nullable T> valueSupplier) { + static IsLessThanOrEqualToWhenPresent isLessThanOrEqualToWhenPresent(Supplier<@Nullable T> valueSupplier) { return isLessThanOrEqualToWhenPresent(valueSupplier.get()); } @SafeVarargs - static IsIn isIn(T... values) { + static IsIn isIn(@NonNull T... values) { return IsIn.of(values); } - static IsIn isIn(Collection values) { + static IsIn isIn(Collection<@NonNull T> values) { return IsIn.of(values); } @@ -782,15 +796,15 @@ static IsInWhenPresent isInWhenPresent(@Nullable T... values) { } static IsInWhenPresent isInWhenPresent(@Nullable Collection<@Nullable T> values) { - return values == null ? IsInWhenPresent.empty() : IsInWhenPresent.of(values); + return IsInWhenPresent.of(values); } @SafeVarargs - static IsNotIn isNotIn(T... values) { + static IsNotIn isNotIn(@NonNull T... values) { return IsNotIn.of(values); } - static IsNotIn isNotIn(Collection values) { + static IsNotIn isNotIn(Collection<@NonNull T> values) { return IsNotIn.of(values); } @@ -804,22 +818,22 @@ static IsNotInWhenPresent isNotInWhenPresent(@Nullable T... values) { } static IsNotInWhenPresent isNotInWhenPresent(@Nullable Collection<@Nullable T> values) { - return values == null ? IsNotInWhenPresent.empty() : IsNotInWhenPresent.of(values); + return IsNotInWhenPresent.of(values); } static IsBetween.Builder isBetween(T value1) { return IsBetween.isBetween(value1); } - static IsBetween.Builder isBetween(Supplier valueSupplier1) { + static IsBetween.Builder isBetween(Supplier<@NonNull T> valueSupplier1) { return isBetween(valueSupplier1.get()); } - static IsBetween.WhenPresentBuilder isBetweenWhenPresent(@Nullable T value1) { - return IsBetween.isBetweenWhenPresent(value1); + static IsBetweenWhenPresent.Builder isBetweenWhenPresent(@Nullable T value1) { + return IsBetweenWhenPresent.isBetweenWhenPresent(value1); } - static IsBetween.WhenPresentBuilder isBetweenWhenPresent(Supplier<@Nullable T> valueSupplier1) { + static IsBetweenWhenPresent.Builder isBetweenWhenPresent(Supplier<@Nullable T> valueSupplier1) { return isBetweenWhenPresent(valueSupplier1.get()); } @@ -827,15 +841,15 @@ static IsNotBetween.Builder isNotBetween(T value1) { return IsNotBetween.isNotBetween(value1); } - static IsNotBetween.Builder isNotBetween(Supplier valueSupplier1) { + static IsNotBetween.Builder isNotBetween(Supplier<@NonNull T> valueSupplier1) { return isNotBetween(valueSupplier1.get()); } - static IsNotBetween.WhenPresentBuilder isNotBetweenWhenPresent(@Nullable T value1) { - return IsNotBetween.isNotBetweenWhenPresent(value1); + static IsNotBetweenWhenPresent.Builder isNotBetweenWhenPresent(@Nullable T value1) { + return IsNotBetweenWhenPresent.isNotBetweenWhenPresent(value1); } - static IsNotBetween.WhenPresentBuilder isNotBetweenWhenPresent(Supplier<@Nullable T> valueSupplier1) { + static IsNotBetweenWhenPresent.Builder isNotBetweenWhenPresent(Supplier<@Nullable T> valueSupplier1) { return isNotBetweenWhenPresent(valueSupplier1.get()); } @@ -848,11 +862,11 @@ static IsLike isLike(Supplier valueSupplier) { return isLike(valueSupplier.get()); } - static IsLike isLikeWhenPresent(@Nullable T value) { - return value == null ? IsLike.empty() : IsLike.of(value); + static IsLikeWhenPresent isLikeWhenPresent(@Nullable T value) { + return IsLikeWhenPresent.of(value); } - static IsLike isLikeWhenPresent(Supplier<@Nullable T> valueSupplier) { + static IsLikeWhenPresent isLikeWhenPresent(Supplier<@Nullable T> valueSupplier) { return isLikeWhenPresent(valueSupplier.get()); } @@ -864,11 +878,11 @@ static IsNotLike isNotLike(Supplier valueSupplier) { return isNotLike(valueSupplier.get()); } - static IsNotLike isNotLikeWhenPresent(@Nullable T value) { - return value == null ? IsNotLike.empty() : IsNotLike.of(value); + static IsNotLikeWhenPresent isNotLikeWhenPresent(@Nullable T value) { + return IsNotLikeWhenPresent.of(value); } - static IsNotLike isNotLikeWhenPresent(Supplier<@Nullable T> valueSupplier) { + static IsNotLikeWhenPresent isNotLikeWhenPresent(Supplier<@Nullable T> valueSupplier) { return isNotLikeWhenPresent(valueSupplier.get()); } @@ -890,11 +904,12 @@ static IsLikeCaseInsensitive isLikeCaseInsensitive(Supplier valu return isLikeCaseInsensitive(valueSupplier.get()); } - static IsLikeCaseInsensitive isLikeCaseInsensitiveWhenPresent(@Nullable String value) { - return value == null ? IsLikeCaseInsensitive.empty() : IsLikeCaseInsensitive.of(value); + static IsLikeCaseInsensitiveWhenPresent isLikeCaseInsensitiveWhenPresent(@Nullable String value) { + return IsLikeCaseInsensitiveWhenPresent.of(value); } - static IsLikeCaseInsensitive isLikeCaseInsensitiveWhenPresent(Supplier<@Nullable String> valueSupplier) { + static IsLikeCaseInsensitiveWhenPresent isLikeCaseInsensitiveWhenPresent( + Supplier<@Nullable String> valueSupplier) { return isLikeCaseInsensitiveWhenPresent(valueSupplier.get()); } @@ -906,11 +921,11 @@ static IsNotLikeCaseInsensitive isNotLikeCaseInsensitive(Supplier isNotLikeCaseInsensitiveWhenPresent(@Nullable String value) { - return value == null ? IsNotLikeCaseInsensitive.empty() : IsNotLikeCaseInsensitive.of(value); + static IsNotLikeCaseInsensitiveWhenPresent isNotLikeCaseInsensitiveWhenPresent(@Nullable String value) { + return IsNotLikeCaseInsensitiveWhenPresent.of(value); } - static IsNotLikeCaseInsensitive isNotLikeCaseInsensitiveWhenPresent( + static IsNotLikeCaseInsensitiveWhenPresent isNotLikeCaseInsensitiveWhenPresent( Supplier<@Nullable String> valueSupplier) { return isNotLikeCaseInsensitiveWhenPresent(valueSupplier.get()); } @@ -929,7 +944,7 @@ static IsInCaseInsensitiveWhenPresent isInCaseInsensitiveWhenPresent(@Nu static IsInCaseInsensitiveWhenPresent isInCaseInsensitiveWhenPresent( @Nullable Collection<@Nullable String> values) { - return values == null ? IsInCaseInsensitiveWhenPresent.empty() : IsInCaseInsensitiveWhenPresent.of(values); + return IsInCaseInsensitiveWhenPresent.of(values); } static IsNotInCaseInsensitive isNotInCaseInsensitive(String... values) { @@ -946,8 +961,7 @@ static IsNotInCaseInsensitiveWhenPresent isNotInCaseInsensitiveWhenPrese static IsNotInCaseInsensitiveWhenPresent isNotInCaseInsensitiveWhenPresent( @Nullable Collection<@Nullable String> values) { - return values == null ? IsNotInCaseInsensitiveWhenPresent.empty() : - IsNotInCaseInsensitiveWhenPresent.of(values); + return IsNotInCaseInsensitiveWhenPresent.of(values); } // order by support diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/AndGatherer.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/AndGatherer.java index 8a587262a..c9514f3fa 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/AndGatherer.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/AndGatherer.java @@ -17,6 +17,8 @@ import java.util.function.Supplier; +import org.jspecify.annotations.NonNull; + /** * Utility class supporting the "and" part of a between condition. This class supports builders, so it is mutable. * @@ -38,7 +40,7 @@ public R and(T value2) { return build(value2); } - public R and(Supplier valueSupplier2) { + public R and(Supplier<@NonNull T> valueSupplier2) { return and(valueSupplier2.get()); } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsBetween.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsBetween.java index 0e6700fb0..fab5e70f6 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsBetween.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsBetween.java @@ -20,7 +20,6 @@ import java.util.function.Function; import java.util.function.Predicate; -import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.AbstractTwoValueCondition; public class IsBetween extends AbstractTwoValueCondition @@ -86,10 +85,6 @@ public static Builder isBetween(T value1) { return new Builder<>(value1); } - public static WhenPresentBuilder isBetweenWhenPresent(@Nullable T value1) { - return new WhenPresentBuilder<>(value1); - } - public static class Builder extends AndGatherer> { private Builder(T value1) { super(value1); @@ -100,19 +95,4 @@ protected IsBetween build(T value2) { return new IsBetween<>(value1, value2); } } - - public static class WhenPresentBuilder extends AndWhenPresentGatherer> { - private WhenPresentBuilder(@Nullable T value1) { - super(value1); - } - - @Override - protected IsBetween build(@Nullable T value2) { - if (value1 == null || value2 == null) { - return empty(); - } else { - return new IsBetween<>(value1, value2); - } - } - } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsBetweenWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsBetweenWhenPresent.java new file mode 100644 index 000000000..8c23cdfbb --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsBetweenWhenPresent.java @@ -0,0 +1,108 @@ +/* + * Copyright 2016-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mybatis.dynamic.sql.where.condition; + +import java.util.NoSuchElementException; +import java.util.function.BiPredicate; +import java.util.function.Function; +import java.util.function.Predicate; + +import org.jspecify.annotations.Nullable; +import org.mybatis.dynamic.sql.AbstractTwoValueCondition; + +public class IsBetweenWhenPresent extends AbstractTwoValueCondition + implements AbstractTwoValueCondition.Filterable, AbstractTwoValueCondition.Mappable { + private static final IsBetweenWhenPresent EMPTY = new IsBetweenWhenPresent(-1, -1) { + @Override + public Object value1() { + throw new NoSuchElementException("No value present"); //$NON-NLS-1$ + } + + @Override + public Object value2() { + throw new NoSuchElementException("No value present"); //$NON-NLS-1$ + } + + @Override + public boolean isEmpty() { + return true; + } + }; + + public static IsBetweenWhenPresent empty() { + @SuppressWarnings("unchecked") + IsBetweenWhenPresent t = (IsBetweenWhenPresent) EMPTY; + return t; + } + + protected IsBetweenWhenPresent(T value1, T value2) { + super(value1, value2); + } + + @Override + public String operator1() { + return "between"; //$NON-NLS-1$ + } + + @Override + public String operator2() { + return "and"; //$NON-NLS-1$ + } + + @Override + public IsBetweenWhenPresent filter(BiPredicate predicate) { + return filterSupport(predicate, IsBetweenWhenPresent::empty, this); + } + + @Override + public IsBetweenWhenPresent filter(Predicate predicate) { + return filterSupport(predicate, IsBetweenWhenPresent::empty, this); + } + + @Override + public IsBetweenWhenPresent map(Function mapper1, + Function mapper2) { + return mapSupport(mapper1, mapper2, IsBetweenWhenPresent::of, IsBetweenWhenPresent::empty); + } + + @Override + public IsBetweenWhenPresent map(Function mapper) { + return map(mapper, mapper); + } + + public static IsBetweenWhenPresent of(@Nullable T value1, @Nullable T value2) { + if (value1 == null || value2 == null) { + return empty(); + } else { + return new IsBetweenWhenPresent<>(value1, value2); + } + } + + public static Builder isBetweenWhenPresent(@Nullable T value1) { + return new Builder<>(value1); + } + + public static class Builder extends AndWhenPresentGatherer> { + private Builder(@Nullable T value1) { + super(value1); + } + + @Override + protected IsBetweenWhenPresent build(@Nullable T value2) { + return IsBetweenWhenPresent.of(value1, value2); + } + } +} diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsEqualToWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsEqualToWhenPresent.java new file mode 100644 index 000000000..f06489076 --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsEqualToWhenPresent.java @@ -0,0 +1,72 @@ +/* + * Copyright 2016-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mybatis.dynamic.sql.where.condition; + +import java.util.NoSuchElementException; +import java.util.function.Function; +import java.util.function.Predicate; + +import org.jspecify.annotations.Nullable; +import org.mybatis.dynamic.sql.AbstractSingleValueCondition; + +public class IsEqualToWhenPresent extends AbstractSingleValueCondition + implements AbstractSingleValueCondition.Filterable, AbstractSingleValueCondition.Mappable { + + private static final IsEqualToWhenPresent EMPTY = new IsEqualToWhenPresent(-1) { + @Override + public Object value() { + throw new NoSuchElementException("No value present"); //$NON-NLS-1$ + } + + @Override + public boolean isEmpty() { + return true; + } + }; + + public static IsEqualToWhenPresent empty() { + @SuppressWarnings("unchecked") + IsEqualToWhenPresent t = (IsEqualToWhenPresent) EMPTY; + return t; + } + + protected IsEqualToWhenPresent(T value) { + super(value); + } + + @Override + public String operator() { + return "="; //$NON-NLS-1$ + } + + public static IsEqualToWhenPresent of(@Nullable T value) { + if (value == null) { + return empty(); + } else { + return new IsEqualToWhenPresent<>(value); + } + } + + @Override + public IsEqualToWhenPresent filter(Predicate predicate) { + return filterSupport(predicate, IsEqualToWhenPresent::empty, this); + } + + @Override + public IsEqualToWhenPresent map(Function mapper) { + return mapSupport(mapper, IsEqualToWhenPresent::of, IsEqualToWhenPresent::empty); + } +} diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanOrEqualToWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanOrEqualToWhenPresent.java new file mode 100644 index 000000000..89e8cda4f --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanOrEqualToWhenPresent.java @@ -0,0 +1,71 @@ +/* + * Copyright 2016-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mybatis.dynamic.sql.where.condition; + +import java.util.NoSuchElementException; +import java.util.function.Function; +import java.util.function.Predicate; + +import org.jspecify.annotations.Nullable; +import org.mybatis.dynamic.sql.AbstractSingleValueCondition; + +public class IsGreaterThanOrEqualToWhenPresent extends AbstractSingleValueCondition + implements AbstractSingleValueCondition.Filterable, AbstractSingleValueCondition.Mappable { + private static final IsGreaterThanOrEqualToWhenPresent EMPTY = new IsGreaterThanOrEqualToWhenPresent(-1) { + @Override + public Object value() { + throw new NoSuchElementException("No value present"); //$NON-NLS-1$ + } + + @Override + public boolean isEmpty() { + return true; + } + }; + + public static IsGreaterThanOrEqualToWhenPresent empty() { + @SuppressWarnings("unchecked") + IsGreaterThanOrEqualToWhenPresent t = (IsGreaterThanOrEqualToWhenPresent) EMPTY; + return t; + } + + protected IsGreaterThanOrEqualToWhenPresent(T value) { + super(value); + } + + @Override + public String operator() { + return ">="; //$NON-NLS-1$ + } + + public static IsGreaterThanOrEqualToWhenPresent of(@Nullable T value) { + if (value == null) { + return empty(); + } else { + return new IsGreaterThanOrEqualToWhenPresent<>(value); + } + } + + @Override + public IsGreaterThanOrEqualToWhenPresent filter(Predicate predicate) { + return filterSupport(predicate, IsGreaterThanOrEqualToWhenPresent::empty, this); + } + + @Override + public IsGreaterThanOrEqualToWhenPresent map(Function mapper) { + return mapSupport(mapper, IsGreaterThanOrEqualToWhenPresent::of, IsGreaterThanOrEqualToWhenPresent::empty); + } +} diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanWhenPresent.java new file mode 100644 index 000000000..175b5fcf6 --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanWhenPresent.java @@ -0,0 +1,71 @@ +/* + * Copyright 2016-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mybatis.dynamic.sql.where.condition; + +import java.util.NoSuchElementException; +import java.util.function.Function; +import java.util.function.Predicate; + +import org.jspecify.annotations.Nullable; +import org.mybatis.dynamic.sql.AbstractSingleValueCondition; + +public class IsGreaterThanWhenPresent extends AbstractSingleValueCondition + implements AbstractSingleValueCondition.Filterable, AbstractSingleValueCondition.Mappable { + private static final IsGreaterThanWhenPresent EMPTY = new IsGreaterThanWhenPresent(-1) { + @Override + public Object value() { + throw new NoSuchElementException("No value present"); //$NON-NLS-1$ + } + + @Override + public boolean isEmpty() { + return true; + } + }; + + public static IsGreaterThanWhenPresent empty() { + @SuppressWarnings("unchecked") + IsGreaterThanWhenPresent t = (IsGreaterThanWhenPresent) EMPTY; + return t; + } + + protected IsGreaterThanWhenPresent(T value) { + super(value); + } + + @Override + public String operator() { + return ">"; //$NON-NLS-1$ + } + + public static IsGreaterThanWhenPresent of(@Nullable T value) { + if (value == null) { + return empty(); + } else { + return new IsGreaterThanWhenPresent<>(value); + } + } + + @Override + public IsGreaterThanWhenPresent filter(Predicate predicate) { + return filterSupport(predicate, IsGreaterThanWhenPresent::empty, this); + } + + @Override + public IsGreaterThanWhenPresent map(Function mapper) { + return mapSupport(mapper, IsGreaterThanWhenPresent::of, IsGreaterThanWhenPresent::empty); + } +} diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java index bc8bfbdf9..3e2a22d2a 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java @@ -62,11 +62,12 @@ public IsInCaseInsensitive map(Function mapper) { return mapSupport(mapper, IsInCaseInsensitive::new, IsInCaseInsensitive::empty); } - public static IsInCaseInsensitive of(String... values) { + @SafeVarargs + public static IsInCaseInsensitive of(T... values) { return of(Arrays.asList(values)); } - public static IsInCaseInsensitive of(Collection values) { + public static IsInCaseInsensitive of(Collection values) { return new IsInCaseInsensitive<>(values); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java index fee942f7d..ac3ce2787 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java @@ -54,15 +54,20 @@ public IsInCaseInsensitiveWhenPresent filter(Predicate predicate) } @Override - public IsInCaseInsensitiveWhenPresent map(Function mapper) { + public IsInCaseInsensitiveWhenPresent map(Function mapper) { return mapSupport(mapper, IsInCaseInsensitiveWhenPresent::new, IsInCaseInsensitiveWhenPresent::empty); } - public static IsInCaseInsensitiveWhenPresent of(@Nullable String... values) { + @SafeVarargs + public static IsInCaseInsensitiveWhenPresent of(@Nullable T... values) { return of(Arrays.asList(values)); } - public static IsInCaseInsensitiveWhenPresent of(Collection<@Nullable String> values) { - return new IsInCaseInsensitiveWhenPresent<>(values); + public static IsInCaseInsensitiveWhenPresent of(@Nullable Collection<@Nullable T> values) { + if (values == null || values.isEmpty()) { + return empty(); + } else { + return new IsInCaseInsensitiveWhenPresent<>(values); + } } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInWhenPresent.java index 5c431fea3..1ec8185ee 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInWhenPresent.java @@ -50,8 +50,8 @@ public IsInWhenPresent filter(Predicate predicate) { } @Override - public IsInWhenPresent map(Function mapper) { - return mapSupport(mapper, IsInWhenPresent::new, IsInWhenPresent::empty); + public IsInWhenPresent map(Function mapper) { + return mapSupport(mapper, IsInWhenPresent::of, IsInWhenPresent::empty); } @SafeVarargs @@ -59,7 +59,11 @@ public static IsInWhenPresent of(@Nullable T... values) { return of(Arrays.asList(values)); } - public static IsInWhenPresent of(Collection<@Nullable T> values) { - return new IsInWhenPresent<>(values); + public static IsInWhenPresent of(@Nullable Collection<@Nullable T> values) { + if (values == null || values.isEmpty()) { + return empty(); + } else { + return new IsInWhenPresent<>(values); + } } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanOrEqualToWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanOrEqualToWhenPresent.java new file mode 100644 index 000000000..3cdc8ff39 --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanOrEqualToWhenPresent.java @@ -0,0 +1,71 @@ +/* + * Copyright 2016-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mybatis.dynamic.sql.where.condition; + +import java.util.NoSuchElementException; +import java.util.function.Function; +import java.util.function.Predicate; + +import org.jspecify.annotations.Nullable; +import org.mybatis.dynamic.sql.AbstractSingleValueCondition; + +public class IsLessThanOrEqualToWhenPresent extends AbstractSingleValueCondition + implements AbstractSingleValueCondition.Filterable, AbstractSingleValueCondition.Mappable { + private static final IsLessThanOrEqualToWhenPresent EMPTY = new IsLessThanOrEqualToWhenPresent(-1) { + @Override + public Object value() { + throw new NoSuchElementException("No value present"); //$NON-NLS-1$ + } + + @Override + public boolean isEmpty() { + return true; + } + }; + + public static IsLessThanOrEqualToWhenPresent empty() { + @SuppressWarnings("unchecked") + IsLessThanOrEqualToWhenPresent t = (IsLessThanOrEqualToWhenPresent) EMPTY; + return t; + } + + protected IsLessThanOrEqualToWhenPresent(T value) { + super(value); + } + + @Override + public String operator() { + return "<="; //$NON-NLS-1$ + } + + public static IsLessThanOrEqualToWhenPresent of(@Nullable T value) { + if (value == null) { + return empty(); + } else { + return new IsLessThanOrEqualToWhenPresent<>(value); + } + } + + @Override + public IsLessThanOrEqualToWhenPresent filter(Predicate predicate) { + return filterSupport(predicate, IsLessThanOrEqualToWhenPresent::empty, this); + } + + @Override + public IsLessThanOrEqualToWhenPresent map(Function mapper) { + return mapSupport(mapper, IsLessThanOrEqualToWhenPresent::of, IsLessThanOrEqualToWhenPresent::empty); + } +} diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanWhenPresent.java new file mode 100644 index 000000000..78a07f9a2 --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanWhenPresent.java @@ -0,0 +1,72 @@ +/* + * Copyright 2016-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mybatis.dynamic.sql.where.condition; + +import java.util.NoSuchElementException; +import java.util.function.Function; +import java.util.function.Predicate; + +import org.jspecify.annotations.Nullable; +import org.mybatis.dynamic.sql.AbstractSingleValueCondition; + +public class IsLessThanWhenPresent extends AbstractSingleValueCondition + implements AbstractSingleValueCondition.Filterable, AbstractSingleValueCondition.Mappable { + + private static final IsLessThanWhenPresent EMPTY = new IsLessThanWhenPresent(-1) { + @Override + public Object value() { + throw new NoSuchElementException("No value present"); //$NON-NLS-1$ + } + + @Override + public boolean isEmpty() { + return true; + } + }; + + public static IsLessThanWhenPresent empty() { + @SuppressWarnings("unchecked") + IsLessThanWhenPresent t = (IsLessThanWhenPresent) EMPTY; + return t; + } + + protected IsLessThanWhenPresent(T value) { + super(value); + } + + @Override + public String operator() { + return "<"; //$NON-NLS-1$ + } + + public static IsLessThanWhenPresent of(@Nullable T value) { + if (value == null) { + return empty(); + } else { + return new IsLessThanWhenPresent<>(value); + } + } + + @Override + public IsLessThanWhenPresent filter(Predicate predicate) { + return filterSupport(predicate, IsLessThanWhenPresent::empty, this); + } + + @Override + public IsLessThanWhenPresent map(Function mapper) { + return mapSupport(mapper, IsLessThanWhenPresent::of, IsLessThanWhenPresent::empty); + } +} diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitive.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitive.java index e4d31c126..ffdc2bc7d 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitive.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitive.java @@ -62,7 +62,7 @@ public IsLikeCaseInsensitive map(Function mapper) return mapSupport(mapper, IsLikeCaseInsensitive::new, IsLikeCaseInsensitive::empty); } - public static IsLikeCaseInsensitive of(String value) { + public static IsLikeCaseInsensitive of(T value) { return new IsLikeCaseInsensitive<>(value); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitiveWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitiveWhenPresent.java new file mode 100644 index 000000000..89ab9b038 --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitiveWhenPresent.java @@ -0,0 +1,73 @@ +/* + * Copyright 2016-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mybatis.dynamic.sql.where.condition; + +import java.util.NoSuchElementException; +import java.util.function.Function; +import java.util.function.Predicate; + +import org.jspecify.annotations.Nullable; +import org.mybatis.dynamic.sql.AbstractSingleValueCondition; +import org.mybatis.dynamic.sql.util.StringUtilities; + +public class IsLikeCaseInsensitiveWhenPresent extends AbstractSingleValueCondition + implements CaseInsensitiveRenderableCondition, AbstractSingleValueCondition.Filterable, + AbstractSingleValueCondition.Mappable { + private static final IsLikeCaseInsensitiveWhenPresent EMPTY = new IsLikeCaseInsensitiveWhenPresent<>("") { //$NON-NLS-1$ + @Override + public String value() { + throw new NoSuchElementException("No value present"); //$NON-NLS-1$ + } + + @Override + public boolean isEmpty() { + return true; + } + }; + + public static IsLikeCaseInsensitiveWhenPresent empty() { + @SuppressWarnings("unchecked") + IsLikeCaseInsensitiveWhenPresent t = (IsLikeCaseInsensitiveWhenPresent) EMPTY; + return t; + } + + protected IsLikeCaseInsensitiveWhenPresent(T value) { + super(StringUtilities.upperCaseIfPossible(value)); + } + + @Override + public String operator() { + return "like"; //$NON-NLS-1$ + } + + @Override + public IsLikeCaseInsensitiveWhenPresent filter(Predicate predicate) { + return filterSupport(predicate, IsLikeCaseInsensitiveWhenPresent::empty, this); + } + + @Override + public IsLikeCaseInsensitiveWhenPresent map(Function mapper) { + return mapSupport(mapper, IsLikeCaseInsensitiveWhenPresent::of, IsLikeCaseInsensitiveWhenPresent::empty); + } + + public static IsLikeCaseInsensitiveWhenPresent of(@Nullable T value) { + if (value == null) { + return empty(); + } else { + return new IsLikeCaseInsensitiveWhenPresent<>(value); + } + } +} diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeWhenPresent.java new file mode 100644 index 000000000..a69e55356 --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeWhenPresent.java @@ -0,0 +1,72 @@ +/* + * Copyright 2016-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mybatis.dynamic.sql.where.condition; + +import java.util.NoSuchElementException; +import java.util.function.Function; +import java.util.function.Predicate; + +import org.jspecify.annotations.Nullable; +import org.mybatis.dynamic.sql.AbstractSingleValueCondition; + +public class IsLikeWhenPresent extends AbstractSingleValueCondition + implements AbstractSingleValueCondition.Filterable, AbstractSingleValueCondition.Mappable { + + private static final IsLikeWhenPresent EMPTY = new IsLikeWhenPresent(-1) { + @Override + public Object value() { + throw new NoSuchElementException("No value present"); //$NON-NLS-1$ + } + + @Override + public boolean isEmpty() { + return true; + } + }; + + public static IsLikeWhenPresent empty() { + @SuppressWarnings("unchecked") + IsLikeWhenPresent t = (IsLikeWhenPresent) EMPTY; + return t; + } + + protected IsLikeWhenPresent(T value) { + super(value); + } + + @Override + public String operator() { + return "like"; //$NON-NLS-1$ + } + + public static IsLikeWhenPresent of(@Nullable T value) { + if (value == null) { + return empty(); + } else { + return new IsLikeWhenPresent<>(value); + } + } + + @Override + public IsLikeWhenPresent filter(Predicate predicate) { + return filterSupport(predicate, IsLikeWhenPresent::empty, this); + } + + @Override + public IsLikeWhenPresent map(Function mapper) { + return mapSupport(mapper, IsLikeWhenPresent::of, IsLikeWhenPresent::empty); + } +} diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotBetween.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotBetween.java index 6a515d4ac..836e3c741 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotBetween.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotBetween.java @@ -20,7 +20,6 @@ import java.util.function.Function; import java.util.function.Predicate; -import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.AbstractTwoValueCondition; public class IsNotBetween extends AbstractTwoValueCondition @@ -87,10 +86,6 @@ public static Builder isNotBetween(T value1) { return new Builder<>(value1); } - public static WhenPresentBuilder isNotBetweenWhenPresent(@Nullable T value1) { - return new WhenPresentBuilder<>(value1); - } - public static class Builder extends AndGatherer> { private Builder(T value1) { @@ -102,20 +97,4 @@ protected IsNotBetween build(T value2) { return new IsNotBetween<>(value1, value2); } } - - public static class WhenPresentBuilder extends AndWhenPresentGatherer> { - - private WhenPresentBuilder(@Nullable T value1) { - super(value1); - } - - @Override - protected IsNotBetween build(@Nullable T value2) { - if (value1 == null || value2 == null) { - return empty(); - } else { - return new IsNotBetween<>(value1, value2); - } - } - } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotBetweenWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotBetweenWhenPresent.java new file mode 100644 index 000000000..23b6507d5 --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotBetweenWhenPresent.java @@ -0,0 +1,109 @@ +/* + * Copyright 2016-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mybatis.dynamic.sql.where.condition; + +import java.util.NoSuchElementException; +import java.util.function.BiPredicate; +import java.util.function.Function; +import java.util.function.Predicate; + +import org.jspecify.annotations.Nullable; +import org.mybatis.dynamic.sql.AbstractTwoValueCondition; + +public class IsNotBetweenWhenPresent extends AbstractTwoValueCondition + implements AbstractTwoValueCondition.Filterable, AbstractTwoValueCondition.Mappable { + private static final IsNotBetweenWhenPresent EMPTY = new IsNotBetweenWhenPresent(-1, -1) { + @Override + public Object value1() { + throw new NoSuchElementException("No value present"); //$NON-NLS-1$ + } + + @Override + public Object value2() { + throw new NoSuchElementException("No value present"); //$NON-NLS-1$ + } + + @Override + public boolean isEmpty() { + return true; + } + }; + + public static IsNotBetweenWhenPresent empty() { + @SuppressWarnings("unchecked") + IsNotBetweenWhenPresent t = (IsNotBetweenWhenPresent) EMPTY; + return t; + } + + protected IsNotBetweenWhenPresent(T value1, T value2) { + super(value1, value2); + } + + @Override + public String operator1() { + return "not between"; //$NON-NLS-1$ + } + + @Override + public String operator2() { + return "and"; //$NON-NLS-1$ + } + + @Override + public IsNotBetweenWhenPresent filter(BiPredicate predicate) { + return filterSupport(predicate, IsNotBetweenWhenPresent::empty, this); + } + + @Override + public IsNotBetweenWhenPresent filter(Predicate predicate) { + return filterSupport(predicate, IsNotBetweenWhenPresent::empty, this); + } + + @Override + public IsNotBetweenWhenPresent map(Function mapper1, + Function mapper2) { + return mapSupport(mapper1, mapper2, IsNotBetweenWhenPresent::of, IsNotBetweenWhenPresent::empty); + } + + @Override + public IsNotBetweenWhenPresent map(Function mapper) { + return map(mapper, mapper); + } + + public static IsNotBetweenWhenPresent of(@Nullable T value1, @Nullable T value2) { + if (value1 == null || value2 == null) { + return empty(); + } else { + return new IsNotBetweenWhenPresent<>(value1, value2); + } + } + + public static Builder isNotBetweenWhenPresent(@Nullable T value1) { + return new Builder<>(value1); + } + + public static class Builder extends AndWhenPresentGatherer> { + + private Builder(@Nullable T value1) { + super(value1); + } + + @Override + protected IsNotBetweenWhenPresent build(@Nullable T value2) { + return IsNotBetweenWhenPresent.of(value1, value2); + } + } +} diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotEqualToWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotEqualToWhenPresent.java new file mode 100644 index 000000000..07ab3f6cf --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotEqualToWhenPresent.java @@ -0,0 +1,71 @@ +/* + * Copyright 2016-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mybatis.dynamic.sql.where.condition; + +import java.util.NoSuchElementException; +import java.util.function.Function; +import java.util.function.Predicate; + +import org.jspecify.annotations.Nullable; +import org.mybatis.dynamic.sql.AbstractSingleValueCondition; + +public class IsNotEqualToWhenPresent extends AbstractSingleValueCondition + implements AbstractSingleValueCondition.Filterable, AbstractSingleValueCondition.Mappable { + private static final IsNotEqualToWhenPresent EMPTY = new IsNotEqualToWhenPresent(-1) { + @Override + public Object value() { + throw new NoSuchElementException("No value present"); //$NON-NLS-1$ + } + + @Override + public boolean isEmpty() { + return true; + } + }; + + public static IsNotEqualToWhenPresent empty() { + @SuppressWarnings("unchecked") + IsNotEqualToWhenPresent t = (IsNotEqualToWhenPresent) EMPTY; + return t; + } + + protected IsNotEqualToWhenPresent(T value) { + super(value); + } + + @Override + public String operator() { + return "<>"; //$NON-NLS-1$ + } + + public static IsNotEqualToWhenPresent of(@Nullable T value) { + if (value == null) { + return empty(); + } else { + return new IsNotEqualToWhenPresent<>(value); + } + } + + @Override + public IsNotEqualToWhenPresent filter(Predicate predicate) { + return filterSupport(predicate, IsNotEqualToWhenPresent::empty, this); + } + + @Override + public IsNotEqualToWhenPresent map(Function mapper) { + return mapSupport(mapper, IsNotEqualToWhenPresent::of, IsNotEqualToWhenPresent::empty); + } +} diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java index 4486d1df7..2bc802ab8 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java @@ -62,11 +62,12 @@ public IsNotInCaseInsensitive map(Function mapper return mapSupport(mapper, IsNotInCaseInsensitive::new, IsNotInCaseInsensitive::empty); } - public static IsNotInCaseInsensitive of(String... values) { + @SafeVarargs + public static IsNotInCaseInsensitive of(T... values) { return of(Arrays.asList(values)); } - public static IsNotInCaseInsensitive of(Collection values) { + public static IsNotInCaseInsensitive of(Collection values) { return new IsNotInCaseInsensitive<>(values); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java index 992a231eb..82d9d6e27 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java @@ -54,15 +54,20 @@ public IsNotInCaseInsensitiveWhenPresent filter(Predicate predicat } @Override - public IsNotInCaseInsensitiveWhenPresent map(Function mapper) { + public IsNotInCaseInsensitiveWhenPresent map(Function mapper) { return mapSupport(mapper, IsNotInCaseInsensitiveWhenPresent::new, IsNotInCaseInsensitiveWhenPresent::empty); } - public static IsNotInCaseInsensitiveWhenPresent of(@Nullable String... values) { + @SafeVarargs + public static IsNotInCaseInsensitiveWhenPresent of(@Nullable T... values) { return of(Arrays.asList(values)); } - public static IsNotInCaseInsensitiveWhenPresent of(Collection<@Nullable String> values) { - return new IsNotInCaseInsensitiveWhenPresent<>(values); + public static IsNotInCaseInsensitiveWhenPresent of(@Nullable Collection<@Nullable T> values) { + if (values == null || values.isEmpty()) { + return empty(); + } else { + return new IsNotInCaseInsensitiveWhenPresent<>(values); + } } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInWhenPresent.java index ddc8e5470..ed4b27389 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInWhenPresent.java @@ -22,6 +22,7 @@ import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.AbstractListValueCondition; public class IsNotInWhenPresent extends AbstractListValueCondition @@ -49,16 +50,20 @@ public IsNotInWhenPresent filter(Predicate predicate) { } @Override - public IsNotInWhenPresent map(Function mapper) { + public IsNotInWhenPresent map(Function mapper) { return mapSupport(mapper, IsNotInWhenPresent::new, IsNotInWhenPresent::empty); } @SafeVarargs - public static IsNotInWhenPresent of(T... values) { + public static IsNotInWhenPresent of(@Nullable T... values) { return of(Arrays.asList(values)); } - public static IsNotInWhenPresent of(Collection values) { - return new IsNotInWhenPresent<>(values); + public static IsNotInWhenPresent of(@Nullable Collection<@Nullable T> values) { + if (values == null || values.isEmpty()) { + return empty(); + } else { + return new IsNotInWhenPresent<>(values); + } } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitive.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitive.java index 715a19a8d..6bd943227 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitive.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitive.java @@ -62,7 +62,7 @@ public IsNotLikeCaseInsensitive map(Function mapp return mapSupport(mapper, IsNotLikeCaseInsensitive::new, IsNotLikeCaseInsensitive::empty); } - public static IsNotLikeCaseInsensitive of(String value) { + public static IsNotLikeCaseInsensitive of(T value) { return new IsNotLikeCaseInsensitive<>(value); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitiveWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitiveWhenPresent.java new file mode 100644 index 000000000..891525295 --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitiveWhenPresent.java @@ -0,0 +1,73 @@ +/* + * Copyright 2016-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mybatis.dynamic.sql.where.condition; + +import java.util.NoSuchElementException; +import java.util.function.Function; +import java.util.function.Predicate; + +import org.jspecify.annotations.Nullable; +import org.mybatis.dynamic.sql.AbstractSingleValueCondition; +import org.mybatis.dynamic.sql.util.StringUtilities; + +public class IsNotLikeCaseInsensitiveWhenPresent extends AbstractSingleValueCondition + implements CaseInsensitiveRenderableCondition, AbstractSingleValueCondition.Filterable, + AbstractSingleValueCondition.Mappable { + private static final IsNotLikeCaseInsensitiveWhenPresent EMPTY = new IsNotLikeCaseInsensitiveWhenPresent<>("") { //$NON-NLS-1$ + @Override + public String value() { + throw new NoSuchElementException("No value present"); //$NON-NLS-1$ + } + + @Override + public boolean isEmpty() { + return true; + } + }; + + public static IsNotLikeCaseInsensitiveWhenPresent empty() { + @SuppressWarnings("unchecked") + IsNotLikeCaseInsensitiveWhenPresent t = (IsNotLikeCaseInsensitiveWhenPresent) EMPTY; + return t; + } + + protected IsNotLikeCaseInsensitiveWhenPresent(T value) { + super(StringUtilities.upperCaseIfPossible(value)); + } + + @Override + public String operator() { + return "not like"; //$NON-NLS-1$ + } + + @Override + public IsNotLikeCaseInsensitiveWhenPresent filter(Predicate predicate) { + return filterSupport(predicate, IsNotLikeCaseInsensitiveWhenPresent::empty, this); + } + + @Override + public IsNotLikeCaseInsensitiveWhenPresent map(Function mapper) { + return mapSupport(mapper, IsNotLikeCaseInsensitiveWhenPresent::of, IsNotLikeCaseInsensitiveWhenPresent::empty); + } + + public static IsNotLikeCaseInsensitiveWhenPresent of(@Nullable T value) { + if (value == null) { + return empty(); + } else { + return new IsNotLikeCaseInsensitiveWhenPresent<>(value); + } + } +} diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeWhenPresent.java new file mode 100644 index 000000000..d018c9062 --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeWhenPresent.java @@ -0,0 +1,71 @@ +/* + * Copyright 2016-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mybatis.dynamic.sql.where.condition; + +import java.util.NoSuchElementException; +import java.util.function.Function; +import java.util.function.Predicate; + +import org.jspecify.annotations.Nullable; +import org.mybatis.dynamic.sql.AbstractSingleValueCondition; + +public class IsNotLikeWhenPresent extends AbstractSingleValueCondition + implements AbstractSingleValueCondition.Filterable, AbstractSingleValueCondition.Mappable { + private static final IsNotLikeWhenPresent EMPTY = new IsNotLikeWhenPresent(-1) { + @Override + public Object value() { + throw new NoSuchElementException("No value present"); //$NON-NLS-1$ + } + + @Override + public boolean isEmpty() { + return true; + } + }; + + public static IsNotLikeWhenPresent empty() { + @SuppressWarnings("unchecked") + IsNotLikeWhenPresent t = (IsNotLikeWhenPresent) EMPTY; + return t; + } + + protected IsNotLikeWhenPresent(T value) { + super(value); + } + + @Override + public String operator() { + return "not like"; //$NON-NLS-1$ + } + + public static IsNotLikeWhenPresent of(@Nullable T value) { + if (value == null) { + return empty(); + } else { + return new IsNotLikeWhenPresent<>(value); + } + } + + @Override + public IsNotLikeWhenPresent filter(Predicate predicate) { + return filterSupport(predicate, IsNotLikeWhenPresent::empty, this); + } + + @Override + public IsNotLikeWhenPresent map(Function mapper) { + return mapSupport(mapper, IsNotLikeWhenPresent::of, IsNotLikeWhenPresent::empty); + } +} diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/SqlElements.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/SqlElements.kt index 530c962ed..f648496d0 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/SqlElements.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/SqlElements.kt @@ -51,14 +51,18 @@ import org.mybatis.dynamic.sql.util.kotlin.GroupingCriteriaReceiver import org.mybatis.dynamic.sql.util.kotlin.KotlinSubQueryBuilder import org.mybatis.dynamic.sql.util.kotlin.invalidIfNull import org.mybatis.dynamic.sql.where.condition.IsBetween +import org.mybatis.dynamic.sql.where.condition.IsBetweenWhenPresent import org.mybatis.dynamic.sql.where.condition.IsEqualTo import org.mybatis.dynamic.sql.where.condition.IsEqualToColumn +import org.mybatis.dynamic.sql.where.condition.IsEqualToWhenPresent import org.mybatis.dynamic.sql.where.condition.IsEqualToWithSubselect import org.mybatis.dynamic.sql.where.condition.IsGreaterThan import org.mybatis.dynamic.sql.where.condition.IsGreaterThanColumn import org.mybatis.dynamic.sql.where.condition.IsGreaterThanOrEqualTo import org.mybatis.dynamic.sql.where.condition.IsGreaterThanOrEqualToColumn +import org.mybatis.dynamic.sql.where.condition.IsGreaterThanOrEqualToWhenPresent import org.mybatis.dynamic.sql.where.condition.IsGreaterThanOrEqualToWithSubselect +import org.mybatis.dynamic.sql.where.condition.IsGreaterThanWhenPresent import org.mybatis.dynamic.sql.where.condition.IsGreaterThanWithSubselect import org.mybatis.dynamic.sql.where.condition.IsIn import org.mybatis.dynamic.sql.where.condition.IsInCaseInsensitive @@ -69,13 +73,19 @@ import org.mybatis.dynamic.sql.where.condition.IsLessThan import org.mybatis.dynamic.sql.where.condition.IsLessThanColumn import org.mybatis.dynamic.sql.where.condition.IsLessThanOrEqualTo import org.mybatis.dynamic.sql.where.condition.IsLessThanOrEqualToColumn +import org.mybatis.dynamic.sql.where.condition.IsLessThanOrEqualToWhenPresent import org.mybatis.dynamic.sql.where.condition.IsLessThanOrEqualToWithSubselect +import org.mybatis.dynamic.sql.where.condition.IsLessThanWhenPresent import org.mybatis.dynamic.sql.where.condition.IsLessThanWithSubselect import org.mybatis.dynamic.sql.where.condition.IsLike import org.mybatis.dynamic.sql.where.condition.IsLikeCaseInsensitive +import org.mybatis.dynamic.sql.where.condition.IsLikeCaseInsensitiveWhenPresent +import org.mybatis.dynamic.sql.where.condition.IsLikeWhenPresent import org.mybatis.dynamic.sql.where.condition.IsNotBetween +import org.mybatis.dynamic.sql.where.condition.IsNotBetweenWhenPresent import org.mybatis.dynamic.sql.where.condition.IsNotEqualTo import org.mybatis.dynamic.sql.where.condition.IsNotEqualToColumn +import org.mybatis.dynamic.sql.where.condition.IsNotEqualToWhenPresent import org.mybatis.dynamic.sql.where.condition.IsNotEqualToWithSubselect import org.mybatis.dynamic.sql.where.condition.IsNotIn import org.mybatis.dynamic.sql.where.condition.IsNotInCaseInsensitive @@ -84,6 +94,8 @@ import org.mybatis.dynamic.sql.where.condition.IsNotInWhenPresent import org.mybatis.dynamic.sql.where.condition.IsNotInWithSubselect import org.mybatis.dynamic.sql.where.condition.IsNotLike import org.mybatis.dynamic.sql.where.condition.IsNotLikeCaseInsensitive +import org.mybatis.dynamic.sql.where.condition.IsNotLikeCaseInsensitiveWhenPresent +import org.mybatis.dynamic.sql.where.condition.IsNotLikeWhenPresent import org.mybatis.dynamic.sql.where.condition.IsNotNull import org.mybatis.dynamic.sql.where.condition.IsNull @@ -216,7 +228,7 @@ fun isEqualTo(subQuery: KotlinSubQueryBuilder.() -> Unit): IsEqualToWi fun isEqualTo(column: BasicColumn): IsEqualToColumn = SqlBuilder.isEqualTo(column) -fun isEqualToWhenPresent(value: T?): IsEqualTo = SqlBuilder.isEqualToWhenPresent(value) +fun isEqualToWhenPresent(value: T?): IsEqualToWhenPresent = SqlBuilder.isEqualToWhenPresent(value) fun isNotEqualTo(value: T): IsNotEqualTo = SqlBuilder.isNotEqualTo(value) @@ -225,7 +237,8 @@ fun isNotEqualTo(subQuery: KotlinSubQueryBuilder.() -> Unit): IsNotEqu fun isNotEqualTo(column: BasicColumn): IsNotEqualToColumn = SqlBuilder.isNotEqualTo(column) -fun isNotEqualToWhenPresent(value: T?): IsNotEqualTo = SqlBuilder.isNotEqualToWhenPresent(value) +fun isNotEqualToWhenPresent(value: T?): IsNotEqualToWhenPresent = + SqlBuilder.isNotEqualToWhenPresent(value) fun isGreaterThan(value: T): IsGreaterThan = SqlBuilder.isGreaterThan(value) @@ -234,7 +247,8 @@ fun isGreaterThan(subQuery: KotlinSubQueryBuilder.() -> Unit): IsGreat fun isGreaterThan(column: BasicColumn): IsGreaterThanColumn = SqlBuilder.isGreaterThan(column) -fun isGreaterThanWhenPresent(value: T?): IsGreaterThan = SqlBuilder.isGreaterThanWhenPresent(value) +fun isGreaterThanWhenPresent(value: T?): IsGreaterThanWhenPresent = + SqlBuilder.isGreaterThanWhenPresent(value) fun isGreaterThanOrEqualTo(value: T): IsGreaterThanOrEqualTo = SqlBuilder.isGreaterThanOrEqualTo(value) @@ -244,7 +258,7 @@ fun isGreaterThanOrEqualTo(subQuery: KotlinSubQueryBuilder.() -> Unit) fun isGreaterThanOrEqualTo(column: BasicColumn): IsGreaterThanOrEqualToColumn = SqlBuilder.isGreaterThanOrEqualTo(column) -fun isGreaterThanOrEqualToWhenPresent(value: T?): IsGreaterThanOrEqualTo = +fun isGreaterThanOrEqualToWhenPresent(value: T?): IsGreaterThanOrEqualToWhenPresent = SqlBuilder.isGreaterThanOrEqualToWhenPresent(value) fun isLessThan(value: T): IsLessThan = SqlBuilder.isLessThan(value) @@ -254,7 +268,7 @@ fun isLessThan(subQuery: KotlinSubQueryBuilder.() -> Unit): IsLessThan fun isLessThan(column: BasicColumn): IsLessThanColumn = SqlBuilder.isLessThan(column) -fun isLessThanWhenPresent(value: T?): IsLessThan = SqlBuilder.isLessThanWhenPresent(value) +fun isLessThanWhenPresent(value: T?): IsLessThanWhenPresent = SqlBuilder.isLessThanWhenPresent(value) fun isLessThanOrEqualTo(value: T): IsLessThanOrEqualTo = SqlBuilder.isLessThanOrEqualTo(value) @@ -263,7 +277,7 @@ fun isLessThanOrEqualTo(subQuery: KotlinSubQueryBuilder.() -> Unit): I fun isLessThanOrEqualTo(column: BasicColumn): IsLessThanOrEqualToColumn = SqlBuilder.isLessThanOrEqualTo(column) -fun isLessThanOrEqualToWhenPresent(value: T?): IsLessThanOrEqualTo = +fun isLessThanOrEqualToWhenPresent(value: T?): IsLessThanOrEqualToWhenPresent = SqlBuilder.isLessThanOrEqualToWhenPresent(value) fun isIn(vararg values: T): IsIn = isIn(values.asList()) @@ -312,11 +326,11 @@ fun isNotBetweenWhenPresent(value1: T?): NotBetweenWhenPresentBuilder< // for string columns, but generic for columns with type handlers fun isLike(value: T): IsLike = SqlBuilder.isLike(value) -fun isLikeWhenPresent(value: T?): IsLike = SqlBuilder.isLikeWhenPresent(value) +fun isLikeWhenPresent(value: T?): IsLikeWhenPresent = SqlBuilder.isLikeWhenPresent(value) fun isNotLike(value: T): IsNotLike = SqlBuilder.isNotLike(value) -fun isNotLikeWhenPresent(value: T?): IsNotLike = SqlBuilder.isNotLikeWhenPresent(value) +fun isNotLikeWhenPresent(value: T?): IsNotLikeWhenPresent = SqlBuilder.isNotLikeWhenPresent(value) // shortcuts for booleans fun isTrue(): IsEqualTo = isEqualTo(true) @@ -326,12 +340,12 @@ fun isFalse(): IsEqualTo = isEqualTo(false) // conditions for strings only fun isLikeCaseInsensitive(value: String): IsLikeCaseInsensitive = SqlBuilder.isLikeCaseInsensitive(value) -fun isLikeCaseInsensitiveWhenPresent(value: String?): IsLikeCaseInsensitive = +fun isLikeCaseInsensitiveWhenPresent(value: String?): IsLikeCaseInsensitiveWhenPresent = SqlBuilder.isLikeCaseInsensitiveWhenPresent(value) fun isNotLikeCaseInsensitive(value: String): IsNotLikeCaseInsensitive = SqlBuilder.isNotLikeCaseInsensitive(value) -fun isNotLikeCaseInsensitiveWhenPresent(value: String?): IsNotLikeCaseInsensitive = +fun isNotLikeCaseInsensitiveWhenPresent(value: String?): IsNotLikeCaseInsensitiveWhenPresent = SqlBuilder.isNotLikeCaseInsensitiveWhenPresent(value) fun isInCaseInsensitive(vararg values: String): IsInCaseInsensitive = isInCaseInsensitive(values.asList()) @@ -400,7 +414,7 @@ class BetweenBuilder(private val value1: T) { } class BetweenWhenPresentBuilder(private val value1: T?) { - fun and(value2: T?): IsBetween { + fun and(value2: T?): IsBetweenWhenPresent { return SqlBuilder.isBetweenWhenPresent(value1).and(value2) } } @@ -410,7 +424,7 @@ class NotBetweenBuilder(private val value1: T) { } class NotBetweenWhenPresentBuilder(private val value1: T?) { - fun and(value2: T?): IsNotBetween { + fun and(value2: T?): IsNotBetweenWhenPresent { return SqlBuilder.isNotBetweenWhenPresent(value1).and(value2) } } diff --git a/src/test/java/org/mybatis/dynamic/sql/where/condition/NullContractTest.java b/src/test/java/org/mybatis/dynamic/sql/where/condition/NullContractTest.java new file mode 100644 index 000000000..35f0440d8 --- /dev/null +++ b/src/test/java/org/mybatis/dynamic/sql/where/condition/NullContractTest.java @@ -0,0 +1,441 @@ +package org.mybatis.dynamic.sql.where.condition; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; + +import java.util.NoSuchElementException; + +import org.junit.jupiter.api.Test; +import org.mybatis.dynamic.sql.SqlBuilder; + +/** + * This set of tests verifies that the library handles null values in conditions as expected. + * + *

In version 2.0, we adopted JSpecify which brought several issues to light. + * In general, the library does not support passing null values into methods unless the method + * is a "whenPresent" method. However, from the beginning the library has handled null values in conditions + * by placing a null into the generated parameter map. We consider this a misuse of the library, but we are + * keeping that behavior for compatibility. + * + *

In a future version, we will stop supporting this misuse. + * + *

This set of tests should be the only tests in the library that verify this behavior. All other tests + * should use the library properly. + */ +public class NullContractTest { + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsBetween() { + IsBetween nullCond = SqlBuilder.isBetween((Integer) null).and((Integer) null); + assertThat(nullCond.isEmpty()).isFalse(); + + IsBetween cond = SqlBuilder.isBetween(1).and(10); + IsBetween filtered = cond.filter(i -> i >= 1); + IsBetween mapped = filtered.map(i -> null); + assertThat(mapped.isEmpty()).isFalse(); + + mapped = filtered.map(v1 -> null, v2 -> null); + assertThat(mapped.isEmpty()).isFalse(); + assertThat(mapped.value1()).isNull(); + assertThat(mapped.value2()).isNull(); + } + + @Test + void testIsBetweenWhenPresent() { + IsBetweenWhenPresent nullCond = SqlBuilder.isBetweenWhenPresent((Integer) null).and((Integer) null); + assertThat(nullCond.isEmpty()).isTrue(); + + IsBetweenWhenPresent cond = SqlBuilder.isBetweenWhenPresent(1).and(10); + IsBetweenWhenPresent filtered = cond.filter(i -> i == 1); + IsBetweenWhenPresent mapped = filtered.map(i -> null); + assertThat(mapped.isEmpty()).isTrue(); + + mapped = filtered.map(v1 -> null, v2 -> null); + assertThat(mapped.isEmpty()).isTrue(); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(mapped::value1); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(mapped::value2); + } + + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsEqualTo() { + IsEqualTo nullCond = SqlBuilder.isEqualTo((Integer) null); // should be an IDE warning + assertThat(nullCond.isEmpty()).isFalse(); + + IsEqualTo cond = SqlBuilder.isEqualTo(1); + IsEqualTo filtered = cond.filter(i -> i == 1); + IsEqualTo mapped = filtered.map(i -> null); // should be an IDE warning + assertThat(mapped.isEmpty()).isFalse(); + assertThat(mapped.value()).isNull(); + } + + @Test + void testIsEqualToWhenPresent() { + IsEqualToWhenPresent nullCond = SqlBuilder.isEqualToWhenPresent((Integer) null); + assertThat(nullCond.isEmpty()).isTrue(); + + IsEqualToWhenPresent cond = SqlBuilder.isEqualToWhenPresent(1); + IsEqualToWhenPresent filtered = cond.filter(i -> i == 1); + IsEqualToWhenPresent mapped = filtered.map(i -> null); + assertThat(mapped.isEmpty()).isTrue(); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(mapped::value); + } + + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsGreaterThan() { + IsGreaterThan nullCond = SqlBuilder.isGreaterThan((Integer) null); // should be an IDE warning + assertThat(nullCond.isEmpty()).isFalse(); + + IsGreaterThan cond = SqlBuilder.isGreaterThan(1); + IsGreaterThan filtered = cond.filter(i -> i == 1); + IsGreaterThan mapped = filtered.map(i -> null); // should be an IDE warning + assertThat(mapped.isEmpty()).isFalse(); + assertThat(mapped.value()).isNull(); + } + + @Test + void testIsGreaterThanWhenPresent() { + IsGreaterThanWhenPresent nullCond = SqlBuilder.isGreaterThanWhenPresent((Integer) null); + assertThat(nullCond.isEmpty()).isTrue(); + + IsGreaterThanWhenPresent cond = SqlBuilder.isGreaterThanWhenPresent(1); + IsGreaterThanWhenPresent filtered = cond.filter(i -> i == 1); + IsGreaterThanWhenPresent mapped = filtered.map(i -> null); + assertThat(mapped.isEmpty()).isTrue(); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(mapped::value); + } + + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsGreaterThanOrEqualTo() { + IsGreaterThanOrEqualTo nullCond = SqlBuilder.isGreaterThanOrEqualTo((Integer) null); // should be an IDE warning + assertThat(nullCond.isEmpty()).isFalse(); + + IsGreaterThanOrEqualTo cond = SqlBuilder.isGreaterThanOrEqualTo(1); + IsGreaterThanOrEqualTo filtered = cond.filter(i -> i == 1); + IsGreaterThanOrEqualTo mapped = filtered.map(i -> null); // should be an IDE warning + assertThat(mapped.isEmpty()).isFalse(); + assertThat(mapped.value()).isNull(); + } + + @Test + void testIsGreaterThanOrEqualToWhenPresent() { + IsGreaterThanOrEqualToWhenPresent nullCond = SqlBuilder.isGreaterThanOrEqualToWhenPresent((Integer) null); + assertThat(nullCond.isEmpty()).isTrue(); + + IsGreaterThanOrEqualToWhenPresent cond = SqlBuilder.isGreaterThanOrEqualToWhenPresent(1); + IsGreaterThanOrEqualToWhenPresent filtered = cond.filter(i -> i == 1); + IsGreaterThanOrEqualToWhenPresent mapped = filtered.map(i -> null); + assertThat(mapped.isEmpty()).isTrue(); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(mapped::value); + } + + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsLessThan() { + IsLessThan nullCond = SqlBuilder.isLessThan((Integer) null); // should be an IDE warning + assertThat(nullCond.isEmpty()).isFalse(); + + IsLessThan cond = SqlBuilder.isLessThan(1); + IsLessThan filtered = cond.filter(i -> i == 1); + IsLessThan mapped = filtered.map(i -> null); // should be an IDE warning + assertThat(mapped.isEmpty()).isFalse(); + assertThat(mapped.value()).isNull(); + } + + @Test + void testIsLessThanWhenPresent() { + IsLessThanWhenPresent nullCond = SqlBuilder.isLessThanWhenPresent((Integer) null); + assertThat(nullCond.isEmpty()).isTrue(); + + IsLessThanWhenPresent cond = SqlBuilder.isLessThanWhenPresent(1); + IsLessThanWhenPresent filtered = cond.filter(i -> i == 1); + IsLessThanWhenPresent mapped = filtered.map(i -> null); + assertThat(mapped.isEmpty()).isTrue(); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(mapped::value); + } + + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsLessThanOrEqualTo() { + IsLessThanOrEqualTo nullCond = SqlBuilder.isLessThanOrEqualTo((Integer) null); // should be an IDE warning + assertThat(nullCond.isEmpty()).isFalse(); + + IsLessThanOrEqualTo cond = SqlBuilder.isLessThanOrEqualTo(1); + IsLessThanOrEqualTo filtered = cond.filter(i -> i == 1); + IsLessThanOrEqualTo mapped = filtered.map(i -> null); // should be an IDE warning + assertThat(mapped.isEmpty()).isFalse(); + assertThat(mapped.value()).isNull(); + } + + @Test + void testIsLessThanOrEqualToWhenPresent() { + IsLessThanOrEqualToWhenPresent nullCond = SqlBuilder.isLessThanOrEqualToWhenPresent((Integer) null); + assertThat(nullCond.isEmpty()).isTrue(); + + IsLessThanOrEqualToWhenPresent cond = SqlBuilder.isLessThanOrEqualToWhenPresent(1); + IsLessThanOrEqualToWhenPresent filtered = cond.filter(i -> i == 1); + IsLessThanOrEqualToWhenPresent mapped = filtered.map(i -> null); + assertThat(mapped.isEmpty()).isTrue(); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(mapped::value); + } + + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsNotBetween() { + IsNotBetween nullCond = SqlBuilder.isNotBetween((Integer) null).and((Integer) null); + assertThat(nullCond.isEmpty()).isFalse(); + + IsNotBetween cond = SqlBuilder.isNotBetween(1).and(10); + IsNotBetween filtered = cond.filter(i -> i >= 1); + IsNotBetween mapped = filtered.map(i -> null); + assertThat(mapped.isEmpty()).isFalse(); + + mapped = filtered.map(v1 -> null, v2 -> null); + assertThat(mapped.isEmpty()).isFalse(); + assertThat(mapped.value1()).isNull(); + assertThat(mapped.value2()).isNull(); + } + + @Test + void testIsNotBetweenWhenPresent() { + IsNotBetweenWhenPresent nullCond = SqlBuilder.isNotBetweenWhenPresent((Integer) null).and((Integer) null); + assertThat(nullCond.isEmpty()).isTrue(); + + IsNotBetweenWhenPresent cond = SqlBuilder.isNotBetweenWhenPresent(1).and(10); + IsNotBetweenWhenPresent filtered = cond.filter(i -> i == 1); + IsNotBetweenWhenPresent mapped = filtered.map(i -> null); + assertThat(mapped.isEmpty()).isTrue(); + + mapped = filtered.map(v1 -> null, v2 -> null); + assertThat(mapped.isEmpty()).isTrue(); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(mapped::value1); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(mapped::value2); + } + + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsNotEqualTo() { + IsNotEqualTo nullCond = SqlBuilder.isNotEqualTo((Integer) null); // should be an IDE warning + assertThat(nullCond.isEmpty()).isFalse(); + + IsNotEqualTo cond = SqlBuilder.isNotEqualTo(1); + IsNotEqualTo filtered = cond.filter(i -> i == 1); + IsNotEqualTo mapped = filtered.map(i -> null); // should be an IDE warning + assertThat(mapped.isEmpty()).isFalse(); + assertThat(mapped.value()).isNull(); + } + + @Test + void testIsNotEqualToWhenPresent() { + IsNotEqualToWhenPresent nullCond = SqlBuilder.isNotEqualToWhenPresent((Integer) null); + assertThat(nullCond.isEmpty()).isTrue(); + + IsNotEqualToWhenPresent cond = SqlBuilder.isNotEqualToWhenPresent(1); + IsNotEqualToWhenPresent filtered = cond.filter(i -> i == 1); + IsNotEqualToWhenPresent mapped = filtered.map(i -> null); + assertThat(mapped.isEmpty()).isTrue(); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(mapped::value); + } + + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsLike() { + IsLike nullCond = SqlBuilder.isLike((String) null); // should be an IDE warning + assertThat(nullCond.isEmpty()).isFalse(); + + IsLike cond = SqlBuilder.isLike("fred"); + IsLike filtered = cond.filter(i -> i.equals("fred")); + IsLike mapped = filtered.map(i -> null); // should be an IDE warning + assertThat(mapped.isEmpty()).isFalse(); + assertThat(mapped.value()).isNull(); + } + + @Test + void testIsLikeWhenPresent() { + IsLikeWhenPresent nullCond = SqlBuilder.isLikeWhenPresent((String) null); + assertThat(nullCond.isEmpty()).isTrue(); + + IsLikeWhenPresent cond = SqlBuilder.isLikeWhenPresent("fred"); + IsLikeWhenPresent filtered = cond.filter(i -> i.equals("fred")); + IsLikeWhenPresent mapped = filtered.map(i -> null); + assertThat(mapped.isEmpty()).isTrue(); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(mapped::value); + } + + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsLikeCaseInsensitive() { + IsLikeCaseInsensitive nullCond = SqlBuilder.isLikeCaseInsensitive((String) null); // should be an IDE warning + assertThat(nullCond.isEmpty()).isFalse(); + + IsLikeCaseInsensitive cond = SqlBuilder.isLikeCaseInsensitive("fred"); + IsLikeCaseInsensitive filtered = cond.filter(i -> i.equals("FRED")); + IsLikeCaseInsensitive mapped = filtered.map(i -> null); // should be an IDE warning + assertThat(mapped.isEmpty()).isFalse(); + assertThat(mapped.value()).isNull(); + } + + @Test + void testIsLikeCaseInsensitiveWhenPresent() { + IsLikeCaseInsensitiveWhenPresent nullCond = SqlBuilder.isLikeCaseInsensitiveWhenPresent((String) null); + assertThat(nullCond.isEmpty()).isTrue(); + + IsLikeCaseInsensitiveWhenPresent cond = SqlBuilder.isLikeCaseInsensitiveWhenPresent("fred"); + IsLikeCaseInsensitiveWhenPresent filtered = cond.filter(i -> i.equals("fred")); + IsLikeCaseInsensitiveWhenPresent mapped = filtered.map(i -> null); + assertThat(mapped.isEmpty()).isTrue(); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(mapped::value); + } + + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsNotLike() { + IsNotLike nullCond = SqlBuilder.isNotLike((String) null); // should be an IDE warning + assertThat(nullCond.isEmpty()).isFalse(); + + IsNotLike cond = SqlBuilder.isNotLike("fred"); + IsNotLike filtered = cond.filter(i -> i.equals("fred")); + IsNotLike mapped = filtered.map(i -> null); // should be an IDE warning + assertThat(mapped.isEmpty()).isFalse(); + assertThat(mapped.value()).isNull(); + } + + @Test + void testIsNotLikeWhenPresent() { + IsNotLikeWhenPresent nullCond = SqlBuilder.isNotLikeWhenPresent((String) null); + assertThat(nullCond.isEmpty()).isTrue(); + + IsNotLikeWhenPresent cond = SqlBuilder.isNotLikeWhenPresent("fred"); + IsNotLikeWhenPresent filtered = cond.filter(i -> i.equals("fred")); + IsNotLikeWhenPresent mapped = filtered.map(i -> null); + assertThat(mapped.isEmpty()).isTrue(); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(mapped::value); + } + + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsNotLikeCaseInsensitive() { + IsNotLikeCaseInsensitive nullCond = SqlBuilder.isNotLikeCaseInsensitive((String) null); // should be an IDE warning + assertThat(nullCond.isEmpty()).isFalse(); + + IsNotLikeCaseInsensitive cond = SqlBuilder.isNotLikeCaseInsensitive("fred"); + IsNotLikeCaseInsensitive filtered = cond.filter(i -> i.equals("FRED")); + IsNotLikeCaseInsensitive mapped = filtered.map(i -> null); // should be an IDE warning + assertThat(mapped.isEmpty()).isFalse(); + assertThat(mapped.value()).isNull(); + } + + @Test + void testIsNotLikeCaseInsensitiveWhenPresent() { + IsNotLikeCaseInsensitiveWhenPresent nullCond = SqlBuilder.isNotLikeCaseInsensitiveWhenPresent((String) null); + assertThat(nullCond.isEmpty()).isTrue(); + + IsNotLikeCaseInsensitiveWhenPresent cond = SqlBuilder.isNotLikeCaseInsensitiveWhenPresent("fred"); + IsNotLikeCaseInsensitiveWhenPresent filtered = cond.filter(i -> i.equals("FRED")); + IsNotLikeCaseInsensitiveWhenPresent mapped = filtered.map(i -> null); + assertThat(mapped.isEmpty()).isTrue(); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(mapped::value); + } + + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsIn() { + IsIn nullCond = SqlBuilder.isIn((Integer) null); // should be an IDE warning + assertThat(nullCond.isEmpty()).isFalse(); + + IsIn cond = SqlBuilder.isIn(1); + IsIn filtered = cond.filter(i -> i == 1); + IsIn mapped = filtered.map(i -> null); // should be an IDE warning + assertThat(mapped.isEmpty()).isFalse(); + assertThat(mapped.values().toList()).containsExactly((Integer) null); + } + + @Test + void testIsInWhenPresent() { + IsInWhenPresent nullCond = SqlBuilder.isInWhenPresent((Integer) null); + assertThat(nullCond.isEmpty()).isTrue(); + + IsInWhenPresent cond = SqlBuilder.isInWhenPresent(1); + IsInWhenPresent filtered = cond.filter(i -> i == 1); + IsInWhenPresent mapped = filtered.map(i -> null); + assertThat(mapped.isEmpty()).isTrue(); + assertThat(mapped.values().toList()).isEmpty();; + } + + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsInCaseInsensitive() { + IsInCaseInsensitive nullCond = SqlBuilder.isInCaseInsensitive((String) null); // should be an IDE warning + assertThat(nullCond.isEmpty()).isFalse(); + + IsInCaseInsensitive cond = SqlBuilder.isInCaseInsensitive("fred"); + IsInCaseInsensitive filtered = cond.filter(i -> i.equals("FRED")); + IsInCaseInsensitive mapped = filtered.map(i -> null); // should be an IDE warning + assertThat(mapped.isEmpty()).isFalse(); + assertThat(mapped.values().toList()).containsExactly((String) null); + } + + @Test + void testIsInCaseInsensitiveWhenPresent() { + IsInCaseInsensitiveWhenPresent nullCond = SqlBuilder.isInCaseInsensitiveWhenPresent((String) null); + assertThat(nullCond.isEmpty()).isTrue(); + + IsInCaseInsensitiveWhenPresent cond = SqlBuilder.isInCaseInsensitiveWhenPresent("fred"); + IsInCaseInsensitiveWhenPresent filtered = cond.filter(i -> i.equals("FRED")); + IsInCaseInsensitiveWhenPresent mapped = filtered.map(i -> null); + assertThat(mapped.isEmpty()).isTrue(); + assertThat(mapped.values().toList()).isEmpty();; + } + + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsNotIn() { + IsNotIn nullCond = SqlBuilder.isNotIn((Integer) null); // should be an IDE warning + assertThat(nullCond.isEmpty()).isFalse(); + + IsNotIn cond = SqlBuilder.isNotIn(1); + IsNotIn filtered = cond.filter(i -> i == 1); + IsNotIn mapped = filtered.map(i -> null); // should be an IDE warning + assertThat(mapped.isEmpty()).isFalse(); + assertThat(mapped.values().toList()).containsExactly((Integer) null); + } + + @Test + void testIsNotInWhenPresent() { + IsNotInWhenPresent nullCond = SqlBuilder.isNotInWhenPresent((Integer) null); + assertThat(nullCond.isEmpty()).isTrue(); + + IsNotInWhenPresent cond = SqlBuilder.isNotInWhenPresent(1); + IsNotInWhenPresent filtered = cond.filter(i -> i == 1); + IsNotInWhenPresent mapped = filtered.map(i -> null); + assertThat(mapped.isEmpty()).isTrue(); + assertThat(mapped.values().toList()).isEmpty();; + } + + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsNotInCaseInsensitive() { + IsNotInCaseInsensitive nullCond = SqlBuilder.isNotInCaseInsensitive((String) null); // should be an IDE warning + assertThat(nullCond.isEmpty()).isFalse(); + + IsNotInCaseInsensitive cond = SqlBuilder.isNotInCaseInsensitive("fred"); + IsNotInCaseInsensitive filtered = cond.filter(i -> i.equals("FRED")); + IsNotInCaseInsensitive mapped = filtered.map(i -> null); // should be an IDE warning + assertThat(mapped.isEmpty()).isFalse(); + assertThat(mapped.values().toList()).containsExactly((String) null); + } + + @Test + void testIsNotInCaseInsensitiveWhenPresent() { + IsNotInCaseInsensitiveWhenPresent nullCond = SqlBuilder.isNotInCaseInsensitiveWhenPresent((String) null); + assertThat(nullCond.isEmpty()).isTrue(); + + IsNotInCaseInsensitiveWhenPresent cond = SqlBuilder.isNotInCaseInsensitiveWhenPresent("fred"); + IsNotInCaseInsensitiveWhenPresent filtered = cond.filter(i -> i.equals("FRED")); + IsNotInCaseInsensitiveWhenPresent mapped = filtered.map(i -> null); + assertThat(mapped.isEmpty()).isTrue(); + assertThat(mapped.values().toList()).isEmpty();; + } +} diff --git a/src/test/java/org/mybatis/dynamic/sql/where/condition/SupplierTest.java b/src/test/java/org/mybatis/dynamic/sql/where/condition/SupplierTest.java index b85a7f412..c2bf40ddf 100644 --- a/src/test/java/org/mybatis/dynamic/sql/where/condition/SupplierTest.java +++ b/src/test/java/org/mybatis/dynamic/sql/where/condition/SupplierTest.java @@ -44,7 +44,7 @@ void testIsBetweenNull() { @Test void testIsBetweenWhenPresent() { - IsBetween cond = SqlBuilder.isBetweenWhenPresent(() -> 3).and(() -> 4); + IsBetweenWhenPresent cond = SqlBuilder.isBetweenWhenPresent(() -> 3).and(() -> 4); assertThat(cond.value1()).isEqualTo(3); assertThat(cond.value2()).isEqualTo(4); assertThat(cond.isEmpty()).isFalse(); @@ -52,7 +52,7 @@ void testIsBetweenWhenPresent() { @Test void testIsBetweenWhenPresentNull() { - IsBetween cond = SqlBuilder.isBetweenWhenPresent(() -> (Integer) null).and(() -> null); + IsBetweenWhenPresent cond = SqlBuilder.isBetweenWhenPresent(() -> (Integer) null).and(() -> null); assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value1); assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value2); assertThat(cond.isEmpty()).isTrue(); @@ -76,7 +76,7 @@ void testIsNotBetweenNull() { @Test void testIsNotBetweenWhenPresent() { - IsNotBetween cond = SqlBuilder.isNotBetweenWhenPresent(() -> 3).and(() -> 4); + IsNotBetweenWhenPresent cond = SqlBuilder.isNotBetweenWhenPresent(() -> 3).and(() -> 4); assertThat(cond.value1()).isEqualTo(3); assertThat(cond.value2()).isEqualTo(4); assertThat(cond.isEmpty()).isFalse(); @@ -84,7 +84,7 @@ void testIsNotBetweenWhenPresent() { @Test void testIsNotBetweenWhenPresentNull() { - IsNotBetween cond = SqlBuilder.isNotBetweenWhenPresent(() -> (Integer) null).and(() -> null); + IsNotBetweenWhenPresent cond = SqlBuilder.isNotBetweenWhenPresent(() -> (Integer) null).and(() -> null); assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value1); assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value2); assertThat(cond.isEmpty()).isTrue(); @@ -92,14 +92,14 @@ void testIsNotBetweenWhenPresentNull() { @Test void testIsEqualToWhenPresent() { - IsEqualTo cond = SqlBuilder.isEqualToWhenPresent(() -> 3); + IsEqualToWhenPresent cond = SqlBuilder.isEqualToWhenPresent(() -> 3); assertThat(cond.value()).isEqualTo(3); assertThat(cond.isEmpty()).isFalse(); } @Test void testIsEqualToWhenPresentNull() { - IsEqualTo cond = SqlBuilder.isEqualToWhenPresent(() -> null); + IsEqualToWhenPresent cond = SqlBuilder.isEqualToWhenPresent(() -> null); assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value); assertThat(cond.isEmpty()).isTrue(); } @@ -120,14 +120,14 @@ void testIsNotEqualToNull() { @Test void testIsNotEqualToWhenPresent() { - IsNotEqualTo cond = SqlBuilder.isNotEqualToWhenPresent(() -> 3); + IsNotEqualToWhenPresent cond = SqlBuilder.isNotEqualToWhenPresent(() -> 3); assertThat(cond.value()).isEqualTo(3); assertThat(cond.isEmpty()).isFalse(); } @Test void testIsNotEqualToWhenPresentNull() { - IsNotEqualTo cond = SqlBuilder.isNotEqualToWhenPresent(() -> null); + IsNotEqualToWhenPresent cond = SqlBuilder.isNotEqualToWhenPresent(() -> null); assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value); assertThat(cond.isEmpty()).isTrue(); } @@ -148,14 +148,14 @@ void testIsGreaterThanNull() { @Test void testIsGreaterThanWhenPresent() { - IsGreaterThan cond = SqlBuilder.isGreaterThanWhenPresent(() -> 3); + IsGreaterThanWhenPresent cond = SqlBuilder.isGreaterThanWhenPresent(() -> 3); assertThat(cond.value()).isEqualTo(3); assertThat(cond.isEmpty()).isFalse(); } @Test void testIsGreaterThanWhenPresentNull() { - IsGreaterThan cond = SqlBuilder.isGreaterThanWhenPresent(() -> null); + IsGreaterThanWhenPresent cond = SqlBuilder.isGreaterThanWhenPresent(() -> null); assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value); assertThat(cond.isEmpty()).isTrue(); } @@ -176,14 +176,14 @@ void testIsGreaterThanOrEqualToNull() { @Test void testIsGreaterThanOrEqualToWhenPresent() { - IsGreaterThanOrEqualTo cond = SqlBuilder.isGreaterThanOrEqualToWhenPresent(() -> 3); + IsGreaterThanOrEqualToWhenPresent cond = SqlBuilder.isGreaterThanOrEqualToWhenPresent(() -> 3); assertThat(cond.value()).isEqualTo(3); assertThat(cond.isEmpty()).isFalse(); } @Test void testIsGreaterThanOrEqualToWhenPresentNull() { - IsGreaterThanOrEqualTo cond = SqlBuilder.isGreaterThanOrEqualToWhenPresent(() -> null); + IsGreaterThanOrEqualToWhenPresent cond = SqlBuilder.isGreaterThanOrEqualToWhenPresent(() -> null); assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value); assertThat(cond.isEmpty()).isTrue(); } @@ -204,14 +204,14 @@ void testIsLessThanNull() { @Test void testIsLessThanWhenPresent() { - IsLessThan cond = SqlBuilder.isLessThanWhenPresent(() -> 3); + IsLessThanWhenPresent cond = SqlBuilder.isLessThanWhenPresent(() -> 3); assertThat(cond.value()).isEqualTo(3); assertThat(cond.isEmpty()).isFalse(); } @Test void testIsLessThanWhenPresentNull() { - IsLessThan cond = SqlBuilder.isLessThanWhenPresent(() -> null); + IsLessThanWhenPresent cond = SqlBuilder.isLessThanWhenPresent(() -> null); assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value); assertThat(cond.isEmpty()).isTrue(); } @@ -232,14 +232,14 @@ void testIsLessThanOrEqualToNull() { @Test void testIsLessThanOrEqualToWhenPresent() { - IsLessThanOrEqualTo cond = SqlBuilder.isLessThanOrEqualToWhenPresent(() -> 3); + IsLessThanOrEqualToWhenPresent cond = SqlBuilder.isLessThanOrEqualToWhenPresent(() -> 3); assertThat(cond.value()).isEqualTo(3); assertThat(cond.isEmpty()).isFalse(); } @Test void testIsLessThanOrEqualToWhenPresentNull() { - IsLessThanOrEqualTo cond = SqlBuilder.isLessThanOrEqualToWhenPresent(() -> null); + IsLessThanOrEqualToWhenPresent cond = SqlBuilder.isLessThanOrEqualToWhenPresent(() -> null); assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value); assertThat(cond.isEmpty()).isTrue(); } @@ -274,28 +274,28 @@ void testIsLikeCaseInsensitiveNull() { @Test void testIsLikeCaseInsensitiveWhenPresent() { - IsLikeCaseInsensitive cond = SqlBuilder.isLikeCaseInsensitiveWhenPresent(() -> "%f%"); + IsLikeCaseInsensitiveWhenPresent cond = SqlBuilder.isLikeCaseInsensitiveWhenPresent(() -> "%f%"); assertThat(cond.value()).isEqualTo("%F%"); assertThat(cond.isEmpty()).isFalse(); } @Test void testIsLikeCaseInsensitiveWhenPresentNull() { - IsLikeCaseInsensitive cond = SqlBuilder.isLikeCaseInsensitiveWhenPresent(() -> null); + IsLikeCaseInsensitiveWhenPresent cond = SqlBuilder.isLikeCaseInsensitiveWhenPresent(() -> null); assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value); assertThat(cond.isEmpty()).isTrue(); } @Test void testIsLikeWhenPresent() { - IsLike cond = SqlBuilder.isLikeWhenPresent(() -> "%F%"); + IsLikeWhenPresent cond = SqlBuilder.isLikeWhenPresent(() -> "%F%"); assertThat(cond.value()).isEqualTo("%F%"); assertThat(cond.isEmpty()).isFalse(); } @Test void testIsLikeWhenPresentNull() { - IsLike cond = SqlBuilder.isLikeWhenPresent(() -> null); + IsLikeWhenPresent cond = SqlBuilder.isLikeWhenPresent(() -> null); assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value); assertThat(cond.isEmpty()).isTrue(); } @@ -316,14 +316,14 @@ void testIsNotLikeNull() { @Test void testIsNotLikeWhenPresent() { - IsNotLike cond = SqlBuilder.isNotLikeWhenPresent(() -> "%F%"); + IsNotLikeWhenPresent cond = SqlBuilder.isNotLikeWhenPresent(() -> "%F%"); assertThat(cond.value()).isEqualTo("%F%"); assertThat(cond.isEmpty()).isFalse(); } @Test void testIsNotLikeWhenPresentNull() { - IsNotLike cond = SqlBuilder.isNotLikeWhenPresent(() -> null); + IsNotLikeWhenPresent cond = SqlBuilder.isNotLikeWhenPresent(() -> null); assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value); assertThat(cond.isEmpty()).isTrue(); } @@ -344,14 +344,14 @@ void testIsNotLikeCaseInsensitiveNull() { @Test void testIsNotLikeCaseInsensitiveWhenPresent() { - IsNotLikeCaseInsensitive cond = SqlBuilder.isNotLikeCaseInsensitiveWhenPresent(() -> "%f%"); + IsNotLikeCaseInsensitiveWhenPresent cond = SqlBuilder.isNotLikeCaseInsensitiveWhenPresent(() -> "%f%"); assertThat(cond.value()).isEqualTo("%F%"); assertThat(cond.isEmpty()).isFalse(); } @Test void testIsNotLikeCaseInsensitiveWhenPresentNull() { - IsNotLikeCaseInsensitive cond = SqlBuilder.isNotLikeCaseInsensitiveWhenPresent(() -> null); + IsNotLikeCaseInsensitiveWhenPresent cond = SqlBuilder.isNotLikeCaseInsensitiveWhenPresent(() -> null); assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value); assertThat(cond.isEmpty()).isTrue(); } From d1771e82ab9177dca387c3060d9e839c48e80a8c Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Sun, 6 Apr 2025 18:19:37 -0400 Subject: [PATCH 232/289] Checkstyle --- .../dynamic/sql/where/condition/NullContractTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/java/org/mybatis/dynamic/sql/where/condition/NullContractTest.java b/src/test/java/org/mybatis/dynamic/sql/where/condition/NullContractTest.java index 35f0440d8..6ea7b2909 100644 --- a/src/test/java/org/mybatis/dynamic/sql/where/condition/NullContractTest.java +++ b/src/test/java/org/mybatis/dynamic/sql/where/condition/NullContractTest.java @@ -361,7 +361,7 @@ void testIsInWhenPresent() { IsInWhenPresent filtered = cond.filter(i -> i == 1); IsInWhenPresent mapped = filtered.map(i -> null); assertThat(mapped.isEmpty()).isTrue(); - assertThat(mapped.values().toList()).isEmpty();; + assertThat(mapped.values().toList()).isEmpty(); } @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing @@ -386,7 +386,7 @@ void testIsInCaseInsensitiveWhenPresent() { IsInCaseInsensitiveWhenPresent filtered = cond.filter(i -> i.equals("FRED")); IsInCaseInsensitiveWhenPresent mapped = filtered.map(i -> null); assertThat(mapped.isEmpty()).isTrue(); - assertThat(mapped.values().toList()).isEmpty();; + assertThat(mapped.values().toList()).isEmpty(); } @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing @@ -411,7 +411,7 @@ void testIsNotInWhenPresent() { IsNotInWhenPresent filtered = cond.filter(i -> i == 1); IsNotInWhenPresent mapped = filtered.map(i -> null); assertThat(mapped.isEmpty()).isTrue(); - assertThat(mapped.values().toList()).isEmpty();; + assertThat(mapped.values().toList()).isEmpty(); } @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing @@ -436,6 +436,6 @@ void testIsNotInCaseInsensitiveWhenPresent() { IsNotInCaseInsensitiveWhenPresent filtered = cond.filter(i -> i.equals("FRED")); IsNotInCaseInsensitiveWhenPresent mapped = filtered.map(i -> null); assertThat(mapped.isEmpty()).isTrue(); - assertThat(mapped.values().toList()).isEmpty();; + assertThat(mapped.values().toList()).isEmpty(); } } From ee2ccbf6c0e3f7c4a2b1f408351af28ff4a58682 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 7 Apr 2025 10:32:22 -0400 Subject: [PATCH 233/289] Add missing jSpecify annotations --- src/main/java/org/mybatis/dynamic/sql/delete/DeleteDSL.java | 2 +- src/main/java/org/mybatis/dynamic/sql/update/UpdateDSL.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/delete/DeleteDSL.java b/src/main/java/org/mybatis/dynamic/sql/delete/DeleteDSL.java index 3724e5395..aeebc5498 100644 --- a/src/main/java/org/mybatis/dynamic/sql/delete/DeleteDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/delete/DeleteDSL.java @@ -120,7 +120,7 @@ public DeleteDSL limit(long limit) { return limitWhenPresent(limit); } - public DeleteDSL limitWhenPresent(Long limit) { + public DeleteDSL limitWhenPresent(@Nullable Long limit) { return DeleteDSL.this.limitWhenPresent(limit); } diff --git a/src/main/java/org/mybatis/dynamic/sql/update/UpdateDSL.java b/src/main/java/org/mybatis/dynamic/sql/update/UpdateDSL.java index f33bbc074..fbac97595 100644 --- a/src/main/java/org/mybatis/dynamic/sql/update/UpdateDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/update/UpdateDSL.java @@ -202,7 +202,7 @@ public UpdateDSL limit(long limit) { return limitWhenPresent(limit); } - public UpdateDSL limitWhenPresent(Long limit) { + public UpdateDSL limitWhenPresent(@Nullable Long limit) { return UpdateDSL.this.limitWhenPresent(limit); } From 6315e94d65638b82d311a2214013e9c702285c1d Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 7 Apr 2025 10:43:12 -0400 Subject: [PATCH 234/289] Properly handle null row in sommon select mapper --- .../sql/util/mybatis3/CommonSelectMapper.java | 18 ++++++++++-------- .../animal/data/CommonSelectMapperTest.java | 16 ++++++++++++++++ 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/util/mybatis3/CommonSelectMapper.java b/src/main/java/org/mybatis/dynamic/sql/util/mybatis3/CommonSelectMapper.java index 1faa0bd05..789538fed 100644 --- a/src/main/java/org/mybatis/dynamic/sql/util/mybatis3/CommonSelectMapper.java +++ b/src/main/java/org/mybatis/dynamic/sql/util/mybatis3/CommonSelectMapper.java @@ -22,6 +22,7 @@ import java.util.function.Function; import org.apache.ibatis.annotations.SelectProvider; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.select.render.SelectStatementProvider; import org.mybatis.dynamic.sql.util.SqlProviderAdapter; @@ -58,7 +59,7 @@ public interface CommonSelectMapper { * @return A Map containing the row values. */ @SelectProvider(type = SqlProviderAdapter.class, method = "select") - Map selectOneMappedRow(SelectStatementProvider selectStatement); + @Nullable Map selectOneMappedRow(SelectStatementProvider selectStatement); /** * Select a single row of values and then convert the values to a custom type. This is similar @@ -74,9 +75,10 @@ public interface CommonSelectMapper { * @param the datatype of the converted object * @return the converted object */ - default R selectOne(SelectStatementProvider selectStatement, + default @Nullable R selectOne(SelectStatementProvider selectStatement, Function, R> rowMapper) { - return rowMapper.apply(selectOneMappedRow(selectStatement)); + var result = selectOneMappedRow(selectStatement); + return result == null ? null : rowMapper.apply(result); } /** @@ -122,7 +124,7 @@ default List selectMany(SelectStatementProvider selectStatement, * column is null */ @SelectProvider(type = SqlProviderAdapter.class, method = "select") - BigDecimal selectOneBigDecimal(SelectStatementProvider selectStatement); + @Nullable BigDecimal selectOneBigDecimal(SelectStatementProvider selectStatement); /** * Retrieve a single {@link java.math.BigDecimal} from a result set. The result set must have @@ -157,7 +159,7 @@ default List selectMany(SelectStatementProvider selectStatement, * column is null */ @SelectProvider(type = SqlProviderAdapter.class, method = "select") - Double selectOneDouble(SelectStatementProvider selectStatement); + @Nullable Double selectOneDouble(SelectStatementProvider selectStatement); /** * Retrieve a single {@link java.lang.Double} from a result set. The result set must have @@ -192,7 +194,7 @@ default List selectMany(SelectStatementProvider selectStatement, * column is null */ @SelectProvider(type = SqlProviderAdapter.class, method = "select") - Integer selectOneInteger(SelectStatementProvider selectStatement); + @Nullable Integer selectOneInteger(SelectStatementProvider selectStatement); /** * Retrieve a single {@link java.lang.Integer} from a result set. The result set must have @@ -227,7 +229,7 @@ default List selectMany(SelectStatementProvider selectStatement, * column is null */ @SelectProvider(type = SqlProviderAdapter.class, method = "select") - Long selectOneLong(SelectStatementProvider selectStatement); + @Nullable Long selectOneLong(SelectStatementProvider selectStatement); /** * Retrieve a single {@link java.lang.Long} from a result set. The result set must have @@ -262,7 +264,7 @@ default List selectMany(SelectStatementProvider selectStatement, * column is null */ @SelectProvider(type = SqlProviderAdapter.class, method = "select") - String selectOneString(SelectStatementProvider selectStatement); + @Nullable String selectOneString(SelectStatementProvider selectStatement); /** * Retrieve a single {@link java.lang.String} from a result set. The result set must have diff --git a/src/test/java/examples/animal/data/CommonSelectMapperTest.java b/src/test/java/examples/animal/data/CommonSelectMapperTest.java index 863df85e6..380d888f7 100644 --- a/src/test/java/examples/animal/data/CommonSelectMapperTest.java +++ b/src/test/java/examples/animal/data/CommonSelectMapperTest.java @@ -106,6 +106,7 @@ void testGeneralSelectOneWithRowMapper() { AnimalData animal = mapper.selectOne(selectStatement, rowMapper); + assertThat(animal).isNotNull(); assertThat(animal.getId()).isEqualTo(1); assertThat(animal.getAnimalName()).isEqualTo("Lesser short-tailed shrew"); assertThat(animal.getBodyWeight()).isEqualTo(0.14); @@ -113,6 +114,21 @@ void testGeneralSelectOneWithRowMapper() { } } + @Test + void testGeneralSelectOneWithRowMapperAndNullRow() { + try (SqlSession sqlSession = sqlSessionFactory.openSession()) { + CommonSelectMapper mapper = sqlSession.getMapper(CommonSelectMapper.class); + SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) + .from(animalData) + .where(id, isEqualTo(-237)) + .build() + .render(RenderingStrategies.MYBATIS3); + + AnimalData animal = mapper.selectOne(selectStatement, rowMapper); + assertThat(animal).isNull(); + } + } + @Test void testGeneralSelectMany() { try (SqlSession sqlSession = sqlSessionFactory.openSession()) { From 37fa65f2339ca2cf31a32b706c4b0d9506ebfd80 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 7 Apr 2025 10:50:44 -0400 Subject: [PATCH 235/289] Documentation --- .../mybatis/dynamic/sql/util/mybatis3/CommonSelectMapper.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/util/mybatis3/CommonSelectMapper.java b/src/main/java/org/mybatis/dynamic/sql/util/mybatis3/CommonSelectMapper.java index 789538fed..8f0f350ee 100644 --- a/src/main/java/org/mybatis/dynamic/sql/util/mybatis3/CommonSelectMapper.java +++ b/src/main/java/org/mybatis/dynamic/sql/util/mybatis3/CommonSelectMapper.java @@ -50,7 +50,7 @@ public interface CommonSelectMapper { /** * Select a single row as a Map of values. The row may have any number of columns. * The Map key will be the column name as returned from the - * database (may be aliased if an alias is specified in the select statement). Map entries will be + * database (the key will be aliased if an alias is specified in the select statement). Map entries will be * of data types determined by the JDBC driver. MyBatis will call ResultSet.getObject() to retrieve * values from the ResultSet. Reference your JDBC driver documentation to learn about type mappings * for your specific database. @@ -85,7 +85,7 @@ public interface CommonSelectMapper { * Select any number of rows and return a List of Maps containing row values (one Map for each row returned). * The rows may have any number of columns. * The Map key will be the column name as returned from the - * database (may be aliased if an alias is specified in the select statement). Map entries will be + * database (the key will be aliased if an alias is specified in the select statement). Map entries will be * of data types determined by the JDBC driver. MyBatis will call ResultSet.getObject() to retrieve * values from the ResultSet. Reference your JDBC driver documentation to learn about type mappings * for your specific database. From 26c973a6dfd9846975f0aa2d9afa2f10b2d38c07 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 7 Apr 2025 10:52:32 -0400 Subject: [PATCH 236/289] Fully denote the nullability of filter and map methods. Also fix al the tests that were, essentially, misuses of the library. --- .../sql/AbstractListValueCondition.java | 5 +- .../sql/AbstractSingleValueCondition.java | 5 +- .../sql/AbstractTwoValueCondition.java | 11 +- .../sql/where/condition/IsBetween.java | 12 +- .../where/condition/IsBetweenWhenPresent.java | 11 +- .../sql/where/condition/IsEqualTo.java | 5 +- .../where/condition/IsEqualToWhenPresent.java | 5 +- .../sql/where/condition/IsGreaterThan.java | 5 +- .../condition/IsGreaterThanOrEqualTo.java | 5 +- .../IsGreaterThanOrEqualToWhenPresent.java | 5 +- .../condition/IsGreaterThanWhenPresent.java | 5 +- .../dynamic/sql/where/condition/IsIn.java | 5 +- .../where/condition/IsInCaseInsensitive.java | 5 +- .../IsInCaseInsensitiveWhenPresent.java | 7 +- .../sql/where/condition/IsInWhenPresent.java | 7 +- .../sql/where/condition/IsLessThan.java | 5 +- .../where/condition/IsLessThanOrEqualTo.java | 5 +- .../IsLessThanOrEqualToWhenPresent.java | 5 +- .../condition/IsLessThanWhenPresent.java | 5 +- .../dynamic/sql/where/condition/IsLike.java | 5 +- .../condition/IsLikeCaseInsensitive.java | 5 +- .../IsLikeCaseInsensitiveWhenPresent.java | 5 +- .../where/condition/IsLikeWhenPresent.java | 5 +- .../sql/where/condition/IsNotBetween.java | 11 +- .../condition/IsNotBetweenWhenPresent.java | 11 +- .../sql/where/condition/IsNotEqualTo.java | 5 +- .../condition/IsNotEqualToWhenPresent.java | 5 +- .../dynamic/sql/where/condition/IsNotIn.java | 5 +- .../condition/IsNotInCaseInsensitive.java | 5 +- .../IsNotInCaseInsensitiveWhenPresent.java | 7 +- .../where/condition/IsNotInWhenPresent.java | 7 +- .../sql/where/condition/IsNotLike.java | 5 +- .../condition/IsNotLikeCaseInsensitive.java | 5 +- .../IsNotLikeCaseInsensitiveWhenPresent.java | 5 +- .../where/condition/IsNotLikeWhenPresent.java | 5 +- ...onditionsWithPredicatesAnimalDataTest.java | 109 +++++++----------- .../complexquery/ComplexQueryTest.java | 10 +- .../examples/emptywhere/EmptyWhereTest.java | 43 +++---- .../examples/simple/PersonMapperTest.java | 3 +- src/test/java/issues/gh105/Issue105Test.java | 43 ++++--- .../sql/where/condition/FilterAndMapTest.java | 27 ++--- .../sql/where/condition/NullContractTest.java | 90 +++++++++++++++ .../sql/where/condition/SupplierTest.java | 79 ------------- .../render/OptionalCriterionRenderTest.java | 3 +- 44 files changed, 315 insertions(+), 306 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/AbstractListValueCondition.java b/src/main/java/org/mybatis/dynamic/sql/AbstractListValueCondition.java index 41c6a56e2..e178c6bf3 100644 --- a/src/main/java/org/mybatis/dynamic/sql/AbstractListValueCondition.java +++ b/src/main/java/org/mybatis/dynamic/sql/AbstractListValueCondition.java @@ -23,6 +23,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import org.jspecify.annotations.NonNull; import org.mybatis.dynamic.sql.render.RenderedParameterInfo; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.util.FragmentAndParameters; @@ -113,7 +114,7 @@ public interface Filterable { * @return this condition if renderable and the value matches the predicate, otherwise a condition * that will not render. */ - AbstractListValueCondition filter(Predicate predicate); + AbstractListValueCondition filter(Predicate predicate); } /** @@ -138,6 +139,6 @@ public interface Mappable { * @return a new condition with the result of applying the mapper to the value of this condition, * if renderable, otherwise a condition that will not render. */ - AbstractListValueCondition map(Function mapper); + AbstractListValueCondition map(Function mapper); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/AbstractSingleValueCondition.java b/src/main/java/org/mybatis/dynamic/sql/AbstractSingleValueCondition.java index c16dbf08c..eb56eef39 100644 --- a/src/main/java/org/mybatis/dynamic/sql/AbstractSingleValueCondition.java +++ b/src/main/java/org/mybatis/dynamic/sql/AbstractSingleValueCondition.java @@ -21,6 +21,7 @@ import java.util.function.Predicate; import java.util.function.Supplier; +import org.jspecify.annotations.NonNull; import org.mybatis.dynamic.sql.render.RenderedParameterInfo; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.util.FragmentAndParameters; @@ -88,7 +89,7 @@ public interface Filterable { * @return this condition if renderable and the value matches the predicate, otherwise a condition * that will not render. */ - AbstractSingleValueCondition filter(Predicate predicate); + AbstractSingleValueCondition filter(Predicate predicate); } /** @@ -113,6 +114,6 @@ public interface Mappable { * @return a new condition with the result of applying the mapper to the value of this condition, * if renderable, otherwise a condition that will not render. */ - AbstractSingleValueCondition map(Function mapper); + AbstractSingleValueCondition map(Function mapper); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/AbstractTwoValueCondition.java b/src/main/java/org/mybatis/dynamic/sql/AbstractTwoValueCondition.java index 6cceff16e..d409ffbb8 100644 --- a/src/main/java/org/mybatis/dynamic/sql/AbstractTwoValueCondition.java +++ b/src/main/java/org/mybatis/dynamic/sql/AbstractTwoValueCondition.java @@ -23,6 +23,7 @@ import java.util.function.Predicate; import java.util.function.Supplier; +import org.jspecify.annotations.NonNull; import org.mybatis.dynamic.sql.render.RenderedParameterInfo; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.util.FragmentAndParameters; @@ -110,7 +111,7 @@ public interface Filterable { * @return this condition if renderable and the values match the predicate, otherwise a condition * that will not render. */ - AbstractTwoValueCondition filter(BiPredicate predicate); + AbstractTwoValueCondition filter(BiPredicate predicate); /** * If renderable and both values match the predicate, returns this condition. Else returns a condition @@ -121,7 +122,7 @@ public interface Filterable { * @return this condition if renderable and the values match the predicate, otherwise a condition * that will not render. */ - AbstractTwoValueCondition filter(Predicate predicate); + AbstractTwoValueCondition filter(Predicate predicate); } /** @@ -147,8 +148,8 @@ public interface Mappable { * @return a new condition with the result of applying the mappers to the values of this condition, * if renderable, otherwise a condition that will not render. */ - AbstractTwoValueCondition map(Function mapper1, - Function mapper2); + AbstractTwoValueCondition map(Function mapper1, + Function mapper2); /** * If renderable, apply the mapping to both values and return a new condition with the new values. Else return a @@ -159,6 +160,6 @@ AbstractTwoValueCondition map(Function mapper1, * @return a new condition with the result of applying the mappers to the values of this condition, * if renderable, otherwise a condition that will not render. */ - AbstractTwoValueCondition map(Function mapper); + AbstractTwoValueCondition map(Function mapper); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsBetween.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsBetween.java index fab5e70f6..0f7fcd66a 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsBetween.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsBetween.java @@ -20,9 +20,10 @@ import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; import org.mybatis.dynamic.sql.AbstractTwoValueCondition; -public class IsBetween extends AbstractTwoValueCondition +public class IsBetween extends AbstractTwoValueCondition<@NonNull T> implements AbstractTwoValueCondition.Filterable, AbstractTwoValueCondition.Mappable { private static final IsBetween EMPTY = new IsBetween(-1, -1) { @Override @@ -62,22 +63,23 @@ public String operator2() { } @Override - public IsBetween filter(BiPredicate predicate) { + public IsBetween filter(BiPredicate predicate) { return filterSupport(predicate, IsBetween::empty, this); } @Override - public IsBetween filter(Predicate predicate) { + public IsBetween filter(Predicate predicate) { return filterSupport(predicate, IsBetween::empty, this); } @Override - public IsBetween map(Function mapper1, Function mapper2) { + public IsBetween map(Function mapper1, + Function mapper2) { return mapSupport(mapper1, mapper2, IsBetween::new, IsBetween::empty); } @Override - public IsBetween map(Function mapper) { + public IsBetween map(Function mapper) { return map(mapper, mapper); } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsBetweenWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsBetweenWhenPresent.java index 8c23cdfbb..a3eb2a91e 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsBetweenWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsBetweenWhenPresent.java @@ -20,6 +20,7 @@ import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.AbstractTwoValueCondition; @@ -63,23 +64,23 @@ public String operator2() { } @Override - public IsBetweenWhenPresent filter(BiPredicate predicate) { + public IsBetweenWhenPresent filter(BiPredicate predicate) { return filterSupport(predicate, IsBetweenWhenPresent::empty, this); } @Override - public IsBetweenWhenPresent filter(Predicate predicate) { + public IsBetweenWhenPresent filter(Predicate predicate) { return filterSupport(predicate, IsBetweenWhenPresent::empty, this); } @Override - public IsBetweenWhenPresent map(Function mapper1, - Function mapper2) { + public IsBetweenWhenPresent map(Function mapper1, + Function mapper2) { return mapSupport(mapper1, mapper2, IsBetweenWhenPresent::of, IsBetweenWhenPresent::empty); } @Override - public IsBetweenWhenPresent map(Function mapper) { + public IsBetweenWhenPresent map(Function mapper) { return map(mapper, mapper); } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsEqualTo.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsEqualTo.java index 51e6e4d47..db8548f61 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsEqualTo.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsEqualTo.java @@ -19,6 +19,7 @@ import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; import org.mybatis.dynamic.sql.AbstractSingleValueCondition; public class IsEqualTo extends AbstractSingleValueCondition @@ -56,12 +57,12 @@ public static IsEqualTo of(T value) { } @Override - public IsEqualTo filter(Predicate predicate) { + public IsEqualTo filter(Predicate predicate) { return filterSupport(predicate, IsEqualTo::empty, this); } @Override - public IsEqualTo map(Function mapper) { + public IsEqualTo map(Function mapper) { return mapSupport(mapper, IsEqualTo::new, IsEqualTo::empty); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsEqualToWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsEqualToWhenPresent.java index f06489076..2dd8c746d 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsEqualToWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsEqualToWhenPresent.java @@ -19,6 +19,7 @@ import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.AbstractSingleValueCondition; @@ -61,12 +62,12 @@ public static IsEqualToWhenPresent of(@Nullable T value) { } @Override - public IsEqualToWhenPresent filter(Predicate predicate) { + public IsEqualToWhenPresent filter(Predicate predicate) { return filterSupport(predicate, IsEqualToWhenPresent::empty, this); } @Override - public IsEqualToWhenPresent map(Function mapper) { + public IsEqualToWhenPresent map(Function mapper) { return mapSupport(mapper, IsEqualToWhenPresent::of, IsEqualToWhenPresent::empty); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThan.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThan.java index 93be70911..577a400f2 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThan.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThan.java @@ -19,6 +19,7 @@ import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; import org.mybatis.dynamic.sql.AbstractSingleValueCondition; public class IsGreaterThan extends AbstractSingleValueCondition @@ -55,12 +56,12 @@ public static IsGreaterThan of(T value) { } @Override - public IsGreaterThan filter(Predicate predicate) { + public IsGreaterThan filter(Predicate predicate) { return filterSupport(predicate, IsGreaterThan::empty, this); } @Override - public IsGreaterThan map(Function mapper) { + public IsGreaterThan map(Function mapper) { return mapSupport(mapper, IsGreaterThan::new, IsGreaterThan::empty); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanOrEqualTo.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanOrEqualTo.java index 8373bf352..5fb4bd0d4 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanOrEqualTo.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanOrEqualTo.java @@ -19,6 +19,7 @@ import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; import org.mybatis.dynamic.sql.AbstractSingleValueCondition; public class IsGreaterThanOrEqualTo extends AbstractSingleValueCondition @@ -55,12 +56,12 @@ public static IsGreaterThanOrEqualTo of(T value) { } @Override - public IsGreaterThanOrEqualTo filter(Predicate predicate) { + public IsGreaterThanOrEqualTo filter(Predicate predicate) { return filterSupport(predicate, IsGreaterThanOrEqualTo::empty, this); } @Override - public IsGreaterThanOrEqualTo map(Function mapper) { + public IsGreaterThanOrEqualTo map(Function mapper) { return mapSupport(mapper, IsGreaterThanOrEqualTo::new, IsGreaterThanOrEqualTo::empty); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanOrEqualToWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanOrEqualToWhenPresent.java index 89e8cda4f..825b5c6cf 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanOrEqualToWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanOrEqualToWhenPresent.java @@ -19,6 +19,7 @@ import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.AbstractSingleValueCondition; @@ -60,12 +61,12 @@ public static IsGreaterThanOrEqualToWhenPresent of(@Nullable T value) { } @Override - public IsGreaterThanOrEqualToWhenPresent filter(Predicate predicate) { + public IsGreaterThanOrEqualToWhenPresent filter(Predicate predicate) { return filterSupport(predicate, IsGreaterThanOrEqualToWhenPresent::empty, this); } @Override - public IsGreaterThanOrEqualToWhenPresent map(Function mapper) { + public IsGreaterThanOrEqualToWhenPresent map(Function mapper) { return mapSupport(mapper, IsGreaterThanOrEqualToWhenPresent::of, IsGreaterThanOrEqualToWhenPresent::empty); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanWhenPresent.java index 175b5fcf6..779a15596 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanWhenPresent.java @@ -19,6 +19,7 @@ import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.AbstractSingleValueCondition; @@ -60,12 +61,12 @@ public static IsGreaterThanWhenPresent of(@Nullable T value) { } @Override - public IsGreaterThanWhenPresent filter(Predicate predicate) { + public IsGreaterThanWhenPresent filter(Predicate predicate) { return filterSupport(predicate, IsGreaterThanWhenPresent::empty, this); } @Override - public IsGreaterThanWhenPresent map(Function mapper) { + public IsGreaterThanWhenPresent map(Function mapper) { return mapSupport(mapper, IsGreaterThanWhenPresent::of, IsGreaterThanWhenPresent::empty); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsIn.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsIn.java index 8beeacc8d..886980610 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsIn.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsIn.java @@ -21,6 +21,7 @@ import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; import org.mybatis.dynamic.sql.AbstractListValueCondition; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.util.Validator; @@ -51,12 +52,12 @@ public String operator() { } @Override - public IsIn filter(Predicate predicate) { + public IsIn filter(Predicate predicate) { return filterSupport(predicate, IsIn::new, this, IsIn::empty); } @Override - public IsIn map(Function mapper) { + public IsIn map(Function mapper) { return mapSupport(mapper, IsIn::new, IsIn::empty); } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java index 3e2a22d2a..d26a9c30f 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java @@ -21,6 +21,7 @@ import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; import org.mybatis.dynamic.sql.AbstractListValueCondition; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.util.StringUtilities; @@ -53,12 +54,12 @@ public String operator() { } @Override - public IsInCaseInsensitive filter(Predicate predicate) { + public IsInCaseInsensitive filter(Predicate predicate) { return filterSupport(predicate, IsInCaseInsensitive::new, this, IsInCaseInsensitive::empty); } @Override - public IsInCaseInsensitive map(Function mapper) { + public IsInCaseInsensitive map(Function mapper) { return mapSupport(mapper, IsInCaseInsensitive::new, IsInCaseInsensitive::empty); } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java index ac3ce2787..934df359b 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java @@ -22,6 +22,7 @@ import java.util.Objects; import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.AbstractListValueCondition; import org.mybatis.dynamic.sql.util.StringUtilities; @@ -48,13 +49,13 @@ public String operator() { } @Override - public IsInCaseInsensitiveWhenPresent filter(Predicate predicate) { + public IsInCaseInsensitiveWhenPresent filter(Predicate predicate) { return filterSupport(predicate, IsInCaseInsensitiveWhenPresent::new, this, IsInCaseInsensitiveWhenPresent::empty); } @Override - public IsInCaseInsensitiveWhenPresent map(Function mapper) { + public IsInCaseInsensitiveWhenPresent map(Function mapper) { return mapSupport(mapper, IsInCaseInsensitiveWhenPresent::new, IsInCaseInsensitiveWhenPresent::empty); } @@ -64,7 +65,7 @@ public static IsInCaseInsensitiveWhenPresent of(@Nullable T... values) { } public static IsInCaseInsensitiveWhenPresent of(@Nullable Collection<@Nullable T> values) { - if (values == null || values.isEmpty()) { + if (values == null) { return empty(); } else { return new IsInCaseInsensitiveWhenPresent<>(values); diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInWhenPresent.java index 1ec8185ee..2dec62d72 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInWhenPresent.java @@ -22,6 +22,7 @@ import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.AbstractListValueCondition; @@ -45,12 +46,12 @@ public String operator() { } @Override - public IsInWhenPresent filter(Predicate predicate) { + public IsInWhenPresent filter(Predicate predicate) { return filterSupport(predicate, IsInWhenPresent::new, this, IsInWhenPresent::empty); } @Override - public IsInWhenPresent map(Function mapper) { + public IsInWhenPresent map(Function mapper) { return mapSupport(mapper, IsInWhenPresent::of, IsInWhenPresent::empty); } @@ -60,7 +61,7 @@ public static IsInWhenPresent of(@Nullable T... values) { } public static IsInWhenPresent of(@Nullable Collection<@Nullable T> values) { - if (values == null || values.isEmpty()) { + if (values == null) { return empty(); } else { return new IsInWhenPresent<>(values); diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThan.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThan.java index 3ed383fbd..ffe66bd97 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThan.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThan.java @@ -19,6 +19,7 @@ import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; import org.mybatis.dynamic.sql.AbstractSingleValueCondition; public class IsLessThan extends AbstractSingleValueCondition @@ -56,12 +57,12 @@ public static IsLessThan of(T value) { } @Override - public IsLessThan filter(Predicate predicate) { + public IsLessThan filter(Predicate predicate) { return filterSupport(predicate, IsLessThan::empty, this); } @Override - public IsLessThan map(Function mapper) { + public IsLessThan map(Function mapper) { return mapSupport(mapper, IsLessThan::new, IsLessThan::empty); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanOrEqualTo.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanOrEqualTo.java index 1b92e0c40..a73707e3e 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanOrEqualTo.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanOrEqualTo.java @@ -19,6 +19,7 @@ import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; import org.mybatis.dynamic.sql.AbstractSingleValueCondition; public class IsLessThanOrEqualTo extends AbstractSingleValueCondition @@ -55,12 +56,12 @@ public static IsLessThanOrEqualTo of(T value) { } @Override - public IsLessThanOrEqualTo filter(Predicate predicate) { + public IsLessThanOrEqualTo filter(Predicate predicate) { return filterSupport(predicate, IsLessThanOrEqualTo::empty, this); } @Override - public IsLessThanOrEqualTo map(Function mapper) { + public IsLessThanOrEqualTo map(Function mapper) { return mapSupport(mapper, IsLessThanOrEqualTo::new, IsLessThanOrEqualTo::empty); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanOrEqualToWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanOrEqualToWhenPresent.java index 3cdc8ff39..d944b7a45 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanOrEqualToWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanOrEqualToWhenPresent.java @@ -19,6 +19,7 @@ import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.AbstractSingleValueCondition; @@ -60,12 +61,12 @@ public static IsLessThanOrEqualToWhenPresent of(@Nullable T value) { } @Override - public IsLessThanOrEqualToWhenPresent filter(Predicate predicate) { + public IsLessThanOrEqualToWhenPresent filter(Predicate predicate) { return filterSupport(predicate, IsLessThanOrEqualToWhenPresent::empty, this); } @Override - public IsLessThanOrEqualToWhenPresent map(Function mapper) { + public IsLessThanOrEqualToWhenPresent map(Function mapper) { return mapSupport(mapper, IsLessThanOrEqualToWhenPresent::of, IsLessThanOrEqualToWhenPresent::empty); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanWhenPresent.java index 78a07f9a2..830bf788c 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanWhenPresent.java @@ -19,6 +19,7 @@ import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.AbstractSingleValueCondition; @@ -61,12 +62,12 @@ public static IsLessThanWhenPresent of(@Nullable T value) { } @Override - public IsLessThanWhenPresent filter(Predicate predicate) { + public IsLessThanWhenPresent filter(Predicate predicate) { return filterSupport(predicate, IsLessThanWhenPresent::empty, this); } @Override - public IsLessThanWhenPresent map(Function mapper) { + public IsLessThanWhenPresent map(Function mapper) { return mapSupport(mapper, IsLessThanWhenPresent::of, IsLessThanWhenPresent::empty); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLike.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLike.java index e738bda4c..f2d2a419a 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLike.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLike.java @@ -19,6 +19,7 @@ import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; import org.mybatis.dynamic.sql.AbstractSingleValueCondition; public class IsLike extends AbstractSingleValueCondition @@ -56,12 +57,12 @@ public static IsLike of(T value) { } @Override - public IsLike filter(Predicate predicate) { + public IsLike filter(Predicate predicate) { return filterSupport(predicate, IsLike::empty, this); } @Override - public IsLike map(Function mapper) { + public IsLike map(Function mapper) { return mapSupport(mapper, IsLike::new, IsLike::empty); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitive.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitive.java index ffdc2bc7d..43525e287 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitive.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitive.java @@ -19,6 +19,7 @@ import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; import org.mybatis.dynamic.sql.AbstractSingleValueCondition; import org.mybatis.dynamic.sql.util.StringUtilities; @@ -53,12 +54,12 @@ public String operator() { } @Override - public IsLikeCaseInsensitive filter(Predicate predicate) { + public IsLikeCaseInsensitive filter(Predicate predicate) { return filterSupport(predicate, IsLikeCaseInsensitive::empty, this); } @Override - public IsLikeCaseInsensitive map(Function mapper) { + public IsLikeCaseInsensitive map(Function mapper) { return mapSupport(mapper, IsLikeCaseInsensitive::new, IsLikeCaseInsensitive::empty); } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitiveWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitiveWhenPresent.java index 89ab9b038..bebbff30d 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitiveWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitiveWhenPresent.java @@ -19,6 +19,7 @@ import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.AbstractSingleValueCondition; import org.mybatis.dynamic.sql.util.StringUtilities; @@ -54,12 +55,12 @@ public String operator() { } @Override - public IsLikeCaseInsensitiveWhenPresent filter(Predicate predicate) { + public IsLikeCaseInsensitiveWhenPresent filter(Predicate predicate) { return filterSupport(predicate, IsLikeCaseInsensitiveWhenPresent::empty, this); } @Override - public IsLikeCaseInsensitiveWhenPresent map(Function mapper) { + public IsLikeCaseInsensitiveWhenPresent map(Function mapper) { return mapSupport(mapper, IsLikeCaseInsensitiveWhenPresent::of, IsLikeCaseInsensitiveWhenPresent::empty); } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeWhenPresent.java index a69e55356..fc20722a2 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeWhenPresent.java @@ -19,6 +19,7 @@ import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.AbstractSingleValueCondition; @@ -61,12 +62,12 @@ public static IsLikeWhenPresent of(@Nullable T value) { } @Override - public IsLikeWhenPresent filter(Predicate predicate) { + public IsLikeWhenPresent filter(Predicate predicate) { return filterSupport(predicate, IsLikeWhenPresent::empty, this); } @Override - public IsLikeWhenPresent map(Function mapper) { + public IsLikeWhenPresent map(Function mapper) { return mapSupport(mapper, IsLikeWhenPresent::of, IsLikeWhenPresent::empty); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotBetween.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotBetween.java index 836e3c741..b3d0d59ff 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotBetween.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotBetween.java @@ -20,6 +20,7 @@ import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; import org.mybatis.dynamic.sql.AbstractTwoValueCondition; public class IsNotBetween extends AbstractTwoValueCondition @@ -62,23 +63,23 @@ public String operator2() { } @Override - public IsNotBetween filter(BiPredicate predicate) { + public IsNotBetween filter(BiPredicate predicate) { return filterSupport(predicate, IsNotBetween::empty, this); } @Override - public IsNotBetween filter(Predicate predicate) { + public IsNotBetween filter(Predicate predicate) { return filterSupport(predicate, IsNotBetween::empty, this); } @Override - public IsNotBetween map(Function mapper1, - Function mapper2) { + public IsNotBetween map(Function mapper1, + Function mapper2) { return mapSupport(mapper1, mapper2, IsNotBetween::new, IsNotBetween::empty); } @Override - public IsNotBetween map(Function mapper) { + public IsNotBetween map(Function mapper) { return map(mapper, mapper); } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotBetweenWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotBetweenWhenPresent.java index 23b6507d5..cb9860384 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotBetweenWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotBetweenWhenPresent.java @@ -20,6 +20,7 @@ import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.AbstractTwoValueCondition; @@ -63,23 +64,23 @@ public String operator2() { } @Override - public IsNotBetweenWhenPresent filter(BiPredicate predicate) { + public IsNotBetweenWhenPresent filter(BiPredicate predicate) { return filterSupport(predicate, IsNotBetweenWhenPresent::empty, this); } @Override - public IsNotBetweenWhenPresent filter(Predicate predicate) { + public IsNotBetweenWhenPresent filter(Predicate predicate) { return filterSupport(predicate, IsNotBetweenWhenPresent::empty, this); } @Override - public IsNotBetweenWhenPresent map(Function mapper1, - Function mapper2) { + public IsNotBetweenWhenPresent map(Function mapper1, + Function mapper2) { return mapSupport(mapper1, mapper2, IsNotBetweenWhenPresent::of, IsNotBetweenWhenPresent::empty); } @Override - public IsNotBetweenWhenPresent map(Function mapper) { + public IsNotBetweenWhenPresent map(Function mapper) { return map(mapper, mapper); } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotEqualTo.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotEqualTo.java index 39070c2e8..fc0292070 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotEqualTo.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotEqualTo.java @@ -19,6 +19,7 @@ import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; import org.mybatis.dynamic.sql.AbstractSingleValueCondition; public class IsNotEqualTo extends AbstractSingleValueCondition @@ -55,12 +56,12 @@ public static IsNotEqualTo of(T value) { } @Override - public IsNotEqualTo filter(Predicate predicate) { + public IsNotEqualTo filter(Predicate predicate) { return filterSupport(predicate, IsNotEqualTo::empty, this); } @Override - public IsNotEqualTo map(Function mapper) { + public IsNotEqualTo map(Function mapper) { return mapSupport(mapper, IsNotEqualTo::new, IsNotEqualTo::empty); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotEqualToWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotEqualToWhenPresent.java index 07ab3f6cf..1fff2d9ba 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotEqualToWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotEqualToWhenPresent.java @@ -19,6 +19,7 @@ import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.AbstractSingleValueCondition; @@ -60,12 +61,12 @@ public static IsNotEqualToWhenPresent of(@Nullable T value) { } @Override - public IsNotEqualToWhenPresent filter(Predicate predicate) { + public IsNotEqualToWhenPresent filter(Predicate predicate) { return filterSupport(predicate, IsNotEqualToWhenPresent::empty, this); } @Override - public IsNotEqualToWhenPresent map(Function mapper) { + public IsNotEqualToWhenPresent map(Function mapper) { return mapSupport(mapper, IsNotEqualToWhenPresent::of, IsNotEqualToWhenPresent::empty); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotIn.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotIn.java index 33f5d14c7..f6c70d180 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotIn.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotIn.java @@ -21,6 +21,7 @@ import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; import org.mybatis.dynamic.sql.AbstractListValueCondition; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.util.Validator; @@ -51,12 +52,12 @@ public String operator() { } @Override - public IsNotIn filter(Predicate predicate) { + public IsNotIn filter(Predicate predicate) { return filterSupport(predicate, IsNotIn::new, this, IsNotIn::empty); } @Override - public IsNotIn map(Function mapper) { + public IsNotIn map(Function mapper) { return mapSupport(mapper, IsNotIn::new, IsNotIn::empty); } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java index 2bc802ab8..98a9ca9db 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java @@ -21,6 +21,7 @@ import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; import org.mybatis.dynamic.sql.AbstractListValueCondition; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.util.StringUtilities; @@ -53,12 +54,12 @@ public String operator() { } @Override - public IsNotInCaseInsensitive filter(Predicate predicate) { + public IsNotInCaseInsensitive filter(Predicate predicate) { return filterSupport(predicate, IsNotInCaseInsensitive::new, this, IsNotInCaseInsensitive::empty); } @Override - public IsNotInCaseInsensitive map(Function mapper) { + public IsNotInCaseInsensitive map(Function mapper) { return mapSupport(mapper, IsNotInCaseInsensitive::new, IsNotInCaseInsensitive::empty); } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java index 82d9d6e27..5646168c1 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java @@ -22,6 +22,7 @@ import java.util.Objects; import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.AbstractListValueCondition; import org.mybatis.dynamic.sql.util.StringUtilities; @@ -48,13 +49,13 @@ public String operator() { } @Override - public IsNotInCaseInsensitiveWhenPresent filter(Predicate predicate) { + public IsNotInCaseInsensitiveWhenPresent filter(Predicate predicate) { return filterSupport(predicate, IsNotInCaseInsensitiveWhenPresent::new, this, IsNotInCaseInsensitiveWhenPresent::empty); } @Override - public IsNotInCaseInsensitiveWhenPresent map(Function mapper) { + public IsNotInCaseInsensitiveWhenPresent map(Function mapper) { return mapSupport(mapper, IsNotInCaseInsensitiveWhenPresent::new, IsNotInCaseInsensitiveWhenPresent::empty); } @@ -64,7 +65,7 @@ public static IsNotInCaseInsensitiveWhenPresent of(@Nullable T... values) } public static IsNotInCaseInsensitiveWhenPresent of(@Nullable Collection<@Nullable T> values) { - if (values == null || values.isEmpty()) { + if (values == null) { return empty(); } else { return new IsNotInCaseInsensitiveWhenPresent<>(values); diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInWhenPresent.java index ed4b27389..375f7d69b 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInWhenPresent.java @@ -22,6 +22,7 @@ import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.AbstractListValueCondition; @@ -45,12 +46,12 @@ public String operator() { } @Override - public IsNotInWhenPresent filter(Predicate predicate) { + public IsNotInWhenPresent filter(Predicate predicate) { return filterSupport(predicate, IsNotInWhenPresent::new, this, IsNotInWhenPresent::empty); } @Override - public IsNotInWhenPresent map(Function mapper) { + public IsNotInWhenPresent map(Function mapper) { return mapSupport(mapper, IsNotInWhenPresent::new, IsNotInWhenPresent::empty); } @@ -60,7 +61,7 @@ public static IsNotInWhenPresent of(@Nullable T... values) { } public static IsNotInWhenPresent of(@Nullable Collection<@Nullable T> values) { - if (values == null || values.isEmpty()) { + if (values == null) { return empty(); } else { return new IsNotInWhenPresent<>(values); diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLike.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLike.java index a62dc3e9e..b5b82d675 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLike.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLike.java @@ -19,6 +19,7 @@ import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; import org.mybatis.dynamic.sql.AbstractSingleValueCondition; public class IsNotLike extends AbstractSingleValueCondition @@ -55,12 +56,12 @@ public static IsNotLike of(T value) { } @Override - public IsNotLike filter(Predicate predicate) { + public IsNotLike filter(Predicate predicate) { return filterSupport(predicate, IsNotLike::empty, this); } @Override - public IsNotLike map(Function mapper) { + public IsNotLike map(Function mapper) { return mapSupport(mapper, IsNotLike::new, IsNotLike::empty); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitive.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitive.java index 6bd943227..1604deb3b 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitive.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitive.java @@ -19,6 +19,7 @@ import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; import org.mybatis.dynamic.sql.AbstractSingleValueCondition; import org.mybatis.dynamic.sql.util.StringUtilities; @@ -53,12 +54,12 @@ public String operator() { } @Override - public IsNotLikeCaseInsensitive filter(Predicate predicate) { + public IsNotLikeCaseInsensitive filter(Predicate predicate) { return filterSupport(predicate, IsNotLikeCaseInsensitive::empty, this); } @Override - public IsNotLikeCaseInsensitive map(Function mapper) { + public IsNotLikeCaseInsensitive map(Function mapper) { return mapSupport(mapper, IsNotLikeCaseInsensitive::new, IsNotLikeCaseInsensitive::empty); } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitiveWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitiveWhenPresent.java index 891525295..e1e17f9da 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitiveWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitiveWhenPresent.java @@ -19,6 +19,7 @@ import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.AbstractSingleValueCondition; import org.mybatis.dynamic.sql.util.StringUtilities; @@ -54,12 +55,12 @@ public String operator() { } @Override - public IsNotLikeCaseInsensitiveWhenPresent filter(Predicate predicate) { + public IsNotLikeCaseInsensitiveWhenPresent filter(Predicate predicate) { return filterSupport(predicate, IsNotLikeCaseInsensitiveWhenPresent::empty, this); } @Override - public IsNotLikeCaseInsensitiveWhenPresent map(Function mapper) { + public IsNotLikeCaseInsensitiveWhenPresent map(Function mapper) { return mapSupport(mapper, IsNotLikeCaseInsensitiveWhenPresent::of, IsNotLikeCaseInsensitiveWhenPresent::empty); } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeWhenPresent.java index d018c9062..a3571b0ee 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeWhenPresent.java @@ -19,6 +19,7 @@ import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.AbstractSingleValueCondition; @@ -60,12 +61,12 @@ public static IsNotLikeWhenPresent of(@Nullable T value) { } @Override - public IsNotLikeWhenPresent filter(Predicate predicate) { + public IsNotLikeWhenPresent filter(Predicate predicate) { return filterSupport(predicate, IsNotLikeWhenPresent::empty, this); } @Override - public IsNotLikeWhenPresent map(Function mapper) { + public IsNotLikeWhenPresent map(Function mapper) { return mapSupport(mapper, IsNotLikeWhenPresent::of, IsNotLikeWhenPresent::empty); } } diff --git a/src/test/java/examples/animal/data/OptionalConditionsWithPredicatesAnimalDataTest.java b/src/test/java/examples/animal/data/OptionalConditionsWithPredicatesAnimalDataTest.java index a46190941..89d349825 100644 --- a/src/test/java/examples/animal/data/OptionalConditionsWithPredicatesAnimalDataTest.java +++ b/src/test/java/examples/animal/data/OptionalConditionsWithPredicatesAnimalDataTest.java @@ -30,7 +30,6 @@ import java.sql.Connection; import java.sql.DriverManager; import java.util.List; -import java.util.Objects; import org.apache.ibatis.datasource.unpooled.UnpooledDataSource; import org.apache.ibatis.jdbc.ScriptRunner; @@ -44,7 +43,6 @@ 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.Predicates; class OptionalConditionsWithPredicatesAnimalDataTest { @@ -78,7 +76,7 @@ void testAllIgnored() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isGreaterThan(NULL_INTEGER).filter(Objects::nonNull)) // the where clause should not render + .where(id, isGreaterThanWhenPresent(NULL_INTEGER)) // the where clause should not render .orderBy(id) .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) .build() @@ -93,26 +91,6 @@ void testAllIgnored() { } } - @Test - void testSelectByNull() { - // this method demonstrates that ignoring the null value warning will still work - try (SqlSession sqlSession = sqlSessionFactory.openSession()) { - AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); - SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) - .from(animalData) - .where(id, isGreaterThan(NULL_INTEGER)) // should be an IDE warning about passing null to a nonnull method - .orderBy(id) - .build() - .render(RenderingStrategies.MYBATIS3); - List animals = mapper.selectMany(selectStatement); - assertAll( - () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id > #{parameters.p1,jdbcType=INTEGER} order by id"), - () -> assertThat(selectStatement.getParameters()).containsEntry("p1", null), - () -> assertThat(animals).isEmpty() - ); - } - } - @Test void testIgnoredBetweenRendered() { try (SqlSession sqlSession = sqlSessionFactory.openSession()) { @@ -120,8 +98,8 @@ void testIgnoredBetweenRendered() { SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) .where(id, isEqualTo(3)) - .and(id, isNotEqualTo(NULL_INTEGER).filter(Objects::nonNull)) - .or(id, isEqualTo(4).filter(Objects::nonNull)) + .and(id, isNotEqualToWhenPresent(NULL_INTEGER)) + .or(id, isEqualTo(4)) .orderBy(id) .build() .render(RenderingStrategies.MYBATIS3); @@ -141,9 +119,9 @@ void testIgnoredInWhere() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isLessThan(NULL_INTEGER).filter(Objects::nonNull)) - .and(id, isEqualTo(3).filter(Objects::nonNull)) - .or(id, isEqualTo(4).filter(Objects::nonNull)) + .where(id, isLessThanWhenPresent(NULL_INTEGER)) + .and(id, isEqualTo(3)) + .or(id, isEqualTo(4)) .orderBy(id) .build() .render(RenderingStrategies.MYBATIS3); @@ -163,10 +141,10 @@ void testManyIgnored() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isLessThan(NULL_INTEGER).filter(Objects::nonNull), and(id, isGreaterThanOrEqualTo(NULL_INTEGER).filter(Objects::nonNull))) - .and(id, isEqualTo(NULL_INTEGER).filter(Objects::nonNull), or(id, isEqualTo(3), and(id, isLessThan(NULL_INTEGER).filter(Objects::nonNull)))) - .or(id, isEqualTo(4).filter(Objects::nonNull), and(id, isGreaterThanOrEqualTo(NULL_INTEGER).filter(Objects::nonNull))) - .and(id, isNotEqualTo(NULL_INTEGER).filter(Objects::nonNull)) + .where(id, isLessThanWhenPresent(NULL_INTEGER), and(id, isGreaterThanOrEqualToWhenPresent(NULL_INTEGER))) + .and(id, isEqualToWhenPresent(NULL_INTEGER), or(id, isEqualTo(3), and(id, isLessThanWhenPresent(NULL_INTEGER)))) + .or(id, isEqualTo(4), and(id, isGreaterThanOrEqualToWhenPresent(NULL_INTEGER))) + .and(id, isNotEqualToWhenPresent(NULL_INTEGER)) .orderBy(id) .build() .render(RenderingStrategies.MYBATIS3); @@ -186,8 +164,8 @@ void testIgnoredInitialWhere() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isLessThan(NULL_INTEGER).filter(Objects::nonNull), and(id, isEqualTo(3).filter(Objects::nonNull))) - .or(id, isEqualTo(4).filter(Objects::nonNull)) + .where(id, isLessThanWhenPresent(NULL_INTEGER), and(id, isEqualTo(3))) + .or(id, isEqualTo(4)) .orderBy(id) .build() .render(RenderingStrategies.MYBATIS3); @@ -207,7 +185,7 @@ void testEqualWhenWithValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isEqualTo(4).filter(Objects::nonNull)) + .where(id, isEqualTo(4)) .orderBy(id) .build() .render(RenderingStrategies.MYBATIS3); @@ -226,7 +204,7 @@ void testEqualWhenWithoutValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isEqualTo(NULL_INTEGER).filter(Objects::nonNull)) + .where(id, isEqualToWhenPresent(NULL_INTEGER)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -246,7 +224,7 @@ void testNotEqualWhenWithValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isNotEqualTo(4).filter(Objects::nonNull)) + .where(id, isNotEqualTo(4)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -266,7 +244,7 @@ void testNotEqualWhenWithoutValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isNotEqualTo(NULL_INTEGER).filter(Objects::nonNull)) + .where(id, isNotEqualToWhenPresent(NULL_INTEGER)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -286,7 +264,7 @@ void testGreaterThanWhenWithValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isGreaterThan(4).filter(Objects::nonNull)) + .where(id, isGreaterThan(4)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -306,7 +284,7 @@ void testGreaterThanWhenWithoutValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isGreaterThan(NULL_INTEGER).filter(Objects::nonNull)) + .where(id, isGreaterThanWhenPresent(NULL_INTEGER)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -326,7 +304,7 @@ void testGreaterThanOrEqualToWhenWithValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isGreaterThanOrEqualTo(4).filter(Objects::nonNull)) + .where(id, isGreaterThanOrEqualTo(4)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -346,7 +324,7 @@ void testGreaterThanOrEqualToWhenWithoutValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isGreaterThanOrEqualTo(NULL_INTEGER).filter(Objects::nonNull)) + .where(id, isGreaterThanOrEqualToWhenPresent(NULL_INTEGER)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -366,7 +344,7 @@ void testLessThanWhenWithValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isLessThan(4).filter(Objects::nonNull)) + .where(id, isLessThan(4)) .orderBy(id) .build() .render(RenderingStrategies.MYBATIS3); @@ -385,7 +363,7 @@ void testLessThanWhenWithoutValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isLessThan(NULL_INTEGER).filter(Objects::nonNull)) + .where(id, isLessThanWhenPresent(NULL_INTEGER)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -405,7 +383,7 @@ void testLessThanOrEqualToWhenWithValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isLessThanOrEqualTo(4).filter(Objects::nonNull)) + .where(id, isLessThanOrEqualTo(4)) .orderBy(id) .build() .render(RenderingStrategies.MYBATIS3); @@ -424,7 +402,7 @@ void testLessThanOrEqualToWhenWithoutValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isLessThanOrEqualTo(NULL_INTEGER).filter(Objects::nonNull)) + .where(id, isLessThanOrEqualToWhenPresent(NULL_INTEGER)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -463,7 +441,7 @@ void testIsInWhenWithSomeValues() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isIn(3, NULL_INTEGER, 5).filter(Objects::nonNull).map(i -> i + 3)) + .where(id, isInWhenPresent(3, NULL_INTEGER, 5).map(i -> i + 3)) .orderBy(id) .build() .render(RenderingStrategies.MYBATIS3); @@ -502,8 +480,7 @@ void testValueStreamTransformer() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(animalName, isIn(" Mouse", " ", null, "", "Musk shrew ") - .filter(Objects::nonNull) + .where(animalName, isInWhenPresent(" Mouse", " ", null, "", "Musk shrew ") .map(String::trim) .filter(not(String::isEmpty))) .orderBy(id) @@ -583,7 +560,7 @@ void testIsNotInWhenWithSomeValues() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isNotIn(3, NULL_INTEGER, 5).filter(Objects::nonNull)) + .where(id, isNotInWhenPresent(3, NULL_INTEGER, 5)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -643,7 +620,7 @@ void testIsBetweenWhenWithValues() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isBetween(3).and(6).filter(Predicates.bothPresent())) + .where(id, isBetween(3).and(6)) .orderBy(id) .build() .render(RenderingStrategies.MYBATIS3); @@ -662,7 +639,7 @@ void testIsBetweenWhenWithFirstMissing() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isBetween(NULL_INTEGER).and(6).filter(Predicates.bothPresent())) + .where(id, isBetweenWhenPresent(NULL_INTEGER).and(6)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -682,7 +659,7 @@ void testIsBetweenWhenWithSecondMissing() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isBetween(3).and(NULL_INTEGER).filter(Predicates.bothPresent())) + .where(id, isBetweenWhenPresent(3).and(NULL_INTEGER)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -702,7 +679,7 @@ void testIsBetweenWhenWithBothMissing() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isBetween(NULL_INTEGER).and(NULL_INTEGER).filter(Predicates.bothPresent())) + .where(id, isBetweenWhenPresent(NULL_INTEGER).and(NULL_INTEGER)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -722,7 +699,7 @@ void testIsNotBetweenWhenWithValues() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isNotBetween(3).and(6).filter(Predicates.bothPresent())) + .where(id, isNotBetween(3).and(6)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -742,7 +719,7 @@ void testIsNotBetweenWhenWithFirstMissing() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isNotBetween(NULL_INTEGER).and(6).filter(Predicates.bothPresent())) + .where(id, isNotBetweenWhenPresent(NULL_INTEGER).and(6)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -762,7 +739,7 @@ void testIsNotBetweenWhenWithSecondMissing() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isNotBetween(3).and(NULL_INTEGER).filter(Predicates.bothPresent())) + .where(id, isNotBetweenWhenPresent(3).and(NULL_INTEGER)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -782,7 +759,7 @@ void testIsNotBetweenWhenWithBothMissing() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isNotBetween(NULL_INTEGER).and(NULL_INTEGER).filter(Predicates.bothPresent())) + .where(id, isNotBetweenWhenPresent(NULL_INTEGER).and(NULL_INTEGER)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -802,7 +779,7 @@ void testIsLikeWhenWithValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(animalName, isLike("%mole").filter(Objects::nonNull)) + .where(animalName, isLike("%mole")) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -822,7 +799,7 @@ void testIsLikeWhenWithoutValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(animalName, isLike((String) null).filter(Objects::nonNull)) + .where(animalName, isLikeWhenPresent((String) null)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -842,7 +819,7 @@ void testIsLikeCaseInsensitiveWhenWithValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(animalName, isLikeCaseInsensitive("%MoLe").filter(Objects::nonNull)) + .where(animalName, isLikeCaseInsensitive("%MoLe")) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -862,7 +839,7 @@ void testIsLikeCaseInsensitiveWhenWithoutValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(animalName, isLikeCaseInsensitive((String) null).filter(Objects::nonNull)) + .where(animalName, isLikeCaseInsensitiveWhenPresent((String) null)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -882,7 +859,7 @@ void testIsNotLikeWhenWithValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(animalName, isNotLike("%mole").filter(Objects::nonNull)) + .where(animalName, isNotLike("%mole")) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -902,7 +879,7 @@ void testIsNotLikeWhenWithoutValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(animalName, isNotLike((String) null).filter(Objects::nonNull)) + .where(animalName, isNotLikeWhenPresent((String) null)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -922,7 +899,7 @@ void testIsNotLikeCaseInsensitiveWhenWithValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(animalName, isNotLikeCaseInsensitive("%MoLe").filter(Objects::nonNull)) + .where(animalName, isNotLikeCaseInsensitive("%MoLe")) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -942,7 +919,7 @@ void testIsNotLikeCaseInsensitiveWhenWithoutValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(animalName, isNotLikeCaseInsensitive((String) null).filter(Objects::nonNull)) + .where(animalName, isNotLikeCaseInsensitiveWhenPresent((String) null)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() diff --git a/src/test/java/examples/complexquery/ComplexQueryTest.java b/src/test/java/examples/complexquery/ComplexQueryTest.java index fca43c133..3912040cb 100644 --- a/src/test/java/examples/complexquery/ComplexQueryTest.java +++ b/src/test/java/examples/complexquery/ComplexQueryTest.java @@ -22,8 +22,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mybatis.dynamic.sql.SqlBuilder.*; -import java.util.Objects; - +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.mybatis.dynamic.sql.render.RenderingStrategies; import org.mybatis.dynamic.sql.select.QueryExpressionDSL; @@ -107,18 +106,17 @@ void testAllNull() { assertThat(selectStatement.getParameters()).containsEntry("p1", 50L); } - SelectStatementProvider search(Integer targetId, String fName, String lName) { + SelectStatementProvider search(@Nullable Integer targetId, @Nullable String fName, @Nullable String lName) { QueryExpressionDSL.QueryExpressionWhereBuilder builder = select(id, firstName, lastName) .from(person) .where() .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)); if (targetId != null) { - builder - .and(id, isEqualTo(targetId)); + builder.and(id, isEqualTo(targetId)); } else { builder - .and(firstName, isLike(fName).filter(Objects::nonNull).map(s -> "%" + s + "%")) + .and(firstName, isLikeWhenPresent(fName).map(s -> "%" + s + "%")) .and(lastName, isLikeWhenPresent(lName).map(this::addWildcards)); } diff --git a/src/test/java/examples/emptywhere/EmptyWhereTest.java b/src/test/java/examples/emptywhere/EmptyWhereTest.java index 4c02f4f66..fd699da23 100644 --- a/src/test/java/examples/emptywhere/EmptyWhereTest.java +++ b/src/test/java/examples/emptywhere/EmptyWhereTest.java @@ -20,7 +20,8 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mybatis.dynamic.sql.SqlBuilder.*; -import java.util.*; +import java.util.List; +import java.util.Optional; import java.util.stream.Stream; import org.junit.jupiter.api.Test; @@ -93,8 +94,8 @@ void testDeleteThreeConditions() { DeleteDSL.DeleteWhereBuilder builder = deleteFrom(person) .where(id, isEqualTo(3)); - builder.and(firstName, isEqualTo(fName).filter(Objects::nonNull)); - builder.and(PersonDynamicSqlSupport.lastName, isEqualTo(lName).filter(Objects::nonNull)); + builder.and(firstName, isEqualTo(fName)); + builder.and(PersonDynamicSqlSupport.lastName, isEqualTo(lName)); DeleteStatementProvider deleteStatement = builder.build().render(RenderingStrategies.MYBATIS3); @@ -112,8 +113,8 @@ void testDeleteVariations(Variation variation) { DeleteDSL.DeleteWhereBuilder builder = deleteFrom(person) .where(); - builder.and(firstName, isEqualTo(variation.firstName).filter(Objects::nonNull)); - builder.or(PersonDynamicSqlSupport.lastName, isEqualTo(variation.lastName).filter(Objects::nonNull)); + builder.and(firstName, isEqualToWhenPresent(variation.firstName)); + builder.or(PersonDynamicSqlSupport.lastName, isEqualToWhenPresent(variation.lastName)); builder.configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)); DeleteStatementProvider deleteStatement = builder.build().render(RenderingStrategies.MYBATIS3); @@ -132,8 +133,8 @@ void testSelectThreeConditions() { .from(person) .where(id, isEqualTo(3)); - builder.and(firstName, isEqualTo(fName).filter(Objects::nonNull)); - builder.and(PersonDynamicSqlSupport.lastName, isEqualTo(lName).filter(Objects::nonNull)); + builder.and(firstName, isEqualTo(fName)); + builder.and(PersonDynamicSqlSupport.lastName, isEqualTo(lName)); SelectStatementProvider selectStatement = builder.build().render(RenderingStrategies.MYBATIS3); @@ -153,8 +154,8 @@ void testSelectVariations(Variation variation) { .from(person) .where(); - builder.and(firstName, isEqualTo(variation.firstName).filter(Objects::nonNull)); - builder.or(PersonDynamicSqlSupport.lastName, isEqualTo(variation.lastName).filter(Objects::nonNull)); + builder.and(firstName, isEqualToWhenPresent(variation.firstName)); + builder.or(PersonDynamicSqlSupport.lastName, isEqualToWhenPresent(variation.lastName)); builder.configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)); SelectStatementProvider selectStatement = builder.build().render(RenderingStrategies.MYBATIS3); @@ -173,8 +174,8 @@ void testJoinThreeConditions() { .from(person).join(order).on(person.id, isEqualTo(order.personId)) .where(id, isEqualTo(3)); - builder.and(firstName, isEqualTo(fName).filter(Objects::nonNull)); - builder.and(PersonDynamicSqlSupport.lastName, isEqualTo(lName).filter(Objects::nonNull)); + builder.and(firstName, isEqualTo(fName)); + builder.and(PersonDynamicSqlSupport.lastName, isEqualTo(lName)); SelectStatementProvider selectStatement = builder.build().render(RenderingStrategies.MYBATIS3); @@ -195,8 +196,8 @@ void testJoinVariations(Variation variation) { .from(person).join(order).on(person.id, isEqualTo(order.personId)) .where(); - builder.and(firstName, isEqualTo(variation.firstName).filter(Objects::nonNull)); - builder.or(PersonDynamicSqlSupport.lastName, isEqualTo(variation.lastName).filter(Objects::nonNull)); + builder.and(firstName, isEqualToWhenPresent(variation.firstName)); + builder.or(PersonDynamicSqlSupport.lastName, isEqualToWhenPresent(variation.lastName)); builder.configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)); SelectStatementProvider selectStatement = builder.build().render(RenderingStrategies.MYBATIS3); @@ -218,8 +219,8 @@ void testUpdateThreeConditions() { .set(id).equalTo(3) .where(id, isEqualTo(3)); - builder.and(firstName, isEqualTo(fName).filter(Objects::nonNull)); - builder.and(PersonDynamicSqlSupport.lastName, isEqualTo(lName).filter(Objects::nonNull)); + builder.and(firstName, isEqualTo(fName)); + builder.and(PersonDynamicSqlSupport.lastName, isEqualTo(lName)); UpdateStatementProvider updateStatement = builder.build().render(RenderingStrategies.MYBATIS3); @@ -239,8 +240,8 @@ void testUpdateVariations(Variation variation) { .set(id).equalTo(3) .where(); - builder.and(firstName, isEqualTo(variation.firstName).filter(Objects::nonNull)); - builder.or(PersonDynamicSqlSupport.lastName, isEqualTo(variation.lastName).filter(Objects::nonNull)); + builder.and(firstName, isEqualToWhenPresent(variation.firstName)); + builder.or(PersonDynamicSqlSupport.lastName, isEqualToWhenPresent(variation.lastName)); builder.configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)); UpdateStatementProvider updateStatement = builder.build().render(RenderingStrategies.MYBATIS3); @@ -259,8 +260,8 @@ void testWhereThreeConditions() { WhereDSL.StandaloneWhereFinisher builder = where(id, isEqualTo(3)); - builder.and(firstName, isEqualTo(fName).filter(Objects::nonNull)); - builder.and(PersonDynamicSqlSupport.lastName, isEqualTo(lName).filter(Objects::nonNull)); + builder.and(firstName, isEqualTo(fName)); + builder.and(PersonDynamicSqlSupport.lastName, isEqualTo(lName)); Optional whereClause = builder.build().render(RenderingStrategies.MYBATIS3); @@ -278,8 +279,8 @@ void testWhereThreeConditions() { void testWhereVariations(Variation variation) { WhereDSL.StandaloneWhereFinisher builder = where(); - builder.and(firstName, isEqualTo(variation.firstName).filter(Objects::nonNull)); - builder.or(PersonDynamicSqlSupport.lastName, isEqualTo(variation.lastName).filter(Objects::nonNull)); + builder.and(firstName, isEqualToWhenPresent(variation.firstName)); + builder.or(PersonDynamicSqlSupport.lastName, isEqualToWhenPresent(variation.lastName)); builder.configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)); Optional whereClause = builder.build().render(RenderingStrategies.MYBATIS3); diff --git a/src/test/java/examples/simple/PersonMapperTest.java b/src/test/java/examples/simple/PersonMapperTest.java index 7aed9182d..acbda68ad 100644 --- a/src/test/java/examples/simple/PersonMapperTest.java +++ b/src/test/java/examples/simple/PersonMapperTest.java @@ -36,7 +36,6 @@ import java.util.Collection; import java.util.Date; import java.util.List; -import java.util.Objects; import java.util.Optional; import org.apache.ibatis.datasource.unpooled.UnpooledDataSource; @@ -146,7 +145,7 @@ void testSelectWithTypeConversionAndFilterAndNull() { PersonMapper mapper = session.getMapper(PersonMapper.class); List rows = mapper.select(c -> - c.where(id, isEqualTo((String) null).filter(Objects::nonNull).map(Integer::parseInt)) + c.where(id, isEqualToWhenPresent((String) null).map(Integer::parseInt)) .or(occupation, isNull())); assertThat(rows).hasSize(2); diff --git a/src/test/java/issues/gh105/Issue105Test.java b/src/test/java/issues/gh105/Issue105Test.java index 8fb16f22d..81ecb79c2 100644 --- a/src/test/java/issues/gh105/Issue105Test.java +++ b/src/test/java/issues/gh105/Issue105Test.java @@ -19,12 +19,9 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mybatis.dynamic.sql.SqlBuilder.*; -import java.util.Objects; - 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.Predicates; class Issue105Test { @@ -35,8 +32,8 @@ void testFuzzyLikeBothPresent() { SelectStatementProvider selectStatement = select(id, firstName, lastName) .from(person) - .where(firstName, isLike(fName).filter(Objects::nonNull).map(s -> "%" + s + "%")) - .and(lastName, isLike(lName).filter(Objects::nonNull).map(s -> "%" + s + "%")) + .where(firstName, isLike(fName).map(s -> "%" + s + "%")) + .and(lastName, isLike(lName).map(s -> "%" + s + "%")) .build() .render(RenderingStrategies.MYBATIS3); @@ -57,8 +54,8 @@ void testFuzzyLikeFirstNameNull() { SelectStatementProvider selectStatement = select(id, firstName, lastName) .from(person) - .where(firstName, isLike(fName).filter(Objects::nonNull).map(SearchUtils::addWildcards)) - .and(lastName, isLike(lName).filter(Objects::nonNull).map(SearchUtils::addWildcards)) + .where(firstName, isLikeWhenPresent(fName).map(SearchUtils::addWildcards)) + .and(lastName, isLike(lName).map(SearchUtils::addWildcards)) .build() .render(RenderingStrategies.MYBATIS3); @@ -77,8 +74,8 @@ void testFuzzyLikeLastNameNull() { SelectStatementProvider selectStatement = select(id, firstName, lastName) .from(person) - .where(firstName, isLike(fName).filter(Objects::nonNull).map(SearchUtils::addWildcards)) - .and(lastName, isLike(lName).filter(Objects::nonNull).map(SearchUtils::addWildcards)) + .where(firstName, isLike(fName).map(SearchUtils::addWildcards)) + .and(lastName, isLikeWhenPresent(lName).map(SearchUtils::addWildcards)) .build() .render(RenderingStrategies.MYBATIS3); @@ -97,8 +94,8 @@ void testFuzzyLikeBothNull() { SelectStatementProvider selectStatement = select(id, firstName, lastName) .from(person) - .where(firstName, isLike(fName).filter(Objects::nonNull).map(SearchUtils::addWildcards)) - .and(lastName, isLike(lName).filter(Objects::nonNull).map(SearchUtils::addWildcards)) + .where(firstName, isLikeWhenPresent(fName).map(SearchUtils::addWildcards)) + .and(lastName, isLikeWhenPresent(lName).map(SearchUtils::addWildcards)) .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) .build() .render(RenderingStrategies.MYBATIS3); @@ -527,7 +524,7 @@ void testBetweenTransformWithNull() { SelectStatementProvider selectStatement = select(id, firstName, lastName) .from(person) - .where(age, isBetween(1).and((Integer) null).filter(Predicates.bothPresent()).map(i1 -> i1 + 1, i2 -> i2 + 2)) + .where(age, isBetweenWhenPresent(1).and((Integer) null).map(i1 -> i1 + 1, i2 -> i2 + 2)) .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) .build() .render(RenderingStrategies.MYBATIS3); @@ -559,7 +556,7 @@ void testEqualTransformWithNull() { SelectStatementProvider selectStatement = select(id, firstName, lastName) .from(person) - .where(age, isEqualTo((Integer) null).filter(Objects::nonNull).map(i -> i + 1)) + .where(age, isEqualToWhenPresent((Integer) null).map(i -> i + 1)) .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) .build() .render(RenderingStrategies.MYBATIS3); @@ -591,7 +588,7 @@ void testGreaterThanTransformWithNull() { SelectStatementProvider selectStatement = select(id, firstName, lastName) .from(person) - .where(age, isGreaterThan((Integer) null).filter(Objects::nonNull).map(i -> i + 1)) + .where(age, isGreaterThanWhenPresent((Integer) null).map(i -> i + 1)) .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) .build() .render(RenderingStrategies.MYBATIS3); @@ -607,7 +604,7 @@ void testGreaterThanOrEqualTransformWithNull() { SelectStatementProvider selectStatement = select(id, firstName, lastName) .from(person) - .where(age, isGreaterThanOrEqualTo((Integer) null).filter(Objects::nonNull).map(i -> i + 1)) + .where(age, isGreaterThanOrEqualToWhenPresent((Integer) null).map(i -> i + 1)) .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) .build() .render(RenderingStrategies.MYBATIS3); @@ -655,7 +652,7 @@ void testLessThanTransformWithNull() { SelectStatementProvider selectStatement = select(id, firstName, lastName) .from(person) - .where(age, isLessThan((Integer) null).filter(Objects::nonNull).map(i -> i + 1)) + .where(age, isLessThanWhenPresent((Integer) null).map(i -> i + 1)) .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) .build() .render(RenderingStrategies.MYBATIS3); @@ -671,7 +668,7 @@ void testLessThanOrEqualTransformWithNull() { SelectStatementProvider selectStatement = select(id, firstName, lastName) .from(person) - .where(age, isLessThanOrEqualTo((Integer) null).filter(Objects::nonNull).map(i -> i + 1)) + .where(age, isLessThanOrEqualToWhenPresent((Integer) null).map(i -> i + 1)) .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) .build() .render(RenderingStrategies.MYBATIS3); @@ -719,7 +716,7 @@ void testLikeTransformWithNull() { SelectStatementProvider selectStatement = select(id, firstName, lastName) .from(person) - .where(firstName, isLike((String) null).filter(Objects::nonNull).map(SearchUtils::addWildcards)) + .where(firstName, isLikeWhenPresent((String) null).map(SearchUtils::addWildcards)) .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) .build() .render(RenderingStrategies.MYBATIS3); @@ -735,7 +732,7 @@ void testLikeCaseInsensitiveTransformWithNull() { SelectStatementProvider selectStatement = select(id, firstName, lastName) .from(person) - .where(firstName, isLikeCaseInsensitive((String) null).filter(Objects::nonNull).map(SearchUtils::addWildcards)) + .where(firstName, isLikeCaseInsensitiveWhenPresent((String) null).map(SearchUtils::addWildcards)) .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) .build() .render(RenderingStrategies.MYBATIS3); @@ -783,7 +780,7 @@ void testNotBetweenTransformWithNull() { SelectStatementProvider selectStatement = select(id, firstName, lastName) .from(person) - .where(age, isNotBetween((Integer) null).and(10).filter(Predicates.bothPresent()).map(i1 -> i1 + 1, i2 -> i2 + 2)) + .where(age, isNotBetweenWhenPresent((Integer) null).and(10).map(i1 -> i1 + 1, i2 -> i2 + 2)) .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) .build() .render(RenderingStrategies.MYBATIS3); @@ -815,7 +812,7 @@ void testNotEqualTransformWithNull() { SelectStatementProvider selectStatement = select(id, firstName, lastName) .from(person) - .where(age, isNotEqualTo((Integer) null).filter(Objects::nonNull).map(i -> i + 1)) + .where(age, isNotEqualToWhenPresent((Integer) null).map(i -> i + 1)) .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) .build() .render(RenderingStrategies.MYBATIS3); @@ -847,7 +844,7 @@ void testNotLikeTransformWithNull() { SelectStatementProvider selectStatement = select(id, firstName, lastName) .from(person) - .where(firstName, isNotLike((String) null).filter(Objects::nonNull).map(SearchUtils::addWildcards)) + .where(firstName, isNotLikeWhenPresent((String) null).map(SearchUtils::addWildcards)) .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) .build() .render(RenderingStrategies.MYBATIS3); @@ -863,7 +860,7 @@ void testNotLikeCaseInsensitiveTransformWithNull() { SelectStatementProvider selectStatement = select(id, firstName, lastName) .from(person) - .where(firstName, isNotLikeCaseInsensitive((String) null).filter(Objects::nonNull).map(SearchUtils::addWildcards)) + .where(firstName, isNotLikeCaseInsensitiveWhenPresent((String) null).map(SearchUtils::addWildcards)) .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) .build() .render(RenderingStrategies.MYBATIS3); diff --git a/src/test/java/org/mybatis/dynamic/sql/where/condition/FilterAndMapTest.java b/src/test/java/org/mybatis/dynamic/sql/where/condition/FilterAndMapTest.java index bd2e56fbb..a3bb3d620 100644 --- a/src/test/java/org/mybatis/dynamic/sql/where/condition/FilterAndMapTest.java +++ b/src/test/java/org/mybatis/dynamic/sql/where/condition/FilterAndMapTest.java @@ -20,7 +20,6 @@ import java.util.List; import java.util.NoSuchElementException; -import java.util.Objects; import org.junit.jupiter.api.Test; import org.mybatis.dynamic.sql.SqlBuilder; @@ -33,17 +32,9 @@ void testTypeConversion() { assertThat(cond.value()).isEqualTo(1); } - @Test - void testTypeConversionWithNullThrowsException() { - var cond = SqlBuilder.isEqualTo((String) null); - assertThatExceptionOfType(NumberFormatException.class).isThrownBy(() -> - cond.map(Integer::parseInt) - ); - } - @Test void testTypeConversionWithNullAndFilterDoesNotThrowException() { - var cond = SqlBuilder.isEqualTo((String) null).filter(Objects::nonNull).map(Integer::parseInt); + var cond = SqlBuilder.isEqualToWhenPresent((String) null).map(Integer::parseInt); assertThat(cond.isEmpty()).isTrue(); } @@ -479,17 +470,17 @@ void testBetweenUnRenderableFilterShouldReturnSameObject() { @Test void testBetweenUnRenderableFirstNullFilterShouldReturnSameObject() { - IsBetween cond = SqlBuilder.isBetween((Integer) null).and(4).filter(Objects::nonNull); + IsBetweenWhenPresent cond = SqlBuilder.isBetweenWhenPresent((Integer) null).and(4); assertThat(cond.isEmpty()).isTrue(); - IsBetween filtered = cond.filter(v -> true); + IsBetweenWhenPresent filtered = cond.filter(v -> true); assertThat(cond).isSameAs(filtered); } @Test void testBetweenUnRenderableSecondNullFilterShouldReturnSameObject() { - IsBetween cond = SqlBuilder.isBetween(3).and((Integer) null).filter(Objects::nonNull); + IsBetweenWhenPresent cond = SqlBuilder.isBetweenWhenPresent(3).and((Integer) null); assertThat(cond.isEmpty()).isTrue(); - IsBetween filtered = cond.filter(v -> true); + IsBetweenWhenPresent filtered = cond.filter(v -> true); assertThat(cond).isSameAs(filtered); } @@ -511,17 +502,17 @@ void testNotBetweenUnRenderableFilterShouldReturnSameObject() { @Test void testNotBetweenUnRenderableFirstNullFilterShouldReturnSameObject() { - IsNotBetween cond = SqlBuilder.isNotBetween((Integer) null).and(4).filter(Objects::nonNull); + IsNotBetweenWhenPresent cond = SqlBuilder.isNotBetweenWhenPresent((Integer) null).and(4); assertThat(cond.isEmpty()).isTrue(); - IsNotBetween filtered = cond.filter(v -> true); + IsNotBetweenWhenPresent filtered = cond.filter(v -> true); assertThat(cond).isSameAs(filtered); } @Test void testNotBetweenUnRenderableSecondNullFilterShouldReturnSameObject() { - IsNotBetween cond = SqlBuilder.isNotBetween(3).and((Integer) null).filter(Objects::nonNull); + IsNotBetweenWhenPresent cond = SqlBuilder.isNotBetweenWhenPresent(3).and((Integer) null); assertThat(cond.isEmpty()).isTrue(); - IsNotBetween filtered = cond.filter(v -> true); + IsNotBetweenWhenPresent filtered = cond.filter(v -> true); assertThat(cond).isSameAs(filtered); } diff --git a/src/test/java/org/mybatis/dynamic/sql/where/condition/NullContractTest.java b/src/test/java/org/mybatis/dynamic/sql/where/condition/NullContractTest.java index 6ea7b2909..ed7d4e01c 100644 --- a/src/test/java/org/mybatis/dynamic/sql/where/condition/NullContractTest.java +++ b/src/test/java/org/mybatis/dynamic/sql/where/condition/NullContractTest.java @@ -438,4 +438,94 @@ void testIsNotInCaseInsensitiveWhenPresent() { assertThat(mapped.isEmpty()).isTrue(); assertThat(mapped.values().toList()).isEmpty(); } + + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsBetweenNull() { + IsBetween cond = SqlBuilder.isBetween(() -> (Integer) null).and(() -> null); + assertThat(cond.value1()).isNull(); + assertThat(cond.value2()).isNull(); + assertThat(cond.isEmpty()).isFalse(); + } + + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsNotBetweenNull() { + IsNotBetween cond = SqlBuilder.isNotBetween(() -> (Integer) null).and(() -> null); + assertThat(cond.value1()).isNull(); + assertThat(cond.value2()).isNull(); + assertThat(cond.isEmpty()).isFalse(); + } + + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsNotEqualToNull() { + IsNotEqualTo cond = SqlBuilder.isNotEqualTo(() -> (Integer) null); + assertThat(cond.value()).isNull(); + assertThat(cond.isEmpty()).isFalse(); + } + + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsGreaterThanNull() { + IsGreaterThan cond = SqlBuilder.isGreaterThan(() -> (Integer) null); + assertThat(cond.value()).isNull(); + assertThat(cond.isEmpty()).isFalse(); + } + + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsGreaterThanOrEqualToNull() { + IsGreaterThanOrEqualTo cond = SqlBuilder.isGreaterThanOrEqualTo(() -> (Integer) null); + assertThat(cond.value()).isNull(); + assertThat(cond.isEmpty()).isFalse(); + } + + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsLessThanNull() { + IsLessThan cond = SqlBuilder.isLessThan(() -> (Integer) null); + assertThat(cond.value()).isNull(); + assertThat(cond.isEmpty()).isFalse(); + } + + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsLessThanOrEqualToNull() { + IsLessThanOrEqualTo cond = SqlBuilder.isLessThanOrEqualTo(() -> (Integer) null); + assertThat(cond.value()).isNull(); + assertThat(cond.isEmpty()).isFalse(); + } + + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsLikeNull() { + IsLike cond = SqlBuilder.isLike(() -> null); + assertThat(cond.value()).isNull(); + assertThat(cond.isEmpty()).isFalse(); + } + + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsLikeCaseInsensitiveNull() { + IsLikeCaseInsensitive cond = SqlBuilder.isLikeCaseInsensitive(() -> null); + assertThat(cond.value()).isNull(); + assertThat(cond.isEmpty()).isFalse(); + } + + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsNotLikeNull() { + IsNotLike cond = SqlBuilder.isNotLike(() -> null); + assertThat(cond.value()).isNull(); + assertThat(cond.isEmpty()).isFalse(); + } + + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsNotLikeCaseInsensitiveNull() { + IsNotLikeCaseInsensitive cond = SqlBuilder.isNotLikeCaseInsensitive(() -> null); + assertThat(cond.value()).isNull(); + assertThat(cond.isEmpty()).isFalse(); + } } diff --git a/src/test/java/org/mybatis/dynamic/sql/where/condition/SupplierTest.java b/src/test/java/org/mybatis/dynamic/sql/where/condition/SupplierTest.java index c2bf40ddf..113c60321 100644 --- a/src/test/java/org/mybatis/dynamic/sql/where/condition/SupplierTest.java +++ b/src/test/java/org/mybatis/dynamic/sql/where/condition/SupplierTest.java @@ -34,14 +34,6 @@ void testIsBetween() { assertThat(cond.isEmpty()).isFalse(); } - @Test - void testIsBetweenNull() { - IsBetween cond = SqlBuilder.isBetween(() -> (Integer) null).and(() -> null); - assertThat(cond.value1()).isNull(); - assertThat(cond.value2()).isNull(); - assertThat(cond.isEmpty()).isFalse(); - } - @Test void testIsBetweenWhenPresent() { IsBetweenWhenPresent cond = SqlBuilder.isBetweenWhenPresent(() -> 3).and(() -> 4); @@ -66,14 +58,6 @@ void testIsNotBetween() { assertThat(cond.isEmpty()).isFalse(); } - @Test - void testIsNotBetweenNull() { - IsNotBetween cond = SqlBuilder.isNotBetween(() -> (Integer) null).and(() -> null); - assertThat(cond.value1()).isNull(); - assertThat(cond.value2()).isNull(); - assertThat(cond.isEmpty()).isFalse(); - } - @Test void testIsNotBetweenWhenPresent() { IsNotBetweenWhenPresent cond = SqlBuilder.isNotBetweenWhenPresent(() -> 3).and(() -> 4); @@ -111,13 +95,6 @@ void testIsNotEqualTo() { assertThat(cond.isEmpty()).isFalse(); } - @Test - void testIsNotEqualToNull() { - IsNotEqualTo cond = SqlBuilder.isNotEqualTo(() -> (Integer) null); - assertThat(cond.value()).isNull(); - assertThat(cond.isEmpty()).isFalse(); - } - @Test void testIsNotEqualToWhenPresent() { IsNotEqualToWhenPresent cond = SqlBuilder.isNotEqualToWhenPresent(() -> 3); @@ -139,13 +116,6 @@ void testIsGreaterThan() { assertThat(cond.isEmpty()).isFalse(); } - @Test - void testIsGreaterThanNull() { - IsGreaterThan cond = SqlBuilder.isGreaterThan(() -> (Integer) null); - assertThat(cond.value()).isNull(); - assertThat(cond.isEmpty()).isFalse(); - } - @Test void testIsGreaterThanWhenPresent() { IsGreaterThanWhenPresent cond = SqlBuilder.isGreaterThanWhenPresent(() -> 3); @@ -167,13 +137,6 @@ void testIsGreaterThanOrEqualTo() { assertThat(cond.isEmpty()).isFalse(); } - @Test - void testIsGreaterThanOrEqualToNull() { - IsGreaterThanOrEqualTo cond = SqlBuilder.isGreaterThanOrEqualTo(() -> (Integer) null); - assertThat(cond.value()).isNull(); - assertThat(cond.isEmpty()).isFalse(); - } - @Test void testIsGreaterThanOrEqualToWhenPresent() { IsGreaterThanOrEqualToWhenPresent cond = SqlBuilder.isGreaterThanOrEqualToWhenPresent(() -> 3); @@ -195,13 +158,6 @@ void testIsLessThan() { assertThat(cond.isEmpty()).isFalse(); } - @Test - void testIsLessThanNull() { - IsLessThan cond = SqlBuilder.isLessThan(() -> (Integer) null); - assertThat(cond.value()).isNull(); - assertThat(cond.isEmpty()).isFalse(); - } - @Test void testIsLessThanWhenPresent() { IsLessThanWhenPresent cond = SqlBuilder.isLessThanWhenPresent(() -> 3); @@ -223,13 +179,6 @@ void testIsLessThanOrEqualTo() { assertThat(cond.isEmpty()).isFalse(); } - @Test - void testIsLessThanOrEqualToNull() { - IsLessThanOrEqualTo cond = SqlBuilder.isLessThanOrEqualTo(() -> (Integer) null); - assertThat(cond.value()).isNull(); - assertThat(cond.isEmpty()).isFalse(); - } - @Test void testIsLessThanOrEqualToWhenPresent() { IsLessThanOrEqualToWhenPresent cond = SqlBuilder.isLessThanOrEqualToWhenPresent(() -> 3); @@ -251,13 +200,6 @@ void testIsLike() { assertThat(cond.isEmpty()).isFalse(); } - @Test - void testIsLikeNull() { - IsLike cond = SqlBuilder.isLike(() -> null); - assertThat(cond.value()).isNull(); - assertThat(cond.isEmpty()).isFalse(); - } - @Test void testIsLikeCaseInsensitive() { IsLikeCaseInsensitive cond = SqlBuilder.isLikeCaseInsensitive(() -> "%f%"); @@ -265,13 +207,6 @@ void testIsLikeCaseInsensitive() { assertThat(cond.isEmpty()).isFalse(); } - @Test - void testIsLikeCaseInsensitiveNull() { - IsLikeCaseInsensitive cond = SqlBuilder.isLikeCaseInsensitive(() -> null); - assertThat(cond.value()).isNull(); - assertThat(cond.isEmpty()).isFalse(); - } - @Test void testIsLikeCaseInsensitiveWhenPresent() { IsLikeCaseInsensitiveWhenPresent cond = SqlBuilder.isLikeCaseInsensitiveWhenPresent(() -> "%f%"); @@ -307,13 +242,6 @@ void testIsNotLike() { assertThat(cond.isEmpty()).isFalse(); } - @Test - void testIsNotLikeNull() { - IsNotLike cond = SqlBuilder.isNotLike(() -> null); - assertThat(cond.value()).isNull(); - assertThat(cond.isEmpty()).isFalse(); - } - @Test void testIsNotLikeWhenPresent() { IsNotLikeWhenPresent cond = SqlBuilder.isNotLikeWhenPresent(() -> "%F%"); @@ -335,13 +263,6 @@ void testIsNotLikeCaseInsensitive() { assertThat(cond.isEmpty()).isFalse(); } - @Test - void testIsNotLikeCaseInsensitiveNull() { - IsNotLikeCaseInsensitive cond = SqlBuilder.isNotLikeCaseInsensitive(() -> null); - assertThat(cond.value()).isNull(); - assertThat(cond.isEmpty()).isFalse(); - } - @Test void testIsNotLikeCaseInsensitiveWhenPresent() { IsNotLikeCaseInsensitiveWhenPresent cond = SqlBuilder.isNotLikeCaseInsensitiveWhenPresent(() -> "%f%"); diff --git a/src/test/java/org/mybatis/dynamic/sql/where/render/OptionalCriterionRenderTest.java b/src/test/java/org/mybatis/dynamic/sql/where/render/OptionalCriterionRenderTest.java index 1e6e56a92..25ea36a3e 100644 --- a/src/test/java/org/mybatis/dynamic/sql/where/render/OptionalCriterionRenderTest.java +++ b/src/test/java/org/mybatis/dynamic/sql/where/render/OptionalCriterionRenderTest.java @@ -19,7 +19,6 @@ import static org.assertj.core.api.Assertions.entry; import static org.mybatis.dynamic.sql.SqlBuilder.*; -import java.util.Objects; import java.util.Optional; import org.junit.jupiter.api.Test; @@ -49,7 +48,7 @@ void testNoRenderableCriteria() { void testNoRenderableCriteriaWithIf() { Integer nullId = null; - Optional whereClause = where(id, isEqualTo(nullId).filter(Objects::nonNull)) + Optional whereClause = where(id, isEqualToWhenPresent(nullId)) .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) .build() .render(RenderingStrategies.SPRING_NAMED_PARAMETER); From 384c758b0b865033d44df8eb8ad87470be64fcdd Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 7 Apr 2025 11:34:55 -0400 Subject: [PATCH 237/289] Licensing --- .../sql/where/condition/NullContractTest.java | 15 +++++++++++++++ .../kotlin/mybatis3/mariadb/KIsLikeEscape.kt | 15 +++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/src/test/java/org/mybatis/dynamic/sql/where/condition/NullContractTest.java b/src/test/java/org/mybatis/dynamic/sql/where/condition/NullContractTest.java index ed7d4e01c..17b96973e 100644 --- a/src/test/java/org/mybatis/dynamic/sql/where/condition/NullContractTest.java +++ b/src/test/java/org/mybatis/dynamic/sql/where/condition/NullContractTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2016-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.mybatis.dynamic.sql.where.condition; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/kotlin/examples/kotlin/mybatis3/mariadb/KIsLikeEscape.kt b/src/test/kotlin/examples/kotlin/mybatis3/mariadb/KIsLikeEscape.kt index b47f09110..6746dc03e 100644 --- a/src/test/kotlin/examples/kotlin/mybatis3/mariadb/KIsLikeEscape.kt +++ b/src/test/kotlin/examples/kotlin/mybatis3/mariadb/KIsLikeEscape.kt @@ -1,3 +1,18 @@ +/* + * Copyright 2016-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package examples.kotlin.mybatis3.mariadb import java.util.function.Predicate From a781f6ae35d62b0cbf992eb9ceccd5d8ed44ecd1 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 7 Apr 2025 12:36:02 -0400 Subject: [PATCH 238/289] Sonar should talk to localhost by default --- pom.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pom.xml b/pom.xml index cad1ea0b9..2f37f9c03 100644 --- a/pom.xml +++ b/pom.xml @@ -76,6 +76,8 @@ pom.xml,src/main/java,src/main/kotlin src/test/java,src/test/kotlin + + http://localhost:9000 official 1.20.6 From 428fc915dd94cfe8e162d75b2e0c4fb22698769f Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 7 Apr 2025 12:36:27 -0400 Subject: [PATCH 239/289] Checkstyle --- .../java/org/mybatis/dynamic/sql/AbstractNoValueCondition.java | 3 ++- .../sql/where/condition/IsGreaterThanOrEqualToWhenPresent.java | 3 ++- .../java/org/mybatis/dynamic/sql/where/condition/IsIn.java | 2 +- .../sql/where/condition/IsInCaseInsensitiveWhenPresent.java | 2 +- .../mybatis/dynamic/sql/where/condition/IsInWhenPresent.java | 2 +- .../sql/where/condition/IsLikeCaseInsensitiveWhenPresent.java | 3 ++- .../java/org/mybatis/dynamic/sql/where/condition/IsNotIn.java | 2 +- .../sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java | 2 +- .../dynamic/sql/where/condition/IsNotInWhenPresent.java | 2 +- .../where/condition/IsNotLikeCaseInsensitiveWhenPresent.java | 3 ++- 10 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/AbstractNoValueCondition.java b/src/main/java/org/mybatis/dynamic/sql/AbstractNoValueCondition.java index 20e6251d6..71daa7763 100644 --- a/src/main/java/org/mybatis/dynamic/sql/AbstractNoValueCondition.java +++ b/src/main/java/org/mybatis/dynamic/sql/AbstractNoValueCondition.java @@ -60,7 +60,8 @@ public interface Filterable { * @param * condition type - not used except for compilation compliance * - * @return this condition if renderable and the supplier returns true, otherwise a condition that will not render. + * @return this condition if renderable and the supplier returns true, otherwise a condition that will not + * render. */ AbstractNoValueCondition filter(BooleanSupplier booleanSupplier); } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanOrEqualToWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanOrEqualToWhenPresent.java index 825b5c6cf..01f895dc9 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanOrEqualToWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanOrEqualToWhenPresent.java @@ -25,7 +25,8 @@ public class IsGreaterThanOrEqualToWhenPresent extends AbstractSingleValueCondition implements AbstractSingleValueCondition.Filterable, AbstractSingleValueCondition.Mappable { - private static final IsGreaterThanOrEqualToWhenPresent EMPTY = new IsGreaterThanOrEqualToWhenPresent(-1) { + private static final IsGreaterThanOrEqualToWhenPresent EMPTY = + new IsGreaterThanOrEqualToWhenPresent(-1) { @Override public Object value() { throw new NoSuchElementException("No value present"); //$NON-NLS-1$ diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsIn.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsIn.java index 886980610..67072dc8a 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsIn.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsIn.java @@ -27,7 +27,7 @@ import org.mybatis.dynamic.sql.util.Validator; public class IsIn extends AbstractListValueCondition - implements AbstractListValueCondition.Filterable, AbstractListValueCondition.Mappable{ + implements AbstractListValueCondition.Filterable, AbstractListValueCondition.Mappable { private static final IsIn EMPTY = new IsIn<>(Collections.emptyList()); public static IsIn empty() { diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java index 934df359b..6b4c1e1cd 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java @@ -18,8 +18,8 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.function.Function; import java.util.Objects; +import java.util.function.Function; import java.util.function.Predicate; import org.jspecify.annotations.NonNull; diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInWhenPresent.java index 2dec62d72..abacd2690 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInWhenPresent.java @@ -27,7 +27,7 @@ import org.mybatis.dynamic.sql.AbstractListValueCondition; public class IsInWhenPresent extends AbstractListValueCondition - implements AbstractListValueCondition.Filterable, AbstractListValueCondition.Mappable{ + implements AbstractListValueCondition.Filterable, AbstractListValueCondition.Mappable { private static final IsInWhenPresent EMPTY = new IsInWhenPresent<>(Collections.emptyList()); public static IsInWhenPresent empty() { diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitiveWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitiveWhenPresent.java index bebbff30d..60307625f 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitiveWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitiveWhenPresent.java @@ -27,7 +27,8 @@ public class IsLikeCaseInsensitiveWhenPresent extends AbstractSingleValueCondition implements CaseInsensitiveRenderableCondition, AbstractSingleValueCondition.Filterable, AbstractSingleValueCondition.Mappable { - private static final IsLikeCaseInsensitiveWhenPresent EMPTY = new IsLikeCaseInsensitiveWhenPresent<>("") { //$NON-NLS-1$ + private static final IsLikeCaseInsensitiveWhenPresent EMPTY = + new IsLikeCaseInsensitiveWhenPresent<>("") { //$NON-NLS-1$ @Override public String value() { throw new NoSuchElementException("No value present"); //$NON-NLS-1$ diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotIn.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotIn.java index f6c70d180..af6c248f4 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotIn.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotIn.java @@ -27,7 +27,7 @@ import org.mybatis.dynamic.sql.util.Validator; public class IsNotIn extends AbstractListValueCondition - implements AbstractListValueCondition.Filterable, AbstractListValueCondition.Mappable{ + implements AbstractListValueCondition.Filterable, AbstractListValueCondition.Mappable { private static final IsNotIn EMPTY = new IsNotIn<>(Collections.emptyList()); public static IsNotIn empty() { diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java index 5646168c1..6852c67fd 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java @@ -18,8 +18,8 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.function.Function; import java.util.Objects; +import java.util.function.Function; import java.util.function.Predicate; import org.jspecify.annotations.NonNull; diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInWhenPresent.java index 375f7d69b..33efb1782 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInWhenPresent.java @@ -27,7 +27,7 @@ import org.mybatis.dynamic.sql.AbstractListValueCondition; public class IsNotInWhenPresent extends AbstractListValueCondition - implements AbstractListValueCondition.Filterable, AbstractListValueCondition.Mappable{ + implements AbstractListValueCondition.Filterable, AbstractListValueCondition.Mappable { private static final IsNotInWhenPresent EMPTY = new IsNotInWhenPresent<>(Collections.emptyList()); public static IsNotInWhenPresent empty() { diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitiveWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitiveWhenPresent.java index e1e17f9da..cc0b04549 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitiveWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitiveWhenPresent.java @@ -27,7 +27,8 @@ public class IsNotLikeCaseInsensitiveWhenPresent extends AbstractSingleValueCondition implements CaseInsensitiveRenderableCondition, AbstractSingleValueCondition.Filterable, AbstractSingleValueCondition.Mappable { - private static final IsNotLikeCaseInsensitiveWhenPresent EMPTY = new IsNotLikeCaseInsensitiveWhenPresent<>("") { //$NON-NLS-1$ + private static final IsNotLikeCaseInsensitiveWhenPresent EMPTY = + new IsNotLikeCaseInsensitiveWhenPresent<>("") { //$NON-NLS-1$ @Override public String value() { throw new NoSuchElementException("No value present"); //$NON-NLS-1$ From 42a905c88d19f83859c94e663351be1ad0fc11d8 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 7 Apr 2025 15:27:34 -0400 Subject: [PATCH 240/289] Checkstyle, Sonar, Coverage, etc. --- .../where/condition/IsBetweenWhenPresent.java | 2 +- .../condition/IsNotBetweenWhenPresent.java | 2 +- .../examples/animal/data/AnimalDataTest.java | 12 +- src/test/java/issues/gh105/Issue105Test.java | 176 ------------------ .../dynamic/sql/util/PredicatesTest.java | 42 +++++ .../sql/where/condition/FilterAndMapTest.java | 62 ++++++ .../sql/where/condition/NullContractTest.java | 2 +- .../render/OptionalCriterionRenderTest.java | 48 +---- 8 files changed, 122 insertions(+), 224 deletions(-) create mode 100644 src/test/java/org/mybatis/dynamic/sql/util/PredicatesTest.java diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsBetweenWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsBetweenWhenPresent.java index a3eb2a91e..bc9c12d37 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsBetweenWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsBetweenWhenPresent.java @@ -103,7 +103,7 @@ private Builder(@Nullable T value1) { @Override protected IsBetweenWhenPresent build(@Nullable T value2) { - return IsBetweenWhenPresent.of(value1, value2); + return of(value1, value2); } } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotBetweenWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotBetweenWhenPresent.java index cb9860384..3c9c8fc9f 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotBetweenWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotBetweenWhenPresent.java @@ -104,7 +104,7 @@ private Builder(@Nullable T value1) { @Override protected IsNotBetweenWhenPresent build(@Nullable T value2) { - return IsNotBetweenWhenPresent.of(value1, value2); + return of(value1, value2); } } } diff --git a/src/test/java/examples/animal/data/AnimalDataTest.java b/src/test/java/examples/animal/data/AnimalDataTest.java index a883b4bd2..1ea44184c 100644 --- a/src/test/java/examples/animal/data/AnimalDataTest.java +++ b/src/test/java/examples/animal/data/AnimalDataTest.java @@ -33,7 +33,6 @@ import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Optional; import org.apache.ibatis.datasource.unpooled.UnpooledDataSource; @@ -717,7 +716,7 @@ void testInConditionWithEventuallyEmptyListForceRendering() { SelectModel selectModel = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isInWhenPresent(inValues).filter(Objects::nonNull).filter(i -> i != 22)) + .where(id, isInWhenPresent(inValues).filter(i -> i != 22)) .build(); assertThatExceptionOfType(NonRenderingWhereClauseException.class).isThrownBy(() -> @@ -744,7 +743,7 @@ void testInCaseSensitiveCondition() { SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(animalName, isInCaseInsensitive("yellow-bellied marmot", "verbet", null)) + .where(animalName, isInCaseInsensitiveWhenPresent("yellow-bellied marmot", "verbet", null)) .build() .render(RenderingStrategies.MYBATIS3); @@ -792,12 +791,13 @@ void testNotInCaseSensitiveConditionWithNull() { SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(animalName, isNotInCaseInsensitive((String)null)) + .where(animalName, isNotInCaseInsensitiveWhenPresent((String) null)) + .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) .build() .render(RenderingStrategies.MYBATIS3); List animals = mapper.selectMany(selectStatement); - assertThat(animals).isEmpty(); + assertThat(animals).hasSize(65); } } @@ -825,7 +825,7 @@ void testNotInConditionWithEventuallyEmptyListForceRendering() { SelectModel selectModel = select(id, animalName, bodyWeight, brainWeight) .from(animalData) .where(id, isNotInWhenPresent(null, 22, null) - .filter(Objects::nonNull).filter(i -> i != 22)) + .filter(i -> i != 22)) .build(); assertThatExceptionOfType(NonRenderingWhereClauseException.class).isThrownBy(() -> diff --git a/src/test/java/issues/gh105/Issue105Test.java b/src/test/java/issues/gh105/Issue105Test.java index 81ecb79c2..c12f4fde9 100644 --- a/src/test/java/issues/gh105/Issue105Test.java +++ b/src/test/java/issues/gh105/Issue105Test.java @@ -519,22 +519,6 @@ void testNotLikeWhenPresentTransform() { assertThat(selectStatement.getParameters()).containsEntry("p1", "%fred%"); } - @Test - void testBetweenTransformWithNull() { - - SelectStatementProvider selectStatement = select(id, firstName, lastName) - .from(person) - .where(age, isBetweenWhenPresent(1).and((Integer) null).map(i1 -> i1 + 1, i2 -> i2 + 2)) - .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) - .build() - .render(RenderingStrategies.MYBATIS3); - - String expected = "select person_id, first_name, last_name" - + " from Person"; - - assertThat(selectStatement.getSelectStatement()).isEqualTo(expected); - } - @Test void testBetweenWhenPresentTransformWithNull() { @@ -551,22 +535,6 @@ void testBetweenWhenPresentTransformWithNull() { assertThat(selectStatement.getSelectStatement()).isEqualTo(expected); } - @Test - void testEqualTransformWithNull() { - - SelectStatementProvider selectStatement = select(id, firstName, lastName) - .from(person) - .where(age, isEqualToWhenPresent((Integer) null).map(i -> i + 1)) - .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) - .build() - .render(RenderingStrategies.MYBATIS3); - - String expected = "select person_id, first_name, last_name" - + " from Person"; - - assertThat(selectStatement.getSelectStatement()).isEqualTo(expected); - } - @Test void testEqualWhenPresentTransformWithNull() { @@ -583,38 +551,6 @@ void testEqualWhenPresentTransformWithNull() { assertThat(selectStatement.getSelectStatement()).isEqualTo(expected); } - @Test - void testGreaterThanTransformWithNull() { - - SelectStatementProvider selectStatement = select(id, firstName, lastName) - .from(person) - .where(age, isGreaterThanWhenPresent((Integer) null).map(i -> i + 1)) - .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) - .build() - .render(RenderingStrategies.MYBATIS3); - - String expected = "select person_id, first_name, last_name" - + " from Person"; - - assertThat(selectStatement.getSelectStatement()).isEqualTo(expected); - } - - @Test - void testGreaterThanOrEqualTransformWithNull() { - - SelectStatementProvider selectStatement = select(id, firstName, lastName) - .from(person) - .where(age, isGreaterThanOrEqualToWhenPresent((Integer) null).map(i -> i + 1)) - .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) - .build() - .render(RenderingStrategies.MYBATIS3); - - String expected = "select person_id, first_name, last_name" - + " from Person"; - - assertThat(selectStatement.getSelectStatement()).isEqualTo(expected); - } - @Test void testGreaterThanOrEqualWhenPresentTransformWithNull() { @@ -647,38 +583,6 @@ void testGreaterThanWhenPresentTransformWithNull() { assertThat(selectStatement.getSelectStatement()).isEqualTo(expected); } - @Test - void testLessThanTransformWithNull() { - - SelectStatementProvider selectStatement = select(id, firstName, lastName) - .from(person) - .where(age, isLessThanWhenPresent((Integer) null).map(i -> i + 1)) - .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) - .build() - .render(RenderingStrategies.MYBATIS3); - - String expected = "select person_id, first_name, last_name" - + " from Person"; - - assertThat(selectStatement.getSelectStatement()).isEqualTo(expected); - } - - @Test - void testLessThanOrEqualTransformWithNull() { - - SelectStatementProvider selectStatement = select(id, firstName, lastName) - .from(person) - .where(age, isLessThanOrEqualToWhenPresent((Integer) null).map(i -> i + 1)) - .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) - .build() - .render(RenderingStrategies.MYBATIS3); - - String expected = "select person_id, first_name, last_name" - + " from Person"; - - assertThat(selectStatement.getSelectStatement()).isEqualTo(expected); - } - @Test void testLessThanOrEqualWhenPresentTransformWithNull() { @@ -711,38 +615,6 @@ void testLessThanWhenPresentTransformWithNull() { assertThat(selectStatement.getSelectStatement()).isEqualTo(expected); } - @Test - void testLikeTransformWithNull() { - - SelectStatementProvider selectStatement = select(id, firstName, lastName) - .from(person) - .where(firstName, isLikeWhenPresent((String) null).map(SearchUtils::addWildcards)) - .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) - .build() - .render(RenderingStrategies.MYBATIS3); - - String expected = "select person_id, first_name, last_name" - + " from Person"; - - assertThat(selectStatement.getSelectStatement()).isEqualTo(expected); - } - - @Test - void testLikeCaseInsensitiveTransformWithNull() { - - SelectStatementProvider selectStatement = select(id, firstName, lastName) - .from(person) - .where(firstName, isLikeCaseInsensitiveWhenPresent((String) null).map(SearchUtils::addWildcards)) - .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) - .build() - .render(RenderingStrategies.MYBATIS3); - - String expected = "select person_id, first_name, last_name" - + " from Person"; - - assertThat(selectStatement.getSelectStatement()).isEqualTo(expected); - } - @Test void testLikeCaseInsensitiveWhenPresentTransformWithNull() { @@ -807,22 +679,6 @@ void testNotBetweenWhenPresentTransformWithNull() { assertThat(selectStatement.getSelectStatement()).isEqualTo(expected); } - @Test - void testNotEqualTransformWithNull() { - - SelectStatementProvider selectStatement = select(id, firstName, lastName) - .from(person) - .where(age, isNotEqualToWhenPresent((Integer) null).map(i -> i + 1)) - .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) - .build() - .render(RenderingStrategies.MYBATIS3); - - String expected = "select person_id, first_name, last_name" - + " from Person"; - - assertThat(selectStatement.getSelectStatement()).isEqualTo(expected); - } - @Test void testNotEqualWhenPresentTransformWithNull() { @@ -839,38 +695,6 @@ void testNotEqualWhenPresentTransformWithNull() { assertThat(selectStatement.getSelectStatement()).isEqualTo(expected); } - @Test - void testNotLikeTransformWithNull() { - - SelectStatementProvider selectStatement = select(id, firstName, lastName) - .from(person) - .where(firstName, isNotLikeWhenPresent((String) null).map(SearchUtils::addWildcards)) - .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) - .build() - .render(RenderingStrategies.MYBATIS3); - - String expected = "select person_id, first_name, last_name" - + " from Person"; - - assertThat(selectStatement.getSelectStatement()).isEqualTo(expected); - } - - @Test - void testNotLikeCaseInsensitiveTransformWithNull() { - - SelectStatementProvider selectStatement = select(id, firstName, lastName) - .from(person) - .where(firstName, isNotLikeCaseInsensitiveWhenPresent((String) null).map(SearchUtils::addWildcards)) - .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) - .build() - .render(RenderingStrategies.MYBATIS3); - - String expected = "select person_id, first_name, last_name" - + " from Person"; - - assertThat(selectStatement.getSelectStatement()).isEqualTo(expected); - } - @Test void testNotLikeCaseInsensitiveWhenPresentTransformWithNull() { diff --git a/src/test/java/org/mybatis/dynamic/sql/util/PredicatesTest.java b/src/test/java/org/mybatis/dynamic/sql/util/PredicatesTest.java new file mode 100644 index 000000000..950af088a --- /dev/null +++ b/src/test/java/org/mybatis/dynamic/sql/util/PredicatesTest.java @@ -0,0 +1,42 @@ +/* + * Copyright 2016-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mybatis.dynamic.sql.util; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +class PredicatesTest { + @Test + void testFirstNull() { + assertThat(Predicates.bothPresent().test(null, 1)).isFalse(); + } + + @Test + void testSecondNull() { + assertThat(Predicates.bothPresent().test(1, null)).isFalse(); + } + + @Test + void testBothNull() { + assertThat(Predicates.bothPresent().test(null, null)).isFalse(); + } + + @Test + void testNeitherNull() { + assertThat(Predicates.bothPresent().test(1, 1)).isTrue(); + } +} diff --git a/src/test/java/org/mybatis/dynamic/sql/where/condition/FilterAndMapTest.java b/src/test/java/org/mybatis/dynamic/sql/where/condition/FilterAndMapTest.java index a3bb3d620..7ea071e87 100644 --- a/src/test/java/org/mybatis/dynamic/sql/where/condition/FilterAndMapTest.java +++ b/src/test/java/org/mybatis/dynamic/sql/where/condition/FilterAndMapTest.java @@ -20,8 +20,12 @@ import java.util.List; import java.util.NoSuchElementException; +import java.util.function.Predicate; +import java.util.stream.Stream; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; import org.mybatis.dynamic.sql.SqlBuilder; class FilterAndMapTest { @@ -492,6 +496,46 @@ void testBetweenMapWithSingleMapper() { assertThat(cond.value2()).isEqualTo(4); } + @Test + void testBetweenWhenPresentFilterWithBiPredicate() { + IsBetweenWhenPresent cond = SqlBuilder.isBetweenWhenPresent("3").and("4") + .map(Integer::parseInt) + .filter((v1, v2) -> true); + assertThat(cond.isEmpty()).isFalse(); + assertThat(cond.value1()).isEqualTo(3); + assertThat(cond.value2()).isEqualTo(4); + } + + @Test + void testNotBetweenWhenPresentFilterWithBiPredicate() { + IsNotBetweenWhenPresent cond = SqlBuilder.isNotBetweenWhenPresent("3").and("4") + .map(Integer::parseInt) + .filter((v1, v2) -> true); + assertThat(cond.isEmpty()).isFalse(); + assertThat(cond.value1()).isEqualTo(3); + assertThat(cond.value2()).isEqualTo(4); + } + + @ParameterizedTest + @MethodSource("testBetweenFilterVariations") + void testBetweenFilterVariations(FilterVariation variation) { + IsBetween cond = SqlBuilder.isBetween("4").and("6") + .map(Integer::parseInt) + .filter(variation.predicate); + assertThat(cond.isEmpty()).isEqualTo(variation.empty); + } + + private record FilterVariation(Predicate predicate, boolean empty) {} + + private static Stream testBetweenFilterVariations() { + return Stream.of( + new FilterVariation(v -> v == 4, true), + new FilterVariation(v -> v == 6, true), + new FilterVariation(v -> v == 1, true), + new FilterVariation(v -> v % 2 == 0, false) + ); + } + @Test void testNotBetweenUnRenderableFilterShouldReturnSameObject() { IsNotBetween cond = SqlBuilder.isNotBetween(3).and(4).filter((i1, i2) -> false); @@ -524,6 +568,24 @@ void testNotBetweenMapWithSingleMapper() { assertThat(cond.value2()).isEqualTo(4); } + @Test + void testBetweenFilterToEmpty() { + var cond = SqlBuilder.isBetween("3").and("4").map(Integer::parseInt) + .filter((i1, i2) -> false); + assertThat(cond.isEmpty()).isTrue(); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value1); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value2); + } + + @Test + void testNotBetweenFilterToEmpty() { + var cond = SqlBuilder.isNotBetween("3").and("4").map(Integer::parseInt) + .filter((i1, i2) -> false); + assertThat(cond.isEmpty()).isTrue(); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value1); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value2); + } + @Test void testMappingAnEmptyListCondition() { var cond = SqlBuilder.isNotIn("Fred", "Wilma"); diff --git a/src/test/java/org/mybatis/dynamic/sql/where/condition/NullContractTest.java b/src/test/java/org/mybatis/dynamic/sql/where/condition/NullContractTest.java index 17b96973e..cd55d9e52 100644 --- a/src/test/java/org/mybatis/dynamic/sql/where/condition/NullContractTest.java +++ b/src/test/java/org/mybatis/dynamic/sql/where/condition/NullContractTest.java @@ -37,7 +37,7 @@ *

This set of tests should be the only tests in the library that verify this behavior. All other tests * should use the library properly. */ -public class NullContractTest { +class NullContractTest { @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing @Test void testIsBetween() { diff --git a/src/test/java/org/mybatis/dynamic/sql/where/render/OptionalCriterionRenderTest.java b/src/test/java/org/mybatis/dynamic/sql/where/render/OptionalCriterionRenderTest.java index 25ea36a3e..48bd36755 100644 --- a/src/test/java/org/mybatis/dynamic/sql/where/render/OptionalCriterionRenderTest.java +++ b/src/test/java/org/mybatis/dynamic/sql/where/render/OptionalCriterionRenderTest.java @@ -34,21 +34,7 @@ class OptionalCriterionRenderTest { @Test void testNoRenderableCriteria() { - Integer nullId = null; - - Optional whereClause = where(id, isEqualToWhenPresent(nullId)) - .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) - .build() - .render(RenderingStrategies.SPRING_NAMED_PARAMETER); - - assertThat(whereClause).isEmpty(); - } - - @Test - void testNoRenderableCriteriaWithIf() { - Integer nullId = null; - - Optional whereClause = where(id, isEqualToWhenPresent(nullId)) + Optional whereClause = where(id, isEqualToWhenPresent((Integer) null)) .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) .build() .render(RenderingStrategies.SPRING_NAMED_PARAMETER); @@ -102,10 +88,8 @@ void testEnabledIsNotNull() { @Test void testOneRenderableCriteriaBeforeNull() { - String nullFirstName = null; - Optional whereClause = where(id, isEqualToWhenPresent(22)) - .and(firstName, isEqualToWhenPresent(nullFirstName)) + .and(firstName, isEqualToWhenPresent((String) null)) .build() .render(RenderingStrategies.SPRING_NAMED_PARAMETER); @@ -117,9 +101,7 @@ void testOneRenderableCriteriaBeforeNull() { @Test void testOneRenderableCriteriaBeforeNull2() { - String nullFirstName = null; - - Optional whereClause = where(id, isEqualToWhenPresent(22), and(firstName, isEqualToWhenPresent(nullFirstName))) + Optional whereClause = where(id, isEqualToWhenPresent(22), and(firstName, isEqualToWhenPresent((String) null))) .build() .render(RenderingStrategies.SPRING_NAMED_PARAMETER); @@ -131,9 +113,7 @@ void testOneRenderableCriteriaBeforeNull2() { @Test void testOneRenderableCriteriaAfterNull() { - Integer nullId = null; - - Optional whereClause = where(id, isEqualToWhenPresent(nullId)) + Optional whereClause = where(id, isEqualToWhenPresent((Integer) null)) .and(firstName, isEqualToWhenPresent("fred")) .build() .render(RenderingStrategies.SPRING_NAMED_PARAMETER); @@ -146,9 +126,7 @@ void testOneRenderableCriteriaAfterNull() { @Test void testOneRenderableCriteriaAfterNull2() { - Integer nullId = null; - - Optional whereClause = where(id, isEqualToWhenPresent(nullId), and(firstName, isEqualToWhenPresent("fred"))) + Optional whereClause = where(id, isEqualToWhenPresent((Integer) null), and(firstName, isEqualToWhenPresent("fred"))) .build() .render(RenderingStrategies.SPRING_NAMED_PARAMETER); @@ -160,9 +138,7 @@ void testOneRenderableCriteriaAfterNull2() { @Test void testOverrideFirstConnector() { - Integer nullId = null; - - Optional whereClause = where(id, isEqualToWhenPresent(nullId), and(firstName, isEqualToWhenPresent("fred")), or(lastName, isEqualTo("flintstone"))) + Optional whereClause = where(id, isEqualToWhenPresent((Integer) null), and(firstName, isEqualToWhenPresent("fred")), or(lastName, isEqualTo("flintstone"))) .build() .render(RenderingStrategies.SPRING_NAMED_PARAMETER); @@ -305,10 +281,8 @@ void testWhereExistsAndAnd() { @Test void testCollapsingCriteriaGroup1() { - String name1 = null; - Optional whereClause = where( - group(firstName, isEqualToWhenPresent(name1)), or(lastName, isEqualToWhenPresent(name1))) + group(firstName, isEqualToWhenPresent((String) null)), or(lastName, isEqualToWhenPresent((String) null))) .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) .build() .render(RenderingStrategies.SPRING_NAMED_PARAMETER); @@ -318,10 +292,8 @@ void testCollapsingCriteriaGroup1() { @Test void testCollapsingCriteriaGroup2() { - String name1 = null; - Optional whereClause = where( - group(firstName, isEqualTo("Fred")), or(lastName, isEqualToWhenPresent(name1))) + group(firstName, isEqualTo("Fred")), or(lastName, isEqualToWhenPresent((String) null))) .build() .render(RenderingStrategies.SPRING_NAMED_PARAMETER); @@ -335,10 +307,8 @@ void testCollapsingCriteriaGroup2() { @Test void testCollapsingCriteriaGroup3() { - String name1 = null; - Optional whereClause = where( - group(firstName, isEqualTo("Fred")), or(lastName, isEqualToWhenPresent(name1)), or(firstName, isEqualTo("Betty"))) + group(firstName, isEqualTo("Fred")), or(lastName, isEqualToWhenPresent((String) null)), or(firstName, isEqualTo("Betty"))) .build() .render(RenderingStrategies.SPRING_NAMED_PARAMETER); From b3b3b7d8f9cc26aa86f5b36bdef1dd28bf917dba Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 7 Apr 2025 15:38:09 -0400 Subject: [PATCH 241/289] Documentation --- CHANGELOG.md | 2 ++ src/site/markdown/docs/conditions.md | 16 +++++++++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cec9f683f..c65f2c09c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -82,6 +82,8 @@ Runtime behavior changes: 2. We have updated the "ParameterTypeConverter" used in Spring applications to maintain compatibility with Spring's "Converter" interface. The primary change is that the framework will no longer call a type converter if the input value is null. This should simplify the coding of converters and foster reuse with existing Spring converters. +3. The "map" method on the "WhenPresent" conditions will accept a mapper function that may return a null value. The + conditions will now properly handle this outcome ### Other important changes: diff --git a/src/site/markdown/docs/conditions.md b/src/site/markdown/docs/conditions.md index 2e266e22b..438249400 100644 --- a/src/site/markdown/docs/conditions.md +++ b/src/site/markdown/docs/conditions.md @@ -166,8 +166,8 @@ table lists the optional conditions and shows how to use them: | Null | where(id, isNull().filter(BooleanSupplier) | The condition will render if BooleanSupplier.getAsBoolean() returns true | ### "When Present" Condition Builders -The library supplies several methods that supply conditions to be used in the common case of checking for null -values. The table below lists the rendering rules for each of these "when present" condition builder methods. +The library supplies conditions for use in the common case of checking for null +values. The table below lists the rendering rules for each of these "when present" conditions. | Condition | Example | Rendering Rules | |---------------------------|---------------------------------------------------|---------------------------------------------------------------| @@ -184,14 +184,20 @@ values. The table below lists the rendering rules for each of these "when presen | Not Like | where(id, isNotLikeWhenPresent(x)) | The condition will render if x is non-null | | Not Like Case Insensitive | where(id, isNotLikeCaseInsensitiveWhenPresent(x)) | The condition will render if x is non-null | -Note that these methods simply apply a "NotNull" filter to a condition. For example: +With our adoption of JSpecify, it is now considered a misuse of the library to pass a null value into a condition +unless the condition is one of the "when present" conditions. If you previously wrote code like this: ```java -// the following two lines are functionally equivalent -... where (id, isEqualToWhenPresent(x)) ... ... where (id, isEqualTo(x).filter(Objects::nonNull)) ... ``` +Starting in version 2.0.0 of the library, you will now see IDE warnings related to nullability. You should change it +to this: + +```java +... where (id, isEqualToWhenPresent(x)) ... +``` + ### Optionality with the "In" Conditions Optionality with the "in" and "not in" conditions is a bit more complex than the other types of conditions. The rules are different for the base conditions ("isIn", "isNotIn", etc.) and the "when present" conditions ("isInWhenPresent", From f06686dfe0eb344f0e9c505cf1f02e27e7985278 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 7 Apr 2025 17:31:56 -0400 Subject: [PATCH 242/289] Animal data nullability updates --- .../examples/animal/data/AnimalDataTest.java | 1 - .../examples/animal/data/MyInCondition.java | 6 ++-- .../OptionalConditionsAnimalDataTest.java | 3 +- ...onditionsWithPredicatesAnimalDataTest.java | 35 ++++--------------- .../data/VariousListConditionsTest.java | 12 ++----- 5 files changed, 14 insertions(+), 43 deletions(-) diff --git a/src/test/java/examples/animal/data/AnimalDataTest.java b/src/test/java/examples/animal/data/AnimalDataTest.java index b028868ad..efedc0aea 100644 --- a/src/test/java/examples/animal/data/AnimalDataTest.java +++ b/src/test/java/examples/animal/data/AnimalDataTest.java @@ -33,7 +33,6 @@ import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Optional; import org.apache.ibatis.datasource.unpooled.UnpooledDataSource; diff --git a/src/test/java/examples/animal/data/MyInCondition.java b/src/test/java/examples/animal/data/MyInCondition.java index 7203e4fb5..de62d55f6 100644 --- a/src/test/java/examples/animal/data/MyInCondition.java +++ b/src/test/java/examples/animal/data/MyInCondition.java @@ -22,11 +22,11 @@ import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.SqlBuilder; import org.mybatis.dynamic.sql.where.condition.IsIn; +import org.mybatis.dynamic.sql.where.condition.IsInWhenPresent; public class MyInCondition { - public static IsIn isIn(@Nullable String...values) { - return SqlBuilder.isIn(values) - .filter(Objects::nonNull) + public static IsInWhenPresent isIn(@Nullable String...values) { + return SqlBuilder.isInWhenPresent(values) .map(String::trim) .filter(not(String::isEmpty)); } diff --git a/src/test/java/examples/animal/data/OptionalConditionsAnimalDataTest.java b/src/test/java/examples/animal/data/OptionalConditionsAnimalDataTest.java index 166c21a05..0917160a0 100644 --- a/src/test/java/examples/animal/data/OptionalConditionsAnimalDataTest.java +++ b/src/test/java/examples/animal/data/OptionalConditionsAnimalDataTest.java @@ -34,6 +34,7 @@ import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mybatis.dynamic.sql.render.RenderingStrategies; @@ -43,7 +44,7 @@ class OptionalConditionsAnimalDataTest { private static final String JDBC_URL = "jdbc:hsqldb:mem:aname"; private static final String JDBC_DRIVER = "org.hsqldb.jdbcDriver"; - private static final Integer NULL_INTEGER = null; + private static final @Nullable Integer NULL_INTEGER = null; private SqlSessionFactory sqlSessionFactory; diff --git a/src/test/java/examples/animal/data/OptionalConditionsWithPredicatesAnimalDataTest.java b/src/test/java/examples/animal/data/OptionalConditionsWithPredicatesAnimalDataTest.java index 671a171bc..4c65708cd 100644 --- a/src/test/java/examples/animal/data/OptionalConditionsWithPredicatesAnimalDataTest.java +++ b/src/test/java/examples/animal/data/OptionalConditionsWithPredicatesAnimalDataTest.java @@ -30,7 +30,6 @@ import java.sql.Connection; import java.sql.DriverManager; import java.util.List; -import java.util.Objects; import org.apache.ibatis.datasource.unpooled.UnpooledDataSource; import org.apache.ibatis.jdbc.ScriptRunner; @@ -94,26 +93,6 @@ void testAllIgnored() { } } - @Test - void testSelectByNull() { - // this method demonstrates that ignoring the null value warning will still work - try (SqlSession sqlSession = sqlSessionFactory.openSession()) { - AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); - SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) - .from(animalData) - .where(id, isGreaterThan(NULL_INTEGER)) // should be an IDE warning about passing null to a nonnull method - .orderBy(id) - .build() - .render(RenderingStrategies.MYBATIS3); - List animals = mapper.selectMany(selectStatement); - assertAll( - () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id > #{parameters.p1,jdbcType=INTEGER} order by id"), - () -> assertThat(selectStatement.getParameters()).containsEntry("p1", null), - () -> assertThat(animals).isEmpty() - ); - } - } - @Test void testIgnoredBetweenRendered() { try (SqlSession sqlSession = sqlSessionFactory.openSession()) { @@ -122,7 +101,7 @@ void testIgnoredBetweenRendered() { .from(animalData) .where(id, isEqualTo(3)) .and(id, isNotEqualToWhenPresent(NULL_INTEGER)) - .or(id, isEqualTo(4).filter(Objects::nonNull)) + .or(id, isEqualTo(4)) .orderBy(id) .build() .render(RenderingStrategies.MYBATIS3); @@ -143,8 +122,8 @@ void testIgnoredInWhere() { SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) .where(id, isLessThanWhenPresent(NULL_INTEGER)) - .and(id, isEqualTo(3).filter(Objects::nonNull)) - .or(id, isEqualTo(4).filter(Objects::nonNull)) + .and(id, isEqualTo(3)) + .or(id, isEqualTo(4)) .orderBy(id) .build() .render(RenderingStrategies.MYBATIS3); @@ -187,8 +166,8 @@ void testIgnoredInitialWhere() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isLessThanWhenPresent(NULL_INTEGER), and(id, isEqualTo(3).filter(Objects::nonNull))) - .or(id, isEqualTo(4).filter(Objects::nonNull)) + .where(id, isLessThanWhenPresent(NULL_INTEGER), and(id, isEqualTo(3))) + .or(id, isEqualTo(4)) .orderBy(id) .build() .render(RenderingStrategies.MYBATIS3); @@ -802,7 +781,7 @@ void testIsLikeWhenWithValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(animalName, isLike("%mole").filter(Objects::nonNull)) + .where(animalName, isLike("%mole")) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -882,7 +861,7 @@ void testIsNotLikeWhenWithValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(animalName, isNotLike("%mole").filter(Objects::nonNull)) + .where(animalName, isNotLike("%mole")) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() diff --git a/src/test/java/examples/animal/data/VariousListConditionsTest.java b/src/test/java/examples/animal/data/VariousListConditionsTest.java index c3cc8777e..1fef3d88b 100644 --- a/src/test/java/examples/animal/data/VariousListConditionsTest.java +++ b/src/test/java/examples/animal/data/VariousListConditionsTest.java @@ -86,19 +86,18 @@ void testInWithNull() { SelectStatementProvider selectStatement = select(id, animalName) .from(animalData) - .where(id, isIn(2, 3, null)) + .where(id, isInWhenPresent(2, 3, null)) .orderBy(id) .build() .render(RenderingStrategies.MYBATIS3); assertThat(selectStatement.getSelectStatement()).isEqualTo( "select id, animal_name from AnimalData where id " + - "in (#{parameters.p1,jdbcType=INTEGER},#{parameters.p2,jdbcType=INTEGER},#{parameters.p3,jdbcType=INTEGER}) " + + "in (#{parameters.p1,jdbcType=INTEGER},#{parameters.p2,jdbcType=INTEGER}) " + "order by id" ); assertThat(selectStatement.getParameters()).containsEntry("p1", 2); assertThat(selectStatement.getParameters()).containsEntry("p2", 3); - assertThat(selectStatement.getParameters()).containsEntry("p3", null); List> rows = mapper.selectManyMappedRows(selectStatement); assertThat(rows).hasSize(2); @@ -171,13 +170,6 @@ void testInWhenPresentWithEmptyList() { } } - @Test - void testInWithNullList() { - assertThatExceptionOfType(NullPointerException.class).isThrownBy(() -> - isIn((Collection) null) - ); - } - @Test void testInWhenPresentWithNullList() { try (SqlSession sqlSession = sqlSessionFactory.openSession()) { From e827b579560c7136a512433c119e7b1e5e96c2a5 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 7 Apr 2025 17:33:04 -0400 Subject: [PATCH 243/289] Remove unused imports --- src/test/java/examples/animal/data/MyInCondition.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/test/java/examples/animal/data/MyInCondition.java b/src/test/java/examples/animal/data/MyInCondition.java index de62d55f6..13f076331 100644 --- a/src/test/java/examples/animal/data/MyInCondition.java +++ b/src/test/java/examples/animal/data/MyInCondition.java @@ -17,11 +17,8 @@ import static java.util.function.Predicate.not; -import java.util.Objects; - import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.SqlBuilder; -import org.mybatis.dynamic.sql.where.condition.IsIn; import org.mybatis.dynamic.sql.where.condition.IsInWhenPresent; public class MyInCondition { From 3f5b36357070e00dcc2c2c11631974aca48fae42 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 7 Apr 2025 17:39:48 -0400 Subject: [PATCH 244/289] Convert to record --- .../comparison/ColumnComparisonMapper.java | 6 ++--- .../comparison/ColumnComparisonRecord.java | 21 +-------------- .../comparison/ColumnComparisonTest.java | 26 +++++++++---------- 3 files changed, 17 insertions(+), 36 deletions(-) diff --git a/src/test/java/examples/column/comparison/ColumnComparisonMapper.java b/src/test/java/examples/column/comparison/ColumnComparisonMapper.java index a8acf0c88..dc27de8d0 100644 --- a/src/test/java/examples/column/comparison/ColumnComparisonMapper.java +++ b/src/test/java/examples/column/comparison/ColumnComparisonMapper.java @@ -17,7 +17,7 @@ import java.util.List; -import org.apache.ibatis.annotations.Result; +import org.apache.ibatis.annotations.Arg; import org.apache.ibatis.annotations.SelectProvider; import org.mybatis.dynamic.sql.select.SelectDSLCompleter; import org.mybatis.dynamic.sql.select.render.SelectStatementProvider; @@ -27,8 +27,8 @@ public interface ColumnComparisonMapper { @SelectProvider(type=SqlProviderAdapter.class, method="select") - @Result(column="number1", property="number1", id=true) - @Result(column="number2", property="number2", id=true) + @Arg(column="number1", javaType = int.class, id=true) + @Arg(column="number2", javaType = int.class, id=true) List selectMany(SelectStatementProvider selectStatement); default List select(SelectDSLCompleter completer) { diff --git a/src/test/java/examples/column/comparison/ColumnComparisonRecord.java b/src/test/java/examples/column/comparison/ColumnComparisonRecord.java index b783d61b4..8222ca042 100644 --- a/src/test/java/examples/column/comparison/ColumnComparisonRecord.java +++ b/src/test/java/examples/column/comparison/ColumnComparisonRecord.java @@ -15,23 +15,4 @@ */ package examples.column.comparison; -public class ColumnComparisonRecord { - private int number1; - private int number2; - - public int getNumber1() { - return number1; - } - - public void setNumber1(int number1) { - this.number1 = number1; - } - - public int getNumber2() { - return number2; - } - - public void setNumber2(int number2) { - this.number2 = number2; - } -} +public record ColumnComparisonRecord (int number1, int number2) {} diff --git a/src/test/java/examples/column/comparison/ColumnComparisonTest.java b/src/test/java/examples/column/comparison/ColumnComparisonTest.java index 91a6036c5..746db94cd 100644 --- a/src/test/java/examples/column/comparison/ColumnComparisonTest.java +++ b/src/test/java/examples/column/comparison/ColumnComparisonTest.java @@ -51,8 +51,8 @@ void testColumnComparisonLessThan() { assertThat(selectStatement.getSelectStatement()).isEqualTo(expected); assertThat(records).hasSize(5); - assertThat(records.get(0).getNumber1()).isEqualTo(1); - assertThat(records.get(4).getNumber1()).isEqualTo(5); + assertThat(records.get(0).number1()).isEqualTo(1); + assertThat(records.get(4).number1()).isEqualTo(5); } @Test @@ -73,8 +73,8 @@ void testColumnComparisonLessThanOrEqual() { assertThat(selectStatement.getSelectStatement()).isEqualTo(expected); assertThat(records).hasSize(6); - assertThat(records.get(0).getNumber1()).isEqualTo(1); - assertThat(records.get(5).getNumber1()).isEqualTo(6); + assertThat(records.get(0).number1()).isEqualTo(1); + assertThat(records.get(5).number2()).isEqualTo(6); } @Test @@ -95,8 +95,8 @@ void testColumnComparisonGreaterThan() { assertThat(selectStatement.getSelectStatement()).isEqualTo(expected); assertThat(records).hasSize(5); - assertThat(records.get(0).getNumber1()).isEqualTo(7); - assertThat(records.get(4).getNumber1()).isEqualTo(11); + assertThat(records.get(0).number1()).isEqualTo(7); + assertThat(records.get(4).number1()).isEqualTo(11); } @Test @@ -117,8 +117,8 @@ void testColumnComparisonGreaterThanOrEqual() { assertThat(selectStatement.getSelectStatement()).isEqualTo(expected); assertThat(records).hasSize(6); - assertThat(records.get(0).getNumber1()).isEqualTo(6); - assertThat(records.get(5).getNumber1()).isEqualTo(11); + assertThat(records.get(0).number1()).isEqualTo(6); + assertThat(records.get(5).number1()).isEqualTo(11); } @Test @@ -139,7 +139,7 @@ void testColumnComparisonEqual() { assertThat(selectStatement.getSelectStatement()).isEqualTo(expected); assertThat(records).hasSize(1); - assertThat(records.get(0).getNumber1()).isEqualTo(6); + assertThat(records.get(0).number1()).isEqualTo(6); } @Test @@ -160,8 +160,8 @@ void testColumnComparisonNotEqual() { assertThat(selectStatement.getSelectStatement()).isEqualTo(expected); assertThat(records).hasSize(10); - assertThat(records.get(0).getNumber1()).isEqualTo(1); - assertThat(records.get(9).getNumber1()).isEqualTo(11); + assertThat(records.get(0).number1()).isEqualTo(1); + assertThat(records.get(9).number1()).isEqualTo(11); } @Test @@ -172,7 +172,7 @@ void testHelperMethod() { ); assertThat(records).hasSize(10); - assertThat(records.get(0).getNumber1()).isEqualTo(1); - assertThat(records.get(9).getNumber1()).isEqualTo(11); + assertThat(records.get(0).number1()).isEqualTo(1); + assertThat(records.get(9).number1()).isEqualTo(11); } } From 9c82e61c903753c2a64e8e434b6d8056563799d0 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 7 Apr 2025 17:41:00 -0400 Subject: [PATCH 245/289] Use search utils --- src/test/java/examples/complexquery/ComplexQueryTest.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/test/java/examples/complexquery/ComplexQueryTest.java b/src/test/java/examples/complexquery/ComplexQueryTest.java index 3912040cb..e31ab536b 100644 --- a/src/test/java/examples/complexquery/ComplexQueryTest.java +++ b/src/test/java/examples/complexquery/ComplexQueryTest.java @@ -117,7 +117,7 @@ SelectStatementProvider search(@Nullable Integer targetId, @Nullable String fNam } else { builder .and(firstName, isLikeWhenPresent(fName).map(s -> "%" + s + "%")) - .and(lastName, isLikeWhenPresent(lName).map(this::addWildcards)); + .and(lastName, isLikeWhenPresent(lName).map(SearchUtils::addWildcards)); } builder @@ -126,8 +126,4 @@ SelectStatementProvider search(@Nullable Integer targetId, @Nullable String fNam return builder.build().render(RenderingStrategies.MYBATIS3); } - - String addWildcards(String s) { - return "%" + s + "%"; - } } From b390f1f1cb098223a680d5d6510848ad0fc329e8 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 7 Apr 2025 17:55:09 -0400 Subject: [PATCH 246/289] Use search utils --- .../custom_render/CustomRenderingTest.java | 86 +++++++------------ .../custom_render/JsonTestMapper.java | 16 ++-- .../custom_render/JsonTestRecord.java | 30 +------ .../examples/custom_render/package-info.java | 19 ++++ 4 files changed, 60 insertions(+), 91 deletions(-) create mode 100644 src/test/java/examples/custom_render/package-info.java diff --git a/src/test/java/examples/custom_render/CustomRenderingTest.java b/src/test/java/examples/custom_render/CustomRenderingTest.java index 11d7e331c..8b0541c1e 100644 --- a/src/test/java/examples/custom_render/CustomRenderingTest.java +++ b/src/test/java/examples/custom_render/CustomRenderingTest.java @@ -40,7 +40,7 @@ import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory; -import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mybatis.dynamic.sql.SqlColumn; import org.mybatis.dynamic.sql.insert.render.GeneralInsertStatementProvider; @@ -63,10 +63,10 @@ class CustomRenderingTest { new PostgreSQLContainer<>(TestContainersConfiguration.POSTGRES_LATEST) .withInitScript("examples/custom_render/dbInit.sql"); - private static SqlSessionFactory sqlSessionFactory; + private SqlSessionFactory sqlSessionFactory; - @BeforeAll - static void setUp() { + @BeforeEach + void setUp() { UnpooledDataSource ds = new UnpooledDataSource(postgres.getDriverClassName(), postgres.getJdbcUrl(), postgres.getUsername(), postgres.getPassword()); Environment environment = new Environment("test", new JdbcTransactionFactory(), ds); @@ -81,10 +81,8 @@ void testInsertRecord() { try (SqlSession sqlSession = sqlSessionFactory.openSession()) { JsonTestMapper mapper = sqlSession.getMapper(JsonTestMapper.class); - JsonTestRecord row = new JsonTestRecord(); - row.setId(1); - row.setDescription("Fred"); - row.setInfo("{\"firstName\": \"Fred\", \"lastName\": \"Flintstone\", \"age\": 30}"); + JsonTestRecord row = new JsonTestRecord(1, "Fred", + "{\"firstName\": \"Fred\", \"lastName\": \"Flintstone\", \"age\": 30}"); InsertStatementProvider insertStatement = insert(row).into(jsonTest) .map(id).toProperty("id") @@ -102,10 +100,8 @@ void testInsertRecord() { int rows = mapper.insert(insertStatement); assertThat(rows).isEqualTo(1); - row = new JsonTestRecord(); - row.setId(2); - row.setDescription("Wilma"); - row.setInfo("{\"firstName\": \"Wilma\", \"lastName\": \"Flintstone\", \"age\": 25}"); + row = new JsonTestRecord(2, "Wilma", + "{\"firstName\": \"Wilma\", \"lastName\": \"Flintstone\", \"age\": 25}"); insertStatement = insert(row).into(jsonTest) .map(id).toProperty("id") @@ -125,8 +121,8 @@ void testInsertRecord() { List records = mapper.selectMany(selectStatement); assertThat(records).hasSize(2); - assertThat(records.get(0).getInfo()).isEqualTo("{\"firstName\": \"Fred\", \"lastName\": \"Flintstone\", \"age\": 30}"); - assertThat(records.get(1).getInfo()).isEqualTo("{\"firstName\": \"Wilma\", \"lastName\": \"Flintstone\", \"age\": 25}"); + assertThat(records.get(0).info()).isEqualTo("{\"firstName\": \"Fred\", \"lastName\": \"Flintstone\", \"age\": 30}"); + assertThat(records.get(1).info()).isEqualTo("{\"firstName\": \"Wilma\", \"lastName\": \"Flintstone\", \"age\": 25}"); } } @@ -169,8 +165,8 @@ void testGeneralInsert() { List records = mapper.selectMany(selectStatement); assertThat(records).hasSize(2); - assertThat(records.get(0).getInfo()).isEqualTo("{\"firstName\": \"Fred\", \"lastName\": \"Flintstone\", \"age\": 30}"); - assertThat(records.get(1).getInfo()).isEqualTo("{\"firstName\": \"Wilma\", \"lastName\": \"Flintstone\", \"age\": 25}"); + assertThat(records.get(0).info()).isEqualTo("{\"firstName\": \"Fred\", \"lastName\": \"Flintstone\", \"age\": 30}"); + assertThat(records.get(1).info()).isEqualTo("{\"firstName\": \"Wilma\", \"lastName\": \"Flintstone\", \"age\": 25}"); } } @@ -179,15 +175,11 @@ void testInsertMultiple() { try (SqlSession sqlSession = sqlSessionFactory.openSession()) { JsonTestMapper mapper = sqlSession.getMapper(JsonTestMapper.class); - JsonTestRecord record1 = new JsonTestRecord(); - record1.setId(1); - record1.setDescription("Fred"); - record1.setInfo("{\"firstName\": \"Fred\", \"lastName\": \"Flintstone\", \"age\": 30}"); + JsonTestRecord record1 = new JsonTestRecord(1, "Fred", + "{\"firstName\": \"Fred\", \"lastName\": \"Flintstone\", \"age\": 30}"); - JsonTestRecord record2 = new JsonTestRecord(); - record2.setId(2); - record2.setDescription("Wilma"); - record2.setInfo("{\"firstName\": \"Wilma\", \"lastName\": \"Flintstone\", \"age\": 25}"); + JsonTestRecord record2 = new JsonTestRecord(2, "Wilma", + "{\"firstName\": \"Wilma\", \"lastName\": \"Flintstone\", \"age\": 25}"); MultiRowInsertStatementProvider insertStatement = insertMultiple(record1, record2) .into(jsonTest) @@ -216,8 +208,8 @@ void testInsertMultiple() { List records = mapper.selectMany(selectStatement); assertThat(records).hasSize(2); - assertThat(records.get(0).getInfo()).isEqualTo("{\"firstName\": \"Fred\", \"lastName\": \"Flintstone\", \"age\": 30}"); - assertThat(records.get(1).getInfo()).isEqualTo("{\"firstName\": \"Wilma\", \"lastName\": \"Flintstone\", \"age\": 25}"); + assertThat(records.get(0).info()).isEqualTo("{\"firstName\": \"Fred\", \"lastName\": \"Flintstone\", \"age\": 30}"); + assertThat(records.get(1).info()).isEqualTo("{\"firstName\": \"Wilma\", \"lastName\": \"Flintstone\", \"age\": 25}"); } } @@ -226,15 +218,11 @@ void testUpdate() { try (SqlSession sqlSession = sqlSessionFactory.openSession()) { JsonTestMapper mapper = sqlSession.getMapper(JsonTestMapper.class); - JsonTestRecord record1 = new JsonTestRecord(); - record1.setId(1); - record1.setDescription("Fred"); - record1.setInfo("{\"firstName\": \"Fred\", \"lastName\": \"Flintstone\", \"age\": 30}"); + JsonTestRecord record1 = new JsonTestRecord(1, "Fred", + "{\"firstName\": \"Fred\", \"lastName\": \"Flintstone\", \"age\": 30}"); - JsonTestRecord record2 = new JsonTestRecord(); - record2.setId(2); - record2.setDescription("Wilma"); - record2.setInfo("{\"firstName\": \"Wilma\", \"lastName\": \"Flintstone\", \"age\": 25}"); + JsonTestRecord record2 = new JsonTestRecord(2, "Wilma", + "{\"firstName\": \"Wilma\", \"lastName\": \"Flintstone\", \"age\": 25}"); MultiRowInsertStatementProvider insertStatement = insertMultiple(record1, record2) .into(jsonTest) @@ -270,8 +258,8 @@ void testUpdate() { List records = mapper.selectMany(selectStatement); assertThat(records).hasSize(2); - assertThat(records.get(0).getInfo()).isEqualTo("{\"firstName\": \"Fred\", \"lastName\": \"Flintstone\", \"age\": 30}"); - assertThat(records.get(1).getInfo()).isEqualTo("{\"firstName\": \"Wilma\", \"lastName\": \"Flintstone\", \"age\": 26}"); + assertThat(records.get(0).info()).isEqualTo("{\"firstName\": \"Fred\", \"lastName\": \"Flintstone\", \"age\": 30}"); + assertThat(records.get(1).info()).isEqualTo("{\"firstName\": \"Wilma\", \"lastName\": \"Flintstone\", \"age\": 26}"); } } @@ -280,15 +268,11 @@ void testDeReference() { try (SqlSession sqlSession = sqlSessionFactory.openSession()) { JsonTestMapper mapper = sqlSession.getMapper(JsonTestMapper.class); - JsonTestRecord record1 = new JsonTestRecord(); - record1.setId(1); - record1.setDescription("Fred"); - record1.setInfo("{\"firstName\": \"Fred\", \"lastName\": \"Flintstone\", \"age\": 30}"); + JsonTestRecord record1 = new JsonTestRecord(1, "Fred", + "{\"firstName\": \"Fred\", \"lastName\": \"Flintstone\", \"age\": 30}"); - JsonTestRecord record2 = new JsonTestRecord(); - record2.setId(2); - record2.setDescription("Wilma"); - record2.setInfo("{\"firstName\": \"Wilma\", \"lastName\": \"Flintstone\", \"age\": 25}"); + JsonTestRecord record2 = new JsonTestRecord(2, "Wilma", + "{\"firstName\": \"Wilma\", \"lastName\": \"Flintstone\", \"age\": 25}"); MultiRowInsertStatementProvider insertStatement = insertMultiple(record1, record2) .into(jsonTest) @@ -316,7 +300,7 @@ void testDeReference() { Optional row = mapper.selectOne(selectStatement); assertThat(row).hasValueSatisfying( r -> - assertThat(r.getInfo()) + assertThat(r.info()) .isEqualTo("{\"firstName\": \"Wilma\", \"lastName\": \"Flintstone\", \"age\": 25}") ); } @@ -327,15 +311,11 @@ void testDereference2() { try (SqlSession sqlSession = sqlSessionFactory.openSession()) { JsonTestMapper mapper = sqlSession.getMapper(JsonTestMapper.class); - JsonTestRecord record1 = new JsonTestRecord(); - record1.setId(1); - record1.setDescription("Fred"); - record1.setInfo("{\"firstName\": \"Fred\", \"lastName\": \"Flintstone\", \"age\": 30}"); + JsonTestRecord record1 = new JsonTestRecord(1, "Fred", + "{\"firstName\": \"Fred\", \"lastName\": \"Flintstone\", \"age\": 30}"); - JsonTestRecord record2 = new JsonTestRecord(); - record2.setId(2); - record2.setDescription("Wilma"); - record2.setInfo("{\"firstName\": \"Wilma\", \"lastName\": \"Flintstone\", \"age\": 25}"); + JsonTestRecord record2 = new JsonTestRecord(2, "Wilma", + "{\"firstName\": \"Wilma\", \"lastName\": \"Flintstone\", \"age\": 25}"); MultiRowInsertStatementProvider insertStatement = insertMultiple(record1, record2) .into(jsonTest) diff --git a/src/test/java/examples/custom_render/JsonTestMapper.java b/src/test/java/examples/custom_render/JsonTestMapper.java index d928c8a11..4b919ea34 100644 --- a/src/test/java/examples/custom_render/JsonTestMapper.java +++ b/src/test/java/examples/custom_render/JsonTestMapper.java @@ -18,9 +18,7 @@ import java.util.List; import java.util.Optional; -import org.apache.ibatis.annotations.Result; -import org.apache.ibatis.annotations.ResultMap; -import org.apache.ibatis.annotations.Results; +import org.apache.ibatis.annotations.Arg; import org.apache.ibatis.annotations.SelectProvider; import org.mybatis.dynamic.sql.select.render.SelectStatementProvider; import org.mybatis.dynamic.sql.util.SqlProviderAdapter; @@ -32,14 +30,14 @@ public interface JsonTestMapper extends CommonDeleteMapper, CommonInsertMapper, CommonSelectMapper, CommonUpdateMapper { @SelectProvider(type = SqlProviderAdapter.class, method = "select") - @Results(id = "JsonTestResult", value = { - @Result(column = "id", property = "id", id = true), - @Result(column = "description", property = "description"), - @Result(column = "info", property = "info") - }) + @Arg(column = "id", javaType = int.class, id = true) + @Arg(column = "description", javaType = String.class) + @Arg(column = "info", javaType = String.class) List selectMany(SelectStatementProvider selectStatement); @SelectProvider(type = SqlProviderAdapter.class, method = "select") - @ResultMap("JsonTestResult") + @Arg(column = "id", javaType = int.class, id = true) + @Arg(column = "description", javaType = String.class) + @Arg(column = "info", javaType = String.class) Optional selectOne(SelectStatementProvider selectStatement); } diff --git a/src/test/java/examples/custom_render/JsonTestRecord.java b/src/test/java/examples/custom_render/JsonTestRecord.java index 2d0da5331..6b7090d58 100644 --- a/src/test/java/examples/custom_render/JsonTestRecord.java +++ b/src/test/java/examples/custom_render/JsonTestRecord.java @@ -15,32 +15,4 @@ */ package examples.custom_render; -public class JsonTestRecord { - private int id; - private String description; - private String info; - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public String getInfo() { - return info; - } - - public void setInfo(String info) { - this.info = info; - } -} +public record JsonTestRecord (int id, String description, String info) {} diff --git a/src/test/java/examples/custom_render/package-info.java b/src/test/java/examples/custom_render/package-info.java new file mode 100644 index 000000000..a735b9733 --- /dev/null +++ b/src/test/java/examples/custom_render/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright 2016-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@NullMarked +package examples.custom_render; + +import org.jspecify.annotations.NullMarked; From ebccaa5e5d7da109b7641a41004aebd78fe1c460 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 7 Apr 2025 17:56:05 -0400 Subject: [PATCH 247/289] Remove unused import --- src/test/java/examples/emptywhere/EmptyWhereTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/test/java/examples/emptywhere/EmptyWhereTest.java b/src/test/java/examples/emptywhere/EmptyWhereTest.java index 28a718d06..f20a81a9a 100644 --- a/src/test/java/examples/emptywhere/EmptyWhereTest.java +++ b/src/test/java/examples/emptywhere/EmptyWhereTest.java @@ -20,8 +20,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mybatis.dynamic.sql.SqlBuilder.*; -import java.util.Optional; -import java.util.List; import java.util.Optional; import java.util.stream.Stream; From 57ebe037c1adf68315a02ddf829fea99d792f3bb Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 7 Apr 2025 18:10:07 -0400 Subject: [PATCH 248/289] Convert to record --- .../java/examples/spring/CompoundKeyRow.java | 21 +------------------ .../examples/spring/SpringMapToRowTest.java | 7 +------ 2 files changed, 2 insertions(+), 26 deletions(-) diff --git a/src/test/java/examples/spring/CompoundKeyRow.java b/src/test/java/examples/spring/CompoundKeyRow.java index ea7162e04..d9422b447 100644 --- a/src/test/java/examples/spring/CompoundKeyRow.java +++ b/src/test/java/examples/spring/CompoundKeyRow.java @@ -15,23 +15,4 @@ */ package examples.spring; -public class CompoundKeyRow { - private Integer id1; - private Integer id2; - - public Integer getId1() { - return id1; - } - - public void setId1(Integer id1) { - this.id1 = id1; - } - - public Integer getId2() { - return id2; - } - - public void setId2(Integer id2) { - this.id2 = id2; - } -} +public record CompoundKeyRow (Integer id1, Integer id2) {} diff --git a/src/test/java/examples/spring/SpringMapToRowTest.java b/src/test/java/examples/spring/SpringMapToRowTest.java index cf9b52258..0a2d5fe61 100644 --- a/src/test/java/examples/spring/SpringMapToRowTest.java +++ b/src/test/java/examples/spring/SpringMapToRowTest.java @@ -123,10 +123,5 @@ void testInsertBatch() { } static final RowMapper rowMapper = - (rs, i) -> { - CompoundKeyRow answer = new CompoundKeyRow(); - answer.setId1(rs.getInt("ID1")); - answer.setId2(rs.getInt("ID2")); - return answer; - }; + (rs, i) -> new CompoundKeyRow(rs.getInt("ID1"), rs.getInt("ID2")); } From 80e939a596a752168ef7f379b4fe0159c0d8a955 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Tue, 8 Apr 2025 10:05:58 -0400 Subject: [PATCH 249/289] Convert to record --- src/test/java/examples/joins/JoinMapper.java | 8 ++--- .../java/examples/joins/JoinMapperTest.java | 18 +++++------ src/test/java/examples/joins/User.java | 30 ++----------------- .../java/examples/joins/package-info.java | 19 ++++++++++++ .../type_conversion/package-info.java | 19 ++++++++++++ 5 files changed, 53 insertions(+), 41 deletions(-) create mode 100644 src/test/java/examples/joins/package-info.java create mode 100644 src/test/java/examples/type_conversion/package-info.java diff --git a/src/test/java/examples/joins/JoinMapper.java b/src/test/java/examples/joins/JoinMapper.java index 0ce4cc42c..66241b7e5 100644 --- a/src/test/java/examples/joins/JoinMapper.java +++ b/src/test/java/examples/joins/JoinMapper.java @@ -17,7 +17,7 @@ import java.util.List; -import org.apache.ibatis.annotations.Result; +import org.apache.ibatis.annotations.Arg; import org.apache.ibatis.annotations.ResultMap; import org.apache.ibatis.annotations.SelectProvider; import org.mybatis.dynamic.sql.select.render.SelectStatementProvider; @@ -29,8 +29,8 @@ public interface JoinMapper { List selectMany(SelectStatementProvider selectStatement); @SelectProvider(type=SqlProviderAdapter.class, method="select") - @Result(column="user_id", property="userId") - @Result(column="user_name", property="userName") - @Result(column="parent_id", property="parentId") + @Arg(column="user_id", javaType = Integer.class) + @Arg(column="user_name", javaType = String.class) + @Arg(column="parent_id", javaType = Integer.class) List selectUsers(SelectStatementProvider selectStatement); } diff --git a/src/test/java/examples/joins/JoinMapperTest.java b/src/test/java/examples/joins/JoinMapperTest.java index ace7b2115..6d6647219 100644 --- a/src/test/java/examples/joins/JoinMapperTest.java +++ b/src/test/java/examples/joins/JoinMapperTest.java @@ -945,9 +945,9 @@ void testSelf() { assertThat(rows).hasSize(1); User row = rows.get(0); - assertThat(row.getUserId()).isEqualTo(2); - assertThat(row.getUserName()).isEqualTo("Barney"); - assertThat(row.getParentId()).isNull(); + assertThat(row.userId()).isEqualTo(2); + assertThat(row.userName()).isEqualTo("Barney"); + assertThat(row.parentId()).isNull(); } } @@ -985,9 +985,9 @@ void testSelfWithNewAlias() { assertThat(rows).hasSize(1); User row = rows.get(0); - assertThat(row.getUserId()).isEqualTo(2); - assertThat(row.getUserName()).isEqualTo("Barney"); - assertThat(row.getParentId()).isNull(); + assertThat(row.userId()).isEqualTo(2); + assertThat(row.userName()).isEqualTo("Barney"); + assertThat(row.parentId()).isNull(); } } @@ -1016,9 +1016,9 @@ void testSelfWithNewAliasAndOverride() { assertThat(rows).hasSize(1); User row = rows.get(0); - assertThat(row.getUserId()).isEqualTo(2); - assertThat(row.getUserName()).isEqualTo("Barney"); - assertThat(row.getParentId()).isNull(); + assertThat(row.userId()).isEqualTo(2); + assertThat(row.userName()).isEqualTo("Barney"); + assertThat(row.parentId()).isNull(); } } diff --git a/src/test/java/examples/joins/User.java b/src/test/java/examples/joins/User.java index e8c242a25..1d9e36795 100644 --- a/src/test/java/examples/joins/User.java +++ b/src/test/java/examples/joins/User.java @@ -15,32 +15,6 @@ */ package examples.joins; -public class User { - private Integer userId; - private String userName; - private Integer parentId; +import org.jspecify.annotations.Nullable; - public Integer getUserId() { - return userId; - } - - public void setUserId(Integer userId) { - this.userId = userId; - } - - public String getUserName() { - return userName; - } - - public void setUserName(String userName) { - this.userName = userName; - } - - public Integer getParentId() { - return parentId; - } - - public void setParentId(Integer parentId) { - this.parentId = parentId; - } -} +public record User (Integer userId, String userName, @Nullable Integer parentId) {} diff --git a/src/test/java/examples/joins/package-info.java b/src/test/java/examples/joins/package-info.java new file mode 100644 index 000000000..a994448fb --- /dev/null +++ b/src/test/java/examples/joins/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright 2016-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@NullMarked +package examples.joins; + +import org.jspecify.annotations.NullMarked; diff --git a/src/test/java/examples/type_conversion/package-info.java b/src/test/java/examples/type_conversion/package-info.java new file mode 100644 index 000000000..4848de776 --- /dev/null +++ b/src/test/java/examples/type_conversion/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright 2016-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@NullMarked +package examples.type_conversion; + +import org.jspecify.annotations.NullMarked; From 5013d44b742efdc4cef8d6ead81c9d514acc7081 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Tue, 8 Apr 2025 10:12:13 -0400 Subject: [PATCH 250/289] Convert to record --- .../java/examples/joins/JoinMapperTest.java | 32 +++++++-------- .../java/examples/joins/JoinSubQueryTest.java | 14 +++---- src/test/java/examples/joins/OrderDetail.java | 39 +------------------ .../resources/examples/joins/JoinMapper.xml | 10 +++-- 4 files changed, 30 insertions(+), 65 deletions(-) diff --git a/src/test/java/examples/joins/JoinMapperTest.java b/src/test/java/examples/joins/JoinMapperTest.java index 6d6647219..1f1c6a27c 100644 --- a/src/test/java/examples/joins/JoinMapperTest.java +++ b/src/test/java/examples/joins/JoinMapperTest.java @@ -98,15 +98,15 @@ void testSingleTableJoin1() { assertThat(orderMaster.getId()).isEqualTo(1); assertThat(orderMaster.getDetails()).hasSize(2); OrderDetail orderDetail = orderMaster.getDetails().get(0); - assertThat(orderDetail.getLineNumber()).isEqualTo(1); + assertThat(orderDetail.lineNumber()).isEqualTo(1); orderDetail = orderMaster.getDetails().get(1); - assertThat(orderDetail.getLineNumber()).isEqualTo(2); + assertThat(orderDetail.lineNumber()).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); + assertThat(orderDetail.lineNumber()).isEqualTo(1); } } @@ -132,15 +132,15 @@ void testSingleTableJoin2() { assertThat(orderMaster.getId()).isEqualTo(1); assertThat(orderMaster.getDetails()).hasSize(2); OrderDetail orderDetail = orderMaster.getDetails().get(0); - assertThat(orderDetail.getLineNumber()).isEqualTo(1); + assertThat(orderDetail.lineNumber()).isEqualTo(1); orderDetail = orderMaster.getDetails().get(1); - assertThat(orderDetail.getLineNumber()).isEqualTo(2); + assertThat(orderDetail.lineNumber()).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); + assertThat(orderDetail.lineNumber()).isEqualTo(1); } } @@ -255,9 +255,9 @@ void testMultipleTableJoinWithWhereClause() { assertThat(orderMaster.getId()).isEqualTo(2); assertThat(orderMaster.getDetails()).hasSize(2); OrderDetail orderDetail = orderMaster.getDetails().get(0); - assertThat(orderDetail.getLineNumber()).isEqualTo(1); + assertThat(orderDetail.lineNumber()).isEqualTo(1); orderDetail = orderMaster.getDetails().get(1); - assertThat(orderDetail.getLineNumber()).isEqualTo(2); + assertThat(orderDetail.lineNumber()).isEqualTo(2); } } @@ -286,9 +286,9 @@ void testMultipleTableJoinWithApplyWhere() { assertThat(orderMaster.getId()).isEqualTo(2); assertThat(orderMaster.getDetails()).hasSize(2); OrderDetail orderDetail = orderMaster.getDetails().get(0); - assertThat(orderDetail.getLineNumber()).isEqualTo(1); + assertThat(orderDetail.lineNumber()).isEqualTo(1); orderDetail = orderMaster.getDetails().get(1); - assertThat(orderDetail.getLineNumber()).isEqualTo(2); + assertThat(orderDetail.lineNumber()).isEqualTo(2); } } @@ -317,7 +317,7 @@ void testMultipleTableJoinWithComplexWhereClause() { assertThat(orderMaster.getId()).isEqualTo(2); assertThat(orderMaster.getDetails()).hasSize(1); OrderDetail orderDetail = orderMaster.getDetails().get(0); - assertThat(orderDetail.getLineNumber()).isEqualTo(2); + assertThat(orderDetail.lineNumber()).isEqualTo(2); } } @@ -346,15 +346,15 @@ void testMultipleTableJoinWithOrderBy() { assertThat(orderMaster.getId()).isEqualTo(1); assertThat(orderMaster.getDetails()).hasSize(1); OrderDetail orderDetail = orderMaster.getDetails().get(0); - assertThat(orderDetail.getLineNumber()).isEqualTo(1); + assertThat(orderDetail.lineNumber()).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); + assertThat(orderDetail.lineNumber()).isEqualTo(1); orderDetail = orderMaster.getDetails().get(1); - assertThat(orderDetail.getLineNumber()).isEqualTo(2); + assertThat(orderDetail.lineNumber()).isEqualTo(2); } } @@ -385,9 +385,9 @@ void testMultipleTableJoinNoAliasWithOrderBy() { assertThat(orderMaster.getId()).isEqualTo(2); assertThat(orderMaster.getDetails()).hasSize(2); OrderDetail orderDetail = orderMaster.getDetails().get(0); - assertThat(orderDetail.getLineNumber()).isEqualTo(1); + assertThat(orderDetail.lineNumber()).isEqualTo(1); orderDetail = orderMaster.getDetails().get(1); - assertThat(orderDetail.getLineNumber()).isEqualTo(2); + assertThat(orderDetail.lineNumber()).isEqualTo(2); } } diff --git a/src/test/java/examples/joins/JoinSubQueryTest.java b/src/test/java/examples/joins/JoinSubQueryTest.java index 11b4ce192..abf3eaf6f 100644 --- a/src/test/java/examples/joins/JoinSubQueryTest.java +++ b/src/test/java/examples/joins/JoinSubQueryTest.java @@ -97,15 +97,15 @@ void testSingleTableJoin1() { assertThat(orderMaster.getId()).isEqualTo(1); assertThat(orderMaster.getDetails()).hasSize(2); OrderDetail orderDetail = orderMaster.getDetails().get(0); - assertThat(orderDetail.getLineNumber()).isEqualTo(1); + assertThat(orderDetail.lineNumber()).isEqualTo(1); orderDetail = orderMaster.getDetails().get(1); - assertThat(orderDetail.getLineNumber()).isEqualTo(2); + assertThat(orderDetail.lineNumber()).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); + assertThat(orderDetail.lineNumber()).isEqualTo(1); } } @@ -143,9 +143,9 @@ void testMultipleTableJoinWithWhereClause() { assertThat(orderMaster.getId()).isEqualTo(2); assertThat(orderMaster.getDetails()).hasSize(2); OrderDetail orderDetail = orderMaster.getDetails().get(0); - assertThat(orderDetail.getLineNumber()).isEqualTo(1); + assertThat(orderDetail.lineNumber()).isEqualTo(1); orderDetail = orderMaster.getDetails().get(1); - assertThat(orderDetail.getLineNumber()).isEqualTo(2); + assertThat(orderDetail.lineNumber()).isEqualTo(2); } } @@ -180,10 +180,10 @@ void testMultipleTableJoinWithSelectStar() { assertThat(orderMaster.getDetails()).hasSize(2); OrderDetail orderDetail = orderMaster.getDetails().get(0); - assertThat(orderDetail.getLineNumber()).isEqualTo(1); + assertThat(orderDetail.lineNumber()).isEqualTo(1); orderDetail = orderMaster.getDetails().get(1); - assertThat(orderDetail.getLineNumber()).isEqualTo(2); + assertThat(orderDetail.lineNumber()).isEqualTo(2); } } diff --git a/src/test/java/examples/joins/OrderDetail.java b/src/test/java/examples/joins/OrderDetail.java index 6c9cdd8c5..9f9abd4ce 100644 --- a/src/test/java/examples/joins/OrderDetail.java +++ b/src/test/java/examples/joins/OrderDetail.java @@ -15,41 +15,4 @@ */ package examples.joins; -public class OrderDetail { - private Integer orderId; - private Integer lineNumber; - private String description; - private Integer quantity; - - public Integer getOrderId() { - return orderId; - } - - public void setOrderId(Integer orderId) { - this.orderId = orderId; - } - - public Integer getLineNumber() { - return lineNumber; - } - - public void setLineNumber(Integer lineNumber) { - this.lineNumber = lineNumber; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public Integer getQuantity() { - return quantity; - } - - public void setQuantity(Integer quantity) { - this.quantity = quantity; - } -} +public record OrderDetail (Integer orderId, Integer lineNumber, String description, Integer quantity) {} diff --git a/src/test/resources/examples/joins/JoinMapper.xml b/src/test/resources/examples/joins/JoinMapper.xml index e70e6b242..22aa930e9 100644 --- a/src/test/resources/examples/joins/JoinMapper.xml +++ b/src/test/resources/examples/joins/JoinMapper.xml @@ -22,10 +22,12 @@ - - - - + + + + + + From 3ffc250a84d70f35948aee47331138b903e83b11 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Tue, 8 Apr 2025 13:11:24 -0400 Subject: [PATCH 251/289] Null Marking --- .../java/examples/mysql/IsLikeEscape.java | 2 -- .../examples/mysql/MemberOfCondition.java | 2 -- .../java/examples/mysql/MemberOfFunction.java | 2 -- src/test/java/examples/mysql/MySQLTest.java | 7 ++++--- .../java/examples/mysql/package-info.java | 19 +++++++++++++++++++ 5 files changed, 23 insertions(+), 9 deletions(-) create mode 100644 src/test/java/examples/mysql/package-info.java diff --git a/src/test/java/examples/mysql/IsLikeEscape.java b/src/test/java/examples/mysql/IsLikeEscape.java index 6b8799abb..418ff7141 100644 --- a/src/test/java/examples/mysql/IsLikeEscape.java +++ b/src/test/java/examples/mysql/IsLikeEscape.java @@ -19,14 +19,12 @@ import java.util.function.Function; import java.util.function.Predicate; -import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.AbstractSingleValueCondition; import org.mybatis.dynamic.sql.BindableColumn; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.util.FragmentAndParameters; -@NullMarked public class IsLikeEscape extends AbstractSingleValueCondition implements AbstractSingleValueCondition.Filterable, AbstractSingleValueCondition.Mappable { private static final IsLikeEscape EMPTY = new IsLikeEscape(-1, null) { diff --git a/src/test/java/examples/mysql/MemberOfCondition.java b/src/test/java/examples/mysql/MemberOfCondition.java index 33b967556..962ad5c38 100644 --- a/src/test/java/examples/mysql/MemberOfCondition.java +++ b/src/test/java/examples/mysql/MemberOfCondition.java @@ -17,10 +17,8 @@ import java.util.Objects; -import org.jspecify.annotations.NullMarked; import org.mybatis.dynamic.sql.AbstractNoValueCondition; -@NullMarked public class MemberOfCondition extends AbstractNoValueCondition { private final String jsonArray; diff --git a/src/test/java/examples/mysql/MemberOfFunction.java b/src/test/java/examples/mysql/MemberOfFunction.java index 1035bf3e0..d41f95f8c 100644 --- a/src/test/java/examples/mysql/MemberOfFunction.java +++ b/src/test/java/examples/mysql/MemberOfFunction.java @@ -17,14 +17,12 @@ import java.util.Objects; -import org.jspecify.annotations.NullMarked; import org.mybatis.dynamic.sql.BasicColumn; import org.mybatis.dynamic.sql.BindableColumn; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.select.function.AbstractTypeConvertingFunction; import org.mybatis.dynamic.sql.util.FragmentAndParameters; -@NullMarked public class MemberOfFunction extends AbstractTypeConvertingFunction> { private final String jsonArray; diff --git a/src/test/java/examples/mysql/MySQLTest.java b/src/test/java/examples/mysql/MySQLTest.java index 45c403bd7..d37b7de13 100644 --- a/src/test/java/examples/mysql/MySQLTest.java +++ b/src/test/java/examples/mysql/MySQLTest.java @@ -34,6 +34,7 @@ import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory; import org.junit.jupiter.api.BeforeAll; +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; @@ -51,10 +52,10 @@ class MySQLTest { new MySQLContainer<>(TestContainersConfiguration.MYSQL_LATEST) .withInitScript("examples/mariadb/CreateDB.sql"); - private static SqlSessionFactory sqlSessionFactory; + private SqlSessionFactory sqlSessionFactory; - @BeforeAll - static void setup() { + @BeforeEach + void setup() { UnpooledDataSource ds = new UnpooledDataSource(mysql.getDriverClassName(), mysql.getJdbcUrl(), mysql.getUsername(), mysql.getPassword()); Environment environment = new Environment("test", new JdbcTransactionFactory(), ds); diff --git a/src/test/java/examples/mysql/package-info.java b/src/test/java/examples/mysql/package-info.java new file mode 100644 index 000000000..70357075d --- /dev/null +++ b/src/test/java/examples/mysql/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright 2016-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@NullMarked +package examples.mysql; + +import org.jspecify.annotations.NullMarked; From eb1a7049ab50c0cda3f05828c5cc54975d27efa6 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Tue, 8 Apr 2025 13:13:03 -0400 Subject: [PATCH 252/289] Null Marking --- .../java/examples/sharding/package-info.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 src/test/java/examples/sharding/package-info.java diff --git a/src/test/java/examples/sharding/package-info.java b/src/test/java/examples/sharding/package-info.java new file mode 100644 index 000000000..8c1f71235 --- /dev/null +++ b/src/test/java/examples/sharding/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright 2016-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@NullMarked +package examples.sharding; + +import org.jspecify.annotations.NullMarked; From 0c6ec65cbc7a84b8b4358471f703627f93bb584f Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Wed, 9 Apr 2025 10:15:30 -0400 Subject: [PATCH 253/289] LastName can be a record --- src/test/java/examples/simple/LastName.java | 40 +------------------ .../examples/simple/LastNameTypeHandler.java | 13 ++++-- .../examples/simple/PersonMapperTest.java | 40 +++++++++---------- .../java/examples/simple/package-info.java | 19 +++++++++ 4 files changed, 49 insertions(+), 63 deletions(-) create mode 100644 src/test/java/examples/simple/package-info.java diff --git a/src/test/java/examples/simple/LastName.java b/src/test/java/examples/simple/LastName.java index 1caaef4e2..2a2499e14 100644 --- a/src/test/java/examples/simple/LastName.java +++ b/src/test/java/examples/simple/LastName.java @@ -15,42 +15,4 @@ */ package examples.simple; -public class LastName { - private String name; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public static LastName of(String name) { - LastName lastName = new LastName(); - lastName.setName(name); - return lastName; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((name == null) ? 0 : name.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - LastName other = (LastName) obj; - if (name == null) { - return other.name == null; - } else return name.equals(other.name); - } -} +public record LastName (String name) {} diff --git a/src/test/java/examples/simple/LastNameTypeHandler.java b/src/test/java/examples/simple/LastNameTypeHandler.java index e8a26486e..de14fcc0d 100644 --- a/src/test/java/examples/simple/LastNameTypeHandler.java +++ b/src/test/java/examples/simple/LastNameTypeHandler.java @@ -22,12 +22,17 @@ import org.apache.ibatis.type.JdbcType; import org.apache.ibatis.type.TypeHandler; +import org.jspecify.annotations.Nullable; public class LastNameTypeHandler implements TypeHandler { @Override - public void setParameter(PreparedStatement ps, int i, LastName parameter, JdbcType jdbcType) throws SQLException { - ps.setString(i, parameter == null ? null : parameter.getName()); + public void setParameter(PreparedStatement ps, int i, @Nullable LastName parameter, JdbcType jdbcType) throws SQLException { + if (parameter == null) { + ps.setNull(i, jdbcType.TYPE_CODE); + } else { + ps.setString(i, parameter.name()); + } } @Override @@ -45,7 +50,7 @@ public LastName getResult(CallableStatement cs, int columnIndex) throws SQLExcep return toLastName(cs.getString(columnIndex)); } - private LastName toLastName(String s) { - return s == null ? null : LastName.of(s); + private @Nullable LastName toLastName(@Nullable String s) { + return s == null ? null : new LastName(s); } } diff --git a/src/test/java/examples/simple/PersonMapperTest.java b/src/test/java/examples/simple/PersonMapperTest.java index acbda68ad..1fd44f5a3 100644 --- a/src/test/java/examples/simple/PersonMapperTest.java +++ b/src/test/java/examples/simple/PersonMapperTest.java @@ -245,8 +245,8 @@ void testFirstNameIn() { c.where(firstName, isIn("Fred", "Barney"))); assertThat(rows).hasSize(2); - assertThat(rows.get(0).getLastName().getName()).isEqualTo("Flintstone"); - assertThat(rows.get(1).getLastName().getName()).isEqualTo("Rubble"); + assertThat(rows.get(0).getLastName().name()).isEqualTo("Flintstone"); + assertThat(rows.get(1).getLastName().name()).isEqualTo("Rubble"); } } @@ -263,8 +263,8 @@ void testOrderByCollection() { ); assertThat(rows).hasSize(2); - assertThat(rows.get(0).getLastName().getName()).isEqualTo("Rubble"); - assertThat(rows.get(1).getLastName().getName()).isEqualTo("Flintstone"); + assertThat(rows.get(0).getLastName().name()).isEqualTo("Rubble"); + assertThat(rows.get(1).getLastName().name()).isEqualTo("Flintstone"); } } @@ -321,7 +321,7 @@ void testInsert() { PersonRecord row = new PersonRecord(); row.setId(100); row.setFirstName("Joe"); - row.setLastName(LastName.of("Jones")); + row.setLastName(new LastName("Jones")); row.setBirthDate(new Date()); row.setEmployed(true); row.setOccupation("Developer"); @@ -339,7 +339,7 @@ void testGeneralInsert() { int rows = mapper.generalInsert(c -> c.set(id).toValue(100) .set(firstName).toValue("Joe") - .set(lastName).toValue(LastName.of("Jones")) + .set(lastName).toValue(new LastName("Jones")) .set(birthDate).toValue(new Date()) .set(employed).toValue(true) .set(occupation).toValue("Developer") @@ -360,7 +360,7 @@ void testInsertMultiple() { PersonRecord row = new PersonRecord(); row.setId(100); row.setFirstName("Joe"); - row.setLastName(LastName.of("Jones")); + row.setLastName(new LastName("Jones")); row.setBirthDate(new Date()); row.setEmployed(true); row.setOccupation("Developer"); @@ -370,7 +370,7 @@ void testInsertMultiple() { row = new PersonRecord(); row.setId(101); row.setFirstName("Sarah"); - row.setLastName(LastName.of("Smith")); + row.setLastName(new LastName("Smith")); row.setBirthDate(new Date()); row.setEmployed(true); row.setOccupation("Architect"); @@ -389,7 +389,7 @@ void testInsertSelective() { PersonRecord row = new PersonRecord(); row.setId(100); row.setFirstName("Joe"); - row.setLastName(LastName.of("Jones")); + row.setLastName(new LastName("Jones")); row.setBirthDate(new Date()); row.setEmployed(false); row.setAddressId(1); @@ -406,7 +406,7 @@ void testUpdateByPrimaryKey() { PersonRecord row = new PersonRecord(); row.setId(100); row.setFirstName("Joe"); - row.setLastName(LastName.of("Jones")); + row.setLastName(new LastName("Jones")); row.setBirthDate(new Date()); row.setEmployed(true); row.setOccupation("Developer"); @@ -432,7 +432,7 @@ void testUpdateByPrimaryKeySelective() { PersonRecord row = new PersonRecord(); row.setId(100); row.setFirstName("Joe"); - row.setLastName(LastName.of("Jones")); + row.setLastName(new LastName("Jones")); row.setBirthDate(new Date()); row.setEmployed(true); row.setOccupation("Developer"); @@ -462,7 +462,7 @@ void testUpdate() { PersonRecord row = new PersonRecord(); row.setId(100); row.setFirstName("Joe"); - row.setLastName(LastName.of("Jones")); + row.setLastName(new LastName("Jones")); row.setBirthDate(new Date()); row.setEmployed(true); row.setOccupation("Developer"); @@ -493,7 +493,7 @@ void testUpdateOneField() { PersonRecord row = new PersonRecord(); row.setId(100); row.setFirstName("Joe"); - row.setLastName(LastName.of("Jones")); + row.setLastName(new LastName("Jones")); row.setBirthDate(new Date()); row.setEmployed(true); row.setOccupation("Developer"); @@ -521,7 +521,7 @@ void testUpdateAll() { PersonRecord row = new PersonRecord(); row.setId(100); row.setFirstName("Joe"); - row.setLastName(LastName.of("Jones")); + row.setLastName(new LastName("Jones")); row.setBirthDate(new Date()); row.setEmployed(true); row.setOccupation("Developer"); @@ -550,7 +550,7 @@ void testUpdateSelective() { PersonRecord row = new PersonRecord(); row.setId(100); row.setFirstName("Joe"); - row.setLastName(LastName.of("Jones")); + row.setLastName(new LastName("Jones")); row.setBirthDate(new Date()); row.setEmployed(true); row.setOccupation("Developer"); @@ -620,7 +620,7 @@ void testTypeHandledLike() { PersonMapper mapper = session.getMapper(PersonMapper.class); List rows = mapper.select(c -> - c.where(lastName, isLike(LastName.of("Fl%"))) + c.where(lastName, isLike(new LastName("Fl%"))) .orderBy(id)); assertThat(rows).hasSize(3); @@ -634,7 +634,7 @@ void testTypeHandledNotLike() { PersonMapper mapper = session.getMapper(PersonMapper.class); List rows = mapper.select(c -> - c.where(lastName, isNotLike(LastName.of("Fl%"))) + c.where(lastName, isNotLike(new LastName("Fl%"))) .orderBy(id)); assertThat(rows).hasSize(3); @@ -654,7 +654,7 @@ void testJoinAllRows() { assertThat(records.get(0).getId()).isEqualTo(1); assertThat(records.get(0).getEmployed()).isTrue(); assertThat(records.get(0).getFirstName()).isEqualTo("Fred"); - assertThat(records.get(0).getLastName()).isEqualTo(LastName.of("Flintstone")); + assertThat(records.get(0).getLastName()).isEqualTo(new LastName("Flintstone")); assertThat(records.get(0).getOccupation()).isEqualTo("Brontosaurus Operator"); assertThat(records.get(0).getBirthDate()).isNotNull(); assertThat(records.get(0).getAddress().getId()).isEqualTo(1); @@ -677,7 +677,7 @@ void testJoinOneRow() { assertThat(records.get(0).getId()).isEqualTo(1); assertThat(records.get(0).getEmployed()).isTrue(); assertThat(records.get(0).getFirstName()).isEqualTo("Fred"); - assertThat(records.get(0).getLastName()).isEqualTo(LastName.of("Flintstone")); + assertThat(records.get(0).getLastName()).isEqualTo(new LastName("Flintstone")); assertThat(records.get(0).getOccupation()).isEqualTo("Brontosaurus Operator"); assertThat(records.get(0).getBirthDate()).isNotNull(); assertThat(records.get(0).getAddress().getId()).isEqualTo(1); @@ -697,7 +697,7 @@ void testJoinPrimaryKey() { assertThat(r.getId()).isEqualTo(1); assertThat(r.getEmployed()).isTrue(); assertThat(r.getFirstName()).isEqualTo("Fred"); - assertThat(r.getLastName()).isEqualTo(LastName.of("Flintstone")); + assertThat(r.getLastName()).isEqualTo(new LastName("Flintstone")); assertThat(r.getOccupation()).isEqualTo("Brontosaurus Operator"); assertThat(r.getBirthDate()).isNotNull(); assertThat(r.getAddress().getId()).isEqualTo(1); diff --git a/src/test/java/examples/simple/package-info.java b/src/test/java/examples/simple/package-info.java new file mode 100644 index 000000000..79a124103 --- /dev/null +++ b/src/test/java/examples/simple/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright 2016-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@NullMarked +package examples.simple; + +import org.jspecify.annotations.NullMarked; From 25f1fcbcb2ad38c96bcf15ce1ff5e6f206958dc9 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Wed, 9 Apr 2025 17:51:24 -0400 Subject: [PATCH 254/289] Use records where possible --- .../java/examples/simple/CompoundKeyRow.java | 21 +- .../examples/simple/MyBatisMapToRowTest.java | 15 +- .../java/examples/simple/PersonMapper.java | 100 +++++----- .../examples/simple/PersonMapperTest.java | 187 +++++++----------- .../java/examples/simple/PersonRecord.java | 70 +------ 5 files changed, 133 insertions(+), 260 deletions(-) diff --git a/src/test/java/examples/simple/CompoundKeyRow.java b/src/test/java/examples/simple/CompoundKeyRow.java index c710d4b26..dc65b005a 100644 --- a/src/test/java/examples/simple/CompoundKeyRow.java +++ b/src/test/java/examples/simple/CompoundKeyRow.java @@ -15,23 +15,4 @@ */ package examples.simple; -public class CompoundKeyRow { - private Integer id1; - private Integer id2; - - public Integer getId1() { - return id1; - } - - public void setId1(Integer id1) { - this.id1 = id1; - } - - public Integer getId2() { - return id2; - } - - public void setId2(Integer id2) { - this.id2 = id2; - } -} +public record CompoundKeyRow (Integer id1, Integer id2) {} diff --git a/src/test/java/examples/simple/MyBatisMapToRowTest.java b/src/test/java/examples/simple/MyBatisMapToRowTest.java index 473a4cd47..7750195e9 100644 --- a/src/test/java/examples/simple/MyBatisMapToRowTest.java +++ b/src/test/java/examples/simple/MyBatisMapToRowTest.java @@ -30,6 +30,7 @@ import java.sql.DriverManager; import java.util.List; import java.util.Map; +import java.util.function.Function; import java.util.stream.IntStream; import org.apache.ibatis.datasource.unpooled.UnpooledDataSource; @@ -98,7 +99,7 @@ void testInsertOne() { .orderBy(id1, id2) .build().render(RenderingStrategies.MYBATIS3); - List records = mapper.selectMany(selectStatement, this::mapRow); + List records = mapper.selectMany(selectStatement, rowMapper); assertThat(records).hasSize(1); } } @@ -128,7 +129,7 @@ void testInsertMultiple() { .orderBy(id1, id2) .build().render(RenderingStrategies.MYBATIS3); - List records = mapper.selectMany(selectStatement, this::mapRow); + List records = mapper.selectMany(selectStatement, rowMapper); assertThat(records).hasSize(3); } } @@ -165,15 +166,11 @@ void testInsertBatch() { .orderBy(id1, id2) .build().render(RenderingStrategies.MYBATIS3); - List records = mapper.selectMany(selectStatement, this::mapRow); + List records = mapper.selectMany(selectStatement, rowMapper); assertThat(records).hasSize(3); } } - private CompoundKeyRow mapRow(Map map) { - CompoundKeyRow answer = new CompoundKeyRow(); - answer.setId1((Integer) map.get("ID1")); - answer.setId2((Integer) map.get("ID2")); - return answer; - } + private final Function, CompoundKeyRow> rowMapper = + m -> new CompoundKeyRow((Integer) m.get("ID1"), (Integer) m.get("ID2")); } diff --git a/src/test/java/examples/simple/PersonMapper.java b/src/test/java/examples/simple/PersonMapper.java index dffc66ee4..819b72c3b 100644 --- a/src/test/java/examples/simple/PersonMapper.java +++ b/src/test/java/examples/simple/PersonMapper.java @@ -17,17 +17,17 @@ import static examples.simple.PersonDynamicSqlSupport.*; import static org.mybatis.dynamic.sql.SqlBuilder.isEqualTo; +import static org.mybatis.dynamic.sql.SqlBuilder.isEqualToWhenPresent; import java.util.Arrays; import java.util.Collection; +import java.util.Date; import java.util.List; import java.util.Optional; import java.util.function.UnaryOperator; +import org.apache.ibatis.annotations.Arg; import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Result; -import org.apache.ibatis.annotations.ResultMap; -import org.apache.ibatis.annotations.Results; import org.apache.ibatis.annotations.SelectProvider; import org.apache.ibatis.type.JdbcType; import org.mybatis.dynamic.sql.BasicColumn; @@ -56,19 +56,23 @@ public interface PersonMapper extends CommonCountMapper, CommonDeleteMapper, CommonInsertMapper, CommonUpdateMapper { @SelectProvider(type=SqlProviderAdapter.class, method="select") - @Results(id="PersonResult", value= { - @Result(column="A_ID", property="id", jdbcType=JdbcType.INTEGER, id=true), - @Result(column="first_name", property="firstName", jdbcType=JdbcType.VARCHAR), - @Result(column="last_name", property="lastName", jdbcType=JdbcType.VARCHAR, typeHandler=LastNameTypeHandler.class), - @Result(column="birth_date", property="birthDate", jdbcType=JdbcType.DATE), - @Result(column="employed", property="employed", jdbcType=JdbcType.VARCHAR, typeHandler=YesNoTypeHandler.class), - @Result(column="occupation", property="occupation", jdbcType=JdbcType.VARCHAR), - @Result(column="address_id", property="addressId", jdbcType=JdbcType.INTEGER) - }) + @Arg(column="A_ID", jdbcType=JdbcType.INTEGER, id=true, javaType = Integer.class) + @Arg(column="first_name", jdbcType=JdbcType.VARCHAR, javaType = String.class) + @Arg(column="last_name", jdbcType=JdbcType.VARCHAR, typeHandler=LastNameTypeHandler.class, javaType = LastName.class) + @Arg(column="birth_date", jdbcType=JdbcType.DATE, javaType = Date.class) + @Arg(column="employed", jdbcType=JdbcType.VARCHAR, typeHandler=YesNoTypeHandler.class, javaType = Boolean.class) + @Arg(column="occupation", jdbcType=JdbcType.VARCHAR, javaType = String.class) + @Arg(column="address_id", jdbcType=JdbcType.INTEGER, javaType = Integer.class) List selectMany(SelectStatementProvider selectStatement); @SelectProvider(type=SqlProviderAdapter.class, method="select") - @ResultMap("PersonResult") + @Arg(column="A_ID", jdbcType=JdbcType.INTEGER, id=true, javaType = Integer.class) + @Arg(column="first_name", jdbcType=JdbcType.VARCHAR, javaType = String.class) + @Arg(column="last_name", jdbcType=JdbcType.VARCHAR, typeHandler=LastNameTypeHandler.class, javaType = LastName.class) + @Arg(column="birth_date", jdbcType=JdbcType.DATE, javaType = Date.class) + @Arg(column="employed", jdbcType=JdbcType.VARCHAR, typeHandler=YesNoTypeHandler.class, javaType = Boolean.class) + @Arg(column="occupation", jdbcType=JdbcType.VARCHAR, javaType = String.class) + @Arg(column="address_id", jdbcType=JdbcType.INTEGER, javaType = Integer.class) Optional selectOne(SelectStatementProvider selectStatement); BasicColumn[] selectList = @@ -130,13 +134,13 @@ default int insertMultiple(Collection records) { default int insertSelective(PersonRecord row) { return MyBatis3Utils.insert(this::insert, row, person, c -> - c.map(id).toPropertyWhenPresent("id", row::getId) - .map(firstName).toPropertyWhenPresent("firstName", row::getFirstName) - .map(lastName).toPropertyWhenPresent("lastName", row::getLastName) - .map(birthDate).toPropertyWhenPresent("birthDate", row::getBirthDate) - .map(employed).toPropertyWhenPresent("employed", row::getEmployed) - .map(occupation).toPropertyWhenPresent("occupation", row::getOccupation) - .map(addressId).toPropertyWhenPresent("addressId", row::getAddressId) + c.map(id).toPropertyWhenPresent("id", row::id) + .map(firstName).toPropertyWhenPresent("firstName", row::firstName) + .map(lastName).toPropertyWhenPresent("lastName", row::lastName) + .map(birthDate).toPropertyWhenPresent("birthDate", row::birthDate) + .map(employed).toPropertyWhenPresent("employed", row::employed) + .map(occupation).toPropertyWhenPresent("occupation", row::occupation) + .map(addressId).toPropertyWhenPresent("addressId", row::addressId) ); } @@ -164,47 +168,47 @@ default int update(UpdateDSLCompleter completer) { static UpdateDSL updateAllColumns(PersonRecord row, UpdateDSL dsl) { - return dsl.set(id).equalTo(row::getId) - .set(firstName).equalTo(row::getFirstName) - .set(lastName).equalTo(row::getLastName) - .set(birthDate).equalTo(row::getBirthDate) - .set(employed).equalTo(row::getEmployed) - .set(occupation).equalTo(row::getOccupation) - .set(addressId).equalTo(row::getAddressId); + return dsl.set(id).equalToOrNull(row::id) + .set(firstName).equalToOrNull(row::firstName) + .set(lastName).equalToOrNull(row::lastName) + .set(birthDate).equalToOrNull(row::birthDate) + .set(employed).equalToOrNull(row::employed) + .set(occupation).equalToOrNull(row::occupation) + .set(addressId).equalToOrNull(row::addressId); } static UpdateDSL updateSelectiveColumns(PersonRecord row, UpdateDSL dsl) { - return dsl.set(id).equalToWhenPresent(row::getId) - .set(firstName).equalToWhenPresent(row::getFirstName) - .set(lastName).equalToWhenPresent(row::getLastName) - .set(birthDate).equalToWhenPresent(row::getBirthDate) - .set(employed).equalToWhenPresent(row::getEmployed) - .set(occupation).equalToWhenPresent(row::getOccupation) - .set(addressId).equalToWhenPresent(row::getAddressId); + return dsl.set(id).equalToWhenPresent(row::id) + .set(firstName).equalToWhenPresent(row::firstName) + .set(lastName).equalToWhenPresent(row::lastName) + .set(birthDate).equalToWhenPresent(row::birthDate) + .set(employed).equalToWhenPresent(row::employed) + .set(occupation).equalToWhenPresent(row::occupation) + .set(addressId).equalToWhenPresent(row::addressId); } default int updateByPrimaryKey(PersonRecord row) { return update(c -> - c.set(firstName).equalTo(row::getFirstName) - .set(lastName).equalTo(row::getLastName) - .set(birthDate).equalTo(row::getBirthDate) - .set(employed).equalTo(row::getEmployed) - .set(occupation).equalTo(row::getOccupation) - .set(addressId).equalTo(row::getAddressId) - .where(id, isEqualTo(row::getId)) + c.set(firstName).equalToOrNull(row::firstName) + .set(lastName).equalToOrNull(row::lastName) + .set(birthDate).equalToOrNull(row::birthDate) + .set(employed).equalToOrNull(row::employed) + .set(occupation).equalToOrNull(row::occupation) + .set(addressId).equalToOrNull(row::addressId) + .where(id, isEqualToWhenPresent(row::id)) ); } default int updateByPrimaryKeySelective(PersonRecord row) { return update(c -> - c.set(firstName).equalToWhenPresent(row::getFirstName) - .set(lastName).equalToWhenPresent(row::getLastName) - .set(birthDate).equalToWhenPresent(row::getBirthDate) - .set(employed).equalToWhenPresent(row::getEmployed) - .set(occupation).equalToWhenPresent(row::getOccupation) - .set(addressId).equalToWhenPresent(row::getAddressId) - .where(id, isEqualTo(row::getId)) + c.set(firstName).equalToWhenPresent(row::firstName) + .set(lastName).equalToWhenPresent(row::lastName) + .set(birthDate).equalToWhenPresent(row::birthDate) + .set(employed).equalToWhenPresent(row::employed) + .set(occupation).equalToWhenPresent(row::occupation) + .set(addressId).equalToWhenPresent(row::addressId) + .where(id, isEqualToWhenPresent(row::id)) ); } } diff --git a/src/test/java/examples/simple/PersonMapperTest.java b/src/test/java/examples/simple/PersonMapperTest.java index 1fd44f5a3..b02d52c4c 100644 --- a/src/test/java/examples/simple/PersonMapperTest.java +++ b/src/test/java/examples/simple/PersonMapperTest.java @@ -25,6 +25,7 @@ import static examples.simple.PersonDynamicSqlSupport.occupation; import static examples.simple.PersonDynamicSqlSupport.person; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.assertj.core.api.Assertions.entry; import static org.mybatis.dynamic.sql.SqlBuilder.*; @@ -32,7 +33,6 @@ import java.io.InputStreamReader; import java.sql.Connection; import java.sql.DriverManager; -import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.List; @@ -51,6 +51,7 @@ import org.mybatis.dynamic.sql.SortSpecification; import org.mybatis.dynamic.sql.delete.DeleteDSLCompleter; import org.mybatis.dynamic.sql.delete.render.DeleteStatementProvider; +import org.mybatis.dynamic.sql.exception.NonRenderingWhereClauseException; import org.mybatis.dynamic.sql.insert.render.GeneralInsertStatementProvider; import org.mybatis.dynamic.sql.render.RenderingStrategies; import org.mybatis.dynamic.sql.select.CountDSLCompleter; @@ -108,7 +109,7 @@ void testSelectEmployed() { .orderBy(id)); assertThat(rows).hasSize(4); - assertThat(rows.get(0).getId()).isEqualTo(1); + assertThat(rows.get(0).id()).isEqualTo(1); } } @@ -122,7 +123,7 @@ void testSelectUnemployed() { .orderBy(id)); assertThat(rows).hasSize(2); - assertThat(rows.get(0).getId()).isEqualTo(3); + assertThat(rows.get(0).id()).isEqualTo(3); } } @@ -179,8 +180,8 @@ void testSelectAll() { List rows = mapper.select(SelectDSLCompleter.allRows()); assertThat(rows).hasSize(6); - assertThat(rows.get(0).getId()).isEqualTo(1); - assertThat(rows.get(5).getId()).isEqualTo(6); + assertThat(rows.get(0).id()).isEqualTo(1); + assertThat(rows.get(5).id()).isEqualTo(6); } } @@ -193,8 +194,8 @@ void testSelectAllOrdered() { .select(SelectDSLCompleter.allRowsOrderedBy(lastName.descending(), firstName.descending())); assertThat(rows).hasSize(6); - assertThat(rows.get(0).getId()).isEqualTo(5); - assertThat(rows.get(5).getId()).isEqualTo(1); + assertThat(rows.get(0).id()).isEqualTo(5); + assertThat(rows.get(5).id()).isEqualTo(1); } } @@ -221,8 +222,8 @@ void testSelectWithTypeHandler() { .orderBy(id)); assertThat(rows).hasSize(2); - assertThat(rows.get(0).getId()).isEqualTo(3); - assertThat(rows.get(1).getId()).isEqualTo(6); + assertThat(rows.get(0).id()).isEqualTo(3); + assertThat(rows.get(1).id()).isEqualTo(6); } } @@ -245,8 +246,14 @@ void testFirstNameIn() { c.where(firstName, isIn("Fred", "Barney"))); assertThat(rows).hasSize(2); - assertThat(rows.get(0).getLastName().name()).isEqualTo("Flintstone"); - assertThat(rows.get(1).getLastName().name()).isEqualTo("Rubble"); + assertThat(rows.get(0)) + .isNotNull() + .extracting("lastName").isNotNull() + .extracting("name").isEqualTo("Flintstone"); + assertThat(rows.get(1)) + .isNotNull() + .extracting("lastName").isNotNull() + .extracting("name").isEqualTo("Rubble"); } } @@ -263,8 +270,14 @@ void testOrderByCollection() { ); assertThat(rows).hasSize(2); - assertThat(rows.get(0).getLastName().name()).isEqualTo("Rubble"); - assertThat(rows.get(1).getLastName().name()).isEqualTo("Flintstone"); + assertThat(rows.get(0)) + .isNotNull() + .extracting("lastName").isNotNull() + .extracting("name").isEqualTo("Rubble"); + assertThat(rows.get(1)) + .isNotNull() + .extracting("lastName").isNotNull() + .extracting("name").isEqualTo("Flintstone"); } } @@ -318,14 +331,7 @@ void testDeleteByPrimaryKey() { void testInsert() { try (SqlSession session = sqlSessionFactory.openSession()) { PersonMapper mapper = session.getMapper(PersonMapper.class); - PersonRecord row = new PersonRecord(); - row.setId(100); - row.setFirstName("Joe"); - row.setLastName(new LastName("Jones")); - row.setBirthDate(new Date()); - row.setEmployed(true); - row.setOccupation("Developer"); - row.setAddressId(1); + PersonRecord row = new PersonRecord(100, "Joe", new LastName("Jones"), new Date(), true, "Developer", 1); int rows = mapper.insert(row); assertThat(rows).isEqualTo(1); @@ -355,27 +361,10 @@ void testInsertMultiple() { try (SqlSession session = sqlSessionFactory.openSession()) { PersonMapper mapper = session.getMapper(PersonMapper.class); - List records = new ArrayList<>(); - - PersonRecord row = new PersonRecord(); - row.setId(100); - row.setFirstName("Joe"); - row.setLastName(new LastName("Jones")); - row.setBirthDate(new Date()); - row.setEmployed(true); - row.setOccupation("Developer"); - row.setAddressId(1); - records.add(row); - - row = new PersonRecord(); - row.setId(101); - row.setFirstName("Sarah"); - row.setLastName(new LastName("Smith")); - row.setBirthDate(new Date()); - row.setEmployed(true); - row.setOccupation("Architect"); - row.setAddressId(2); - records.add(row); + List records = List.of( + new PersonRecord(100, "Joe", new LastName("Jones"), new Date(), true, "Developer", 1), + new PersonRecord(101, "Sarah", new LastName("Smith"), new Date(), true, "Architect", 2) + ); int rows = mapper.insertMultiple(records); assertThat(rows).isEqualTo(2); @@ -386,42 +375,39 @@ void testInsertMultiple() { void testInsertSelective() { try (SqlSession session = sqlSessionFactory.openSession()) { PersonMapper mapper = session.getMapper(PersonMapper.class); - PersonRecord row = new PersonRecord(); - row.setId(100); - row.setFirstName("Joe"); - row.setLastName(new LastName("Jones")); - row.setBirthDate(new Date()); - row.setEmployed(false); - row.setAddressId(1); + PersonRecord row = new PersonRecord(100, "Joe", new LastName("Jones"), new Date(), false, null, 1); int rows = mapper.insertSelective(row); assertThat(rows).isEqualTo(1); } } + @Test + void testUpdateByPrimaryKeyNullKeyShouldThrowException() { + try (SqlSession session = sqlSessionFactory.openSession()) { + PersonMapper mapper = session.getMapper(PersonMapper.class); + PersonRecord row = new PersonRecord(null, "Joe", new LastName("Jones"), new Date(), true, "Developer", 1); + + assertThatExceptionOfType(NonRenderingWhereClauseException.class).isThrownBy(() -> mapper.updateByPrimaryKey(row)); + } + } + @Test void testUpdateByPrimaryKey() { try (SqlSession session = sqlSessionFactory.openSession()) { PersonMapper mapper = session.getMapper(PersonMapper.class); - PersonRecord row = new PersonRecord(); - row.setId(100); - row.setFirstName("Joe"); - row.setLastName(new LastName("Jones")); - row.setBirthDate(new Date()); - row.setEmployed(true); - row.setOccupation("Developer"); - row.setAddressId(1); + PersonRecord row = new PersonRecord(100, "Joe", new LastName("Jones"), new Date(), true, "Developer", 1); int rows = mapper.insert(row); assertThat(rows).isEqualTo(1); - row.setOccupation("Programmer"); + row = row.withOccupation("Programmer"); rows = mapper.updateByPrimaryKey(row); assertThat(rows).isEqualTo(1); Optional newRecord = mapper.selectByPrimaryKey(100); assertThat(newRecord).hasValueSatisfying(r -> - assertThat(r.getOccupation()).isEqualTo("Programmer")); + assertThat(r.occupation()).isEqualTo("Programmer")); } } @@ -429,28 +415,19 @@ void testUpdateByPrimaryKey() { void testUpdateByPrimaryKeySelective() { try (SqlSession session = sqlSessionFactory.openSession()) { PersonMapper mapper = session.getMapper(PersonMapper.class); - PersonRecord row = new PersonRecord(); - row.setId(100); - row.setFirstName("Joe"); - row.setLastName(new LastName("Jones")); - row.setBirthDate(new Date()); - row.setEmployed(true); - row.setOccupation("Developer"); - row.setAddressId(1); + PersonRecord row = new PersonRecord(100, "Joe", new LastName("Jones"), new Date(), true, "Developer", 1); int rows = mapper.insert(row); assertThat(rows).isEqualTo(1); - PersonRecord updateRecord = new PersonRecord(); - updateRecord.setId(100); - updateRecord.setOccupation("Programmer"); + PersonRecord updateRecord = new PersonRecord(100, null, null, null, null, "Programmer", null); rows = mapper.updateByPrimaryKeySelective(updateRecord); assertThat(rows).isEqualTo(1); Optional newRecord = mapper.selectByPrimaryKey(100); assertThat(newRecord).hasValueSatisfying(r -> { - assertThat(r.getOccupation()).isEqualTo("Programmer"); - assertThat(r.getFirstName()).isEqualTo("Joe"); + assertThat(r.occupation()).isEqualTo("Programmer"); + assertThat(r.firstName()).isEqualTo("Joe"); }); } } @@ -459,22 +436,15 @@ void testUpdateByPrimaryKeySelective() { void testUpdate() { try (SqlSession session = sqlSessionFactory.openSession()) { PersonMapper mapper = session.getMapper(PersonMapper.class); - PersonRecord row = new PersonRecord(); - row.setId(100); - row.setFirstName("Joe"); - row.setLastName(new LastName("Jones")); - row.setBirthDate(new Date()); - row.setEmployed(true); - row.setOccupation("Developer"); - row.setAddressId(1); + PersonRecord row = new PersonRecord(100, "Joe", new LastName("Jones"), new Date(), true, "Developer", 1); int rows = mapper.insert(row); assertThat(rows).isEqualTo(1); - row.setOccupation("Programmer"); + PersonRecord updateRow = row.withOccupation("Programmer"); rows = mapper.update(c -> - PersonMapper.updateAllColumns(row, c) + PersonMapper.updateAllColumns(updateRow, c) .where(id, isEqualTo(100)) .and(firstName, isEqualTo("Joe"))); @@ -482,7 +452,7 @@ void testUpdate() { Optional newRecord = mapper.selectByPrimaryKey(100); assertThat(newRecord).hasValueSatisfying(r -> - assertThat(r.getOccupation()).isEqualTo("Programmer")); + assertThat(r.occupation()).isEqualTo("Programmer")); } } @@ -490,14 +460,7 @@ void testUpdate() { void testUpdateOneField() { try (SqlSession session = sqlSessionFactory.openSession()) { PersonMapper mapper = session.getMapper(PersonMapper.class); - PersonRecord row = new PersonRecord(); - row.setId(100); - row.setFirstName("Joe"); - row.setLastName(new LastName("Jones")); - row.setBirthDate(new Date()); - row.setEmployed(true); - row.setOccupation("Developer"); - row.setAddressId(1); + PersonRecord row = new PersonRecord(100, "Joe", new LastName("Jones"), new Date(), true, "Developer", 1); int rows = mapper.insert(row); assertThat(rows).isEqualTo(1); @@ -510,7 +473,7 @@ void testUpdateOneField() { Optional newRecord = mapper.selectByPrimaryKey(100); assertThat(newRecord).hasValueSatisfying(r -> - assertThat(r.getOccupation()).isEqualTo("Programmer")); + assertThat(r.occupation()).isEqualTo("Programmer")); } } @@ -518,20 +481,12 @@ void testUpdateOneField() { void testUpdateAll() { try (SqlSession session = sqlSessionFactory.openSession()) { PersonMapper mapper = session.getMapper(PersonMapper.class); - PersonRecord row = new PersonRecord(); - row.setId(100); - row.setFirstName("Joe"); - row.setLastName(new LastName("Jones")); - row.setBirthDate(new Date()); - row.setEmployed(true); - row.setOccupation("Developer"); - row.setAddressId(1); + PersonRecord row = new PersonRecord(100, "Joe", new LastName("Jones"), new Date(), true, "Developer", 1); int rows = mapper.insert(row); assertThat(rows).isEqualTo(1); - PersonRecord updateRecord = new PersonRecord(); - updateRecord.setOccupation("Programmer"); + PersonRecord updateRecord = new PersonRecord(null, null, null, null, null, "Programmer", null); rows = mapper.update(c -> PersonMapper.updateSelectiveColumns(updateRecord, c)); @@ -539,7 +494,7 @@ void testUpdateAll() { Optional newRecord = mapper.selectByPrimaryKey(100); assertThat(newRecord).hasValueSatisfying(r -> - assertThat(r.getOccupation()).isEqualTo("Programmer")); + assertThat(r.occupation()).isEqualTo("Programmer")); } } @@ -547,20 +502,12 @@ void testUpdateAll() { void testUpdateSelective() { try (SqlSession session = sqlSessionFactory.openSession()) { PersonMapper mapper = session.getMapper(PersonMapper.class); - PersonRecord row = new PersonRecord(); - row.setId(100); - row.setFirstName("Joe"); - row.setLastName(new LastName("Jones")); - row.setBirthDate(new Date()); - row.setEmployed(true); - row.setOccupation("Developer"); - row.setAddressId(1); + PersonRecord row = new PersonRecord(100, "Joe", new LastName("Jones"), new Date(), true, "Developer", 1); int rows = mapper.insert(row); assertThat(rows).isEqualTo(1); - PersonRecord updateRecord = new PersonRecord(); - updateRecord.setOccupation("Programmer"); + PersonRecord updateRecord = new PersonRecord(null, null, null, null, null, "Programmer", null); rows = mapper.update(c -> PersonMapper.updateSelectiveColumns(updateRecord, c) .where(id, isEqualTo(100))); @@ -569,7 +516,7 @@ void testUpdateSelective() { Optional newRecord = mapper.selectByPrimaryKey(100); assertThat(newRecord).hasValueSatisfying(r -> - assertThat(r.getOccupation()).isEqualTo("Programmer")); + assertThat(r.occupation()).isEqualTo("Programmer")); } } @@ -624,7 +571,7 @@ void testTypeHandledLike() { .orderBy(id)); assertThat(rows).hasSize(3); - assertThat(rows.get(0).getFirstName()).isEqualTo("Fred"); + assertThat(rows.get(0).firstName()).isEqualTo("Fred"); } } @@ -638,7 +585,7 @@ void testTypeHandledNotLike() { .orderBy(id)); assertThat(rows).hasSize(3); - assertThat(rows.get(0).getFirstName()).isEqualTo("Barney"); + assertThat(rows.get(0).firstName()).isEqualTo("Barney"); } } @@ -807,8 +754,8 @@ void testMultiSelectWithUnion() { List records = mapper.selectMany(selectStatement); assertThat(records).hasSize(2); - assertThat(records.get(0).getId()).isEqualTo(1); - assertThat(records.get(1).getId()).isEqualTo(6); + assertThat(records.get(0).id()).isEqualTo(1); + assertThat(records.get(1).id()).isEqualTo(6); } } @@ -852,8 +799,8 @@ void testMultiSelectWithUnionAll() { List records = mapper.selectMany(selectStatement); assertThat(records).hasSize(2); - assertThat(records.get(0).getId()).isEqualTo(1); - assertThat(records.get(1).getId()).isEqualTo(6); + assertThat(records.get(0).id()).isEqualTo(1); + assertThat(records.get(1).id()).isEqualTo(6); } } diff --git a/src/test/java/examples/simple/PersonRecord.java b/src/test/java/examples/simple/PersonRecord.java index bb7702cc1..10a9d9edf 100644 --- a/src/test/java/examples/simple/PersonRecord.java +++ b/src/test/java/examples/simple/PersonRecord.java @@ -15,70 +15,14 @@ */ package examples.simple; -import java.util.Date; - -public class PersonRecord { - private Integer id; - private String firstName; - private LastName lastName; - private Date birthDate; - private Boolean employed; - private String occupation; - private Integer addressId; - - public Integer getId() { - return id; - } - - public void setId(Integer id) { - this.id = id; - } - - public String getFirstName() { - return firstName; - } - - public void setFirstName(String firstName) { - this.firstName = firstName; - } - - public LastName getLastName() { - return lastName; - } - - public void setLastName(LastName lastName) { - this.lastName = lastName; - } +import org.jspecify.annotations.Nullable; - public Date getBirthDate() { - return birthDate; - } - - public void setBirthDate(Date birthDate) { - this.birthDate = birthDate; - } - - public String getOccupation() { - return occupation; - } - - public void setOccupation(String occupation) { - this.occupation = occupation; - } - - public Boolean getEmployed() { - return employed; - } - - public void setEmployed(Boolean employed) { - this.employed = employed; - } - - public Integer getAddressId() { - return addressId; - } +import java.util.Date; - public void setAddressId(Integer addressId) { - this.addressId = addressId; +public record PersonRecord (@Nullable Integer id, @Nullable String firstName, @Nullable LastName lastName, + @Nullable Date birthDate, @Nullable Boolean employed, @Nullable String occupation, + @Nullable Integer addressId) { + public PersonRecord withOccupation(String occupation) { + return new PersonRecord(id, firstName, lastName, birthDate, employed, occupation, addressId); } } From baf165dbfec85bf8ce37fc413acfa601bcc009c3 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Wed, 9 Apr 2025 17:52:12 -0400 Subject: [PATCH 255/289] Unused import --- src/test/java/examples/mysql/MySQLTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/java/examples/mysql/MySQLTest.java b/src/test/java/examples/mysql/MySQLTest.java index d37b7de13..f9c047f77 100644 --- a/src/test/java/examples/mysql/MySQLTest.java +++ b/src/test/java/examples/mysql/MySQLTest.java @@ -33,7 +33,6 @@ import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory; -import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mybatis.dynamic.sql.render.RenderingStrategies; From e1ea69d04e33a433f5ad8d987b662fef116169ee Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Thu, 10 Apr 2025 13:19:24 -0400 Subject: [PATCH 256/289] Use record --- .../dynamic/sql/util/spring/BatchInsertUtility.java | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/util/spring/BatchInsertUtility.java b/src/main/java/org/mybatis/dynamic/sql/util/spring/BatchInsertUtility.java index 81f5a5ed6..8672e98ea 100644 --- a/src/main/java/org/mybatis/dynamic/sql/util/spring/BatchInsertUtility.java +++ b/src/main/java/org/mybatis/dynamic/sql/util/spring/BatchInsertUtility.java @@ -39,15 +39,5 @@ public static SqlParameterSource[] createBatch(List rows) { return SqlParameterSourceUtils.createBatch(tt); } - public static class RowHolder { - private final T row; - - public RowHolder(T row) { - this.row = row; - } - - public T getRow() { - return row; - } - } + public record RowHolder (T row) {} } From 0848d7c6fbe3815bc1f36754fdd40da7baf07eac Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Thu, 10 Apr 2025 13:20:25 -0400 Subject: [PATCH 257/289] Random cleanup --- src/test/java/issues/gh105/Issue105Test.java | 13 ++++--------- .../sql/insert/GeneralInsertStatementTest.java | 6 ++---- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/src/test/java/issues/gh105/Issue105Test.java b/src/test/java/issues/gh105/Issue105Test.java index c12f4fde9..63d2b2f16 100644 --- a/src/test/java/issues/gh105/Issue105Test.java +++ b/src/test/java/issues/gh105/Issue105Test.java @@ -49,12 +49,11 @@ void testFuzzyLikeBothPresent() { @Test void testFuzzyLikeFirstNameNull() { - String fName = null; String lName = "Flintstone"; SelectStatementProvider selectStatement = select(id, firstName, lastName) .from(person) - .where(firstName, isLikeWhenPresent(fName).map(SearchUtils::addWildcards)) + .where(firstName, isLikeWhenPresent((String) null).map(SearchUtils::addWildcards)) .and(lastName, isLike(lName).map(SearchUtils::addWildcards)) .build() .render(RenderingStrategies.MYBATIS3); @@ -70,12 +69,11 @@ void testFuzzyLikeFirstNameNull() { @Test void testFuzzyLikeLastNameNull() { String fName = "Fred"; - String lName = null; SelectStatementProvider selectStatement = select(id, firstName, lastName) .from(person) .where(firstName, isLike(fName).map(SearchUtils::addWildcards)) - .and(lastName, isLikeWhenPresent(lName).map(SearchUtils::addWildcards)) + .and(lastName, isLikeWhenPresent((String) null).map(SearchUtils::addWildcards)) .build() .render(RenderingStrategies.MYBATIS3); @@ -89,13 +87,10 @@ void testFuzzyLikeLastNameNull() { @Test void testFuzzyLikeBothNull() { - String fName = null; - String lName = null; - SelectStatementProvider selectStatement = select(id, firstName, lastName) .from(person) - .where(firstName, isLikeWhenPresent(fName).map(SearchUtils::addWildcards)) - .and(lastName, isLikeWhenPresent(lName).map(SearchUtils::addWildcards)) + .where(firstName, isLikeWhenPresent((String) null).map(SearchUtils::addWildcards)) + .and(lastName, isLikeWhenPresent((String) null).map(SearchUtils::addWildcards)) .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) .build() .render(RenderingStrategies.MYBATIS3); diff --git a/src/test/java/org/mybatis/dynamic/sql/insert/GeneralInsertStatementTest.java b/src/test/java/org/mybatis/dynamic/sql/insert/GeneralInsertStatementTest.java index 5c470cdcc..22813df69 100644 --- a/src/test/java/org/mybatis/dynamic/sql/insert/GeneralInsertStatementTest.java +++ b/src/test/java/org/mybatis/dynamic/sql/insert/GeneralInsertStatementTest.java @@ -85,14 +85,12 @@ void testInsertStatementBuilderWithConstants() { @Test void testSelectiveInsertStatementBuilder() { - Integer myId = null; - String myFirstName = null; String myLastName = "jones"; String myOccupation = "dino driver"; GeneralInsertStatementProvider insertStatement = insertInto(foo) - .set(id).toValueWhenPresent(() -> myId) - .set(firstName).toValueWhenPresent(myFirstName) + .set(id).toValueWhenPresent(() -> null) + .set(firstName).toValueWhenPresent((String) null) .set(lastName).toValueWhenPresent(() -> myLastName) .set(occupation).toValueWhenPresent(myOccupation) .build() From b0e8124270105bc55d4ae18850db241a9a97807e Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Fri, 11 Apr 2025 09:36:27 -0400 Subject: [PATCH 258/289] Null mark by package --- .../examples/emptywhere/EmptyWhereTest.java | 2 -- .../examples/emptywhere/package-info.java | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 src/test/java/examples/emptywhere/package-info.java diff --git a/src/test/java/examples/emptywhere/EmptyWhereTest.java b/src/test/java/examples/emptywhere/EmptyWhereTest.java index f20a81a9a..6d6ea5ba7 100644 --- a/src/test/java/examples/emptywhere/EmptyWhereTest.java +++ b/src/test/java/examples/emptywhere/EmptyWhereTest.java @@ -23,7 +23,6 @@ import java.util.Optional; import java.util.stream.Stream; -import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -41,7 +40,6 @@ import org.mybatis.dynamic.sql.where.WhereDSL; import org.mybatis.dynamic.sql.where.render.WhereClauseProvider; -@NullMarked class EmptyWhereTest { private static final String FIRST_NAME = "Fred"; private static final String LAST_NAME = "Flintstone"; diff --git a/src/test/java/examples/emptywhere/package-info.java b/src/test/java/examples/emptywhere/package-info.java new file mode 100644 index 000000000..89f32f987 --- /dev/null +++ b/src/test/java/examples/emptywhere/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright 2016-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@NullMarked +package examples.emptywhere; + +import org.jspecify.annotations.NullMarked; From e52797c8274ac6734669cb6064848b455a2f716e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 11 Apr 2025 18:53:53 +0000 Subject: [PATCH 259/289] Update junit5 monorepo to v5.12.2 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 665634e5d..677844711 100644 --- a/pom.xml +++ b/pom.xml @@ -60,7 +60,7 @@ 17 17 17 - 5.12.1 + 5.12.2 5.2.2 checkstyle-override.xml From 8fb0de72747cbde5e43b19da72511c05ead1f74c Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Fri, 11 Apr 2025 17:44:13 -0400 Subject: [PATCH 260/289] Checkstyle --- .../org/mybatis/dynamic/sql/util/spring/BatchInsertUtility.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/util/spring/BatchInsertUtility.java b/src/main/java/org/mybatis/dynamic/sql/util/spring/BatchInsertUtility.java index 8672e98ea..598a6b4a0 100644 --- a/src/main/java/org/mybatis/dynamic/sql/util/spring/BatchInsertUtility.java +++ b/src/main/java/org/mybatis/dynamic/sql/util/spring/BatchInsertUtility.java @@ -39,5 +39,5 @@ public static SqlParameterSource[] createBatch(List rows) { return SqlParameterSourceUtils.createBatch(tt); } - public record RowHolder (T row) {} + public record RowHolder(T row) {} } From 3adcb2aedefa38262f295c54feeca4ac7758310f Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Fri, 11 Apr 2025 18:05:40 -0400 Subject: [PATCH 261/289] Add support for subqueries in a select list --- .../org/mybatis/dynamic/sql/SqlBuilder.java | 4 ++ .../mybatis/dynamic/sql/SubQueryColumn.java | 60 +++++++++++++++++++ .../util/kotlin/elements/ColumnExtensions.kt | 3 + .../sql/util/kotlin/elements/SqlElements.kt | 4 ++ .../java/examples/joins/JoinMapperTest.java | 55 ++++++++++++++++- .../mybatis3/joins/JoinMapperNewSyntaxTest.kt | 36 +++++++++++ 6 files changed, 160 insertions(+), 2 deletions(-) create mode 100644 src/main/java/org/mybatis/dynamic/sql/SubQueryColumn.java diff --git a/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java b/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java index 9790633b0..84d50d556 100644 --- a/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java +++ b/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java @@ -499,6 +499,10 @@ static CountDistinct countDistinct(BasicColumn column) { return CountDistinct.of(column); } + static SubQueryColumn subQuery(Buildable subQuery) { + return SubQueryColumn.of(subQuery); + } + static Max max(BindableColumn column) { return Max.of(column); } diff --git a/src/main/java/org/mybatis/dynamic/sql/SubQueryColumn.java b/src/main/java/org/mybatis/dynamic/sql/SubQueryColumn.java new file mode 100644 index 000000000..abcd2f4b1 --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/SubQueryColumn.java @@ -0,0 +1,60 @@ +/* + * Copyright 2016-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mybatis.dynamic.sql; + +import java.util.Optional; + +import org.jspecify.annotations.Nullable; +import org.mybatis.dynamic.sql.render.RenderingContext; +import org.mybatis.dynamic.sql.select.SelectModel; +import org.mybatis.dynamic.sql.select.render.SubQueryRenderer; +import org.mybatis.dynamic.sql.util.Buildable; +import org.mybatis.dynamic.sql.util.FragmentAndParameters; + +public class SubQueryColumn implements BasicColumn { + private final Buildable subQuery; + private @Nullable String alias; + + private SubQueryColumn(Buildable subQuery) { + this.subQuery = subQuery; + } + + @Override + public Optional alias() { + return Optional.ofNullable(alias); + } + + @Override + public SubQueryColumn as(String alias) { + SubQueryColumn answer = new SubQueryColumn(subQuery); + answer.alias = alias; + return answer; + } + + @Override + public FragmentAndParameters render(RenderingContext renderingContext) { + return SubQueryRenderer.withSelectModel(subQuery.build()) + .withRenderingContext(renderingContext) + .withPrefix("(") //$NON-NLS-1$ + .withSuffix(")") //$NON-NLS-1$ + .build() + .render(); + } + + public static SubQueryColumn of(Buildable subQuery) { + return new SubQueryColumn(subQuery); + } +} diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/ColumnExtensions.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/ColumnExtensions.kt index ab5f81a2a..c3651d995 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/ColumnExtensions.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/ColumnExtensions.kt @@ -17,6 +17,7 @@ package org.mybatis.dynamic.sql.util.kotlin.elements import org.mybatis.dynamic.sql.DerivedColumn import org.mybatis.dynamic.sql.SqlColumn +import org.mybatis.dynamic.sql.SubQueryColumn import org.mybatis.dynamic.sql.select.caseexpression.SearchedCaseModel import org.mybatis.dynamic.sql.select.caseexpression.SimpleCaseModel @@ -28,6 +29,8 @@ infix fun SearchedCaseModel.`as`(alias: String): SearchedCaseModel = this.`as`(a infix fun SimpleCaseModel.`as`(alias: String): SimpleCaseModel = this.`as`(alias) +infix fun SubQueryColumn.`as`(alias: String): SubQueryColumn = this.`as`(alias) + /** * Adds a qualifier to a column for use with table aliases (typically in joins or sub queries). * This is as close to natural SQL syntax as we can get in Kotlin. Natural SQL would look like diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/SqlElements.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/SqlElements.kt index f648496d0..3956beb0e 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/SqlElements.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/SqlElements.kt @@ -26,6 +26,7 @@ import org.mybatis.dynamic.sql.SortSpecification import org.mybatis.dynamic.sql.SqlBuilder import org.mybatis.dynamic.sql.SqlColumn import org.mybatis.dynamic.sql.StringConstant +import org.mybatis.dynamic.sql.SubQueryColumn import org.mybatis.dynamic.sql.select.caseexpression.SearchedCaseModel import org.mybatis.dynamic.sql.select.caseexpression.SimpleCaseModel import org.mybatis.dynamic.sql.select.aggregate.Avg @@ -141,6 +142,9 @@ fun count(column: BasicColumn): Count = SqlBuilder.count(column) fun countDistinct(column: BasicColumn): CountDistinct = SqlBuilder.countDistinct(column) +fun subQuery(subQuery: KotlinSubQueryBuilder.() -> Unit): SubQueryColumn = + SubQueryColumn.of(KotlinSubQueryBuilder().apply(subQuery)) + fun max(column: BindableColumn): Max = SqlBuilder.max(column) fun min(column: BindableColumn): Min = SqlBuilder.min(column) diff --git a/src/test/java/examples/joins/JoinMapperTest.java b/src/test/java/examples/joins/JoinMapperTest.java index 1f1c6a27c..2c9198aac 100644 --- a/src/test/java/examples/joins/JoinMapperTest.java +++ b/src/test/java/examples/joins/JoinMapperTest.java @@ -16,13 +16,14 @@ package examples.joins; import static examples.joins.ItemMasterDynamicSQLSupport.itemMaster; -import static examples.joins.OrderDetailDynamicSQLSupport.*; +import static examples.joins.OrderDetailDynamicSQLSupport.orderDetail; import static examples.joins.OrderLineDynamicSQLSupport.orderLine; import static examples.joins.OrderMasterDynamicSQLSupport.orderDate; import static examples.joins.OrderMasterDynamicSQLSupport.orderMaster; -import static examples.joins.UserDynamicSQLSupport.*; +import static examples.joins.UserDynamicSQLSupport.user; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.assertj.core.api.Assertions.entry; import static org.mybatis.dynamic.sql.SqlBuilder.*; import java.io.InputStream; @@ -1261,4 +1262,54 @@ void testJoinWithConstant() { assertThat(row).containsEntry("ITEM_ID", 33); } } + + @Test + void testJoinWithGroupBy() { + try (SqlSession session = sqlSessionFactory.openSession()) { + CommonSelectMapper mapper = session.getMapper(CommonSelectMapper.class); + + SelectStatementProvider selectStatement = select(orderMaster.orderId, count().as("linecount")) + .from(orderMaster, "om") + .join(orderDetail, "od").on(orderMaster.orderId, isEqualTo(orderDetail.orderId)) + .groupBy(orderMaster.orderId) + .orderBy(orderDetail.orderId) + .build() + .render(RenderingStrategies.MYBATIS3); + + String expectedStatement = "select om.order_id, count(*) as linecount from OrderMaster om join OrderDetail od on om.order_id = od.order_id group by om.order_id order by order_id"; + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); + + List> rows = mapper.selectManyMappedRows(selectStatement); + + assertThat(rows).hasSize(2); + assertThat(rows.get(0)).containsOnly(entry("ORDER_ID", 1), entry("LINECOUNT", 2L)); + assertThat(rows.get(1)).containsOnly(entry("ORDER_ID", 2), entry("LINECOUNT", 1L)); + } + } + + @Test + void testSubQuery() { + try (SqlSession session = sqlSessionFactory.openSession()) { + CommonSelectMapper mapper = session.getMapper(CommonSelectMapper.class); + + SelectStatementProvider selectStatement = select(orderMaster.orderId, + subQuery(select(count()) + .from(orderDetail, "od") + .where(orderMaster.orderId, isEqualTo(orderDetail.orderId)) + ).as("linecount")) + .from(orderMaster, "om") + .orderBy(orderMaster.orderId) + .build() + .render(RenderingStrategies.MYBATIS3); + + String expectedStatement = "select om.order_id, (select count(*) from OrderDetail od where om.order_id = od.order_id) as linecount from OrderMaster om order by order_id"; + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); + + List> rows = mapper.selectManyMappedRows(selectStatement); + + assertThat(rows).hasSize(2); + assertThat(rows.get(0)).containsOnly(entry("ORDER_ID", 1), entry("LINECOUNT", 2L)); + assertThat(rows.get(1)).containsOnly(entry("ORDER_ID", 2), entry("LINECOUNT", 1L)); + } + } } diff --git a/src/test/kotlin/examples/kotlin/mybatis3/joins/JoinMapperNewSyntaxTest.kt b/src/test/kotlin/examples/kotlin/mybatis3/joins/JoinMapperNewSyntaxTest.kt index 1ad6d71c2..3274d0595 100644 --- a/src/test/kotlin/examples/kotlin/mybatis3/joins/JoinMapperNewSyntaxTest.kt +++ b/src/test/kotlin/examples/kotlin/mybatis3/joins/JoinMapperNewSyntaxTest.kt @@ -30,9 +30,13 @@ import org.junit.jupiter.api.Test import org.junit.jupiter.api.TestInstance import org.mybatis.dynamic.sql.util.Messages import org.mybatis.dynamic.sql.util.kotlin.KInvalidSQLException +import org.mybatis.dynamic.sql.util.kotlin.elements.`as` import org.mybatis.dynamic.sql.util.kotlin.elements.constant +import org.mybatis.dynamic.sql.util.kotlin.elements.count import org.mybatis.dynamic.sql.util.kotlin.elements.invoke +import org.mybatis.dynamic.sql.util.kotlin.elements.subQuery import org.mybatis.dynamic.sql.util.kotlin.mybatis3.select +import org.mybatis.dynamic.sql.util.mybatis3.CommonSelectMapper @Suppress("LargeClass") @TestInstance(TestInstance.Lifecycle.PER_CLASS) @@ -44,6 +48,7 @@ class JoinMapperNewSyntaxTest { sqlSessionFactory = TestUtils.buildSqlSessionFactory { withInitializationScript("/examples/kotlin/mybatis3/joins/CreateJoinDB.sql") withMapper(JoinMapper::class) + withMapper(CommonSelectMapper::class) } } @@ -829,4 +834,35 @@ class JoinMapperNewSyntaxTest { } }.withMessage(Messages.getString("ERROR.22")) //$NON-NLS-1$ } + + @Test + fun testSubQuery() { + sqlSessionFactory.openSession().use { session -> + val mapper = session.getMapper(CommonSelectMapper::class.java) + + val selectStatement = select( + orderMaster.orderId, subQuery { + select(count()) { + from(orderDetail, "od") + where { + orderMaster.orderId isEqualTo orderDetail.orderId + } + } + } `as` "linecount" + ) { + from(orderMaster, "om") + orderBy(orderMaster.orderId) + } + + val expectedStatement = "select om.order_id, (select count(*) from OrderDetail od where om.order_id = od.order_id) as linecount from OrderMaster om order by order_id" + + assertThat(selectStatement.selectStatement).isEqualTo(expectedStatement) + + val rows = mapper.selectManyMappedRows(selectStatement) + + assertThat(rows).hasSize(2) + assertThat(rows[0]).containsOnly(entry("ORDER_ID", 1), entry("LINECOUNT", 2L)) + assertThat(rows[1]).containsOnly(entry("ORDER_ID", 2), entry("LINECOUNT", 1L)) + } + } } From ae4bc67ba96fc73eca3f02caeef406d50dc9500c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 17 Apr 2025 12:03:21 +0000 Subject: [PATCH 262/289] Update dependency org.springframework:spring-jdbc to v6.2.6 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 677844711..e1e1f613d 100644 --- a/pom.xml +++ b/pom.xml @@ -103,7 +103,7 @@ org.springframework spring-jdbc - 6.2.5 + 6.2.6 provided true From 7f64474a9aab2b002d69afed9067aa123ca7e6ed Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 24 Apr 2025 02:10:00 +0000 Subject: [PATCH 263/289] Update testcontainers-java monorepo to v1.21.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e1e1f613d..92bc65d6d 100644 --- a/pom.xml +++ b/pom.xml @@ -80,7 +80,7 @@ http://localhost:9000 official - 1.20.6 + 1.21.0 org.mybatis.dynamic.sql.*;version=${project.version};-noimport:=true From 00bf2528ec347cb8e663a89888a1e55b333b4425 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 29 Apr 2025 16:26:05 +0000 Subject: [PATCH 264/289] Update dependency com.mysql:mysql-connector-j to v9.3.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 92bc65d6d..3324ae65b 100644 --- a/pom.xml +++ b/pom.xml @@ -214,7 +214,7 @@ com.mysql mysql-connector-j - 9.2.0 + 9.3.0 test From 0b7db45155099e256a985bc33dd3559afbd07021 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 1 May 2025 08:19:04 +0000 Subject: [PATCH 265/289] Update dependency org.mybatis:mybatis-parent to v49 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3324ae65b..59708f56e 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ org.mybatis mybatis-parent - 48 + 49 org.mybatis.dynamic-sql From cb669a6cc0d095ce85c7110394796fccbde842da Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 13 May 2025 13:33:07 +0000 Subject: [PATCH 266/289] Update kotlin monorepo to v2.1.21 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 59708f56e..f2c740047 100644 --- a/pom.xml +++ b/pom.xml @@ -69,7 +69,7 @@ org.mybatis.dynamic.sql - 2.1.20 + 2.1.21 17 2.0 2.0 From 93dbda634f17050a615f933d4654afa3b323f9ad Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 15 May 2025 12:00:32 +0000 Subject: [PATCH 267/289] Update dependency org.springframework:spring-jdbc to v6.2.7 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f2c740047..9aae0f900 100644 --- a/pom.xml +++ b/pom.xml @@ -103,7 +103,7 @@ org.springframework spring-jdbc - 6.2.6 + 6.2.7 provided true From 7ba9761f62e1fe939127609871d6f1884e1d0e15 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 19 May 2025 10:38:50 -0400 Subject: [PATCH 268/289] Use select model instead of a builder --- .../java/org/mybatis/dynamic/sql/SqlBuilder.java | 2 +- .../org/mybatis/dynamic/sql/SubQueryColumn.java | 16 ++++++++-------- .../sql/util/kotlin/elements/SqlElements.kt | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java b/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java index 84d50d556..c8fe5c3ba 100644 --- a/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java +++ b/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java @@ -500,7 +500,7 @@ static CountDistinct countDistinct(BasicColumn column) { } static SubQueryColumn subQuery(Buildable subQuery) { - return SubQueryColumn.of(subQuery); + return SubQueryColumn.of(subQuery.build()); } static Max max(BindableColumn column) { diff --git a/src/main/java/org/mybatis/dynamic/sql/SubQueryColumn.java b/src/main/java/org/mybatis/dynamic/sql/SubQueryColumn.java index abcd2f4b1..cc35bdcad 100644 --- a/src/main/java/org/mybatis/dynamic/sql/SubQueryColumn.java +++ b/src/main/java/org/mybatis/dynamic/sql/SubQueryColumn.java @@ -15,21 +15,21 @@ */ package org.mybatis.dynamic.sql; +import java.util.Objects; import java.util.Optional; import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.select.SelectModel; import org.mybatis.dynamic.sql.select.render.SubQueryRenderer; -import org.mybatis.dynamic.sql.util.Buildable; import org.mybatis.dynamic.sql.util.FragmentAndParameters; public class SubQueryColumn implements BasicColumn { - private final Buildable subQuery; + private final SelectModel selectModel; private @Nullable String alias; - private SubQueryColumn(Buildable subQuery) { - this.subQuery = subQuery; + private SubQueryColumn(SelectModel selectModel) { + this.selectModel = Objects.requireNonNull(selectModel); } @Override @@ -39,14 +39,14 @@ public Optional alias() { @Override public SubQueryColumn as(String alias) { - SubQueryColumn answer = new SubQueryColumn(subQuery); + SubQueryColumn answer = new SubQueryColumn(selectModel); answer.alias = alias; return answer; } @Override public FragmentAndParameters render(RenderingContext renderingContext) { - return SubQueryRenderer.withSelectModel(subQuery.build()) + return SubQueryRenderer.withSelectModel(selectModel) .withRenderingContext(renderingContext) .withPrefix("(") //$NON-NLS-1$ .withSuffix(")") //$NON-NLS-1$ @@ -54,7 +54,7 @@ public FragmentAndParameters render(RenderingContext renderingContext) { .render(); } - public static SubQueryColumn of(Buildable subQuery) { - return new SubQueryColumn(subQuery); + public static SubQueryColumn of(SelectModel selectModel) { + return new SubQueryColumn(selectModel); } } diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/SqlElements.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/SqlElements.kt index 3956beb0e..2002fc75a 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/SqlElements.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/SqlElements.kt @@ -143,7 +143,7 @@ fun count(column: BasicColumn): Count = SqlBuilder.count(column) fun countDistinct(column: BasicColumn): CountDistinct = SqlBuilder.countDistinct(column) fun subQuery(subQuery: KotlinSubQueryBuilder.() -> Unit): SubQueryColumn = - SubQueryColumn.of(KotlinSubQueryBuilder().apply(subQuery)) + SubQueryColumn.of(KotlinSubQueryBuilder().apply(subQuery).build()) fun max(column: BindableColumn): Max = SqlBuilder.max(column) From 132b1486d75aba42718e5c1a42fcf421c6773e5d Mon Sep 17 00:00:00 2001 From: Jeremy Landis Date: Wed, 30 Apr 2025 20:57:40 -0400 Subject: [PATCH 269/289] [mvn] Update settings to central --- .mvn/settings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.mvn/settings.xml b/.mvn/settings.xml index af6e63413..18dd7dcfd 100644 --- a/.mvn/settings.xml +++ b/.mvn/settings.xml @@ -22,7 +22,7 @@ - ossrh + central ${env.CI_DEPLOY_USERNAME} ${env.CI_DEPLOY_PASSWORD} From 20ca807229490d8ea6e6a44458b5b3f25771fd20 Mon Sep 17 00:00:00 2001 From: Jeremy Landis Date: Wed, 30 Apr 2025 20:57:55 -0400 Subject: [PATCH 270/289] [mvn] Bump maven profiler to 3.3 --- .mvn/extensions.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml index 93acda146..fa0b7e819 100644 --- a/.mvn/extensions.xml +++ b/.mvn/extensions.xml @@ -20,6 +20,6 @@ fr.jcgay.maven maven-profiler - 3.2 + 3.3 From 8cb72bf5b9883ba572af2ca1b18403c0d106331d Mon Sep 17 00:00:00 2001 From: Jeremy Landis Date: Wed, 30 Apr 2025 20:58:06 -0400 Subject: [PATCH 271/289] [gha] Update site action --- .github/workflows/site.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/site.yaml b/.github/workflows/site.yaml index 5d6998019..de1babe41 100644 --- a/.github/workflows/site.yaml +++ b/.github/workflows/site.yaml @@ -5,6 +5,9 @@ on: branches: - site +permissions: + contents: write + jobs: build: if: github.repository_owner == 'mybatis' && ! contains(toJSON(github.event.head_commit.message), '[maven-release-plugin]') @@ -20,7 +23,6 @@ jobs: - name: Build site run: ./mvnw site site:stage -DskipTests -Dlicense.skip=true -B -V --no-transfer-progress --settings ./.mvn/settings.xml env: - CI_DEPLOY_USERNAME: ${{ secrets.CI_DEPLOY_USERNAME }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} NVD_API_KEY: ${{ secrets.NVD_API_KEY }} - name: Deploy Site to gh-pages @@ -28,4 +30,3 @@ jobs: with: branch: gh-pages folder: target/staging - ssh-key: ${{ secrets.DEPLOY_KEY }} From f92ec29745602217645c506575fa4bd849db61c1 Mon Sep 17 00:00:00 2001 From: Jeremy Landis Date: Wed, 30 Apr 2025 20:58:17 -0400 Subject: [PATCH 272/289] [gha] Drop java 23, use 24 ga --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index e89bd81b6..48d150725 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -9,7 +9,7 @@ jobs: matrix: cache: [maven] distribution: [temurin] - java: [17, 21, 23, 24-ea] + java: [17, 21, 24, 25-ea] os: [ubuntu-latest] fail-fast: false max-parallel: 4 From 6b3ec94756d50797f10074a0038a3ff4c8e22334 Mon Sep 17 00:00:00 2001 From: Jeremy Landis Date: Wed, 30 Apr 2025 21:21:26 -0400 Subject: [PATCH 273/289] [mvn] Remove deploy username for site --- .mvn/settings.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/.mvn/settings.xml b/.mvn/settings.xml index 18dd7dcfd..28f1a37e5 100644 --- a/.mvn/settings.xml +++ b/.mvn/settings.xml @@ -39,7 +39,6 @@ github - ${env.CI_DEPLOY_USERNAME} ${env.GITHUB_TOKEN} From 7f1f44f85a3f48d5969d5f22da1fd0c678a9e707 Mon Sep 17 00:00:00 2001 From: Jeremy Landis Date: Mon, 26 May 2025 20:55:17 -0400 Subject: [PATCH 274/289] [gha] Add explicit permissions --- .github/workflows/ci.yaml | 2 ++ .github/workflows/coveralls.yaml | 2 ++ .github/workflows/sonar.yaml | 2 ++ .github/workflows/sonatype.yaml | 2 ++ 4 files changed, 8 insertions(+) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 48d150725..66bba3618 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -2,6 +2,8 @@ name: Java CI on: [workflow_dispatch, push, pull_request] +permissions: read-all + jobs: test: runs-on: ${{ matrix.os }} diff --git a/.github/workflows/coveralls.yaml b/.github/workflows/coveralls.yaml index 270a6c85b..b4aaaa991 100644 --- a/.github/workflows/coveralls.yaml +++ b/.github/workflows/coveralls.yaml @@ -2,6 +2,8 @@ name: Coveralls on: [push, pull_request] +permissions: read-all + jobs: build: if: github.repository_owner == 'mybatis' diff --git a/.github/workflows/sonar.yaml b/.github/workflows/sonar.yaml index 293c0e4ad..33c70609c 100644 --- a/.github/workflows/sonar.yaml +++ b/.github/workflows/sonar.yaml @@ -5,6 +5,8 @@ on: branches: - master +permissions: read-all + jobs: build: if: github.repository_owner == 'mybatis' diff --git a/.github/workflows/sonatype.yaml b/.github/workflows/sonatype.yaml index 494bb2f4c..c922f382c 100644 --- a/.github/workflows/sonatype.yaml +++ b/.github/workflows/sonatype.yaml @@ -5,6 +5,8 @@ on: branches: - master +permissions: read-all + jobs: build: if: github.repository_owner == 'mybatis' && ! contains(toJSON(github.event.head_commit.message), '[maven-release-plugin]') From 4320fe382c7d3bc93efb47830c9f10458b2856bc Mon Sep 17 00:00:00 2001 From: Jeremy Landis Date: Mon, 26 May 2025 20:55:43 -0400 Subject: [PATCH 275/289] [gha] Cleanup and add cache / security scans to codeql --- .github/workflows/codeql.yml | 93 ++++++++++-------------------------- 1 file changed, 26 insertions(+), 67 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 57452d157..8e5c9c4b6 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -1,90 +1,49 @@ -# For most projects, this workflow file will not need changing; you simply need -# to commit it to your repository. -# -# You may wish to alter this file to override the set of languages analyzed, -# or to provide custom queries or build logic. -# -# ******** NOTE ******** -# We have attempted to detect the languages in your repository. Please check -# the `language` matrix defined below to confirm you have the correct set of -# supported CodeQL languages. -# name: "CodeQL" on: push: - branches: [ "master" ] + branches: [ master ] pull_request: - branches: [ "master" ] + branches: [ master ] schedule: - cron: '26 13 * * 4' jobs: analyze: name: Analyze - # Runner size impacts CodeQL analysis time. To learn more, please see: - # - https://gh.io/recommended-hardware-resources-for-running-codeql - # - https://gh.io/supported-runners-and-hardware-resources - # - https://gh.io/using-larger-runners - # Consider using larger runners for possible analysis time improvements. runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }} permissions: - # required for all workflows - security-events: write - - # only required for workflows in private repositories actions: read contents: read + security-events: write strategy: fail-fast: false matrix: language: [ 'java-kotlin' ] - # CodeQL supports [ 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift' ] - # Use only 'java-kotlin' to analyze code written in Java, Kotlin or both - # Use only 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both - # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Setup Java - uses: actions/setup-java@v4 - with: - java-version: 17 - distribution: 'temurin' - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v3 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - - # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs - # queries: security-extended,security-and-quality - - - # Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v3 - - # â„šī¸ Command-line programs to run using the OS shell. - # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun - - # If the Autobuild fails above, remove it and uncomment the following three lines. - # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. - - # - run: | - # echo "Run, Build Application using script" - # ./location_of_script_within_repo/buildscript.sh - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 - with: - category: "/language:${{matrix.language}}" + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Java + uses: actions/setup-java@v4 + with: + cache: maven + distribution: 'temurin' + java-version: 21 + + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + queries: +security-and-quality + + - name: Autobuild + uses: github/codeql-action/autobuild@v3 + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 + with: + category: "/language:${{ matrix.language }}" From 2a277f513e09d700c2e442a8665bf8fa8314333a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 28 May 2025 13:56:29 +0000 Subject: [PATCH 276/289] Update dependency org.postgresql:postgresql to v42.7.6 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9aae0f900..7ec52aef2 100644 --- a/pom.xml +++ b/pom.xml @@ -190,7 +190,7 @@ org.postgresql postgresql - 42.7.5 + 42.7.6 test From f89988be9be13f8fe9aa1834d27aed87e6c10e53 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 29 May 2025 22:17:24 +0000 Subject: [PATCH 277/289] Update testcontainers-java monorepo to v1.21.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 7ec52aef2..4293d16a6 100644 --- a/pom.xml +++ b/pom.xml @@ -80,7 +80,7 @@ http://localhost:9000 official - 1.21.0 + 1.21.1 org.mybatis.dynamic.sql.*;version=${project.version};-noimport:=true From c3c2f5f896968f9a7ff4b54335f0a8f3dfdbd43b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 30 May 2025 10:41:24 +0000 Subject: [PATCH 278/289] Update dependency org.junit.jupiter:junit-jupiter-engine to v5.13.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 7ec52aef2..1ed38abf2 100644 --- a/pom.xml +++ b/pom.xml @@ -60,7 +60,7 @@ 17 17 17 - 5.12.2 + 5.13.0 5.2.2 checkstyle-override.xml From f07d53e9a535489c719718712bc379000062c48f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 31 May 2025 20:53:51 +0000 Subject: [PATCH 279/289] Update dependency org.mybatis:mybatis-parent to v50 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 4293d16a6..9d9d853ad 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ org.mybatis mybatis-parent - 49 + 50 org.mybatis.dynamic-sql From 8b06decef63dd6917c730125daa99ac118368383 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 5 Jun 2025 00:35:22 +0000 Subject: [PATCH 280/289] Update dependency org.codehaus.mojo:build-helper-maven-plugin to v3.6.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f6c370fa6..892466227 100644 --- a/pom.xml +++ b/pom.xml @@ -344,7 +344,7 @@ org.codehaus.mojo build-helper-maven-plugin - 3.6.0 + 3.6.1 From a700f5f93c9905896194d7293eedc84766eb96e6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 6 Jun 2025 19:21:36 +0000 Subject: [PATCH 281/289] Update dependency maven to v3.9.10 --- .mvn/wrapper/maven-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties index 01aa6654c..0d35f6dbb 100644 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -16,5 +16,5 @@ # under the License. wrapperVersion=3.3.2 distributionType=source -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.10/apache-maven-3.9.10-bin.zip wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar From bc0725f2016cb78eb73ee00aa6f38352ba7dc3e5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 7 Jun 2025 08:52:44 +0000 Subject: [PATCH 282/289] Update junit5 monorepo to v5.13.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 892466227..159273fed 100644 --- a/pom.xml +++ b/pom.xml @@ -60,7 +60,7 @@ 17 17 17 - 5.13.0 + 5.13.1 5.2.2 checkstyle-override.xml From 3a9e494ab486da020466d8b6e456be41b0319d0e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 9 Jun 2025 19:10:24 +0000 Subject: [PATCH 283/289] Update dependency org.mybatis:mybatis-spring to v3.0.5 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 159273fed..a806e8f9c 100644 --- a/pom.xml +++ b/pom.xml @@ -142,7 +142,7 @@ org.mybatis mybatis-spring - 3.0.4 + 3.0.5 test From 7118af74f044679f0a8ff056811ded4291236b78 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 11 Jun 2025 11:04:59 +0000 Subject: [PATCH 284/289] Update dependency org.postgresql:postgresql to v42.7.7 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a806e8f9c..afd96653b 100644 --- a/pom.xml +++ b/pom.xml @@ -190,7 +190,7 @@ org.postgresql postgresql - 42.7.6 + 42.7.7 test From 2f32281d1e45d1dbf0ec4d0e0eb7eed07714f907 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 12 Jun 2025 16:07:56 +0000 Subject: [PATCH 285/289] Update dependency org.springframework:spring-jdbc to v6.2.8 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index afd96653b..76ebf04fd 100644 --- a/pom.xml +++ b/pom.xml @@ -103,7 +103,7 @@ org.springframework spring-jdbc - 6.2.7 + 6.2.8 provided true From b2c216c87ee201a6d58c679b4e9a9b141532d102 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 19 Jun 2025 02:24:14 +0000 Subject: [PATCH 286/289] Update testcontainers-java monorepo to v1.21.2 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 76ebf04fd..d874822e3 100644 --- a/pom.xml +++ b/pom.xml @@ -80,7 +80,7 @@ http://localhost:9000 official - 1.21.1 + 1.21.2 org.mybatis.dynamic.sql.*;version=${project.version};-noimport:=true From 358074a33690ddeed67a373f0f9575c0dad504bb Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 13:42:16 +0000 Subject: [PATCH 287/289] Update junit.jupiter.version to v5.13.2 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d874822e3..65481df6b 100644 --- a/pom.xml +++ b/pom.xml @@ -60,7 +60,7 @@ 17 17 17 - 5.13.1 + 5.13.2 5.2.2 checkstyle-override.xml From 63997704562d5863166d029b7faa019feb4c1b0f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 29 Jun 2025 01:04:36 +0000 Subject: [PATCH 288/289] Update testcontainers-java monorepo to v1.21.3 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 65481df6b..26824df94 100644 --- a/pom.xml +++ b/pom.xml @@ -80,7 +80,7 @@ http://localhost:9000 official - 1.21.2 + 1.21.3 org.mybatis.dynamic.sql.*;version=${project.version};-noimport:=true From 1bb24fe0644b05c807c477bdbbcc63d0ab2525ba Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 30 Jun 2025 16:50:55 +0000 Subject: [PATCH 289/289] Update dependency org.mariadb.jdbc:mariadb-java-client to v3.5.4 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 65481df6b..4465ade68 100644 --- a/pom.xml +++ b/pom.xml @@ -202,7 +202,7 @@ org.mariadb.jdbc mariadb-java-client - 3.5.3 + 3.5.4 test