Skip to content

Commit eeedb40

Browse files
authored
Merge pull request #917 from jeffgbutler/condition-rendering
Improve Condition Rendering Extensibility
2 parents 978152d + 13fb0cf commit eeedb40

32 files changed

+468
-350
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,10 @@ Runtime behavior changes:
100100
these concepts for different databases it simply adds known clauses to a generated SQL statement. You should always
101101
test to make sure these functions work in your target database. Currently, we support, and test, the options
102102
supported by PostgreSQL.
103+
- Rendering for all the conditions (isEqualTo, etc.) has changed. This should be transparent to most users unless you
104+
have coded a direct implementation of `VisitableCondition`. The change makes it easier to code custom conditions that
105+
are not supported by the library out of the box. The statement renderers now call methods `renderCondition` and
106+
`renderLeftColumn` that you can override to implement any rendering you need.
103107

104108
## Release 1.5.2 - June 3, 2024
105109

src/main/java/org/mybatis/dynamic/sql/AbstractColumnComparisonCondition.java

+9-8
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,23 @@
1515
*/
1616
package org.mybatis.dynamic.sql;
1717

18-
public abstract class AbstractColumnComparisonCondition<T> implements VisitableCondition<T> {
18+
import static org.mybatis.dynamic.sql.util.StringUtilities.spaceBefore;
19+
20+
import org.mybatis.dynamic.sql.render.RenderingContext;
21+
import org.mybatis.dynamic.sql.util.FragmentAndParameters;
22+
23+
public abstract class AbstractColumnComparisonCondition<T> implements RenderableCondition<T> {
1924

2025
protected final BasicColumn rightColumn;
2126

2227
protected AbstractColumnComparisonCondition(BasicColumn rightColumn) {
2328
this.rightColumn = rightColumn;
2429
}
2530

26-
public BasicColumn rightColumn() {
27-
return rightColumn;
28-
}
31+
public abstract String operator();
2932

3033
@Override
31-
public <R> R accept(ConditionVisitor<T, R> visitor) {
32-
return visitor.visit(this);
34+
public FragmentAndParameters renderCondition(RenderingContext renderingContext, BindableColumn<T> leftColumn) {
35+
return rightColumn.render(renderingContext).mapFragment(f -> operator() + spaceBefore(f));
3336
}
34-
35-
public abstract String operator();
3637
}

src/main/java/org/mybatis/dynamic/sql/AbstractListValueCondition.java

+24-8
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,12 @@
2323
import java.util.stream.Collectors;
2424
import java.util.stream.Stream;
2525

26-
public abstract class AbstractListValueCondition<T> implements VisitableCondition<T> {
26+
import org.mybatis.dynamic.sql.render.RenderedParameterInfo;
27+
import org.mybatis.dynamic.sql.render.RenderingContext;
28+
import org.mybatis.dynamic.sql.util.FragmentAndParameters;
29+
import org.mybatis.dynamic.sql.util.FragmentCollector;
30+
31+
public abstract class AbstractListValueCondition<T> implements RenderableCondition<T> {
2732
protected final Collection<T> values;
2833

2934
protected AbstractListValueCondition(Collection<T> values) {
@@ -39,19 +44,14 @@ public boolean isEmpty() {
3944
return values.isEmpty();
4045
}
4146

42-
@Override
43-
public <R> R accept(ConditionVisitor<T, R> visitor) {
44-
return visitor.visit(this);
45-
}
46-
4747
private <R> Collection<R> applyMapper(Function<? super T, ? extends R> mapper) {
4848
Objects.requireNonNull(mapper);
49-
return values.stream().map(mapper).collect(Collectors.toList());
49+
return values().map(mapper).collect(Collectors.toList());
5050
}
5151

5252
private Collection<T> applyFilter(Predicate<? super T> predicate) {
5353
Objects.requireNonNull(predicate);
54-
return values.stream().filter(predicate).toList();
54+
return values().filter(predicate).toList();
5555
}
5656

5757
protected <S extends AbstractListValueCondition<T>> S filterSupport(Predicate<? super T> predicate,
@@ -84,4 +84,20 @@ protected <R, S extends AbstractListValueCondition<R>> S mapSupport(Function<? s
8484
public abstract AbstractListValueCondition<T> filter(Predicate<? super T> predicate);
8585

8686
public abstract String operator();
87+
88+
@Override
89+
public FragmentAndParameters renderCondition(RenderingContext renderingContext, BindableColumn<T> leftColumn) {
90+
return values().map(v -> toFragmentAndParameters(v, renderingContext, leftColumn))
91+
.collect(FragmentCollector.collect())
92+
.toFragmentAndParameters(Collectors.joining(",", //$NON-NLS-1$
93+
operator() + " (", ")")); //$NON-NLS-1$ //$NON-NLS-2$
94+
}
95+
96+
private FragmentAndParameters toFragmentAndParameters(T value, RenderingContext renderingContext,
97+
BindableColumn<T> leftColumn) {
98+
RenderedParameterInfo parameterInfo = renderingContext.calculateParameterInfo(leftColumn);
99+
return FragmentAndParameters.withFragment(parameterInfo.renderedPlaceHolder())
100+
.withParameter(parameterInfo.parameterMapKey(), leftColumn.convertParameterType(value))
101+
.build();
102+
}
87103
}

src/main/java/org/mybatis/dynamic/sql/AbstractNoValueCondition.java

+8-5
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,10 @@
1818
import java.util.function.BooleanSupplier;
1919
import java.util.function.Supplier;
2020

21-
public abstract class AbstractNoValueCondition<T> implements VisitableCondition<T> {
21+
import org.mybatis.dynamic.sql.render.RenderingContext;
22+
import org.mybatis.dynamic.sql.util.FragmentAndParameters;
2223

23-
@Override
24-
public <R> R accept(ConditionVisitor<T, R> visitor) {
25-
return visitor.visit(this);
26-
}
24+
public abstract class AbstractNoValueCondition<T> implements RenderableCondition<T> {
2725

2826
protected <S extends AbstractNoValueCondition<?>> S filterSupport(BooleanSupplier booleanSupplier,
2927
Supplier<S> emptySupplier, S self) {
@@ -35,4 +33,9 @@ protected <S extends AbstractNoValueCondition<?>> S filterSupport(BooleanSupplie
3533
}
3634

3735
public abstract String operator();
36+
37+
@Override
38+
public FragmentAndParameters renderCondition(RenderingContext renderingContext, BindableColumn<T> leftColumn) {
39+
return FragmentAndParameters.fromFragment(operator());
40+
}
3841
}

src/main/java/org/mybatis/dynamic/sql/AbstractSingleValueCondition.java

+17-6
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,17 @@
1515
*/
1616
package org.mybatis.dynamic.sql;
1717

18+
import static org.mybatis.dynamic.sql.util.StringUtilities.spaceBefore;
19+
1820
import java.util.function.Function;
1921
import java.util.function.Predicate;
2022
import java.util.function.Supplier;
2123

22-
public abstract class AbstractSingleValueCondition<T> implements VisitableCondition<T> {
24+
import org.mybatis.dynamic.sql.render.RenderedParameterInfo;
25+
import org.mybatis.dynamic.sql.render.RenderingContext;
26+
import org.mybatis.dynamic.sql.util.FragmentAndParameters;
27+
28+
public abstract class AbstractSingleValueCondition<T> implements RenderableCondition<T> {
2329
protected final T value;
2430

2531
protected AbstractSingleValueCondition(T value) {
@@ -30,11 +36,6 @@ public T value() {
3036
return value;
3137
}
3238

33-
@Override
34-
public <R> R accept(ConditionVisitor<T, R> visitor) {
35-
return visitor.visit(this);
36-
}
37-
3839
protected <S extends AbstractSingleValueCondition<T>> S filterSupport(Predicate<? super T> predicate,
3940
Supplier<S> emptySupplier, S self) {
4041
if (isEmpty()) {
@@ -64,4 +65,14 @@ protected <R, S extends AbstractSingleValueCondition<R>> S mapSupport(Function<?
6465
public abstract AbstractSingleValueCondition<T> filter(Predicate<? super T> predicate);
6566

6667
public abstract String operator();
68+
69+
@Override
70+
public FragmentAndParameters renderCondition(RenderingContext renderingContext, BindableColumn<T> leftColumn) {
71+
RenderedParameterInfo parameterInfo = renderingContext.calculateParameterInfo(leftColumn);
72+
String finalFragment = operator() + spaceBefore(parameterInfo.renderedPlaceHolder());
73+
74+
return FragmentAndParameters.withFragment(finalFragment)
75+
.withParameter(parameterInfo.parameterMapKey(), leftColumn.convertParameterType(value()))
76+
.build();
77+
}
6778
}

src/main/java/org/mybatis/dynamic/sql/AbstractSubselectCondition.java

+12-8
Original file line numberDiff line numberDiff line change
@@ -15,24 +15,28 @@
1515
*/
1616
package org.mybatis.dynamic.sql;
1717

18+
import org.mybatis.dynamic.sql.render.RenderingContext;
1819
import org.mybatis.dynamic.sql.select.SelectModel;
20+
import org.mybatis.dynamic.sql.select.render.SubQueryRenderer;
1921
import org.mybatis.dynamic.sql.util.Buildable;
22+
import org.mybatis.dynamic.sql.util.FragmentAndParameters;
2023

21-
public abstract class AbstractSubselectCondition<T> implements VisitableCondition<T> {
24+
public abstract class AbstractSubselectCondition<T> implements RenderableCondition<T> {
2225
private final SelectModel selectModel;
2326

2427
protected AbstractSubselectCondition(Buildable<SelectModel> selectModelBuilder) {
2528
this.selectModel = selectModelBuilder.build();
2629
}
2730

28-
public SelectModel selectModel() {
29-
return selectModel;
30-
}
31+
public abstract String operator();
3132

3233
@Override
33-
public <R> R accept(ConditionVisitor<T, R> visitor) {
34-
return visitor.visit(this);
34+
public FragmentAndParameters renderCondition(RenderingContext renderingContext, BindableColumn<T> leftColumn) {
35+
return SubQueryRenderer.withSelectModel(selectModel)
36+
.withRenderingContext(renderingContext)
37+
.withPrefix(operator() + " (") //$NON-NLS-1$
38+
.withSuffix(")") //$NON-NLS-1$
39+
.build()
40+
.render();
3541
}
36-
37-
public abstract String operator();
3842
}

src/main/java/org/mybatis/dynamic/sql/AbstractTwoValueCondition.java

+23-6
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,19 @@
1515
*/
1616
package org.mybatis.dynamic.sql;
1717

18+
import static org.mybatis.dynamic.sql.util.StringUtilities.spaceBefore;
19+
1820
import java.util.function.BiFunction;
1921
import java.util.function.BiPredicate;
2022
import java.util.function.Function;
2123
import java.util.function.Predicate;
2224
import java.util.function.Supplier;
2325

24-
public abstract class AbstractTwoValueCondition<T> implements VisitableCondition<T> {
26+
import org.mybatis.dynamic.sql.render.RenderedParameterInfo;
27+
import org.mybatis.dynamic.sql.render.RenderingContext;
28+
import org.mybatis.dynamic.sql.util.FragmentAndParameters;
29+
30+
public abstract class AbstractTwoValueCondition<T> implements RenderableCondition<T> {
2531
protected final T value1;
2632
protected final T value2;
2733

@@ -38,11 +44,6 @@ public T value2() {
3844
return value2;
3945
}
4046

41-
@Override
42-
public <R> R accept(ConditionVisitor<T, R> visitor) {
43-
return visitor.visit(this);
44-
}
45-
4647
protected <S extends AbstractTwoValueCondition<T>> S filterSupport(BiPredicate<? super T, ? super T> predicate,
4748
Supplier<S> emptySupplier, S self) {
4849
if (isEmpty()) {
@@ -90,4 +91,20 @@ protected <R, S extends AbstractTwoValueCondition<R>> S mapSupport(Function<? su
9091
public abstract String operator1();
9192

9293
public abstract String operator2();
94+
95+
@Override
96+
public FragmentAndParameters renderCondition(RenderingContext renderingContext, BindableColumn<T> leftColumn) {
97+
RenderedParameterInfo parameterInfo1 = renderingContext.calculateParameterInfo(leftColumn);
98+
RenderedParameterInfo parameterInfo2 = renderingContext.calculateParameterInfo(leftColumn);
99+
100+
String finalFragment = operator1()
101+
+ spaceBefore(parameterInfo1.renderedPlaceHolder())
102+
+ spaceBefore(operator2())
103+
+ spaceBefore(parameterInfo2.renderedPlaceHolder());
104+
105+
return FragmentAndParameters.withFragment(finalFragment)
106+
.withParameter(parameterInfo1.parameterMapKey(), leftColumn.convertParameterType(value1()))
107+
.withParameter(parameterInfo2.parameterMapKey(), leftColumn.convertParameterType(value2()))
108+
.build();
109+
}
93110
}

src/main/java/org/mybatis/dynamic/sql/ColumnAndConditionCriterion.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222
public class ColumnAndConditionCriterion<T> extends SqlCriterion {
2323
private final BindableColumn<T> column;
24-
private final VisitableCondition<T> condition;
24+
private final RenderableCondition<T> condition;
2525

2626
private ColumnAndConditionCriterion(Builder<T> builder) {
2727
super(builder);
@@ -33,7 +33,7 @@ public BindableColumn<T> column() {
3333
return column;
3434
}
3535

36-
public VisitableCondition<T> condition() {
36+
public RenderableCondition<T> condition() {
3737
return condition;
3838
}
3939

@@ -48,14 +48,14 @@ public static <T> Builder<T> withColumn(BindableColumn<T> column) {
4848

4949
public static class Builder<T> extends AbstractBuilder<Builder<T>> {
5050
private @Nullable BindableColumn<T> column;
51-
private @Nullable VisitableCondition<T> condition;
51+
private @Nullable RenderableCondition<T> condition;
5252

5353
public Builder<T> withColumn(BindableColumn<T> column) {
5454
this.column = column;
5555
return this;
5656
}
5757

58-
public Builder<T> withCondition(VisitableCondition<T> condition) {
58+
public Builder<T> withCondition(RenderableCondition<T> condition) {
5959
this.condition = condition;
6060
return this;
6161
}

src/main/java/org/mybatis/dynamic/sql/ConditionVisitor.java

-30
This file was deleted.

0 commit comments

Comments
 (0)