From 5c9454f92618323ba10eb43f7870667a89998d77 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Tue, 19 Mar 2024 09:15:01 -0400 Subject: [PATCH 01/22] Use a builder for boolean expression model --- .../AbstractBooleanExpressionModel.java | 25 +++++++-- .../sql/select/AbstractHavingFinisher.java | 5 +- .../dynamic/sql/select/HavingModel.java | 19 ++++--- .../caseexpression/SearchedCaseDSL.java | 9 ++-- .../caseexpression/SearchedCaseModel.java | 27 ++-------- .../SearchedCaseWhenCondition.java | 52 +++++++++++++++++++ .../select/render/SearchedCaseRenderer.java | 7 +-- .../SearchedCaseWhenConditionRenderer.java | 8 +-- .../sql/where/AbstractWhereFinisher.java | 6 ++- .../mybatis/dynamic/sql/where/WhereModel.java | 28 +++++++--- .../sql/util/kotlin/elements/CaseDSLs.kt | 16 +++--- 11 files changed, 144 insertions(+), 58 deletions(-) create mode 100644 src/main/java/org/mybatis/dynamic/sql/select/caseexpression/SearchedCaseWhenCondition.java diff --git a/src/main/java/org/mybatis/dynamic/sql/common/AbstractBooleanExpressionModel.java b/src/main/java/org/mybatis/dynamic/sql/common/AbstractBooleanExpressionModel.java index 998df3af9..0913fe17c 100644 --- a/src/main/java/org/mybatis/dynamic/sql/common/AbstractBooleanExpressionModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/common/AbstractBooleanExpressionModel.java @@ -25,11 +25,11 @@ public abstract class AbstractBooleanExpressionModel { private final SqlCriterion initialCriterion; - private final List subCriteria = new ArrayList<>(); + private final List subCriteria ; - protected AbstractBooleanExpressionModel(SqlCriterion initialCriterion, List subCriteria) { - this.initialCriterion = initialCriterion; - this.subCriteria.addAll(subCriteria); + protected AbstractBooleanExpressionModel(AbstractBuilder builder) { + initialCriterion = builder.initialCriterion; + subCriteria = builder.subCriteria; } public Optional initialCriterion() { @@ -39,4 +39,21 @@ public Optional initialCriterion() { public List subCriteria() { return Collections.unmodifiableList(subCriteria); } + + public abstract static class AbstractBuilder> { + private SqlCriterion initialCriterion; + private final List subCriteria = new ArrayList<>(); + + public T withInitialCriterion(SqlCriterion initialCriterion) { + this.initialCriterion = initialCriterion; + return getThis(); + } + + public T withSubCriteria(List subCriteria) { + this.subCriteria.addAll(subCriteria); + return getThis(); + } + + protected abstract T getThis(); + } } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/AbstractHavingFinisher.java b/src/main/java/org/mybatis/dynamic/sql/select/AbstractHavingFinisher.java index 779225718..2a668c72c 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/AbstractHavingFinisher.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/AbstractHavingFinisher.java @@ -33,6 +33,9 @@ void initialize(SqlCriterion sqlCriterion, List subCriteria) } protected HavingModel buildModel() { - return new HavingModel(getInitialCriterion(), subCriteria); + return new HavingModel.Builder() + .withInitialCriterion(getInitialCriterion()) + .withSubCriteria(subCriteria) + .build(); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/HavingModel.java b/src/main/java/org/mybatis/dynamic/sql/select/HavingModel.java index 3a129eb4b..5f773cf3b 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/HavingModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/HavingModel.java @@ -15,14 +15,21 @@ */ package org.mybatis.dynamic.sql.select; -import java.util.List; - -import org.mybatis.dynamic.sql.AndOrCriteriaGroup; -import org.mybatis.dynamic.sql.SqlCriterion; import org.mybatis.dynamic.sql.common.AbstractBooleanExpressionModel; public class HavingModel extends AbstractBooleanExpressionModel { - public HavingModel(SqlCriterion initialCriterion, List subCriteria) { - super(initialCriterion, subCriteria); + private HavingModel(Builder builder) { + super(builder); + } + + public static class Builder extends AbstractBuilder { + public HavingModel build() { + return new HavingModel(this); + } + + @Override + protected Builder getThis() { + return this; + } } } 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 4e070b98d..674012d3c 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 @@ -29,7 +29,7 @@ import org.mybatis.dynamic.sql.common.AbstractBooleanExpressionDSL; public class SearchedCaseDSL implements ElseDSL { - private final List whenConditions = new ArrayList<>(); + private final List whenConditions = new ArrayList<>(); private BasicColumn elseValue; public WhenDSL when(BindableColumn column, VisitableCondition condition, @@ -85,8 +85,11 @@ private WhenDSL(SqlCriterion sqlCriterion) { @Override public SearchedCaseDSL then(BasicColumn column) { - whenConditions.add(new SearchedCaseModel.SearchedWhenCondition(getInitialCriterion(), subCriteria, - column)); + whenConditions.add(new SearchedCaseWhenCondition.Builder() + .withInitialCriterion(getInitialCriterion()) + .withSubCriteria(subCriteria) + .withThenValue(column) + .build()); return SearchedCaseDSL.this; } 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 50ca830ad..65d3f949f 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 @@ -17,21 +17,17 @@ import java.util.ArrayList; import java.util.List; -import java.util.Objects; import java.util.Optional; import java.util.stream.Stream; -import org.mybatis.dynamic.sql.AndOrCriteriaGroup; import org.mybatis.dynamic.sql.BasicColumn; -import org.mybatis.dynamic.sql.SqlCriterion; -import org.mybatis.dynamic.sql.common.AbstractBooleanExpressionModel; 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 { - private final List whenConditions; + private final List whenConditions; private final BasicColumn elseValue; private final String alias; @@ -42,7 +38,7 @@ private SearchedCaseModel(Builder builder) { Validator.assertNotEmpty(whenConditions, "ERROR.40"); //$NON-NLS-1$ } - public Stream whenConditions() { + public Stream whenConditions() { return whenConditions.stream(); } @@ -68,27 +64,12 @@ public FragmentAndParameters render(RenderingContext renderingContext) { return new SearchedCaseRenderer(this, renderingContext).render(); } - public static class SearchedWhenCondition extends AbstractBooleanExpressionModel { - - private final BasicColumn thenValue; - - public BasicColumn thenValue() { - return thenValue; - } - - public SearchedWhenCondition(SqlCriterion initialCriterion, List subCriteria, - BasicColumn thenValue) { - super(initialCriterion, subCriteria); - this.thenValue = Objects.requireNonNull(thenValue); - } - } - public static class Builder { - private final List whenConditions = new ArrayList<>(); + private final List whenConditions = new ArrayList<>(); private BasicColumn elseValue; private String alias; - public Builder withWhenConditions(List whenConditions) { + public Builder withWhenConditions(List whenConditions) { this.whenConditions.addAll(whenConditions); return this; } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/SearchedCaseWhenCondition.java b/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/SearchedCaseWhenCondition.java new file mode 100644 index 000000000..e6d57e32c --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/SearchedCaseWhenCondition.java @@ -0,0 +1,52 @@ +/* + * 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.caseexpression; + +import java.util.Objects; + +import org.mybatis.dynamic.sql.BasicColumn; +import org.mybatis.dynamic.sql.common.AbstractBooleanExpressionModel; + +public class SearchedCaseWhenCondition extends AbstractBooleanExpressionModel { + private final BasicColumn thenValue; + + public BasicColumn thenValue() { + return thenValue; + } + + private SearchedCaseWhenCondition(Builder builder) { + super(builder); + thenValue = Objects.requireNonNull(builder.thenValue); + } + + public static class Builder extends AbstractBuilder { + private BasicColumn thenValue; + + public Builder withThenValue(BasicColumn thenValue) { + this.thenValue = thenValue; + return this; + } + + public SearchedCaseWhenCondition build() { + return new SearchedCaseWhenCondition(this); + } + + @Override + protected Builder getThis() { + return this; + } + } +} diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/SearchedCaseRenderer.java b/src/main/java/org/mybatis/dynamic/sql/select/render/SearchedCaseRenderer.java index 050a87204..d273c4c87 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/render/SearchedCaseRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/render/SearchedCaseRenderer.java @@ -24,6 +24,7 @@ import org.mybatis.dynamic.sql.exception.InvalidSqlException; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.select.caseexpression.SearchedCaseModel; +import org.mybatis.dynamic.sql.select.caseexpression.SearchedCaseWhenCondition; import org.mybatis.dynamic.sql.util.FragmentAndParameters; import org.mybatis.dynamic.sql.util.FragmentCollector; import org.mybatis.dynamic.sql.util.Messages; @@ -56,12 +57,12 @@ private FragmentAndParameters renderWhenConditions() { .toFragmentAndParameters(Collectors.joining(" ")); //$NON-NLS-1$ } - private FragmentAndParameters renderWhenCondition(SearchedCaseModel.SearchedWhenCondition whenCondition) { + private FragmentAndParameters renderWhenCondition(SearchedCaseWhenCondition whenCondition) { return Stream.of(renderWhen(whenCondition), renderThen(whenCondition)).collect(FragmentCollector.collect()) .toFragmentAndParameters(Collectors.joining(" ")); //$NON-NLS-1$ } - private FragmentAndParameters renderWhen(SearchedCaseModel.SearchedWhenCondition whenCondition) { + private FragmentAndParameters renderWhen(SearchedCaseWhenCondition whenCondition) { SearchedCaseWhenConditionRenderer renderer = new SearchedCaseWhenConditionRenderer.Builder(whenCondition) .withRenderingContext(renderingContext) .build(); @@ -70,7 +71,7 @@ private FragmentAndParameters renderWhen(SearchedCaseModel.SearchedWhenCondition .orElseThrow(() -> new InvalidSqlException(Messages.getString("ERROR.39"))); //$NON-NLS-1$ } - private FragmentAndParameters renderThen(SearchedCaseModel.SearchedWhenCondition whenCondition) { + private FragmentAndParameters renderThen(SearchedCaseWhenCondition whenCondition) { return whenCondition.thenValue().render(renderingContext).mapFragment(f -> "then " + f); } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/SearchedCaseWhenConditionRenderer.java b/src/main/java/org/mybatis/dynamic/sql/select/render/SearchedCaseWhenConditionRenderer.java index cb487b2d4..8c59e7574 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/render/SearchedCaseWhenConditionRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/render/SearchedCaseWhenConditionRenderer.java @@ -16,17 +16,17 @@ package org.mybatis.dynamic.sql.select.render; import org.mybatis.dynamic.sql.common.AbstractBooleanExpressionRenderer; -import org.mybatis.dynamic.sql.select.caseexpression.SearchedCaseModel.SearchedWhenCondition; +import org.mybatis.dynamic.sql.select.caseexpression.SearchedCaseWhenCondition; -public class SearchedCaseWhenConditionRenderer extends AbstractBooleanExpressionRenderer { +public class SearchedCaseWhenConditionRenderer extends AbstractBooleanExpressionRenderer { protected SearchedCaseWhenConditionRenderer(Builder builder) { super("when", builder); } public static class Builder - extends AbstractBooleanExpressionRenderer.AbstractBuilder { + extends AbstractBooleanExpressionRenderer.AbstractBuilder { - protected Builder(SearchedWhenCondition model) { + protected Builder(SearchedCaseWhenCondition model) { super(model); } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/AbstractWhereFinisher.java b/src/main/java/org/mybatis/dynamic/sql/where/AbstractWhereFinisher.java index dd501d315..e4358a185 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/AbstractWhereFinisher.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/AbstractWhereFinisher.java @@ -49,6 +49,10 @@ public T configureStatement(Consumer consumer) { } protected WhereModel buildModel() { - return new WhereModel(getInitialCriterion(), subCriteria, statementConfiguration); + return new WhereModel.Builder() + .withInitialCriterion(getInitialCriterion()) + .withSubCriteria(subCriteria) + .withStatementConfiguration(statementConfiguration) + .build(); } } 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 2d216cec9..dd7551a81 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/WhereModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/WhereModel.java @@ -15,12 +15,9 @@ */ package org.mybatis.dynamic.sql.where; -import java.util.List; import java.util.Objects; import java.util.Optional; -import org.mybatis.dynamic.sql.AndOrCriteriaGroup; -import org.mybatis.dynamic.sql.SqlCriterion; import org.mybatis.dynamic.sql.common.AbstractBooleanExpressionModel; import org.mybatis.dynamic.sql.configuration.StatementConfiguration; import org.mybatis.dynamic.sql.render.RenderingContext; @@ -33,10 +30,9 @@ public class WhereModel extends AbstractBooleanExpressionModel { private final StatementConfiguration statementConfiguration; - public WhereModel(SqlCriterion initialCriterion, List subCriteria, - StatementConfiguration statementConfiguration) { - super(initialCriterion, subCriteria); - this.statementConfiguration = Objects.requireNonNull(statementConfiguration); + private WhereModel(Builder builder) { + super(builder); + statementConfiguration = Objects.requireNonNull(builder.statementConfiguration); } public boolean isNonRenderingClauseAllowed() { @@ -100,4 +96,22 @@ private WhereClauseProvider toWhereClauseProvider(FragmentAndParameters fragment .withParameters(fragmentAndParameters.parameters()) .build(); } + + public static class Builder extends AbstractBuilder { + private StatementConfiguration statementConfiguration; + + public Builder withStatementConfiguration(StatementConfiguration statementConfiguration) { + this.statementConfiguration = statementConfiguration; + return this; + } + + public WhereModel build() { + return new WhereModel(this); + } + + @Override + protected Builder getThis() { + return this; + } + } } 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 e3f244f8e..98653f434 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 @@ -19,7 +19,7 @@ import org.mybatis.dynamic.sql.BasicColumn import org.mybatis.dynamic.sql.VisitableCondition import org.mybatis.dynamic.sql.select.caseexpression.BasicWhenCondition import org.mybatis.dynamic.sql.select.caseexpression.ConditionBasedWhenCondition -import org.mybatis.dynamic.sql.select.caseexpression.SearchedCaseModel.SearchedWhenCondition +import org.mybatis.dynamic.sql.select.caseexpression.SearchedCaseWhenCondition import org.mybatis.dynamic.sql.select.caseexpression.SimpleCaseWhenCondition import org.mybatis.dynamic.sql.util.kotlin.GroupingCriteriaCollector import org.mybatis.dynamic.sql.util.kotlin.assertNull @@ -30,12 +30,16 @@ class KSearchedCaseDSL : KElseDSL { assertNull(field, "ERROR.42") //$NON-NLS-1$ field = value } - internal val whenConditions = mutableListOf() + internal val whenConditions = mutableListOf() - fun `when`(dslCompleter: SearchedCaseCriteriaCollector.() -> Unit) { - val dsl = SearchedCaseCriteriaCollector().apply(dslCompleter) - whenConditions.add(SearchedWhenCondition(dsl.initialCriterion, dsl.subCriteria, dsl.thenValue)) - } + fun `when`(dslCompleter: SearchedCaseCriteriaCollector.() -> Unit) = + SearchedCaseCriteriaCollector().apply(dslCompleter).run { + whenConditions.add(SearchedCaseWhenCondition.Builder().withInitialCriterion(initialCriterion) + .withSubCriteria(subCriteria) + .withThenValue(thenValue) + .build()) + + } override fun `else`(column: BasicColumn) { this.elseValue = column From daf0cb36aacf31c26b1f47cb738c2042b42b0f74 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Tue, 19 Mar 2024 11:15:47 -0400 Subject: [PATCH 02/22] Move constructor to start of class --- .../mybatis/dynamic/sql/where/AbstractWhereFinisher.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/where/AbstractWhereFinisher.java b/src/main/java/org/mybatis/dynamic/sql/where/AbstractWhereFinisher.java index e4358a185..d37087758 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/AbstractWhereFinisher.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/AbstractWhereFinisher.java @@ -29,6 +29,10 @@ public abstract class AbstractWhereFinisher> implements ConfigurableStatement { private final StatementConfiguration statementConfiguration; + protected AbstractWhereFinisher(StatementConfiguration statementConfiguration) { + this.statementConfiguration = Objects.requireNonNull(statementConfiguration); + } + void initialize(SqlCriterion sqlCriterion) { setInitialCriterion(sqlCriterion, StatementType.WHERE); } @@ -38,10 +42,6 @@ void initialize(SqlCriterion sqlCriterion, List subCriteria) super.subCriteria.addAll(subCriteria); } - protected AbstractWhereFinisher(StatementConfiguration statementConfiguration) { - this.statementConfiguration = Objects.requireNonNull(statementConfiguration); - } - @Override public T configureStatement(Consumer consumer) { consumer.accept(statementConfiguration); From 60d31141d84aeef666ffca68fe58b24a1418cda7 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Tue, 19 Mar 2024 11:16:50 -0400 Subject: [PATCH 03/22] Propagate statement configuration for delete --- .../org/mybatis/dynamic/sql/common/CommonBuilder.java | 11 +++++++++++ .../org/mybatis/dynamic/sql/delete/DeleteDSL.java | 1 + .../org/mybatis/dynamic/sql/delete/DeleteModel.java | 4 ++++ .../dynamic/sql/delete/render/DeleteRenderer.java | 9 +++++++++ 4 files changed, 25 insertions(+) diff --git a/src/main/java/org/mybatis/dynamic/sql/common/CommonBuilder.java b/src/main/java/org/mybatis/dynamic/sql/common/CommonBuilder.java index a9cfb1fa4..198e86f8a 100644 --- a/src/main/java/org/mybatis/dynamic/sql/common/CommonBuilder.java +++ b/src/main/java/org/mybatis/dynamic/sql/common/CommonBuilder.java @@ -16,6 +16,7 @@ package org.mybatis.dynamic.sql.common; import org.mybatis.dynamic.sql.SqlTable; +import org.mybatis.dynamic.sql.configuration.StatementConfiguration; import org.mybatis.dynamic.sql.where.WhereModel; /** @@ -29,6 +30,7 @@ public abstract class CommonBuilder> { private WhereModel whereModel; private Long limit; private OrderByModel orderByModel; + private StatementConfiguration statementConfiguration; public SqlTable table() { return table; @@ -50,6 +52,10 @@ public OrderByModel orderByModel() { return orderByModel; } + public StatementConfiguration statementConfiguration() { + return statementConfiguration; + } + public T withTable(SqlTable table) { this.table = table; return getThis(); @@ -75,5 +81,10 @@ public T withOrderByModel(OrderByModel orderByModel) { return getThis(); } + public T withStatementConfiguration(StatementConfiguration statementConfiguration) { + this.statementConfiguration = statementConfiguration; + return getThis(); + } + protected abstract T getThis(); } 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 1e17235cb..a3d418c22 100644 --- a/src/main/java/org/mybatis/dynamic/sql/delete/DeleteDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/delete/DeleteDSL.java @@ -83,6 +83,7 @@ public R build() { .withLimit(limit) .withOrderByModel(orderByModel) .withWhereModel(whereBuilder == null ? null : whereBuilder.buildWhereModel()) + .withStatementConfiguration(statementConfiguration) .build(); return adapterFunction.apply(deleteModel); 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 dc9e61d8e..1a5b0070e 100644 --- a/src/main/java/org/mybatis/dynamic/sql/delete/DeleteModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/delete/DeleteModel.java @@ -22,6 +22,7 @@ import org.mybatis.dynamic.sql.SqlTable; 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.RenderingStrategy; @@ -33,6 +34,7 @@ public class DeleteModel { private final WhereModel whereModel; private final Long limit; private final OrderByModel orderByModel; + private final StatementConfiguration statementConfiguration; private DeleteModel(Builder builder) { table = Objects.requireNonNull(builder.table()); @@ -40,6 +42,7 @@ private DeleteModel(Builder builder) { tableAlias = builder.tableAlias(); limit = builder.limit(); orderByModel = builder.orderByModel(); + statementConfiguration = Objects.requireNonNull(builder.statementConfiguration()); } public SqlTable table() { @@ -66,6 +69,7 @@ public Optional orderByModel() { public DeleteStatementProvider render(RenderingStrategy renderingStrategy) { return DeleteRenderer.withDeleteModel(this) .withRenderingStrategy(renderingStrategy) + .withStatementConfiguration(statementConfiguration) .build() .render(); } 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 d95464f1b..460f80cd0 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,6 +21,7 @@ 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; @@ -41,6 +42,8 @@ private DeleteRenderer(Builder builder) { TableAliasCalculator tableAliasCalculator = builder.deleteModel.tableAlias() .map(a -> ExplicitTableAliasCalculator.of(deleteModel.table(), a)) .orElseGet(TableAliasCalculator::empty); + // TODO - Add configuration to RenderingContext + Objects.requireNonNull(builder.statementConfiguration); renderingContext = RenderingContext .withRenderingStrategy(Objects.requireNonNull(builder.renderingStrategy)) .withTableAliasCalculator(tableAliasCalculator) @@ -108,6 +111,7 @@ 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; @@ -119,6 +123,11 @@ public Builder withRenderingStrategy(RenderingStrategy renderingStrategy) { return this; } + public Builder withStatementConfiguration(StatementConfiguration statementConfiguration) { + this.statementConfiguration = statementConfiguration; + return this; + } + public DeleteRenderer build() { return new DeleteRenderer(this); } From a8c9d72de3666529b7b2bc6b1e7f41152bfed0b6 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Tue, 19 Mar 2024 11:21:03 -0400 Subject: [PATCH 04/22] Propagate statement configuration for update --- .../java/org/mybatis/dynamic/sql/update/UpdateDSL.java | 1 + .../java/org/mybatis/dynamic/sql/update/UpdateModel.java | 4 ++++ .../dynamic/sql/update/render/UpdateRenderer.java | 9 +++++++++ 3 files changed, 14 insertions(+) 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 55ddc6eff..2ac386465 100644 --- a/src/main/java/org/mybatis/dynamic/sql/update/UpdateDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/update/UpdateDSL.java @@ -104,6 +104,7 @@ public R build() { .withLimit(limit) .withOrderByModel(orderByModel) .withWhereModel(whereBuilder == null ? null : whereBuilder.buildWhereModel()) + .withStatementConfiguration(statementConfiguration) .build(); return adapterFunction.apply(updateModel); 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 5267375d7..3e06c069a 100644 --- a/src/main/java/org/mybatis/dynamic/sql/update/UpdateModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/update/UpdateModel.java @@ -26,6 +26,7 @@ import org.mybatis.dynamic.sql.SqlTable; 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.RenderingStrategy; import org.mybatis.dynamic.sql.update.render.UpdateRenderer; import org.mybatis.dynamic.sql.update.render.UpdateStatementProvider; @@ -40,6 +41,7 @@ public class UpdateModel { private final List columnMappings; private final Long limit; private final OrderByModel orderByModel; + private final StatementConfiguration statementConfiguration; private UpdateModel(Builder builder) { table = Objects.requireNonNull(builder.table()); @@ -49,6 +51,7 @@ private UpdateModel(Builder builder) { limit = builder.limit(); orderByModel = builder.orderByModel(); Validator.assertNotEmpty(columnMappings, "ERROR.17"); //$NON-NLS-1$ + statementConfiguration = Objects.requireNonNull(builder.statementConfiguration()); } public SqlTable table() { @@ -79,6 +82,7 @@ public Optional orderByModel() { public UpdateStatementProvider render(RenderingStrategy renderingStrategy) { return UpdateRenderer.withUpdateModel(this) .withRenderingStrategy(renderingStrategy) + .withStatementConfiguration(statementConfiguration) .build() .render(); } 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 faecffce3..23bde89ba 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,6 +22,7 @@ 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; @@ -43,6 +44,8 @@ private UpdateRenderer(Builder builder) { TableAliasCalculator tableAliasCalculator = builder.updateModel.tableAlias() .map(a -> ExplicitTableAliasCalculator.of(updateModel.table(), a)) .orElseGet(TableAliasCalculator::empty); + // TODO - Add configuration to RenderingContext + Objects.requireNonNull(builder.statementConfiguration); renderingContext = RenderingContext .withRenderingStrategy(Objects.requireNonNull(builder.renderingStrategy)) .withTableAliasCalculator(tableAliasCalculator) @@ -134,6 +137,7 @@ 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; @@ -145,6 +149,11 @@ 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 ff4c34b0f441a270c3a0f2b9fc563dcb5ef0575b Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Tue, 19 Mar 2024 14:00:38 -0400 Subject: [PATCH 05/22] Centralize SQL String Constant Formatting --- src/main/java/org/mybatis/dynamic/sql/StringConstant.java | 4 ++-- .../sql/insert/render/GeneralInsertValuePhraseVisitor.java | 3 ++- .../sql/insert/render/MultiRowValuePhraseVisitor.java | 3 ++- .../dynamic/sql/insert/render/ValuePhraseVisitor.java | 3 ++- .../mybatis/dynamic/sql/update/render/SetPhraseVisitor.java | 6 +++--- .../java/org/mybatis/dynamic/sql/util/StringUtilities.java | 6 ++++++ 6 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/StringConstant.java b/src/main/java/org/mybatis/dynamic/sql/StringConstant.java index ca38ed1da..bced8b446 100644 --- a/src/main/java/org/mybatis/dynamic/sql/StringConstant.java +++ b/src/main/java/org/mybatis/dynamic/sql/StringConstant.java @@ -20,6 +20,7 @@ import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.util.FragmentAndParameters; +import org.mybatis.dynamic.sql.util.StringUtilities; public class StringConstant implements BindableColumn { @@ -42,8 +43,7 @@ public Optional alias() { @Override public FragmentAndParameters render(RenderingContext renderingContext) { - String escaped = value.replace("'", "''"); //$NON-NLS-1$ //$NON-NLS-2$ - return FragmentAndParameters.fromFragment("'" + escaped + "'"); //$NON-NLS-1$ //$NON-NLS-2$ + return FragmentAndParameters.fromFragment(StringUtilities.formatConstantForSQL(value)); } @Override diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/render/GeneralInsertValuePhraseVisitor.java b/src/main/java/org/mybatis/dynamic/sql/insert/render/GeneralInsertValuePhraseVisitor.java index 5f7613cf5..49b239f77 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/render/GeneralInsertValuePhraseVisitor.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/render/GeneralInsertValuePhraseVisitor.java @@ -25,6 +25,7 @@ import org.mybatis.dynamic.sql.util.GeneralInsertMappingVisitor; import org.mybatis.dynamic.sql.util.NullMapping; import org.mybatis.dynamic.sql.util.StringConstantMapping; +import org.mybatis.dynamic.sql.util.StringUtilities; import org.mybatis.dynamic.sql.util.ValueMapping; import org.mybatis.dynamic.sql.util.ValueOrNullMapping; import org.mybatis.dynamic.sql.util.ValueWhenPresentMapping; @@ -52,7 +53,7 @@ public Optional visit(ConstantMapping mapping) { @Override public Optional visit(StringConstantMapping mapping) { return FieldAndValueAndParameters.withFieldName(mapping.columnName()) - .withValuePhrase("'" + mapping.constant() + "'") //$NON-NLS-1$ //$NON-NLS-2$ + .withValuePhrase(StringUtilities.formatConstantForSQL(mapping.constant())) .buildOptional(); } diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/render/MultiRowValuePhraseVisitor.java b/src/main/java/org/mybatis/dynamic/sql/insert/render/MultiRowValuePhraseVisitor.java index 1271a395a..89bf63319 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/render/MultiRowValuePhraseVisitor.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/render/MultiRowValuePhraseVisitor.java @@ -23,6 +23,7 @@ import org.mybatis.dynamic.sql.util.PropertyMapping; import org.mybatis.dynamic.sql.util.RowMapping; import org.mybatis.dynamic.sql.util.StringConstantMapping; +import org.mybatis.dynamic.sql.util.StringUtilities; public class MultiRowValuePhraseVisitor extends MultiRowInsertMappingVisitor { protected final RenderingStrategy renderingStrategy; @@ -50,7 +51,7 @@ public FieldAndValueAndParameters visit(ConstantMapping mapping) { @Override public FieldAndValueAndParameters visit(StringConstantMapping mapping) { return FieldAndValueAndParameters.withFieldName(mapping.columnName()) - .withValuePhrase("'" + mapping.constant() + "'") //$NON-NLS-1$ //$NON-NLS-2$ + .withValuePhrase(StringUtilities.formatConstantForSQL(mapping.constant())) .build(); } diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/render/ValuePhraseVisitor.java b/src/main/java/org/mybatis/dynamic/sql/insert/render/ValuePhraseVisitor.java index d4aceadca..d85b88759 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/render/ValuePhraseVisitor.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/render/ValuePhraseVisitor.java @@ -26,6 +26,7 @@ import org.mybatis.dynamic.sql.util.PropertyWhenPresentMapping; import org.mybatis.dynamic.sql.util.RowMapping; import org.mybatis.dynamic.sql.util.StringConstantMapping; +import org.mybatis.dynamic.sql.util.StringUtilities; public class ValuePhraseVisitor extends InsertMappingVisitor> { @@ -52,7 +53,7 @@ public Optional visit(ConstantMapping mapping) { @Override public Optional visit(StringConstantMapping mapping) { return FieldAndValueAndParameters.withFieldName(mapping.columnName()) - .withValuePhrase("'" + mapping.constant() + "'") //$NON-NLS-1$ //$NON-NLS-2$ + .withValuePhrase(StringUtilities.formatConstantForSQL(mapping.constant())) .buildOptional(); } 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 2334df0b8..eef6e134f 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 @@ -29,6 +29,7 @@ import org.mybatis.dynamic.sql.util.NullMapping; import org.mybatis.dynamic.sql.util.SelectMapping; import org.mybatis.dynamic.sql.util.StringConstantMapping; +import org.mybatis.dynamic.sql.util.StringUtilities; import org.mybatis.dynamic.sql.util.UpdateMappingVisitor; import org.mybatis.dynamic.sql.util.ValueMapping; import org.mybatis.dynamic.sql.util.ValueOrNullMapping; @@ -58,9 +59,8 @@ public Optional visit(ConstantMapping mapping) { @Override public Optional visit(StringConstantMapping mapping) { String fragment = mapping.mapColumn(renderingContext::aliasedColumnName) - + " = '" //$NON-NLS-1$ - + mapping.constant() - + "'"; //$NON-NLS-1$ + + " = " //$NON-NLS-1$ + + StringUtilities.formatConstantForSQL(mapping.constant()); return FragmentAndParameters.withFragment(fragment) .buildOptional(); 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 0606c0e7c..3ef16be5e 100644 --- a/src/main/java/org/mybatis/dynamic/sql/util/StringUtilities.java +++ b/src/main/java/org/mybatis/dynamic/sql/util/StringUtilities.java @@ -52,4 +52,10 @@ static String toCamelCase(String inputString) { return sb.toString(); } + + static String formatConstantForSQL(String in) { + String escaped = in.replace("'", "''"); //$NON-NLS-1$ //$NON-NLS-2$ + return "'" + escaped + "'"; //$NON-NLS-1$ //$NON-NLS-2$ + + } } From 44bc7d9682f8444e97d235fd5672d6f1aa7cd3f1 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Sun, 24 Mar 2024 17:18:43 -0400 Subject: [PATCH 06/22] Share statement configuration across a full select statement This shares the configuration among all query expressions so that union queries will have the same configuration --- .../org/mybatis/dynamic/sql/select/QueryExpressionDSL.java | 7 +++---- .../java/org/mybatis/dynamic/sql/select/SelectDSL.java | 3 ++- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionDSL.java b/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionDSL.java index 4cf0ed56b..e2ce1cbc9 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionDSL.java @@ -50,7 +50,6 @@ public class QueryExpressionDSL private final List selectList; private QueryExpressionWhereBuilder whereBuilder; private GroupByModel groupByModel; - private final StatementConfiguration statementConfiguration = new StatementConfiguration(); private QueryExpressionHavingBuilder havingBuilder; protected QueryExpressionDSL(FromGatherer fromGatherer, TableExpression table) { @@ -75,7 +74,7 @@ public QueryExpressionWhereBuilder where() { @Override public QueryExpressionDSL configureStatement(Consumer consumer) { - consumer.accept(statementConfiguration); + selectDSL.configureStatement(consumer); return this; } @@ -276,7 +275,7 @@ public FromGatherer build() { public class QueryExpressionWhereBuilder extends AbstractWhereFinisher implements Buildable { private QueryExpressionWhereBuilder() { - super(statementConfiguration); + super(selectDSL.statementConfiguration); } public UnionBuilder union() { @@ -394,7 +393,7 @@ public R build() { @Override public JoinSpecificationFinisher configureStatement(Consumer consumer) { - consumer.accept(statementConfiguration); + selectDSL.configureStatement(consumer); return this; } 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 7ba76a432..e0e80cc78 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/SelectDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/SelectDSL.java @@ -50,6 +50,7 @@ public class SelectDSL implements Buildable, ConfigurableStatement adapterFunction) { this.adapterFunction = Objects.requireNonNull(adapterFunction); @@ -124,7 +125,7 @@ public FetchFirstFinisher fetchFirst(long fetchFirstRows) { @Override public SelectDSL configureStatement(Consumer consumer) { - queryExpressions.forEach(q -> q.configureStatement(consumer)); + consumer.accept(statementConfiguration); return this; } From c9c7f9e2c47cd14dac602008d3abfd306195b74d Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Sun, 24 Mar 2024 17:39:49 -0400 Subject: [PATCH 07/22] Standardize sub-query rendering --- .../org/mybatis/dynamic/sql/select/SelectModel.java | 11 +++++++++++ .../sql/select/render/MultiSelectRenderer.java | 10 ++-------- .../sql/select/render/TableExpressionRenderer.java | 6 +----- .../dynamic/sql/update/render/SetPhraseVisitor.java | 7 +------ .../dynamic/sql/where/render/CriterionRenderer.java | 7 +------ .../sql/where/render/DefaultConditionVisitor.java | 5 +---- 6 files changed, 17 insertions(+), 29 deletions(-) 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 653431622..fdee98a63 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/SelectModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/SelectModel.java @@ -57,6 +57,17 @@ public Optional pagingModel() { @NotNull public SelectStatementProvider render(RenderingStrategy renderingStrategy) { RenderingContext renderingContext = RenderingContext.withRenderingStrategy(renderingStrategy).build(); + return render(renderingContext); + } + + /** + * This version is for rendering sub-queries, union queries, etc. + * + * @param renderingContext the rendering context + * @return a rendered select statement and parameters + */ + @NotNull + public SelectStatementProvider render(RenderingContext renderingContext) { return SelectRenderer.withSelectModel(this) .withRenderingContext(renderingContext) .build() 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 c20a41d0e..cd97d8659 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 @@ -62,10 +62,7 @@ private SelectStatementProvider toSelectStatementProvider(FragmentCollector frag } private FragmentAndParameters renderSelect(SelectModel selectModel) { - SelectStatementProvider selectStatement = SelectRenderer.withSelectModel(selectModel) - .withRenderingContext(renderingContext) - .build() - .render(); + SelectStatementProvider selectStatement = selectModel.render(renderingContext); return FragmentAndParameters .withFragment("(" + selectStatement.getSelectStatement() + ")") //$NON-NLS-1$ //$NON-NLS-2$ @@ -74,10 +71,7 @@ private FragmentAndParameters renderSelect(SelectModel selectModel) { } private FragmentAndParameters renderSelect(UnionQuery unionQuery) { - SelectStatementProvider selectStatement = SelectRenderer.withSelectModel(unionQuery.selectModel()) - .withRenderingContext(renderingContext) - .build() - .render(); + SelectStatementProvider selectStatement = unionQuery.selectModel().render(renderingContext); return FragmentAndParameters.withFragment( unionQuery.connector() + " (" + selectStatement.getSelectStatement() + ")") //$NON-NLS-1$ //$NON-NLS-2$ 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 8bdb5a937..ccb9b1d84 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,11 +39,7 @@ public FragmentAndParameters visit(SqlTable table) { @Override public FragmentAndParameters visit(SubQuery subQuery) { - SelectStatementProvider selectStatement = new SelectRenderer.Builder() - .withSelectModel(subQuery.selectModel()) - .withRenderingContext(renderingContext) - .build() - .render(); + SelectStatementProvider selectStatement = subQuery.selectModel().render(renderingContext); String fragment = "(" + selectStatement.getSelectStatement() + ")"; //$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 eef6e134f..a48f1ae1b 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.SelectRenderer; import org.mybatis.dynamic.sql.select.render.SelectStatementProvider; import org.mybatis.dynamic.sql.util.AbstractColumnMapping; import org.mybatis.dynamic.sql.util.ColumnToColumnMapping; @@ -85,11 +84,7 @@ public Optional visit(ValueWhenPresentMapping mapp @Override public Optional visit(SelectMapping mapping) { - SelectStatementProvider selectStatement = SelectRenderer.withSelectModel(mapping.selectModel()) - .withRenderingContext(renderingContext) - .build() - .render(); - + SelectStatementProvider selectStatement = mapping.selectModel().render(renderingContext); String fragment = mapping.mapColumn(renderingContext::aliasedColumnName) + " = (" //$NON-NLS-1$ + selectStatement.getSelectStatement() 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 4be08cc2d..6e3e13254 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.SelectRenderer; import org.mybatis.dynamic.sql.select.render.SelectStatementProvider; import org.mybatis.dynamic.sql.util.FragmentAndParameters; import org.mybatis.dynamic.sql.util.FragmentCollector; @@ -121,11 +120,7 @@ private Optional renderColumnAndCondition(ColumnAndCo private FragmentAndParameters renderExists(ExistsCriterion criterion) { ExistsPredicate existsPredicate = criterion.existsPredicate(); - SelectStatementProvider selectStatement = SelectRenderer - .withSelectModel(existsPredicate.selectModelBuilder().build()) - .withRenderingContext(renderingContext) - .build() - .render(); + SelectStatementProvider selectStatement = existsPredicate.selectModelBuilder().build().render(renderingContext); String fragment = existsPredicate.operator() + " (" //$NON-NLS-1$ 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 63ded9299..ed8be89bb 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,10 +94,7 @@ public FragmentAndParameters visit(AbstractTwoValueCondition condition) { @Override public FragmentAndParameters visit(AbstractSubselectCondition condition) { - SelectStatementProvider selectStatement = SelectRenderer.withSelectModel(condition.selectModel()) - .withRenderingContext(renderingContext) - .build() - .render(); + SelectStatementProvider selectStatement = condition.selectModel().render(renderingContext); String finalFragment = condition.operator() + " (" //$NON-NLS-1$ From 164dd36399776aba8e33bd1317bfab97c1973cf0 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Sun, 24 Mar 2024 17:40:17 -0400 Subject: [PATCH 08/22] Standardize sub-query rendering --- .../dynamic/sql/where/render/DefaultConditionVisitor.java | 1 - 1 file changed, 1 deletion(-) 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 ed8be89bb..d9cb35283 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.SelectRenderer; import org.mybatis.dynamic.sql.select.render.SelectStatementProvider; import org.mybatis.dynamic.sql.util.FragmentAndParameters; import org.mybatis.dynamic.sql.util.FragmentCollector; From 5e87f08940fb6514422c3f3c14c01ab62a6d8c6c Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Sun, 24 Mar 2024 17:46:35 -0400 Subject: [PATCH 09/22] Add statement configuration to select model --- .../java/org/mybatis/dynamic/sql/select/CountDSL.java | 1 + .../java/org/mybatis/dynamic/sql/select/SelectDSL.java | 1 + .../java/org/mybatis/dynamic/sql/select/SelectModel.java | 9 +++++++++ 3 files changed, 11 insertions(+) diff --git a/src/main/java/org/mybatis/dynamic/sql/select/CountDSL.java b/src/main/java/org/mybatis/dynamic/sql/select/CountDSL.java index fcdee35c3..f49c778d2 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/CountDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/CountDSL.java @@ -81,6 +81,7 @@ private SelectModel buildModel() { return new SelectModel.Builder() .withQueryExpression(queryExpressionModel) + .withStatementConfiguration(statementConfiguration) .build(); } 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 e0e80cc78..a509e974b 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/SelectDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/SelectDSL.java @@ -135,6 +135,7 @@ public R build() { SelectModel selectModel = SelectModel.withQueryExpressions(buildModels()) .withOrderByModel(orderByModel) .withPagingModel(buildPagingModel().orElse(null)) + .withStatementConfiguration(statementConfiguration) .build(); return adapterFunction.apply(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 fdee98a63..ef3ef8de1 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/SelectModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/SelectModel.java @@ -24,6 +24,7 @@ import org.jetbrains.annotations.NotNull; import org.mybatis.dynamic.sql.common.OrderByModel; +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.render.SelectRenderer; @@ -34,12 +35,14 @@ public class SelectModel { private final List queryExpressions; private final OrderByModel orderByModel; private final PagingModel pagingModel; + private final StatementConfiguration statementConfiguration; private SelectModel(Builder builder) { queryExpressions = Objects.requireNonNull(builder.queryExpressions); Validator.assertNotEmpty(queryExpressions, "ERROR.14"); //$NON-NLS-1$ orderByModel = builder.orderByModel; pagingModel = builder.pagingModel; + statementConfiguration = Objects.requireNonNull(builder.statementConfiguration); } public Stream mapQueryExpressions(Function mapper) { @@ -82,6 +85,7 @@ public static class Builder { private final List queryExpressions = new ArrayList<>(); private OrderByModel orderByModel; private PagingModel pagingModel; + private StatementConfiguration statementConfiguration; public Builder withQueryExpression(QueryExpressionModel queryExpression) { this.queryExpressions.add(queryExpression); @@ -103,6 +107,11 @@ public Builder withPagingModel(PagingModel pagingModel) { return this; } + public Builder withStatementConfiguration(StatementConfiguration statementConfiguration) { + this.statementConfiguration = statementConfiguration; + return this; + } + public SelectModel build() { return new SelectModel(this); } From 35183af4e00890dc4b13350df8684262285d7a6f Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 25 Mar 2024 09:30:49 -0400 Subject: [PATCH 10/22] Consolidate rendering of where model --- .../dynamic/sql/delete/render/DeleteRenderer.java | 6 +----- .../sql/select/render/QueryExpressionRenderer.java | 6 +----- .../dynamic/sql/update/render/UpdateRenderer.java | 6 +----- .../org/mybatis/dynamic/sql/where/WhereModel.java | 13 ++++++------- 4 files changed, 9 insertions(+), 22 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 460f80cd0..b7625e076 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 @@ -31,7 +31,6 @@ import org.mybatis.dynamic.sql.util.FragmentAndParameters; import org.mybatis.dynamic.sql.util.FragmentCollector; import org.mybatis.dynamic.sql.where.WhereModel; -import org.mybatis.dynamic.sql.where.render.WhereRenderer; public class DeleteRenderer { private final DeleteModel deleteModel; @@ -78,10 +77,7 @@ private Optional calculateWhereClause() { } private Optional renderWhereClause(WhereModel whereModel) { - return WhereRenderer.withWhereModel(whereModel) - .withRenderingContext(renderingContext) - .build() - .render(); + return whereModel.render(renderingContext); } private Optional calculateLimitClause() { 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 dd52e64a4..19ca9b027 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 @@ -33,7 +33,6 @@ import org.mybatis.dynamic.sql.util.FragmentCollector; import org.mybatis.dynamic.sql.util.StringUtilities; import org.mybatis.dynamic.sql.where.WhereModel; -import org.mybatis.dynamic.sql.where.render.WhereRenderer; public class QueryExpressionRenderer { private final QueryExpressionModel queryExpression; @@ -168,10 +167,7 @@ private Optional calculateWhereClause() { } private Optional renderWhereClause(WhereModel whereModel) { - return WhereRenderer.withWhereModel(whereModel) - .withRenderingContext(renderingContext) - .build() - .render(); + return whereModel.render(renderingContext); } private Optional calculateGroupByClause() { 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 23bde89ba..1000d1acb 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 @@ -33,7 +33,6 @@ import org.mybatis.dynamic.sql.util.FragmentCollector; import org.mybatis.dynamic.sql.util.Validator; import org.mybatis.dynamic.sql.where.WhereModel; -import org.mybatis.dynamic.sql.where.render.WhereRenderer; public class UpdateRenderer { private final UpdateModel updateModel; @@ -104,10 +103,7 @@ private Optional calculateWhereClause() { } private Optional renderWhereClause(WhereModel whereModel) { - return WhereRenderer.withWhereModel(whereModel) - .withRenderingContext(renderingContext) - .build() - .render(); + return whereModel.render(renderingContext); } private Optional calculateLimitClause() { 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 dd7551a81..c45cf25ba 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/WhereModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/WhereModel.java @@ -50,7 +50,7 @@ public boolean isNonRenderingClauseAllowed() { public Optional render(RenderingStrategy renderingStrategy) { RenderingContext renderingContext = RenderingContext.withRenderingStrategy(renderingStrategy).build(); - return render(renderingContext); + return render(renderingContext).map(this::toWhereClauseProvider); } public Optional render(RenderingStrategy renderingStrategy, @@ -60,7 +60,7 @@ public Optional render(RenderingStrategy renderingStrategy, .withTableAliasCalculator(tableAliasCalculator) .build(); - return render(renderingContext); + return render(renderingContext).map(this::toWhereClauseProvider); } public Optional render(RenderingStrategy renderingStrategy, String parameterName) { @@ -69,7 +69,7 @@ public Optional render(RenderingStrategy renderingStrategy, .withParameterName(parameterName) .build(); - return render(renderingContext); + return render(renderingContext).map(this::toWhereClauseProvider); } public Optional render(RenderingStrategy renderingStrategy, @@ -80,15 +80,14 @@ public Optional render(RenderingStrategy renderingStrategy, .withParameterName(parameterName) .build(); - return render(renderingContext); + return render(renderingContext).map(this::toWhereClauseProvider); } - private Optional render(RenderingContext renderingContext) { + public Optional render(RenderingContext renderingContext) { return WhereRenderer.withWhereModel(this) .withRenderingContext(renderingContext) .build() - .render() - .map(this::toWhereClauseProvider); + .render(); } private WhereClauseProvider toWhereClauseProvider(FragmentAndParameters fragmentAndParameters) { From 7adfcd0425910e0900141ffb4fdbdbc7cdaf1b46 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 25 Mar 2024 10:19:29 -0400 Subject: [PATCH 11/22] Add StatementConfiguration to RenderingContext --- .../dynamic/sql/delete/render/DeleteRenderer.java | 3 +-- .../dynamic/sql/insert/GeneralInsertDSL.java | 13 ++++++++++++- .../dynamic/sql/insert/GeneralInsertModel.java | 10 ++++++++++ .../sql/insert/render/GeneralInsertRenderer.java | 15 +++++++++++---- .../dynamic/sql/render/RenderingContext.java | 10 ++++++++++ .../dynamic/sql/select/MultiSelectDSL.java | 13 ++++++++++++- .../dynamic/sql/select/MultiSelectModel.java | 10 ++++++++++ .../mybatis/dynamic/sql/select/SelectModel.java | 4 +++- .../sql/select/render/MultiSelectRenderer.java | 10 +++++++++- .../dynamic/sql/update/render/UpdateRenderer.java | 3 +-- .../org/mybatis/dynamic/sql/where/WhereModel.java | 6 +++++- .../org/mybatis/dynamic/sql/InvalidSQLTest.java | 2 ++ .../sql/mybatis3/CriterionRendererTest.java | 7 ++++++- .../dynamic/sql/select/HavingModelTest.java | 2 ++ .../sql/where/render/CriterionRendererTest.java | 3 +++ 15 files changed, 97 insertions(+), 14 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 b7625e076..42ab803d1 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 @@ -41,11 +41,10 @@ private DeleteRenderer(Builder builder) { TableAliasCalculator tableAliasCalculator = builder.deleteModel.tableAlias() .map(a -> ExplicitTableAliasCalculator.of(deleteModel.table(), a)) .orElseGet(TableAliasCalculator::empty); - // TODO - Add configuration to RenderingContext - Objects.requireNonNull(builder.statementConfiguration); renderingContext = RenderingContext .withRenderingStrategy(Objects.requireNonNull(builder.renderingStrategy)) .withTableAliasCalculator(tableAliasCalculator) + .withStatementConfiguration(builder.statementConfiguration) .build(); } diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/GeneralInsertDSL.java b/src/main/java/org/mybatis/dynamic/sql/insert/GeneralInsertDSL.java index 20bd60357..079835fe3 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/GeneralInsertDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/GeneralInsertDSL.java @@ -19,13 +19,16 @@ import java.util.Collection; import java.util.List; import java.util.Objects; +import java.util.function.Consumer; import java.util.function.Supplier; import org.jetbrains.annotations.NotNull; import org.mybatis.dynamic.sql.SqlColumn; import org.mybatis.dynamic.sql.SqlTable; +import org.mybatis.dynamic.sql.configuration.StatementConfiguration; import org.mybatis.dynamic.sql.util.AbstractColumnMapping; import org.mybatis.dynamic.sql.util.Buildable; +import org.mybatis.dynamic.sql.util.ConfigurableStatement; import org.mybatis.dynamic.sql.util.ConstantMapping; import org.mybatis.dynamic.sql.util.NullMapping; import org.mybatis.dynamic.sql.util.StringConstantMapping; @@ -33,9 +36,10 @@ import org.mybatis.dynamic.sql.util.ValueOrNullMapping; import org.mybatis.dynamic.sql.util.ValueWhenPresentMapping; -public class GeneralInsertDSL implements Buildable { +public class GeneralInsertDSL implements Buildable, ConfigurableStatement { private final List columnMappings; private final SqlTable table; + private final StatementConfiguration statementConfiguration = new StatementConfiguration(); private GeneralInsertDSL(Builder builder) { table = Objects.requireNonNull(builder.table); @@ -52,6 +56,7 @@ public GeneralInsertModel build() { return new GeneralInsertModel.Builder() .withTable(table) .withInsertMappings(columnMappings) + .withStatementConfiguration(statementConfiguration) .build(); } @@ -59,6 +64,12 @@ public static GeneralInsertDSL insertInto(SqlTable table) { return new GeneralInsertDSL.Builder().withTable(table).build(); } + @Override + public GeneralInsertDSL configureStatement(Consumer consumer) { + consumer.accept(statementConfiguration); + return this; + } + public class SetClauseFinisher { private final SqlColumn column; 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 7657ac64b..f29b0a926 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/GeneralInsertModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/GeneralInsertModel.java @@ -23,6 +23,7 @@ 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.RenderingStrategy; @@ -33,11 +34,13 @@ public class GeneralInsertModel { private final SqlTable table; private final List insertMappings; + private final StatementConfiguration statementConfiguration; private GeneralInsertModel(Builder builder) { table = Objects.requireNonNull(builder.table); Validator.assertNotEmpty(builder.insertMappings, "ERROR.6"); //$NON-NLS-1$ insertMappings = builder.insertMappings; + statementConfiguration = Objects.requireNonNull(builder.statementConfiguration); } public Stream mapColumnMappings(Function mapper) { @@ -52,6 +55,7 @@ public SqlTable table() { public GeneralInsertStatementProvider render(RenderingStrategy renderingStrategy) { return GeneralInsertRenderer.withInsertModel(this) .withRenderingStrategy(renderingStrategy) + .withStatementConfiguration(statementConfiguration) .build() .render(); } @@ -59,6 +63,7 @@ public GeneralInsertStatementProvider render(RenderingStrategy renderingStrategy public static class Builder { private SqlTable table; private final List insertMappings = new ArrayList<>(); + private StatementConfiguration statementConfiguration; public Builder withTable(SqlTable table) { this.table = table; @@ -70,6 +75,11 @@ public Builder withInsertMappings(List insertMa return this; } + public Builder withStatementConfiguration(StatementConfiguration statementConfiguration) { + this.statementConfiguration = statementConfiguration; + return this; + } + public GeneralInsertModel build() { return new GeneralInsertModel(this); } 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 cfdb01e43..5a42d9422 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,6 +18,7 @@ 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; @@ -26,16 +27,16 @@ public class GeneralInsertRenderer { private final GeneralInsertModel model; - private final RenderingStrategy renderingStrategy; + private final RenderingContext renderingContext; private GeneralInsertRenderer(Builder builder) { model = Objects.requireNonNull(builder.model); - renderingStrategy = Objects.requireNonNull(builder.renderingStrategy); + renderingContext = RenderingContext.withRenderingStrategy(builder.renderingStrategy) + .withStatementConfiguration(builder.statementConfiguration) + .build(); } public GeneralInsertStatementProvider render() { - RenderingContext renderingContext = RenderingContext.withRenderingStrategy(renderingStrategy).build(); - GeneralInsertValuePhraseVisitor visitor = new GeneralInsertValuePhraseVisitor(renderingContext); FieldAndValueCollector collector = model.mapColumnMappings(m -> m.accept(visitor)) .filter(Optional::isPresent) @@ -58,6 +59,7 @@ 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; @@ -69,6 +71,11 @@ 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/render/RenderingContext.java b/src/main/java/org/mybatis/dynamic/sql/render/RenderingContext.java index a2e863ebc..daaa1aefb 100644 --- a/src/main/java/org/mybatis/dynamic/sql/render/RenderingContext.java +++ b/src/main/java/org/mybatis/dynamic/sql/render/RenderingContext.java @@ -23,6 +23,7 @@ import org.mybatis.dynamic.sql.BindableColumn; import org.mybatis.dynamic.sql.SqlColumn; import org.mybatis.dynamic.sql.SqlTable; +import org.mybatis.dynamic.sql.configuration.StatementConfiguration; /** * This class encapsulates all the supporting items related to rendering, and contains many utility methods @@ -38,11 +39,13 @@ public class RenderingContext { private final TableAliasCalculator tableAliasCalculator; private final String configuredParameterName; private final String calculatedParameterName; + private final StatementConfiguration statementConfiguration; private RenderingContext(Builder builder) { renderingStrategy = Objects.requireNonNull(builder.renderingStrategy); configuredParameterName = builder.parameterName; tableAliasCalculator = Objects.requireNonNull(builder.tableAliasCalculator); + statementConfiguration = Objects.requireNonNull(builder.statementConfiguration); // reasonable defaults sequence = builder.sequence == null ? new AtomicInteger(1) : builder.sequence; @@ -114,6 +117,7 @@ public RenderingContext withChildTableAliasCalculator(TableAliasCalculator child .withSequence(this.sequence) .withParameterName(this.configuredParameterName) .withTableAliasCalculator(tac) + .withStatementConfiguration(statementConfiguration) .build(); } @@ -126,6 +130,7 @@ public static class Builder { private AtomicInteger sequence; private TableAliasCalculator tableAliasCalculator = TableAliasCalculator.empty(); private String parameterName; + private StatementConfiguration statementConfiguration; public Builder withRenderingStrategy(RenderingStrategy renderingStrategy) { this.renderingStrategy = renderingStrategy; @@ -147,6 +152,11 @@ public Builder withParameterName(String parameterName) { return this; } + public Builder withStatementConfiguration(StatementConfiguration statementConfiguration) { + this.statementConfiguration = statementConfiguration; + return this; + } + public RenderingContext build() { return new RenderingContext(this); } 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 2524ae591..0dce5c2d1 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/MultiSelectDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/MultiSelectDSL.java @@ -20,19 +20,23 @@ import java.util.Collection; import java.util.List; import java.util.Optional; +import java.util.function.Consumer; import org.jetbrains.annotations.NotNull; import org.mybatis.dynamic.sql.SortSpecification; import org.mybatis.dynamic.sql.common.OrderByModel; +import org.mybatis.dynamic.sql.configuration.StatementConfiguration; import org.mybatis.dynamic.sql.util.Buildable; +import org.mybatis.dynamic.sql.util.ConfigurableStatement; -public class MultiSelectDSL implements Buildable { +public class MultiSelectDSL implements Buildable, ConfigurableStatement { private final List unionQueries = new ArrayList<>(); private final SelectModel initialSelect; private OrderByModel orderByModel; private Long limit; private Long offset; private Long fetchFirstRows; + private StatementConfiguration statementConfiguration = new StatementConfiguration(); public MultiSelectDSL(Buildable builder) { initialSelect = builder.build(); @@ -80,6 +84,7 @@ public MultiSelectModel build() { .withUnionQueries(unionQueries) .withOrderByModel(orderByModel) .withPagingModel(buildPagingModel().orElse(null)) + .withStatementConfiguration(statementConfiguration) .build(); } @@ -91,6 +96,12 @@ private Optional buildPagingModel() { .build(); } + @Override + public MultiSelectDSL configureStatement(Consumer consumer) { + consumer.accept(statementConfiguration); + return this; + } + public class LimitFinisher implements Buildable { public OffsetFinisher offset(long offset) { MultiSelectDSL.this.offset(offset); 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 87b2e54a2..10317a335 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/MultiSelectModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/MultiSelectModel.java @@ -24,6 +24,7 @@ import org.jetbrains.annotations.NotNull; import org.mybatis.dynamic.sql.common.OrderByModel; +import org.mybatis.dynamic.sql.configuration.StatementConfiguration; import org.mybatis.dynamic.sql.render.RenderingStrategy; import org.mybatis.dynamic.sql.select.render.MultiSelectRenderer; import org.mybatis.dynamic.sql.select.render.SelectStatementProvider; @@ -34,12 +35,14 @@ public class MultiSelectModel { private final List unionQueries; private final OrderByModel orderByModel; private final PagingModel pagingModel; + private final StatementConfiguration statementConfiguration; private MultiSelectModel(Builder builder) { initialSelect = Objects.requireNonNull(builder.initialSelect); unionQueries = builder.unionQueries; orderByModel = builder.orderByModel; pagingModel = builder.pagingModel; + statementConfiguration = Objects.requireNonNull(builder.statementConfiguration); Validator.assertNotEmpty(unionQueries, "ERROR.35"); //$NON-NLS-1$ } @@ -64,6 +67,7 @@ public SelectStatementProvider render(RenderingStrategy renderingStrategy) { return new MultiSelectRenderer.Builder() .withMultiSelectModel(this) .withRenderingStrategy(renderingStrategy) + .withStatementConfiguration(statementConfiguration) .build() .render(); } @@ -73,6 +77,7 @@ public static class Builder { private final List unionQueries = new ArrayList<>(); private OrderByModel orderByModel; private PagingModel pagingModel; + private StatementConfiguration statementConfiguration; public Builder withInitialSelect(SelectModel initialSelect) { this.initialSelect = initialSelect; @@ -94,6 +99,11 @@ public Builder withPagingModel(PagingModel pagingModel) { return this; } + public Builder withStatementConfiguration(StatementConfiguration statementConfiguration) { + this.statementConfiguration = statementConfiguration; + return this; + } + public MultiSelectModel build() { return new MultiSelectModel(this); } 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 ef3ef8de1..44044c4ff 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/SelectModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/SelectModel.java @@ -59,7 +59,9 @@ public Optional pagingModel() { @NotNull public SelectStatementProvider render(RenderingStrategy renderingStrategy) { - RenderingContext renderingContext = RenderingContext.withRenderingStrategy(renderingStrategy).build(); + RenderingContext renderingContext = RenderingContext.withRenderingStrategy(renderingStrategy) + .withStatementConfiguration(statementConfiguration) + .build(); return 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 cd97d8659..4d064822d 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.configuration.StatementConfiguration; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.render.RenderingStrategy; import org.mybatis.dynamic.sql.select.MultiSelectModel; @@ -36,7 +37,8 @@ public class MultiSelectRenderer { private MultiSelectRenderer(Builder builder) { renderingContext = RenderingContext - .withRenderingStrategy(Objects.requireNonNull(builder.renderingStrategy)) + .withRenderingStrategy(builder.renderingStrategy) + .withStatementConfiguration(builder.statementConfiguration) .build(); multiSelectModel = Objects.requireNonNull(builder.multiSelectModel); } @@ -102,6 +104,7 @@ 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; @@ -113,6 +116,11 @@ 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/render/UpdateRenderer.java b/src/main/java/org/mybatis/dynamic/sql/update/render/UpdateRenderer.java index 1000d1acb..bcc376d4c 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 @@ -43,11 +43,10 @@ private UpdateRenderer(Builder builder) { TableAliasCalculator tableAliasCalculator = builder.updateModel.tableAlias() .map(a -> ExplicitTableAliasCalculator.of(updateModel.table(), a)) .orElseGet(TableAliasCalculator::empty); - // TODO - Add configuration to RenderingContext - Objects.requireNonNull(builder.statementConfiguration); renderingContext = RenderingContext .withRenderingStrategy(Objects.requireNonNull(builder.renderingStrategy)) .withTableAliasCalculator(tableAliasCalculator) + .withStatementConfiguration(builder.statementConfiguration) .build(); } 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 c45cf25ba..052a3b8b1 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/WhereModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/WhereModel.java @@ -48,7 +48,8 @@ public boolean isNonRenderingClauseAllowed() { * @return rendered where clause */ public Optional render(RenderingStrategy renderingStrategy) { - RenderingContext renderingContext = RenderingContext.withRenderingStrategy(renderingStrategy).build(); + RenderingContext renderingContext = RenderingContext.withRenderingStrategy(renderingStrategy) + .withStatementConfiguration(statementConfiguration).build(); return render(renderingContext).map(this::toWhereClauseProvider); } @@ -58,6 +59,7 @@ public Optional render(RenderingStrategy renderingStrategy, RenderingContext renderingContext = RenderingContext .withRenderingStrategy(renderingStrategy) .withTableAliasCalculator(tableAliasCalculator) + .withStatementConfiguration(statementConfiguration) .build(); return render(renderingContext).map(this::toWhereClauseProvider); @@ -67,6 +69,7 @@ public Optional render(RenderingStrategy renderingStrategy, RenderingContext renderingContext = RenderingContext .withRenderingStrategy(renderingStrategy) .withParameterName(parameterName) + .withStatementConfiguration(statementConfiguration) .build(); return render(renderingContext).map(this::toWhereClauseProvider); @@ -78,6 +81,7 @@ public Optional render(RenderingStrategy renderingStrategy, .withRenderingStrategy(renderingStrategy) .withTableAliasCalculator(tableAliasCalculator) .withParameterName(parameterName) + .withStatementConfiguration(statementConfiguration) .build(); return render(renderingContext).map(this::toWhereClauseProvider); diff --git a/src/test/java/org/mybatis/dynamic/sql/InvalidSQLTest.java b/src/test/java/org/mybatis/dynamic/sql/InvalidSQLTest.java index 22855da4b..c6113c842 100644 --- a/src/test/java/org/mybatis/dynamic/sql/InvalidSQLTest.java +++ b/src/test/java/org/mybatis/dynamic/sql/InvalidSQLTest.java @@ -31,6 +31,7 @@ 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; @@ -243,6 +244,7 @@ void testInvalidPagingModel() { RenderingContext renderingContext = RenderingContext .withRenderingStrategy(RenderingStrategies.MYBATIS3) + .withStatementConfiguration(new StatementConfiguration()) .build(); assertThat(pagingModel).isPresent(); diff --git a/src/test/java/org/mybatis/dynamic/sql/mybatis3/CriterionRendererTest.java b/src/test/java/org/mybatis/dynamic/sql/mybatis3/CriterionRendererTest.java index 29161000f..ef82f3322 100644 --- a/src/test/java/org/mybatis/dynamic/sql/mybatis3/CriterionRendererTest.java +++ b/src/test/java/org/mybatis/dynamic/sql/mybatis3/CriterionRendererTest.java @@ -27,6 +27,7 @@ import org.mybatis.dynamic.sql.SqlBuilder; import org.mybatis.dynamic.sql.SqlColumn; import org.mybatis.dynamic.sql.SqlTable; +import org.mybatis.dynamic.sql.configuration.StatementConfiguration; import org.mybatis.dynamic.sql.render.ExplicitTableAliasCalculator; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.render.RenderingStrategies; @@ -45,7 +46,8 @@ void testAliasWithIgnore() { .withCondition(condition) .build(); - RenderingContext renderingContext =RenderingContext.withRenderingStrategy(RenderingStrategies.MYBATIS3).build(); + RenderingContext renderingContext =RenderingContext.withRenderingStrategy(RenderingStrategies.MYBATIS3) + .withStatementConfiguration(new StatementConfiguration()).build(); CriterionRenderer renderer = new CriterionRenderer(renderingContext); @@ -70,6 +72,7 @@ void testAliasWithoutIgnore() { RenderingContext renderingContext = RenderingContext .withRenderingStrategy(RenderingStrategies.MYBATIS3) .withTableAliasCalculator(ExplicitTableAliasCalculator.of(tableAliases)) + .withStatementConfiguration(new StatementConfiguration()) .build(); CriterionRenderer renderer = new CriterionRenderer(renderingContext); @@ -97,6 +100,7 @@ void testTypeHandler() { RenderingContext renderingContext = RenderingContext .withRenderingStrategy(RenderingStrategies.MYBATIS3) + .withStatementConfiguration(new StatementConfiguration()) .build(); CriterionRenderer renderer = new CriterionRenderer(renderingContext); @@ -122,6 +126,7 @@ void testTypeHandlerAndAlias() { RenderingContext renderingContext = RenderingContext .withRenderingStrategy(RenderingStrategies.MYBATIS3) .withTableAliasCalculator(ExplicitTableAliasCalculator.of(tableAliases)) + .withStatementConfiguration(new StatementConfiguration()) .build(); CriterionRenderer renderer = new CriterionRenderer(renderingContext); diff --git a/src/test/java/org/mybatis/dynamic/sql/select/HavingModelTest.java b/src/test/java/org/mybatis/dynamic/sql/select/HavingModelTest.java index b56611341..47d015da2 100644 --- a/src/test/java/org/mybatis/dynamic/sql/select/HavingModelTest.java +++ b/src/test/java/org/mybatis/dynamic/sql/select/HavingModelTest.java @@ -24,6 +24,7 @@ import org.junit.jupiter.api.Test; import org.mybatis.dynamic.sql.SqlColumn; import org.mybatis.dynamic.sql.SqlTable; +import org.mybatis.dynamic.sql.configuration.StatementConfiguration; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.render.RenderingStrategies; import org.mybatis.dynamic.sql.select.render.HavingRenderer; @@ -65,6 +66,7 @@ void testComplexHaving() { private Optional renderHavingModel(HavingModel havingModel) { RenderingContext renderingContext = RenderingContext .withRenderingStrategy(RenderingStrategies.SPRING_NAMED_PARAMETER) + .withStatementConfiguration(new StatementConfiguration()) .build(); return HavingRenderer.withHavingModel(havingModel) diff --git a/src/test/java/org/mybatis/dynamic/sql/where/render/CriterionRendererTest.java b/src/test/java/org/mybatis/dynamic/sql/where/render/CriterionRendererTest.java index a706d3d7d..39d297fbd 100644 --- a/src/test/java/org/mybatis/dynamic/sql/where/render/CriterionRendererTest.java +++ b/src/test/java/org/mybatis/dynamic/sql/where/render/CriterionRendererTest.java @@ -26,6 +26,7 @@ import org.mybatis.dynamic.sql.ColumnAndConditionCriterion; import org.mybatis.dynamic.sql.SqlColumn; import org.mybatis.dynamic.sql.SqlTable; +import org.mybatis.dynamic.sql.configuration.StatementConfiguration; import org.mybatis.dynamic.sql.render.ExplicitTableAliasCalculator; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.render.RenderingStrategies; @@ -46,6 +47,7 @@ void testAliasWithIgnore() { RenderingContext renderingContext = RenderingContext .withRenderingStrategy(RenderingStrategies.MYBATIS3) + .withStatementConfiguration(new StatementConfiguration()) .build(); CriterionRenderer renderer = new CriterionRenderer(renderingContext); @@ -72,6 +74,7 @@ void testAliasWithoutIgnore() { RenderingContext renderingContext = RenderingContext .withRenderingStrategy(RenderingStrategies.MYBATIS3) .withTableAliasCalculator(ExplicitTableAliasCalculator.of(tableAliases)) + .withStatementConfiguration(new StatementConfiguration()) .build(); CriterionRenderer renderer = new CriterionRenderer(renderingContext); From 526b1b70012c8f036dc7ba865831730e631225c1 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 25 Mar 2024 10:20:22 -0400 Subject: [PATCH 12/22] Add StatementConfiguration to RenderingContext --- .../java/org/mybatis/dynamic/sql/select/MultiSelectDSL.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 0dce5c2d1..ad0f2aba3 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/MultiSelectDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/MultiSelectDSL.java @@ -36,7 +36,7 @@ public class MultiSelectDSL implements Buildable, Configurable private Long limit; private Long offset; private Long fetchFirstRows; - private StatementConfiguration statementConfiguration = new StatementConfiguration(); + private final StatementConfiguration statementConfiguration = new StatementConfiguration(); public MultiSelectDSL(Buildable builder) { initialSelect = builder.build(); From 97e22d26714adf62996a177d87a6e7066b771700 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 25 Mar 2024 10:28:20 -0400 Subject: [PATCH 13/22] Move non-rendering where check to RenderingContext --- .../dynamic/sql/common/AbstractBooleanExpressionRenderer.java | 4 +++- .../java/org/mybatis/dynamic/sql/render/RenderingContext.java | 4 ++++ src/main/java/org/mybatis/dynamic/sql/where/WhereModel.java | 4 ---- .../org/mybatis/dynamic/sql/where/render/WhereRenderer.java | 2 +- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/common/AbstractBooleanExpressionRenderer.java b/src/main/java/org/mybatis/dynamic/sql/common/AbstractBooleanExpressionRenderer.java index 8f2834e5e..e6f433e21 100644 --- a/src/main/java/org/mybatis/dynamic/sql/common/AbstractBooleanExpressionRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/common/AbstractBooleanExpressionRenderer.java @@ -32,11 +32,13 @@ public abstract class AbstractBooleanExpressionRenderer builder) { model = Objects.requireNonNull(builder.model); this.prefix = Objects.requireNonNull(prefix); - criterionRenderer = new CriterionRenderer(builder.renderingContext); + renderingContext = Objects.requireNonNull(builder.renderingContext); + criterionRenderer = new CriterionRenderer(renderingContext); } public Optional render() { 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 daaa1aefb..a23c8d07a 100644 --- a/src/main/java/org/mybatis/dynamic/sql/render/RenderingContext.java +++ b/src/main/java/org/mybatis/dynamic/sql/render/RenderingContext.java @@ -97,6 +97,10 @@ public String aliasedTableName(SqlTable table) { .orElseGet(table::tableNameAtRuntime); } + public boolean isNonRenderingClauseAllowed() { + return statementConfiguration.isNonRenderingWhereClauseAllowed(); + } + /** * Create a new rendering context based on this, with the table alias calculator modified to include the * specified child table alias calculator. This is used by the query expression renderer when the alias calculator 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 052a3b8b1..f865c3f07 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/WhereModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/WhereModel.java @@ -35,10 +35,6 @@ private WhereModel(Builder builder) { statementConfiguration = Objects.requireNonNull(builder.statementConfiguration); } - public boolean isNonRenderingClauseAllowed() { - return statementConfiguration.isNonRenderingWhereClauseAllowed(); - } - /** * Renders a where clause without table aliases. * diff --git a/src/main/java/org/mybatis/dynamic/sql/where/render/WhereRenderer.java b/src/main/java/org/mybatis/dynamic/sql/where/render/WhereRenderer.java index 03e8f7eb5..c44aac90b 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/render/WhereRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/render/WhereRenderer.java @@ -31,7 +31,7 @@ private WhereRenderer(Builder builder) { public Optional render() { Optional whereClause = super.render(); - if (whereClause.isPresent() || model.isNonRenderingClauseAllowed()) { + if (whereClause.isPresent() || renderingContext.isNonRenderingClauseAllowed()) { return whereClause; } else { throw new NonRenderingWhereClauseException(); From b30958cad2bf92319bf93e820d6eb51afe502e2f Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 25 Mar 2024 11:12:19 -0400 Subject: [PATCH 14/22] Simplify Boolean Expression Renderer --- .../common/AbstractBooleanExpressionRenderer.java | 12 ++++++------ .../dynamic/sql/select/render/HavingRenderer.java | 4 ++-- .../render/SearchedCaseWhenConditionRenderer.java | 4 ++-- .../dynamic/sql/where/render/WhereRenderer.java | 10 +++++----- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/common/AbstractBooleanExpressionRenderer.java b/src/main/java/org/mybatis/dynamic/sql/common/AbstractBooleanExpressionRenderer.java index e6f433e21..910e20bd3 100644 --- a/src/main/java/org/mybatis/dynamic/sql/common/AbstractBooleanExpressionRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/common/AbstractBooleanExpressionRenderer.java @@ -28,13 +28,13 @@ import org.mybatis.dynamic.sql.where.render.CriterionRenderer; import org.mybatis.dynamic.sql.where.render.RenderedCriterion; -public abstract class AbstractBooleanExpressionRenderer { - protected final M model; +public abstract class AbstractBooleanExpressionRenderer { + protected final AbstractBooleanExpressionModel model; private final String prefix; private final CriterionRenderer criterionRenderer; protected final RenderingContext renderingContext; - protected AbstractBooleanExpressionRenderer(String prefix, AbstractBuilder builder) { + protected AbstractBooleanExpressionRenderer(String prefix, AbstractBuilder builder) { model = Objects.requireNonNull(builder.model); this.prefix = Objects.requireNonNull(prefix); renderingContext = Objects.requireNonNull(builder.renderingContext); @@ -82,11 +82,11 @@ private String addPrefix(String fragment) { return spaceAfter(prefix) + fragment; } - public abstract static class AbstractBuilder> { - private final M model; + public abstract static class AbstractBuilder> { + private final AbstractBooleanExpressionModel model; private RenderingContext renderingContext; - protected AbstractBuilder(M model) { + protected AbstractBuilder(AbstractBooleanExpressionModel model) { this.model = model; } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/HavingRenderer.java b/src/main/java/org/mybatis/dynamic/sql/select/render/HavingRenderer.java index f99d48410..0c8292a9e 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/render/HavingRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/render/HavingRenderer.java @@ -18,7 +18,7 @@ import org.mybatis.dynamic.sql.common.AbstractBooleanExpressionRenderer; import org.mybatis.dynamic.sql.select.HavingModel; -public class HavingRenderer extends AbstractBooleanExpressionRenderer { +public class HavingRenderer extends AbstractBooleanExpressionRenderer { private HavingRenderer(Builder builder) { super("having", builder); //$NON-NLS-1$ } @@ -27,7 +27,7 @@ public static Builder withHavingModel(HavingModel havingModel) { return new Builder(havingModel); } - public static class Builder extends AbstractBuilder { + public static class Builder extends AbstractBuilder { public Builder(HavingModel havingModel) { super(havingModel); } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/SearchedCaseWhenConditionRenderer.java b/src/main/java/org/mybatis/dynamic/sql/select/render/SearchedCaseWhenConditionRenderer.java index 8c59e7574..b7d9bfff3 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/render/SearchedCaseWhenConditionRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/render/SearchedCaseWhenConditionRenderer.java @@ -18,13 +18,13 @@ import org.mybatis.dynamic.sql.common.AbstractBooleanExpressionRenderer; import org.mybatis.dynamic.sql.select.caseexpression.SearchedCaseWhenCondition; -public class SearchedCaseWhenConditionRenderer extends AbstractBooleanExpressionRenderer { +public class SearchedCaseWhenConditionRenderer extends AbstractBooleanExpressionRenderer { protected SearchedCaseWhenConditionRenderer(Builder builder) { super("when", builder); } public static class Builder - extends AbstractBooleanExpressionRenderer.AbstractBuilder { + extends AbstractBooleanExpressionRenderer.AbstractBuilder { protected Builder(SearchedCaseWhenCondition model) { super(model); diff --git a/src/main/java/org/mybatis/dynamic/sql/where/render/WhereRenderer.java b/src/main/java/org/mybatis/dynamic/sql/where/render/WhereRenderer.java index c44aac90b..244dcfa1b 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/render/WhereRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/render/WhereRenderer.java @@ -17,12 +17,12 @@ import java.util.Optional; +import org.mybatis.dynamic.sql.common.AbstractBooleanExpressionModel; import org.mybatis.dynamic.sql.common.AbstractBooleanExpressionRenderer; import org.mybatis.dynamic.sql.exception.NonRenderingWhereClauseException; import org.mybatis.dynamic.sql.util.FragmentAndParameters; -import org.mybatis.dynamic.sql.where.WhereModel; -public class WhereRenderer extends AbstractBooleanExpressionRenderer { +public class WhereRenderer extends AbstractBooleanExpressionRenderer { private WhereRenderer(Builder builder) { super("where", builder); //$NON-NLS-1$ } @@ -38,12 +38,12 @@ public Optional render() { } } - public static Builder withWhereModel(WhereModel whereModel) { + public static Builder withWhereModel(AbstractBooleanExpressionModel whereModel) { return new Builder(whereModel); } - public static class Builder extends AbstractBuilder { - public Builder(WhereModel whereModel) { + public static class Builder extends AbstractBuilder { + public Builder(AbstractBooleanExpressionModel whereModel) { super(whereModel); } From f385ba48707187fb2d626f774f6005be1efd1d01 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 25 Mar 2024 12:31:09 -0400 Subject: [PATCH 15/22] Implement embedded where clauses This separate the concept of a standalone where clause from a where clause that is a part of another statetment. --- .../dynamic/sql/common/CommonBuilder.java | 8 ++-- .../mybatis/dynamic/sql/delete/DeleteDSL.java | 6 +-- .../dynamic/sql/delete/DeleteModel.java | 6 +-- .../sql/delete/render/DeleteRenderer.java | 4 +- .../mybatis/dynamic/sql/select/CountDSL.java | 6 +-- .../sql/select/QueryExpressionDSL.java | 6 +-- .../sql/select/QueryExpressionModel.java | 10 ++-- .../render/QueryExpressionRenderer.java | 4 +- .../mybatis/dynamic/sql/update/UpdateDSL.java | 6 +-- .../dynamic/sql/update/UpdateModel.java | 6 +-- .../sql/update/render/UpdateRenderer.java | 4 +- .../sql/where/AbstractWhereFinisher.java | 13 +++-- .../dynamic/sql/where/EmbeddedWhereModel.java | 47 +++++++++++++++++++ .../mybatis/dynamic/sql/where/WhereDSL.java | 13 ++++- .../mybatis/dynamic/sql/where/WhereModel.java | 13 ++--- 15 files changed, 104 insertions(+), 48 deletions(-) create mode 100644 src/main/java/org/mybatis/dynamic/sql/where/EmbeddedWhereModel.java diff --git a/src/main/java/org/mybatis/dynamic/sql/common/CommonBuilder.java b/src/main/java/org/mybatis/dynamic/sql/common/CommonBuilder.java index 198e86f8a..f25457398 100644 --- a/src/main/java/org/mybatis/dynamic/sql/common/CommonBuilder.java +++ b/src/main/java/org/mybatis/dynamic/sql/common/CommonBuilder.java @@ -17,7 +17,7 @@ import org.mybatis.dynamic.sql.SqlTable; import org.mybatis.dynamic.sql.configuration.StatementConfiguration; -import org.mybatis.dynamic.sql.where.WhereModel; +import org.mybatis.dynamic.sql.where.EmbeddedWhereModel; /** * Builder class shared between the delete and update model builders. @@ -27,7 +27,7 @@ public abstract class CommonBuilder> { private SqlTable table; private String tableAlias; - private WhereModel whereModel; + private EmbeddedWhereModel whereModel; private Long limit; private OrderByModel orderByModel; private StatementConfiguration statementConfiguration; @@ -40,7 +40,7 @@ public String tableAlias() { return tableAlias; } - public WhereModel whereModel() { + public EmbeddedWhereModel whereModel() { return whereModel; } @@ -66,7 +66,7 @@ public T withTableAlias(String tableAlias) { return getThis(); } - public T withWhereModel(WhereModel whereModel) { + public T withWhereModel(EmbeddedWhereModel whereModel) { this.whereModel = whereModel; return getThis(); } 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 a3d418c22..e7c1ad184 100644 --- a/src/main/java/org/mybatis/dynamic/sql/delete/DeleteDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/delete/DeleteDSL.java @@ -30,7 +30,7 @@ import org.mybatis.dynamic.sql.util.Utilities; import org.mybatis.dynamic.sql.where.AbstractWhereFinisher; import org.mybatis.dynamic.sql.where.AbstractWhereStarter; -import org.mybatis.dynamic.sql.where.WhereModel; +import org.mybatis.dynamic.sql.where.EmbeddedWhereModel; public class DeleteDSL extends AbstractWhereStarter.DeleteWhereBuilder, DeleteDSL> implements Buildable { @@ -111,7 +111,7 @@ public static DeleteDSL deleteFrom(SqlTable table, String tableAlia public class DeleteWhereBuilder extends AbstractWhereFinisher implements Buildable { private DeleteWhereBuilder() { - super(statementConfiguration); + super(DeleteDSL.this); } public DeleteDSL limit(long limit) { @@ -138,7 +138,7 @@ protected DeleteWhereBuilder getThis() { return this; } - protected WhereModel buildWhereModel() { + protected EmbeddedWhereModel buildWhereModel() { return buildModel(); } } 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 1a5b0070e..54770d5d4 100644 --- a/src/main/java/org/mybatis/dynamic/sql/delete/DeleteModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/delete/DeleteModel.java @@ -26,12 +26,12 @@ import org.mybatis.dynamic.sql.delete.render.DeleteRenderer; import org.mybatis.dynamic.sql.delete.render.DeleteStatementProvider; import org.mybatis.dynamic.sql.render.RenderingStrategy; -import org.mybatis.dynamic.sql.where.WhereModel; +import org.mybatis.dynamic.sql.where.EmbeddedWhereModel; public class DeleteModel { private final SqlTable table; private final String tableAlias; - private final WhereModel whereModel; + private final EmbeddedWhereModel whereModel; private final Long limit; private final OrderByModel orderByModel; private final StatementConfiguration statementConfiguration; @@ -53,7 +53,7 @@ public Optional tableAlias() { return Optional.ofNullable(tableAlias); } - public Optional whereModel() { + public Optional whereModel() { return Optional.ofNullable(whereModel); } 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 42ab803d1..ce46c4c10 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 @@ -30,7 +30,7 @@ import org.mybatis.dynamic.sql.render.TableAliasCalculator; import org.mybatis.dynamic.sql.util.FragmentAndParameters; import org.mybatis.dynamic.sql.util.FragmentCollector; -import org.mybatis.dynamic.sql.where.WhereModel; +import org.mybatis.dynamic.sql.where.EmbeddedWhereModel; public class DeleteRenderer { private final DeleteModel deleteModel; @@ -75,7 +75,7 @@ private Optional calculateWhereClause() { return deleteModel.whereModel().flatMap(this::renderWhereClause); } - private Optional renderWhereClause(WhereModel whereModel) { + private Optional renderWhereClause(EmbeddedWhereModel whereModel) { return whereModel.render(renderingContext); } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/CountDSL.java b/src/main/java/org/mybatis/dynamic/sql/select/CountDSL.java index f49c778d2..a684bae66 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/CountDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/CountDSL.java @@ -27,7 +27,7 @@ import org.mybatis.dynamic.sql.util.Buildable; import org.mybatis.dynamic.sql.util.Utilities; import org.mybatis.dynamic.sql.where.AbstractWhereFinisher; -import org.mybatis.dynamic.sql.where.WhereModel; +import org.mybatis.dynamic.sql.where.EmbeddedWhereModel; /** * DSL for building count queries. Count queries are specializations of select queries. They have joins and where @@ -131,7 +131,7 @@ public CountDSL from(SqlTable table) { public class CountWhereBuilder extends AbstractWhereFinisher implements Buildable { private CountWhereBuilder() { - super(statementConfiguration); + super(CountDSL.this); } @NotNull @@ -145,7 +145,7 @@ protected CountWhereBuilder getThis() { return this; } - protected WhereModel buildWhereModel() { + protected EmbeddedWhereModel buildWhereModel() { return super.buildModel(); } } 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 e2ce1cbc9..593252979 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionDSL.java @@ -38,7 +38,7 @@ import org.mybatis.dynamic.sql.util.Utilities; import org.mybatis.dynamic.sql.where.AbstractWhereFinisher; import org.mybatis.dynamic.sql.where.AbstractWhereStarter; -import org.mybatis.dynamic.sql.where.WhereModel; +import org.mybatis.dynamic.sql.where.EmbeddedWhereModel; public class QueryExpressionDSL extends AbstractQueryExpressionDSL.QueryExpressionWhereBuilder, QueryExpressionDSL> @@ -275,7 +275,7 @@ public FromGatherer build() { public class QueryExpressionWhereBuilder extends AbstractWhereFinisher implements Buildable { private QueryExpressionWhereBuilder() { - super(selectDSL.statementConfiguration); + super(QueryExpressionDSL.this); } public UnionBuilder union() { @@ -325,7 +325,7 @@ protected QueryExpressionWhereBuilder getThis() { return this; } - protected WhereModel buildWhereModel() { + protected EmbeddedWhereModel buildWhereModel() { return super.buildModel(); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionModel.java b/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionModel.java index 6855afb1a..f6a67c04b 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionModel.java @@ -29,7 +29,7 @@ import org.mybatis.dynamic.sql.TableExpression; import org.mybatis.dynamic.sql.select.join.JoinModel; import org.mybatis.dynamic.sql.util.Validator; -import org.mybatis.dynamic.sql.where.WhereModel; +import org.mybatis.dynamic.sql.where.EmbeddedWhereModel; public class QueryExpressionModel { private final String connector; @@ -38,7 +38,7 @@ public class QueryExpressionModel { private final TableExpression table; private final JoinModel joinModel; private final Map tableAliases; - private final WhereModel whereModel; + private final EmbeddedWhereModel whereModel; private final GroupByModel groupByModel; private final HavingModel havingModel; @@ -75,7 +75,7 @@ public Map tableAliases() { return tableAliases; } - public Optional whereModel() { + public Optional whereModel() { return Optional.ofNullable(whereModel); } @@ -101,7 +101,7 @@ public static class Builder { private final List selectList = new ArrayList<>(); private TableExpression table; private final Map tableAliases = new HashMap<>(); - private WhereModel whereModel; + private EmbeddedWhereModel whereModel; private JoinModel joinModel; private GroupByModel groupByModel; private HavingModel havingModel; @@ -136,7 +136,7 @@ public Builder withTableAliases(Map tableAliases) { return this; } - public Builder withWhereModel(WhereModel whereModel) { + public Builder withWhereModel(EmbeddedWhereModel whereModel) { this.whereModel = whereModel; return this; } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/QueryExpressionRenderer.java b/src/main/java/org/mybatis/dynamic/sql/select/render/QueryExpressionRenderer.java index 19ca9b027..b5d6a69ce 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 @@ -32,7 +32,7 @@ import org.mybatis.dynamic.sql.util.FragmentAndParameters; import org.mybatis.dynamic.sql.util.FragmentCollector; import org.mybatis.dynamic.sql.util.StringUtilities; -import org.mybatis.dynamic.sql.where.WhereModel; +import org.mybatis.dynamic.sql.where.EmbeddedWhereModel; public class QueryExpressionRenderer { private final QueryExpressionModel queryExpression; @@ -166,7 +166,7 @@ private Optional calculateWhereClause() { return queryExpression.whereModel().flatMap(this::renderWhereClause); } - private Optional renderWhereClause(WhereModel whereModel) { + private Optional renderWhereClause(EmbeddedWhereModel whereModel) { return whereModel.render(renderingContext); } 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 2ac386465..8cf7259a3 100644 --- a/src/main/java/org/mybatis/dynamic/sql/update/UpdateDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/update/UpdateDSL.java @@ -45,7 +45,7 @@ import org.mybatis.dynamic.sql.util.ValueWhenPresentMapping; import org.mybatis.dynamic.sql.where.AbstractWhereFinisher; import org.mybatis.dynamic.sql.where.AbstractWhereStarter; -import org.mybatis.dynamic.sql.where.WhereModel; +import org.mybatis.dynamic.sql.where.EmbeddedWhereModel; public class UpdateDSL extends AbstractWhereStarter.UpdateWhereBuilder, UpdateDSL> implements Buildable { @@ -192,7 +192,7 @@ public UpdateDSL equalToWhenPresent(Supplier valueSupplier) { public class UpdateWhereBuilder extends AbstractWhereFinisher implements Buildable { private UpdateWhereBuilder() { - super(statementConfiguration); + super(UpdateDSL.this); } public UpdateDSL limit(long limit) { @@ -219,7 +219,7 @@ protected UpdateWhereBuilder getThis() { return this; } - protected WhereModel buildWhereModel() { + protected EmbeddedWhereModel buildWhereModel() { return buildModel(); } } 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 3e06c069a..a6d23adff 100644 --- a/src/main/java/org/mybatis/dynamic/sql/update/UpdateModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/update/UpdateModel.java @@ -32,12 +32,12 @@ import org.mybatis.dynamic.sql.update.render.UpdateStatementProvider; import org.mybatis.dynamic.sql.util.AbstractColumnMapping; import org.mybatis.dynamic.sql.util.Validator; -import org.mybatis.dynamic.sql.where.WhereModel; +import org.mybatis.dynamic.sql.where.EmbeddedWhereModel; public class UpdateModel { private final SqlTable table; private final String tableAlias; - private final WhereModel whereModel; + private final EmbeddedWhereModel whereModel; private final List columnMappings; private final Long limit; private final OrderByModel orderByModel; @@ -62,7 +62,7 @@ public Optional tableAlias() { return Optional.ofNullable(tableAlias); } - public Optional whereModel() { + public Optional whereModel() { return Optional.ofNullable(whereModel); } 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 bcc376d4c..3c9c5d73e 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 @@ -32,7 +32,7 @@ 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.WhereModel; +import org.mybatis.dynamic.sql.where.EmbeddedWhereModel; public class UpdateRenderer { private final UpdateModel updateModel; @@ -101,7 +101,7 @@ private Optional calculateWhereClause() { return updateModel.whereModel().flatMap(this::renderWhereClause); } - private Optional renderWhereClause(WhereModel whereModel) { + private Optional renderWhereClause(EmbeddedWhereModel whereModel) { return whereModel.render(renderingContext); } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/AbstractWhereFinisher.java b/src/main/java/org/mybatis/dynamic/sql/where/AbstractWhereFinisher.java index d37087758..edad1cccc 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/AbstractWhereFinisher.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/AbstractWhereFinisher.java @@ -27,10 +27,10 @@ public abstract class AbstractWhereFinisher> extends AbstractBooleanExpressionDSL implements ConfigurableStatement { - private final StatementConfiguration statementConfiguration; + private final ConfigurableStatement parentStatement; - protected AbstractWhereFinisher(StatementConfiguration statementConfiguration) { - this.statementConfiguration = Objects.requireNonNull(statementConfiguration); + protected AbstractWhereFinisher(ConfigurableStatement parentStatement) { + this.parentStatement = Objects.requireNonNull(parentStatement); } void initialize(SqlCriterion sqlCriterion) { @@ -44,15 +44,14 @@ void initialize(SqlCriterion sqlCriterion, List subCriteria) @Override public T configureStatement(Consumer consumer) { - consumer.accept(statementConfiguration); + parentStatement.configureStatement(consumer); return getThis(); } - protected WhereModel buildModel() { - return new WhereModel.Builder() + protected EmbeddedWhereModel buildModel() { + return new EmbeddedWhereModel.Builder() .withInitialCriterion(getInitialCriterion()) .withSubCriteria(subCriteria) - .withStatementConfiguration(statementConfiguration) .build(); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/EmbeddedWhereModel.java b/src/main/java/org/mybatis/dynamic/sql/where/EmbeddedWhereModel.java new file mode 100644 index 000000000..6c52750a0 --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/where/EmbeddedWhereModel.java @@ -0,0 +1,47 @@ +/* + * 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; + +import org.mybatis.dynamic.sql.common.AbstractBooleanExpressionModel; +import org.mybatis.dynamic.sql.render.RenderingContext; +import org.mybatis.dynamic.sql.util.FragmentAndParameters; +import org.mybatis.dynamic.sql.where.render.WhereRenderer; + +import java.util.Optional; + +public class EmbeddedWhereModel extends AbstractBooleanExpressionModel { + private EmbeddedWhereModel(Builder builder) { + super(builder); + } + + public Optional render(RenderingContext renderingContext) { + return WhereRenderer.withWhereModel(this) + .withRenderingContext(renderingContext) + .build() + .render(); + } + + public static class Builder extends AbstractBuilder { + public EmbeddedWhereModel build() { + return new EmbeddedWhereModel(this); + } + + @Override + protected Builder getThis() { + return this; + } + } +} 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 00082056f..80c8f60d9 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/WhereDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/WhereDSL.java @@ -21,6 +21,11 @@ import org.mybatis.dynamic.sql.configuration.StatementConfiguration; import org.mybatis.dynamic.sql.util.Buildable; +/** + * DSL for standalone where clauses. + * + * This can also be used to create reusable where clauses for different statements. + */ public class WhereDSL extends AbstractWhereStarter { private final StatementConfiguration statementConfiguration = new StatementConfiguration(); private final StandaloneWhereFinisher whereBuilder = new StandaloneWhereFinisher(); @@ -39,7 +44,7 @@ public WhereDSL configureStatement(Consumer consumer) { public class StandaloneWhereFinisher extends AbstractWhereFinisher implements Buildable { private StandaloneWhereFinisher() { - super(statementConfiguration); + super(WhereDSL.this); } @Override @@ -50,7 +55,11 @@ protected StandaloneWhereFinisher getThis() { @NotNull @Override public WhereModel build() { - return buildModel(); + return new WhereModel.Builder() + .withInitialCriterion(getInitialCriterion()) + .withSubCriteria(subCriteria) + .withStatementConfiguration(statementConfiguration) + .build(); } public WhereApplier toWhereApplier() { 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 f865c3f07..8db761223 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/WhereModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/WhereModel.java @@ -47,7 +47,7 @@ public Optional render(RenderingStrategy renderingStrategy) RenderingContext renderingContext = RenderingContext.withRenderingStrategy(renderingStrategy) .withStatementConfiguration(statementConfiguration).build(); - return render(renderingContext).map(this::toWhereClauseProvider); + return render(renderingContext); } public Optional render(RenderingStrategy renderingStrategy, @@ -58,7 +58,7 @@ public Optional render(RenderingStrategy renderingStrategy, .withStatementConfiguration(statementConfiguration) .build(); - return render(renderingContext).map(this::toWhereClauseProvider); + return render(renderingContext); } public Optional render(RenderingStrategy renderingStrategy, String parameterName) { @@ -68,7 +68,7 @@ public Optional render(RenderingStrategy renderingStrategy, .withStatementConfiguration(statementConfiguration) .build(); - return render(renderingContext).map(this::toWhereClauseProvider); + return render(renderingContext); } public Optional render(RenderingStrategy renderingStrategy, @@ -80,14 +80,15 @@ public Optional render(RenderingStrategy renderingStrategy, .withStatementConfiguration(statementConfiguration) .build(); - return render(renderingContext).map(this::toWhereClauseProvider); + return render(renderingContext); } - public Optional render(RenderingContext renderingContext) { + private Optional render(RenderingContext renderingContext) { return WhereRenderer.withWhereModel(this) .withRenderingContext(renderingContext) .build() - .render(); + .render() + .map(this::toWhereClauseProvider); } private WhereClauseProvider toWhereClauseProvider(FragmentAndParameters fragmentAndParameters) { From f8b80bbb73170e2a130e0c2cd278637295affab3 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 25 Mar 2024 12:31:44 -0400 Subject: [PATCH 16/22] Checkstyle --- src/main/java/org/mybatis/dynamic/sql/where/WhereDSL.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 80c8f60d9..0eb23f638 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/WhereDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/WhereDSL.java @@ -24,7 +24,7 @@ /** * DSL for standalone where clauses. * - * This can also be used to create reusable where clauses for different statements. + *

This can also be used to create reusable where clauses for different statements. */ public class WhereDSL extends AbstractWhereStarter { private final StatementConfiguration statementConfiguration = new StatementConfiguration(); From 17dcd4979310f1f5f303dbfd6f2584460ec8d026 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 25 Mar 2024 12:33:02 -0400 Subject: [PATCH 17/22] Checkstyle --- .../org/mybatis/dynamic/sql/where/EmbeddedWhereModel.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/where/EmbeddedWhereModel.java b/src/main/java/org/mybatis/dynamic/sql/where/EmbeddedWhereModel.java index 6c52750a0..acede2590 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/EmbeddedWhereModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/EmbeddedWhereModel.java @@ -15,13 +15,13 @@ */ package org.mybatis.dynamic.sql.where; +import java.util.Optional; + import org.mybatis.dynamic.sql.common.AbstractBooleanExpressionModel; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.util.FragmentAndParameters; import org.mybatis.dynamic.sql.where.render.WhereRenderer; -import java.util.Optional; - public class EmbeddedWhereModel extends AbstractBooleanExpressionModel { private EmbeddedWhereModel(Builder builder) { super(builder); From 129fbc45ce6e7b6cc0751ef3a9d2151f04f54ba9 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 25 Mar 2024 13:11:40 -0400 Subject: [PATCH 18/22] GeneralInsert is not configurable yet --- .../dynamic/sql/insert/GeneralInsertDSL.java | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/GeneralInsertDSL.java b/src/main/java/org/mybatis/dynamic/sql/insert/GeneralInsertDSL.java index 079835fe3..f36fd6544 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/GeneralInsertDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/GeneralInsertDSL.java @@ -19,7 +19,6 @@ import java.util.Collection; import java.util.List; import java.util.Objects; -import java.util.function.Consumer; import java.util.function.Supplier; import org.jetbrains.annotations.NotNull; @@ -28,7 +27,6 @@ import org.mybatis.dynamic.sql.configuration.StatementConfiguration; import org.mybatis.dynamic.sql.util.AbstractColumnMapping; import org.mybatis.dynamic.sql.util.Buildable; -import org.mybatis.dynamic.sql.util.ConfigurableStatement; import org.mybatis.dynamic.sql.util.ConstantMapping; import org.mybatis.dynamic.sql.util.NullMapping; import org.mybatis.dynamic.sql.util.StringConstantMapping; @@ -36,10 +34,9 @@ import org.mybatis.dynamic.sql.util.ValueOrNullMapping; import org.mybatis.dynamic.sql.util.ValueWhenPresentMapping; -public class GeneralInsertDSL implements Buildable, ConfigurableStatement { +public class GeneralInsertDSL implements Buildable { private final List columnMappings; private final SqlTable table; - private final StatementConfiguration statementConfiguration = new StatementConfiguration(); private GeneralInsertDSL(Builder builder) { table = Objects.requireNonNull(builder.table); @@ -56,7 +53,7 @@ public GeneralInsertModel build() { return new GeneralInsertModel.Builder() .withTable(table) .withInsertMappings(columnMappings) - .withStatementConfiguration(statementConfiguration) + .withStatementConfiguration(new StatementConfiguration()) // nothing configurable in this statement yet .build(); } @@ -64,12 +61,6 @@ public static GeneralInsertDSL insertInto(SqlTable table) { return new GeneralInsertDSL.Builder().withTable(table).build(); } - @Override - public GeneralInsertDSL configureStatement(Consumer consumer) { - consumer.accept(statementConfiguration); - return this; - } - public class SetClauseFinisher { private final SqlColumn column; From 18cdcebfde49d053f27404e3b20336edc97296d6 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 25 Mar 2024 13:11:55 -0400 Subject: [PATCH 19/22] InsertSelect is configurable --- .../dynamic/sql/insert/InsertSelectDSL.java | 13 ++++++++++++- .../dynamic/sql/insert/InsertSelectModel.java | 10 ++++++++++ .../sql/insert/render/InsertSelectRenderer.java | 16 +++++++++++++--- 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/InsertSelectDSL.java b/src/main/java/org/mybatis/dynamic/sql/insert/InsertSelectDSL.java index dd751f263..20fad06ad 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/InsertSelectDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/InsertSelectDSL.java @@ -18,18 +18,22 @@ import java.util.Arrays; import java.util.List; import java.util.Objects; +import java.util.function.Consumer; import org.jetbrains.annotations.NotNull; import org.mybatis.dynamic.sql.SqlColumn; import org.mybatis.dynamic.sql.SqlTable; +import org.mybatis.dynamic.sql.configuration.StatementConfiguration; import org.mybatis.dynamic.sql.select.SelectModel; import org.mybatis.dynamic.sql.util.Buildable; +import org.mybatis.dynamic.sql.util.ConfigurableStatement; -public class InsertSelectDSL implements Buildable { +public class InsertSelectDSL implements Buildable, ConfigurableStatement { private final SqlTable table; private final InsertColumnListModel columnList; private final SelectModel selectModel; + private final StatementConfiguration statementConfiguration = new StatementConfiguration(); private InsertSelectDSL(SqlTable table, InsertColumnListModel columnList, SelectModel selectModel) { this.table = Objects.requireNonNull(table); @@ -49,6 +53,7 @@ public InsertSelectModel build() { return InsertSelectModel.withTable(table) .withColumnList(columnList) .withSelectModel(selectModel) + .withStatementConfiguration(statementConfiguration) .build(); } @@ -56,6 +61,12 @@ public static InsertColumnGatherer insertInto(SqlTable table) { return new InsertColumnGatherer(table); } + @Override + public InsertSelectDSL configureStatement(Consumer consumer) { + consumer.accept(statementConfiguration); + return this; + } + public static class InsertColumnGatherer { private final SqlTable table; 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 af80a6493..4da2cef1c 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/InsertSelectModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/InsertSelectModel.java @@ -20,6 +20,7 @@ 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.RenderingStrategy; @@ -29,11 +30,13 @@ public class InsertSelectModel { private final SqlTable table; private final InsertColumnListModel columnList; private final SelectModel selectModel; + private final StatementConfiguration statementConfiguration; private InsertSelectModel(Builder builder) { table = Objects.requireNonNull(builder.table); columnList = builder.columnList; selectModel = Objects.requireNonNull(builder.selectModel); + statementConfiguration = Objects.requireNonNull(builder.statementConfiguration); } public SqlTable table() { @@ -52,6 +55,7 @@ public Optional columnList() { public InsertSelectStatementProvider render(RenderingStrategy renderingStrategy) { return InsertSelectRenderer.withInsertSelectModel(this) .withRenderingStrategy(renderingStrategy) + .withStatementConfiguration(statementConfiguration) .build() .render(); } @@ -64,6 +68,7 @@ public static class Builder { private SqlTable table; private InsertColumnListModel columnList; private SelectModel selectModel; + private StatementConfiguration statementConfiguration; public Builder withTable(SqlTable table) { this.table = table; @@ -80,6 +85,11 @@ public Builder withSelectModel(SelectModel selectModel) { return this; } + public Builder withStatementConfiguration(StatementConfiguration statementConfiguration) { + this.statementConfiguration = statementConfiguration; + return this; + } + public InsertSelectModel build() { return new InsertSelectModel(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 522f6b5cb..951426606 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,8 +22,10 @@ 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; import org.mybatis.dynamic.sql.render.RenderingStrategy; import org.mybatis.dynamic.sql.select.render.SelectStatementProvider; import org.mybatis.dynamic.sql.util.StringUtilities; @@ -31,15 +33,17 @@ public class InsertSelectRenderer { private final InsertSelectModel model; - private final RenderingStrategy renderingStrategy; + private final RenderingContext renderingContext; private InsertSelectRenderer(Builder builder) { model = Objects.requireNonNull(builder.model); - renderingStrategy = Objects.requireNonNull(builder.renderingStrategy); + renderingContext = RenderingContext.withRenderingStrategy(builder.renderingStrategy) + .withStatementConfiguration(builder.statementConfiguration) + .build(); } public InsertSelectStatementProvider render() { - SelectStatementProvider selectStatement = model.selectModel().render(renderingStrategy); + SelectStatementProvider selectStatement = model.selectModel().render(renderingContext); String statementStart = InsertRenderingUtilities.calculateInsertStatementStart(model.table()); Optional columnsPhrase = calculateColumnsPhrase(); @@ -70,6 +74,7 @@ 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; @@ -81,6 +86,11 @@ public Builder withRenderingStrategy(RenderingStrategy renderingStrategy) { return this; } + public Builder withStatementConfiguration(StatementConfiguration statementConfiguration) { + this.statementConfiguration = statementConfiguration; + return this; + } + public InsertSelectRenderer build() { return new InsertSelectRenderer(this); } From 4987a0705c05d2b585e1cefd46cc7843708b06e8 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Tue, 26 Mar 2024 09:52:56 -0400 Subject: [PATCH 20/22] Documentation --- src/site/markdown/docs/extending.md | 49 ++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/src/site/markdown/docs/extending.md b/src/site/markdown/docs/extending.md index f0827391a..ae04f434a 100644 --- a/src/site/markdown/docs/extending.md +++ b/src/site/markdown/docs/extending.md @@ -1,6 +1,6 @@ # Extending MyBatis Dynamic SQL -The library has been designed for extension from the very start of the design. We do not believe that the library +The library has been designed for extension from the very beginning. We do not believe that the library covers all possible uses, and we wanted to make it possible to add functionality that suits the needs of different projects. @@ -11,10 +11,18 @@ 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, creating a calculated column. | -| `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 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. | + +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 +instance of `FragmentAndParameters` containing your desired SQL fragment and any bind parameters needed. Bind +parameter markers can be calculated by calling the `RenderingContext.calculateParameterInfo()` method. That method will +return a properly formatted bind marker for the SQL string, and a matching Map key you should use in your parameter map. +In general, you do not need to worry about adding spacing, commas, etc. before or after your fragment - the library +will properly format the final statement from all the different fragments. See the following sections for examples. @@ -166,6 +174,37 @@ public class Upper extends AbstractUniTypeFunction { } ``` +Note that `FragmentAndParameters` has a utility method that can simplify the implementation if you do not need to +add any new parameters to the resulting fragment. For example, the UPPER function can be simplified as follows: + +```java +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) { + super(column); + } + + @Override + public FragmentAndParameters render(RenderingContext renderingContext) { + return = column.render(renderingContext).mapFragment(f -> "upper(" + f + ")"); //$NON-NLS-1$ //$NON-NLS-2$ + } + + @Override + protected Upper copy() { + return new Upper(column); + } + + public static Upper of(BindableColumn column) { + return new Upper(column); + } +} +``` + + ### OperatorFunction Example The following function implements the concatenate operator. Note that the operator can be applied to list of columns of From 0b47e497191dde1fc46711021ad0880d69a9cfee Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Tue, 26 Mar 2024 11:17:55 -0400 Subject: [PATCH 21/22] Kotlin support and test coverage --- .../util/kotlin/KotlinMultiSelectBuilder.kt | 5 ++ .../sql/util/kotlin/KotlinSubQueryBuilders.kt | 14 +++- .../mybatis3/canonical/PersonMapperTest.kt | 81 +++++++++++++++++++ 3 files changed, 97 insertions(+), 3 deletions(-) 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 199b044de..440232397 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 @@ -18,6 +18,7 @@ package org.mybatis.dynamic.sql.util.kotlin import org.mybatis.dynamic.sql.BasicColumn import org.mybatis.dynamic.sql.SortSpecification import org.mybatis.dynamic.sql.SqlBuilder +import org.mybatis.dynamic.sql.configuration.StatementConfiguration import org.mybatis.dynamic.sql.select.MultiSelectDSL import org.mybatis.dynamic.sql.select.MultiSelectModel import org.mybatis.dynamic.sql.util.Buildable @@ -74,6 +75,10 @@ class KotlinMultiSelectBuilder: Buildable { getDsl().fetchFirst(fetchFirstRows).rowsOnly() } + fun configureStatement(c: StatementConfiguration.() -> Unit) { + getDsl().configureStatement(c) + } + override fun build(): MultiSelectModel = getDsl().build() diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinSubQueryBuilders.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinSubQueryBuilders.kt index 90f8c8f80..cf5a12d8a 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinSubQueryBuilders.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinSubQueryBuilders.kt @@ -19,6 +19,7 @@ import org.mybatis.dynamic.sql.BasicColumn import org.mybatis.dynamic.sql.SqlBuilder import org.mybatis.dynamic.sql.SqlColumn import org.mybatis.dynamic.sql.SqlTable +import org.mybatis.dynamic.sql.configuration.StatementConfiguration import org.mybatis.dynamic.sql.insert.InsertSelectModel import org.mybatis.dynamic.sql.select.SelectModel import org.mybatis.dynamic.sql.util.Buildable @@ -63,6 +64,7 @@ typealias InsertSelectCompleter = KotlinInsertSelectSubQueryBuilder.() -> Unit class KotlinInsertSelectSubQueryBuilder : KotlinBaseSubQueryBuilder(), Buildable { private var columnList: List>? = null private var table: SqlTable? = null + private var statementConfigurator: (StatementConfiguration.() -> Unit)? = null fun into(table: SqlTable) { this.table = table @@ -74,18 +76,24 @@ class KotlinInsertSelectSubQueryBuilder : KotlinBaseSubQueryBuilder(), Buildable this.columnList = columnList } + fun configureStatement(c: StatementConfiguration.() -> Unit) { + statementConfigurator = c + } + override fun build(): InsertSelectModel { assertNotNull(table, "ERROR.29") //$NON-NLS-1$ - return if (columnList == null) { + val dsl = if (columnList == null) { SqlBuilder.insertInto(table) .withSelectStatement { buildSelectModel() } - .build() } else { SqlBuilder.insertInto(table) .withColumnList(columnList) .withSelectStatement { buildSelectModel() } - .build() } + + statementConfigurator?.let { dsl.configureStatement(it) } + + return dsl.build() } } diff --git a/src/test/kotlin/examples/kotlin/mybatis3/canonical/PersonMapperTest.kt b/src/test/kotlin/examples/kotlin/mybatis3/canonical/PersonMapperTest.kt index f3d69db30..e09d91210 100644 --- a/src/test/kotlin/examples/kotlin/mybatis3/canonical/PersonMapperTest.kt +++ b/src/test/kotlin/examples/kotlin/mybatis3/canonical/PersonMapperTest.kt @@ -28,10 +28,12 @@ import examples.kotlin.mybatis3.canonical.PersonDynamicSqlSupport.person import org.apache.ibatis.session.ExecutorType import org.apache.ibatis.session.SqlSessionFactory import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.junit.jupiter.api.BeforeAll import org.junit.jupiter.api.Test 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.constant import org.mybatis.dynamic.sql.util.kotlin.elements.isIn @@ -824,4 +826,83 @@ class PersonMapperTest { } } } + + @Test + fun testMultiSelectWithNonRenderingWhereClauseDisAllowed() { + assertThatExceptionOfType(NonRenderingWhereClauseException::class.java).isThrownBy { + multiSelect { + select(id.`as`("A_ID"), firstName, lastName, birthDate, employed, occupation, addressId) { + from(person) + where { id isLessThanOrEqualTo 2 } + orderBy(id) + limit(1) + } + union { + select(id.`as`("A_ID"), firstName, lastName, birthDate, employed, occupation, addressId) { + from(person) + where { id isGreaterThanOrEqualToWhenPresent null } + orderBy(id.descending()) + limit(1) + } + } + orderBy(sortColumn("A_ID")) + limit(2) + offset(1) + } + } + } + + @Test + fun testMultiSelectWithNonRenderingWhereClauseAllowed() { + val selectStatement = multiSelect { + select(id, firstName) { + from(person) + where { id isLessThanOrEqualTo 2 } + } + union { + select(id, firstName) { + from(person) + where { id isGreaterThanOrEqualToWhenPresent null } + // following should be ignored in favor of the statement configuration... + configureStatement { isNonRenderingWhereClauseAllowed = false } + } + } + configureStatement { isNonRenderingWhereClauseAllowed = true } + } + + val expected = "(select id, first_name from Person where id <= #{parameters.p1,jdbcType=INTEGER}) " + + "union (select id, first_name from Person)" + assertThat(selectStatement.selectStatement).isEqualTo(expected) + } + + @Test + fun testInsertSelectWithNonRenderingWhereClauseDisAllowed() { + assertThatExceptionOfType(NonRenderingWhereClauseException::class.java).isThrownBy { + insertSelect { + into(person) + select(id, firstName, lastName, birthDate, employed, occupation, addressId) { + from(person) + where { id isGreaterThanOrEqualToWhenPresent null } + } + } + } + } + + @Test + fun testInsertSelectWithNonRenderingWhereClauseAllowed() { + val insertStatement = insertSelect { + into(person) + select(id, firstName, lastName, birthDate, employed, occupation, addressId) { + from(person) + where { id isGreaterThanOrEqualToWhenPresent null } + // following should be ignored in favor of the statement configuration... + configureStatement { isNonRenderingWhereClauseAllowed = false } + } + configureStatement { isNonRenderingWhereClauseAllowed = true } + } + + val expected = "insert into Person " + + "select id, first_name, last_name, birth_date, employed, occupation, address_id from Person" + assertThat(insertStatement.insertStatement).isEqualTo(expected) + } } From 3b2d7b0e98efe796d3412881065996163897b2c3 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Tue, 26 Mar 2024 11:33:31 -0400 Subject: [PATCH 22/22] Documentation --- src/site/markdown/docs/configuration.md | 29 +++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/site/markdown/docs/configuration.md b/src/site/markdown/docs/configuration.md index e98fba5f8..f413d4150 100644 --- a/src/site/markdown/docs/configuration.md +++ b/src/site/markdown/docs/configuration.md @@ -56,3 +56,32 @@ val deleteStatement = deleteFrom(person) { } ``` +## Configuration Scope with Select Statements + +Select statements can stand alone, or they can be embedded within other statements. For example, the library supports +writing insert statements with an embedded select, or select statements that contain other select statements for sub +queries. The select DSLs (both Java and Kotlin) appear to allow you to specify statement configuration on embedded +select statements, but this is not supported in point of fact. Statement configuration must ALWAYS be specified on the +outermost statement. Any configuration specified on embedded select statements will be ignored. We realize this could be +confusing! But we've made this decision hoping to minimize code duplication and maximize consistency. + +So the best practice is to ALWAYS specify the statement configuration as the LAST call to the DSL before calling +`build`, or before ending a Kotlin lambda. + +The following Kotlin code snippet shows this in action... + +```kotlin +val insertStatement = insertSelect { + into(person) + select(id, firstName, lastName, birthDate, employed, occupation, addressId) { + from(person) + where { id isGreaterThanOrEqualToWhenPresent null } + // the following will be ignored in favor of the enclosing statement configuration... + configureStatement { isNonRenderingWhereClauseAllowed = false } + } + configureStatement { isNonRenderingWhereClauseAllowed = true } +} +``` + +The inner `configureStatement` call will be ignored in this case, only the `configureStatement` call scoped to the +insert statement itself will be in effect.