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 9e78b763b..1866ff8e3 100644 --- a/src/main/java/org/mybatis/dynamic/sql/common/AbstractBooleanExpressionRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/common/AbstractBooleanExpressionRenderer.java @@ -43,10 +43,7 @@ public Optional render() { return model.initialCriterion() .map(this::renderWithInitialCriterion) .orElseGet(this::renderWithoutInitialCriterion) - .map(rc -> FragmentAndParameters.withFragment(rc.fragmentAndParameters().fragment()) - .withParameters(rc.fragmentAndParameters().parameters()) - .build() - ); + .map(RenderedCriterion::fragmentAndParameters); } private Optional renderWithInitialCriterion(SqlCriterion initialCriterion) { 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 7191b39cf..2d912aee8 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 @@ -23,6 +23,7 @@ import org.mybatis.dynamic.sql.common.OrderByRenderer; import org.mybatis.dynamic.sql.delete.DeleteModel; import org.mybatis.dynamic.sql.render.ExplicitTableAliasCalculator; +import org.mybatis.dynamic.sql.render.RenderedParameterInfo; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.render.RenderingStrategy; import org.mybatis.dynamic.sql.render.TableAliasCalculator; @@ -85,10 +86,10 @@ private Optional calculateLimitClause() { } private FragmentAndParameters renderLimitClause(Long limit) { - RenderingContext.ParameterInfo parameterInfo = renderingContext.calculateParameterInfo(); + RenderedParameterInfo parameterInfo = renderingContext.calculateParameterInfo(); return FragmentAndParameters.withFragment("limit " + parameterInfo.renderedPlaceHolder()) //$NON-NLS-1$ - .withParameter(parameterInfo.mapKey(), limit) + .withParameter(parameterInfo.parameterMapKey(), limit) .build(); } 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 86092cb8c..3936a2c87 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 @@ -18,6 +18,7 @@ import java.util.Objects; import java.util.Optional; +import org.mybatis.dynamic.sql.render.RenderedParameterInfo; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.util.AbstractColumnMapping; import org.mybatis.dynamic.sql.util.ConstantMapping; @@ -83,11 +84,11 @@ private Optional buildNullFragment(AbstractColumnMap } private Optional buildFragment(AbstractColumnMapping mapping, Object value) { - RenderingContext.ParameterInfo parameterInfo = mapping.mapColumn(renderingContext::calculateParameterInfo); + RenderedParameterInfo parameterInfo = mapping.mapColumn(renderingContext::calculateParameterInfo); return FieldAndValueAndParameters.withFieldName(mapping.columnName()) .withValuePhrase(parameterInfo.renderedPlaceHolder()) - .withParameter(parameterInfo.mapKey(), value) + .withParameter(parameterInfo.parameterMapKey(), value) .buildOptional(); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/render/RenderedParameterInfo.java b/src/main/java/org/mybatis/dynamic/sql/render/RenderedParameterInfo.java new file mode 100644 index 000000000..c308130ff --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/render/RenderedParameterInfo.java @@ -0,0 +1,36 @@ +/* + * Copyright 2016-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mybatis.dynamic.sql.render; + +import java.util.Objects; + +public class RenderedParameterInfo { + private final String parameterMapKey; + private final String renderedPlaceHolder; + + public RenderedParameterInfo(String parameterMapKey, String renderedPlaceHolder) { + this.parameterMapKey = Objects.requireNonNull(parameterMapKey); + this.renderedPlaceHolder = Objects.requireNonNull(renderedPlaceHolder); + } + + public String parameterMapKey() { + return parameterMapKey; + } + + public String renderedPlaceHolder() { + return renderedPlaceHolder; + } +} 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 96f8db794..1d865a824 100644 --- a/src/main/java/org/mybatis/dynamic/sql/render/RenderingContext.java +++ b/src/main/java/org/mybatis/dynamic/sql/render/RenderingContext.java @@ -33,23 +33,22 @@ */ public class RenderingContext { - private final AtomicInteger sequence; private final RenderingStrategy renderingStrategy; + private final AtomicInteger sequence; private final TableAliasCalculator tableAliasCalculator; private final String configuredParameterName; private final String calculatedParameterName; private RenderingContext(Builder builder) { - this.sequence = builder.sequence == null ? new AtomicInteger(1) : builder.sequence; renderingStrategy = Objects.requireNonNull(builder.renderingStrategy); - tableAliasCalculator = Objects.requireNonNull(builder.tableAliasCalculator); configuredParameterName = builder.parameterName; - if (configuredParameterName == null) { - calculatedParameterName = RenderingStrategy.DEFAULT_PARAMETER_PREFIX; - } else { - calculatedParameterName = - configuredParameterName + "." + RenderingStrategy.DEFAULT_PARAMETER_PREFIX; //$NON-NLS-1$ - } + + // reasonable defaults + sequence = builder.sequence == null ? new AtomicInteger(1) : builder.sequence; + tableAliasCalculator = builder.tableAliasCalculator == null ? TableAliasCalculator.empty() + : builder.tableAliasCalculator; + calculatedParameterName = builder.parameterName == null ? RenderingStrategy.DEFAULT_PARAMETER_PREFIX + : builder.parameterName + "." + RenderingStrategy.DEFAULT_PARAMETER_PREFIX; //$NON-NLS-1$ } public TableAliasCalculator tableAliasCalculator() { @@ -70,18 +69,14 @@ private String renderedPlaceHolder(String mapKey, BindableColumn column) .getFormattedJdbcPlaceholder(column, calculatedParameterName, mapKey); } - public ParameterInfo calculateParameterInfo() { - ParameterInfo p = new ParameterInfo(); - p.mapKey = nextMapKey(); - p.renderedPlaceHolder = renderedPlaceHolder(p.mapKey); - return p; + public RenderedParameterInfo calculateParameterInfo() { + String mapKey = nextMapKey(); + return new RenderedParameterInfo(mapKey, renderedPlaceHolder(mapKey)); } - public ParameterInfo calculateParameterInfo(BindableColumn column) { - ParameterInfo p = new ParameterInfo(); - p.mapKey = nextMapKey(); - p.renderedPlaceHolder = renderedPlaceHolder(p.mapKey, column); - return p; + public RenderedParameterInfo calculateParameterInfo(BindableColumn column) { + String mapKey = nextMapKey(); + return new RenderedParameterInfo(mapKey, renderedPlaceHolder(mapKey, column)); } public String aliasedColumnName(SqlColumn column) { @@ -128,18 +123,18 @@ public static Builder withRenderingStrategy(RenderingStrategy renderingStrategy) } public static class Builder { - private AtomicInteger sequence; private RenderingStrategy renderingStrategy; - private TableAliasCalculator tableAliasCalculator = TableAliasCalculator.empty(); + private AtomicInteger sequence; + private TableAliasCalculator tableAliasCalculator; private String parameterName; - public Builder withSequence(AtomicInteger sequence) { - this.sequence = sequence; + public Builder withRenderingStrategy(RenderingStrategy renderingStrategy) { + this.renderingStrategy = renderingStrategy; return this; } - public Builder withRenderingStrategy(RenderingStrategy renderingStrategy) { - this.renderingStrategy = renderingStrategy; + public Builder withSequence(AtomicInteger sequence) { + this.sequence = sequence; return this; } @@ -157,17 +152,4 @@ public RenderingContext build() { return new RenderingContext(this); } } - - public static class ParameterInfo { - private String mapKey; - private String renderedPlaceHolder; - - public String mapKey() { - return mapKey; - } - - public String renderedPlaceHolder() { - return renderedPlaceHolder; - } - } } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/aggregate/Avg.java b/src/main/java/org/mybatis/dynamic/sql/select/aggregate/Avg.java index 2de5ad619..5ce30559a 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/aggregate/Avg.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/aggregate/Avg.java @@ -28,11 +28,7 @@ private Avg(BindableColumn column) { @Override public FragmentAndParameters render(RenderingContext renderingContext) { - FragmentAndParameters renderedColumn = column.render(renderingContext); - - return FragmentAndParameters.withFragment("avg(" + renderedColumn.fragment() + ")") //$NON-NLS-1$ //$NON-NLS-2$ - .withParameters(renderedColumn.parameters()) - .build(); + return column.render(renderingContext).mapFragment(s -> "avg(" + s + ")"); //$NON-NLS-1$ //$NON-NLS-2$ } @Override diff --git a/src/main/java/org/mybatis/dynamic/sql/select/aggregate/Count.java b/src/main/java/org/mybatis/dynamic/sql/select/aggregate/Count.java index 98d439804..1b481fa4b 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/aggregate/Count.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/aggregate/Count.java @@ -36,12 +36,7 @@ private Count(BasicColumn column, String alias) { @Override public FragmentAndParameters render(RenderingContext renderingContext) { - FragmentAndParameters renderedColumn = column.render(renderingContext); - - return FragmentAndParameters - .withFragment("count(" + renderedColumn.fragment() + ")") //$NON-NLS-1$ //$NON-NLS-2$ - .withParameters(renderedColumn.parameters()) - .build(); + return column.render(renderingContext).mapFragment(s -> "count(" + s + ")"); //$NON-NLS-1$ //$NON-NLS-2$ } @Override diff --git a/src/main/java/org/mybatis/dynamic/sql/select/aggregate/CountDistinct.java b/src/main/java/org/mybatis/dynamic/sql/select/aggregate/CountDistinct.java index edb71f881..5d4642514 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/aggregate/CountDistinct.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/aggregate/CountDistinct.java @@ -36,12 +36,8 @@ private CountDistinct(BasicColumn column, String alias) { @Override public FragmentAndParameters render(RenderingContext renderingContext) { - FragmentAndParameters renderedColumn = column.render(renderingContext); - - return FragmentAndParameters - .withFragment("count(distinct " + renderedColumn.fragment() + ")") //$NON-NLS-1$ //$NON-NLS-2$ - .withParameters(renderedColumn.parameters()) - .build(); + return column.render(renderingContext) + .mapFragment(s -> "count(distinct " + s + ")"); //$NON-NLS-1$ //$NON-NLS-2$) } @Override diff --git a/src/main/java/org/mybatis/dynamic/sql/select/aggregate/Max.java b/src/main/java/org/mybatis/dynamic/sql/select/aggregate/Max.java index 353cfe904..4df7540a3 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/aggregate/Max.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/aggregate/Max.java @@ -28,11 +28,7 @@ private Max(BindableColumn column) { @Override public FragmentAndParameters render(RenderingContext renderingContext) { - FragmentAndParameters renderedColumn = column.render(renderingContext); - - return FragmentAndParameters.withFragment("max(" + renderedColumn.fragment() + ")") //$NON-NLS-1$ //$NON-NLS-2$ - .withParameters(renderedColumn.parameters()) - .build(); + return column.render(renderingContext).mapFragment(s -> "max(" + s + ")"); //$NON-NLS-1$ //$NON-NLS-2$ } @Override diff --git a/src/main/java/org/mybatis/dynamic/sql/select/aggregate/Min.java b/src/main/java/org/mybatis/dynamic/sql/select/aggregate/Min.java index 0d76be1ea..7c6daceaf 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/aggregate/Min.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/aggregate/Min.java @@ -28,11 +28,7 @@ private Min(BindableColumn column) { @Override public FragmentAndParameters render(RenderingContext renderingContext) { - FragmentAndParameters renderedColumn = column.render(renderingContext); - - return FragmentAndParameters.withFragment("min(" + renderedColumn.fragment() + ")") //$NON-NLS-1$ //$NON-NLS-2$ - .withParameters(renderedColumn.parameters()) - .build(); + return column.render(renderingContext).mapFragment(s -> "min(" + s + ")"); //$NON-NLS-1$ //$NON-NLS-2$) } @Override diff --git a/src/main/java/org/mybatis/dynamic/sql/select/aggregate/Sum.java b/src/main/java/org/mybatis/dynamic/sql/select/aggregate/Sum.java index 96f100015..dbb03096f 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/aggregate/Sum.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/aggregate/Sum.java @@ -17,7 +17,7 @@ import org.mybatis.dynamic.sql.BindableColumn; import org.mybatis.dynamic.sql.VisitableCondition; -import org.mybatis.dynamic.sql.exception.DynamicSqlException; +import org.mybatis.dynamic.sql.exception.InvalidSqlException; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.select.function.AbstractUniTypeFunction; import org.mybatis.dynamic.sql.util.FragmentAndParameters; @@ -46,16 +46,12 @@ public FragmentAndParameters render(RenderingContext renderingContext) { } private FragmentAndParameters renderWithoutCondition(RenderingContext renderingContext) { - FragmentAndParameters renderedColumn = column.render(renderingContext); - - return FragmentAndParameters.withFragment("sum(" + renderedColumn.fragment() + ")") //$NON-NLS-1$ //$NON-NLS-2$ - .withParameters(renderedColumn.parameters()) - .build(); + return column.render(renderingContext).mapFragment(this::applyAggregate); } private FragmentAndParameters renderWithCondition(RenderingContext renderingContext) { if (!condition.shouldRender()) { - throw new DynamicSqlException(Messages.getString("ERROR.37", "sum")); //$NON-NLS-1$ //$NON-NLS-2$ + throw new InvalidSqlException(Messages.getString("ERROR.37", "sum")); //$NON-NLS-1$ //$NON-NLS-2$ } DefaultConditionVisitor visitor = new DefaultConditionVisitor.Builder() @@ -63,12 +59,11 @@ private FragmentAndParameters renderWithCondition(RenderingContext renderingCont .withRenderingContext(renderingContext) .build(); - FragmentAndParameters renderedCondition = condition.accept(visitor); + return condition.accept(visitor).mapFragment(this::applyAggregate); + } - return FragmentAndParameters - .withFragment("sum(" + renderedCondition.fragment() + ")") //$NON-NLS-1$ //$NON-NLS-2$ - .withParameters(renderedCondition.parameters()) - .build(); + private String applyAggregate(String s) { + return "sum(" + s + ")"; //$NON-NLS-1$ //$NON-NLS-2$ } @Override diff --git a/src/main/java/org/mybatis/dynamic/sql/select/function/Concat.java b/src/main/java/org/mybatis/dynamic/sql/select/function/Concat.java index 51edb1cf6..63d93e7ed 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/function/Concat.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/function/Concat.java @@ -38,16 +38,10 @@ protected Concat(BindableColumn firstColumn, List subsequentColu @Override public FragmentAndParameters render(RenderingContext renderingContext) { // note - the cast below is added for type inference issues in some compilers - FragmentCollector fc = allColumns.stream() + return allColumns.stream() .map(column -> column.render(renderingContext)) - .collect(FragmentCollector.collect()); - - String fragment = fc.collectFragments( - Collectors.joining(", ", "concat(", ")")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - - return FragmentAndParameters.withFragment(fragment) - .withParameters(fc.parameters()) - .build(); + .collect(FragmentCollector.collect()).toFragmentAndParameters( + Collectors.joining(", ", "concat(", ")")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } @Override diff --git a/src/main/java/org/mybatis/dynamic/sql/select/function/Lower.java b/src/main/java/org/mybatis/dynamic/sql/select/function/Lower.java index f48847c4c..e77a76a19 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/function/Lower.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/function/Lower.java @@ -27,12 +27,7 @@ private Lower(BindableColumn column) { @Override public FragmentAndParameters render(RenderingContext renderingContext) { - FragmentAndParameters renderedColumn = column.render(renderingContext); - - return FragmentAndParameters - .withFragment("lower(" + renderedColumn.fragment() + ")") //$NON-NLS-1$ //$NON-NLS-2$ - .withParameters(renderedColumn.parameters()) - .build(); + return column.render(renderingContext).mapFragment(s -> "lower(" + s + ")"); //$NON-NLS-1$ //$NON-NLS-2$ } @Override diff --git a/src/main/java/org/mybatis/dynamic/sql/select/function/OperatorFunction.java b/src/main/java/org/mybatis/dynamic/sql/select/function/OperatorFunction.java index 2c3fdc2d1..a6ba5fd98 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/function/OperatorFunction.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/function/OperatorFunction.java @@ -50,20 +50,15 @@ protected OperatorFunction copy() { @Override public FragmentAndParameters render(RenderingContext renderingContext) { + String paddedOperator = " " + operator + " "; //$NON-NLS-1$ //$NON-NLS-2$ + // note - the cast below is added for type inference issues in some compilers - FragmentCollector fc = Stream.of(Stream.of((BasicColumn) column), + return Stream.of(Stream.of((BasicColumn) column), Stream.of(secondColumn), subsequentColumns.stream()) .flatMap(Function.identity()) .map(column -> column.render(renderingContext)) - .collect(FragmentCollector.collect()); - - String paddedOperator = " " + operator + " "; //$NON-NLS-1$ //$NON-NLS-2$ - String fragment = fc.collectFragments( - Collectors.joining(paddedOperator, "(", ")")); //$NON-NLS-1$ //$NON-NLS-2$ - - return FragmentAndParameters.withFragment(fragment) - .withParameters(fc.parameters()) - .build(); + .collect(FragmentCollector.collect()) + .toFragmentAndParameters(Collectors.joining(paddedOperator, "(", ")")); //$NON-NLS-1$ //$NON-NLS-2$ } public static OperatorFunction of(String operator, BindableColumn firstColumn, BasicColumn secondColumn, diff --git a/src/main/java/org/mybatis/dynamic/sql/select/function/Substring.java b/src/main/java/org/mybatis/dynamic/sql/select/function/Substring.java index 22ad2790a..1c41acc57 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/function/Substring.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/function/Substring.java @@ -32,19 +32,13 @@ private Substring(BindableColumn column, int offset, int length) { @Override public FragmentAndParameters render(RenderingContext renderingContext) { - FragmentAndParameters renderedColumn = column.render(renderingContext); - - String fragment = "substring(" //$NON-NLS-1$ - + renderedColumn.fragment() + return column.render(renderingContext).mapFragment(s -> "substring(" //$NON-NLS-1$ + + s + ", " //$NON-NLS-1$ + offset + ", " //$NON-NLS-1$ + length - + ")"; //$NON-NLS-1$ - - return FragmentAndParameters.withFragment(fragment) - .withParameters(renderedColumn.parameters()) - .build(); + + ")"); //$NON-NLS-1$ } @Override diff --git a/src/main/java/org/mybatis/dynamic/sql/select/function/Upper.java b/src/main/java/org/mybatis/dynamic/sql/select/function/Upper.java index 000c36fe3..e5bd274f7 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/function/Upper.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/function/Upper.java @@ -27,12 +27,7 @@ private Upper(BindableColumn column) { @Override public FragmentAndParameters render(RenderingContext renderingContext) { - FragmentAndParameters renderedColumn = column.render(renderingContext); - - return FragmentAndParameters - .withFragment("upper(" + renderedColumn.fragment() + ")") //$NON-NLS-1$ //$NON-NLS-2$ - .withParameters(renderedColumn.parameters()) - .build(); + return column.render(renderingContext).mapFragment(s -> "upper(" + s + ")"); //$NON-NLS-1$ //$NON-NLS-2$ } @Override diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/FetchFirstPagingModelRenderer.java b/src/main/java/org/mybatis/dynamic/sql/select/render/FetchFirstPagingModelRenderer.java index 19a50eaa9..4ee676efd 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/render/FetchFirstPagingModelRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/render/FetchFirstPagingModelRenderer.java @@ -16,6 +16,7 @@ package org.mybatis.dynamic.sql.select.render; import org.mybatis.dynamic.sql.exception.InvalidSqlException; +import org.mybatis.dynamic.sql.render.RenderedParameterInfo; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.select.PagingModel; import org.mybatis.dynamic.sql.util.FragmentAndParameters; @@ -50,30 +51,30 @@ private FragmentAndParameters renderFetchFirstRowsOnly() { } private FragmentAndParameters renderFetchFirstRowsOnly(Long fetchFirstRows) { - RenderingContext.ParameterInfo parameterInfo = renderingContext.calculateParameterInfo(); + RenderedParameterInfo parameterInfo = renderingContext.calculateParameterInfo(); return FragmentAndParameters .withFragment("fetch first " + parameterInfo.renderedPlaceHolder() //$NON-NLS-1$ + " rows only") //$NON-NLS-1$ - .withParameter(parameterInfo.mapKey(), fetchFirstRows) + .withParameter(parameterInfo.parameterMapKey(), fetchFirstRows) .build(); } private FragmentAndParameters renderOffsetOnly(Long offset) { - RenderingContext.ParameterInfo parameterInfo = renderingContext.calculateParameterInfo(); + RenderedParameterInfo parameterInfo = renderingContext.calculateParameterInfo(); return FragmentAndParameters.withFragment("offset " + parameterInfo.renderedPlaceHolder() //$NON-NLS-1$ + " rows") //$NON-NLS-1$ - .withParameter(parameterInfo.mapKey(), offset) + .withParameter(parameterInfo.parameterMapKey(), offset) .build(); } private FragmentAndParameters renderOffsetAndFetchFirstRows(Long offset, Long fetchFirstRows) { - RenderingContext.ParameterInfo parameterInfo1 = renderingContext.calculateParameterInfo(); - RenderingContext.ParameterInfo parameterInfo2 = renderingContext.calculateParameterInfo(); + RenderedParameterInfo parameterInfo1 = renderingContext.calculateParameterInfo(); + RenderedParameterInfo parameterInfo2 = renderingContext.calculateParameterInfo(); return FragmentAndParameters.withFragment("offset " + parameterInfo1.renderedPlaceHolder() //$NON-NLS-1$ + " rows fetch first " + parameterInfo2.renderedPlaceHolder() //$NON-NLS-1$ + " rows only") //$NON-NLS-1$ - .withParameter(parameterInfo1.mapKey(), offset) - .withParameter(parameterInfo2.mapKey(), fetchFirstRows) + .withParameter(parameterInfo1.parameterMapKey(), offset) + .withParameter(parameterInfo2.parameterMapKey(), fetchFirstRows) .build(); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/JoinConditionRenderer.java b/src/main/java/org/mybatis/dynamic/sql/select/render/JoinConditionRenderer.java index 2b95cd669..463344fb6 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/render/JoinConditionRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/render/JoinConditionRenderer.java @@ -20,6 +20,7 @@ import java.util.Objects; import org.mybatis.dynamic.sql.BindableColumn; +import org.mybatis.dynamic.sql.render.RenderedParameterInfo; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.select.join.ColumnBasedJoinCondition; import org.mybatis.dynamic.sql.select.join.JoinConditionVisitor; @@ -37,21 +38,18 @@ private JoinConditionRenderer(Builder builder) { @Override public FragmentAndParameters visit(TypedJoinCondition condition) { - RenderingContext.ParameterInfo parameterInfo = renderingContext.calculateParameterInfo(leftColumn); + RenderedParameterInfo parameterInfo = renderingContext.calculateParameterInfo(leftColumn); return FragmentAndParameters .withFragment(condition.operator() + spaceBefore(parameterInfo.renderedPlaceHolder())) - .withParameter(parameterInfo.mapKey(), condition.value()) + .withParameter(parameterInfo.parameterMapKey(), condition.value()) .build(); } @Override public FragmentAndParameters visit(ColumnBasedJoinCondition condition) { - FragmentAndParameters renderedColumn = condition.rightColumn().render(renderingContext); - return FragmentAndParameters - .withFragment(condition.operator() + spaceBefore(renderedColumn.fragment())) - .withParameters(renderedColumn.parameters()) - .build(); + return condition.rightColumn().render(renderingContext) + .mapFragment(s -> condition.operator() + spaceBefore(s)); } public static class Builder { diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/JoinRenderer.java b/src/main/java/org/mybatis/dynamic/sql/select/render/JoinRenderer.java index 5904c2a74..592b003d1 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/render/JoinRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/render/JoinRenderer.java @@ -39,12 +39,9 @@ private JoinRenderer(Builder builder) { } public FragmentAndParameters render() { - FragmentCollector fc = joinModel.mapJoinSpecifications(this::renderJoinSpecification) - .collect(FragmentCollector.collect()); - - return FragmentAndParameters.withFragment(fc.collectFragments(Collectors.joining(" "))) //$NON-NLS-1$ - .withParameters(fc.parameters()) - .build(); + return joinModel.mapJoinSpecifications(this::renderJoinSpecification) + .collect(FragmentCollector.collect()) + .toFragmentAndParameters(Collectors.joining(" ")); //$NON-NLS-1$ } private FragmentAndParameters renderJoinSpecification(JoinSpecification joinSpecification) { @@ -62,13 +59,9 @@ private FragmentAndParameters renderJoinSpecification(JoinSpecification joinSpec } private FragmentAndParameters renderConditions(JoinSpecification joinSpecification) { - FragmentCollector fragmentCollector = joinSpecification.mapJoinCriteria(this::renderCriterion) - .collect(FragmentCollector.collect()); - - return FragmentAndParameters - .withFragment(fragmentCollector.collectFragments(Collectors.joining(" "))) //$NON-NLS-1$ - .withParameters(fragmentCollector.parameters()) - .build(); + return joinSpecification.mapJoinCriteria(this::renderCriterion) + .collect(FragmentCollector.collect()) + .toFragmentAndParameters(Collectors.joining(" ")); //$NON-NLS-1$ } private FragmentAndParameters renderCriterion(JoinCriterion joinCriterion) { diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/LimitAndOffsetPagingModelRenderer.java b/src/main/java/org/mybatis/dynamic/sql/select/render/LimitAndOffsetPagingModelRenderer.java index 25b32767e..baadab492 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/render/LimitAndOffsetPagingModelRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/render/LimitAndOffsetPagingModelRenderer.java @@ -17,6 +17,7 @@ import java.util.Objects; +import org.mybatis.dynamic.sql.render.RenderedParameterInfo; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.select.PagingModel; import org.mybatis.dynamic.sql.util.FragmentAndParameters; @@ -39,19 +40,19 @@ public FragmentAndParameters render() { } private FragmentAndParameters renderLimitOnly() { - RenderingContext.ParameterInfo parameterInfo = renderingContext.calculateParameterInfo(); + RenderedParameterInfo parameterInfo = renderingContext.calculateParameterInfo(); return FragmentAndParameters.withFragment("limit " + parameterInfo.renderedPlaceHolder()) //$NON-NLS-1$ - .withParameter(parameterInfo.mapKey(), limit) + .withParameter(parameterInfo.parameterMapKey(), limit) .build(); } private FragmentAndParameters renderLimitAndOffset(Long offset) { - RenderingContext.ParameterInfo parameterInfo1 = renderingContext.calculateParameterInfo(); - RenderingContext.ParameterInfo parameterInfo2 = renderingContext.calculateParameterInfo(); + RenderedParameterInfo parameterInfo1 = renderingContext.calculateParameterInfo(); + RenderedParameterInfo parameterInfo2 = renderingContext.calculateParameterInfo(); return FragmentAndParameters.withFragment("limit " + parameterInfo1.renderedPlaceHolder() //$NON-NLS-1$ + " offset " + parameterInfo2.renderedPlaceHolder()) //$NON-NLS-1$ - .withParameter(parameterInfo1.mapKey(), limit) - .withParameter(parameterInfo2.mapKey(), offset) + .withParameter(parameterInfo1.parameterMapKey(), limit) + .withParameter(parameterInfo2.parameterMapKey(), offset) .build(); } } 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 8a54794e7..18147152e 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 @@ -109,14 +109,7 @@ public FragmentAndParameters render() { calculateGroupByClause().ifPresent(fragmentCollector::add); calculateHavingClause().ifPresent(fragmentCollector::add); - return toFragmentAndParameters(fragmentCollector); - } - - private FragmentAndParameters toFragmentAndParameters(FragmentCollector fragmentCollector) { - return FragmentAndParameters - .withFragment(fragmentCollector.collectFragments(Collectors.joining(" "))) //$NON-NLS-1$ - .withParameters(fragmentCollector.parameters()) - .build(); + return fragmentCollector.toFragmentAndParameters(Collectors.joining(" ")); //$NON-NLS-1$ } private FragmentAndParameters calculateQueryExpressionStart() { @@ -138,14 +131,9 @@ private FragmentAndParameters calculateQueryExpressionStart() { } private FragmentAndParameters calculateColumnList() { - FragmentCollector fc = queryExpression.mapColumns(this::renderColumnAndAlias) - .collect(FragmentCollector.collect()); - - String s = fc.collectFragments(Collectors.joining(", ")); //$NON-NLS-1$ - - return FragmentAndParameters.withFragment(s) - .withParameters(fc.parameters()) - .build(); + return queryExpression.mapColumns(this::renderColumnAndAlias) + .collect(FragmentCollector.collect()) + .toFragmentAndParameters(Collectors.joining(", ")); //$NON-NLS-1$ } private FragmentAndParameters renderColumnAndAlias(BasicColumn selectListItem) { @@ -191,14 +179,10 @@ private Optional calculateGroupByClause() { } private FragmentAndParameters renderGroupBy(GroupByModel groupByModel) { - FragmentCollector fc = groupByModel.mapColumns(this::renderColumn) - .collect(FragmentCollector.collect()); - String groupBy = fc.collectFragments( - Collectors.joining(", ", "group by ", "")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$) - - return FragmentAndParameters.withFragment(groupBy) - .withParameters(fc.parameters()) - .build(); + return groupByModel.mapColumns(this::renderColumn) + .collect(FragmentCollector.collect()) + .toFragmentAndParameters( + Collectors.joining(", ", "group by ", "")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$) } private FragmentAndParameters renderColumn(BasicColumn column) { 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 486b95f3f..899304ee7 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 @@ -18,6 +18,7 @@ import java.util.Objects; import java.util.Optional; +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; @@ -43,9 +44,7 @@ public SetPhraseVisitor(RenderingContext renderingContext) { @Override public Optional visit(NullMapping mapping) { - return FragmentAndParameters - .withFragment(mapping.mapColumn(renderingContext::aliasedColumnName) + " = null") //$NON-NLS-1$ - .buildOptional(); + return buildNullFragment(mapping); } @Override @@ -69,22 +68,19 @@ public Optional visit(StringConstantMapping mapping) { @Override public Optional visit(ValueMapping mapping) { - return buildFragment(mapping, mapping.value()); + return buildValueFragment(mapping, mapping.value()); } @Override public Optional visit(ValueOrNullMapping mapping) { return mapping.value() - .map(v -> buildFragment(mapping, v)) - .orElseGet(() -> FragmentAndParameters - .withFragment(mapping.mapColumn(renderingContext::aliasedColumnName) + " = null") //$NON-NLS-1$ - .buildOptional() - ); + .map(v -> buildValueFragment(mapping, v)) + .orElseGet(() -> buildNullFragment(mapping)); } @Override public Optional visit(ValueWhenPresentMapping mapping) { - return mapping.value().flatMap(v -> buildFragment(mapping, v)); + return mapping.value().flatMap(v -> buildValueFragment(mapping, v)); } @Override @@ -117,14 +113,20 @@ public Optional visit(ColumnToColumnMapping mapping) { .buildOptional(); } - private Optional buildFragment(AbstractColumnMapping mapping, T value) { - RenderingContext.ParameterInfo parameterInfo = mapping.mapColumn(renderingContext::calculateParameterInfo); + private Optional buildValueFragment(AbstractColumnMapping mapping, T value) { + RenderedParameterInfo parameterInfo = mapping.mapColumn(renderingContext::calculateParameterInfo); String setPhrase = mapping.mapColumn(renderingContext::aliasedColumnName) + " = " //$NON-NLS-1$ + parameterInfo.renderedPlaceHolder(); return FragmentAndParameters.withFragment(setPhrase) - .withParameter(parameterInfo.mapKey(), value) + .withParameter(parameterInfo.parameterMapKey(), value) + .buildOptional(); + } + + private Optional buildNullFragment(AbstractColumnMapping mapping) { + return FragmentAndParameters + .withFragment(mapping.mapColumn(renderingContext::aliasedColumnName) + " = null") //$NON-NLS-1$ .buildOptional(); } } 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 d759a20f8..b58458b89 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 @@ -24,6 +24,7 @@ import org.mybatis.dynamic.sql.common.OrderByRenderer; import org.mybatis.dynamic.sql.exception.InvalidSqlException; import org.mybatis.dynamic.sql.render.ExplicitTableAliasCalculator; +import org.mybatis.dynamic.sql.render.RenderedParameterInfo; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.render.RenderingStrategy; import org.mybatis.dynamic.sql.render.TableAliasCalculator; @@ -93,10 +94,8 @@ private FragmentAndParameters calculateSetPhrase() { } private FragmentAndParameters toSetPhrase(FragmentCollector fragmentCollector) { - return FragmentAndParameters.withFragment(fragmentCollector.collectFragments( - Collectors.joining(", ", "set ", ""))) //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - .withParameters(fragmentCollector.parameters()) - .build(); + return fragmentCollector.toFragmentAndParameters( + Collectors.joining(", ", "set ", "")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } private Optional calculateWhereClause() { @@ -115,10 +114,10 @@ private Optional calculateLimitClause() { } private FragmentAndParameters renderLimitClause(Long limit) { - RenderingContext.ParameterInfo parameterInfo = renderingContext.calculateParameterInfo(); + RenderedParameterInfo parameterInfo = renderingContext.calculateParameterInfo(); return FragmentAndParameters.withFragment("limit " + parameterInfo.renderedPlaceHolder()) //$NON-NLS-1$ - .withParameter(parameterInfo.mapKey(), limit) + .withParameter(parameterInfo.parameterMapKey(), limit) .build(); } diff --git a/src/main/java/org/mybatis/dynamic/sql/util/FragmentAndParameters.java b/src/main/java/org/mybatis/dynamic/sql/util/FragmentAndParameters.java index 8084aa0b1..c5b008104 100644 --- a/src/main/java/org/mybatis/dynamic/sql/util/FragmentAndParameters.java +++ b/src/main/java/org/mybatis/dynamic/sql/util/FragmentAndParameters.java @@ -19,6 +19,7 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; +import java.util.function.UnaryOperator; public class FragmentAndParameters { @@ -38,6 +39,18 @@ public Map parameters() { return parameters; } + /** + * Return a new instance with the same parameters and a transformed fragment. + * + * @param mapper a function that can change the value of the fragment + * @return a new instance with the same parameters and a transformed fragment + */ + public FragmentAndParameters mapFragment(UnaryOperator mapper) { + return FragmentAndParameters.withFragment(mapper.apply(fragment)) + .withParameters(parameters) + .build(); + } + public static Builder withFragment(String fragment) { return new Builder().withFragment(fragment); } diff --git a/src/main/java/org/mybatis/dynamic/sql/util/FragmentCollector.java b/src/main/java/org/mybatis/dynamic/sql/util/FragmentCollector.java index cd47c78ea..fecef5e20 100644 --- a/src/main/java/org/mybatis/dynamic/sql/util/FragmentCollector.java +++ b/src/main/java/org/mybatis/dynamic/sql/util/FragmentCollector.java @@ -46,10 +46,15 @@ public Optional firstFragment() { return fragments.stream().findFirst().map(FragmentAndParameters::fragment); } - public String collectFragments(Collector collector) { - return fragments.stream().map(FragmentAndParameters::fragment).collect(collector); + public String collectFragments(Collector fragmentCollector) { + return fragments.stream().map(FragmentAndParameters::fragment).collect(fragmentCollector); } + public FragmentAndParameters toFragmentAndParameters(Collector fragmentCollector) { + return FragmentAndParameters.withFragment(collectFragments(fragmentCollector)) + .withParameters(parameters()) + .build(); + } public Map parameters() { return fragments.stream() 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 9c5b277d4..c253811e4 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 @@ -28,6 +28,7 @@ import org.mybatis.dynamic.sql.AbstractTwoValueCondition; import org.mybatis.dynamic.sql.BindableColumn; import org.mybatis.dynamic.sql.ConditionVisitor; +import org.mybatis.dynamic.sql.render.RenderedParameterInfo; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.select.render.SelectRenderer; import org.mybatis.dynamic.sql.select.render.SelectStatementProvider; @@ -75,13 +76,13 @@ public FragmentAndParameters visit(AbstractNoValueCondition condition) { @Override public FragmentAndParameters visit(AbstractSingleValueCondition condition) { FragmentAndParameters renderedLeftColumn = column.render(renderingContext); - RenderingContext.ParameterInfo parameterInfo = renderingContext.calculateParameterInfo(column); + RenderedParameterInfo parameterInfo = renderingContext.calculateParameterInfo(column); String finalFragment = condition.overrideRenderedLeftColumn(renderedLeftColumn.fragment()) + spaceBefore(condition.operator()) + spaceBefore(parameterInfo.renderedPlaceHolder()); return FragmentAndParameters.withFragment(finalFragment) - .withParameter(parameterInfo.mapKey(), convertValue(condition.value())) + .withParameter(parameterInfo.parameterMapKey(), convertValue(condition.value())) .withParameters(renderedLeftColumn.parameters()) .build(); } @@ -89,8 +90,8 @@ public FragmentAndParameters visit(AbstractSingleValueCondition condition) { @Override public FragmentAndParameters visit(AbstractTwoValueCondition condition) { FragmentAndParameters renderedLeftColumn = column.render(renderingContext); - RenderingContext.ParameterInfo parameterInfo1 = renderingContext.calculateParameterInfo(column); - RenderingContext.ParameterInfo parameterInfo2 = renderingContext.calculateParameterInfo(column); + RenderedParameterInfo parameterInfo1 = renderingContext.calculateParameterInfo(column); + RenderedParameterInfo parameterInfo2 = renderingContext.calculateParameterInfo(column); String finalFragment = condition.overrideRenderedLeftColumn(renderedLeftColumn.fragment()) + spaceBefore(condition.operator1()) @@ -99,8 +100,8 @@ public FragmentAndParameters visit(AbstractTwoValueCondition condition) { + spaceBefore(parameterInfo2.renderedPlaceHolder()); return FragmentAndParameters.withFragment(finalFragment) - .withParameter(parameterInfo1.mapKey(), convertValue(condition.value1())) - .withParameter(parameterInfo2.mapKey(), convertValue(condition.value2())) + .withParameter(parameterInfo1.parameterMapKey(), convertValue(condition.value1())) + .withParameter(parameterInfo2.parameterMapKey(), convertValue(condition.value2())) .withParameters(renderedLeftColumn.parameters()) .build(); } @@ -143,9 +144,9 @@ private Object convertValue(T value) { } private FragmentAndParameters toFragmentAndParameters(T value) { - RenderingContext.ParameterInfo parameterInfo = renderingContext.calculateParameterInfo(column); + RenderedParameterInfo parameterInfo = renderingContext.calculateParameterInfo(column); return FragmentAndParameters.withFragment(parameterInfo.renderedPlaceHolder()) - .withParameter(parameterInfo.mapKey(), convertValue(value)) + .withParameter(parameterInfo.parameterMapKey(), convertValue(value)) .build(); } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/render/RenderedCriterion.java b/src/main/java/org/mybatis/dynamic/sql/where/render/RenderedCriterion.java index 39f221861..80dd259ad 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/render/RenderedCriterion.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/render/RenderedCriterion.java @@ -15,6 +15,8 @@ */ package org.mybatis.dynamic.sql.where.render; +import static org.mybatis.dynamic.sql.util.StringUtilities.spaceBefore; + import java.util.Objects; import org.mybatis.dynamic.sql.util.FragmentAndParameters; @@ -48,9 +50,7 @@ public RenderedCriterion withConnector(String connector) { } private FragmentAndParameters prependFragment(FragmentAndParameters fragmentAndParameters, String connector) { - return FragmentAndParameters.withFragment(connector + " " + fragmentAndParameters.fragment()) //$NON-NLS-1$ - .withParameters(fragmentAndParameters.parameters()) - .build(); + return fragmentAndParameters.mapFragment(s -> connector + spaceBefore(s)); } public static class Builder { diff --git a/src/test/java/issues/gh655/Gh655Test.java b/src/test/java/issues/gh655/Gh655Test.java index 74385d97f..f7b865d52 100644 --- a/src/test/java/issues/gh655/Gh655Test.java +++ b/src/test/java/issues/gh655/Gh655Test.java @@ -36,7 +36,7 @@ import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import org.mybatis.dynamic.sql.exception.DynamicSqlException; +import org.mybatis.dynamic.sql.exception.InvalidSqlException; import org.mybatis.dynamic.sql.render.RenderingStrategies; import org.mybatis.dynamic.sql.select.SelectModel; import org.mybatis.dynamic.sql.select.render.SelectStatementProvider; @@ -91,7 +91,7 @@ void sumWithOptionalTest() { .from(items) .build(); - assertThatExceptionOfType(DynamicSqlException.class) + assertThatExceptionOfType(InvalidSqlException.class) .isThrownBy(() -> selectModel.render(RenderingStrategies.MYBATIS3)) .withMessage("The \"sum\" function does not support conditions that fail to render"); }