Skip to content

Improve Condition Rendering Extensibility #917

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Mar 6, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -100,6 +100,10 @@ Runtime behavior changes:
these concepts for different databases it simply adds known clauses to a generated SQL statement. You should always
test to make sure these functions work in your target database. Currently, we support, and test, the options
supported by PostgreSQL.
- Rendering for all the conditions (isEqualTo, etc.) has changed. This should be transparent to most users unless you
have coded a direct implementation of `VisitableCondition`. The change makes it easier to code custom conditions that
are not supported by the library out of the box. The statement renderers now call methods `renderCondition` and
`renderLeftColumn` that you can override to implement any rendering you need.

## Release 1.5.2 - June 3, 2024

Original file line number Diff line number Diff line change
@@ -15,22 +15,23 @@
*/
package org.mybatis.dynamic.sql;

public abstract class AbstractColumnComparisonCondition<T> implements VisitableCondition<T> {
import static org.mybatis.dynamic.sql.util.StringUtilities.spaceBefore;

import org.mybatis.dynamic.sql.render.RenderingContext;
import org.mybatis.dynamic.sql.util.FragmentAndParameters;

public abstract class AbstractColumnComparisonCondition<T> implements RenderableCondition<T> {

protected final BasicColumn rightColumn;

protected AbstractColumnComparisonCondition(BasicColumn rightColumn) {
this.rightColumn = rightColumn;
}

public BasicColumn rightColumn() {
return rightColumn;
}
public abstract String operator();

@Override
public <R> R accept(ConditionVisitor<T, R> visitor) {
return visitor.visit(this);
public FragmentAndParameters renderCondition(RenderingContext renderingContext, BindableColumn<T> leftColumn) {
return rightColumn.render(renderingContext).mapFragment(f -> operator() + spaceBefore(f));
}

public abstract String operator();
}
Original file line number Diff line number Diff line change
@@ -23,7 +23,12 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;

public abstract class AbstractListValueCondition<T> implements VisitableCondition<T> {
import org.mybatis.dynamic.sql.render.RenderedParameterInfo;
import org.mybatis.dynamic.sql.render.RenderingContext;
import org.mybatis.dynamic.sql.util.FragmentAndParameters;
import org.mybatis.dynamic.sql.util.FragmentCollector;

public abstract class AbstractListValueCondition<T> implements RenderableCondition<T> {
protected final Collection<T> values;

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

@Override
public <R> R accept(ConditionVisitor<T, R> visitor) {
return visitor.visit(this);
}

private <R> Collection<R> applyMapper(Function<? super T, ? extends R> mapper) {
Objects.requireNonNull(mapper);
return values.stream().map(mapper).collect(Collectors.toList());
return values().map(mapper).collect(Collectors.toList());
}

private Collection<T> applyFilter(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate);
return values.stream().filter(predicate).toList();
return values().filter(predicate).toList();
}

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
public abstract AbstractListValueCondition<T> filter(Predicate<? super T> predicate);

public abstract String operator();

@Override
public FragmentAndParameters renderCondition(RenderingContext renderingContext, BindableColumn<T> leftColumn) {
return values().map(v -> toFragmentAndParameters(v, renderingContext, leftColumn))
.collect(FragmentCollector.collect())
.toFragmentAndParameters(Collectors.joining(",", //$NON-NLS-1$
operator() + " (", ")")); //$NON-NLS-1$ //$NON-NLS-2$
}

private FragmentAndParameters toFragmentAndParameters(T value, RenderingContext renderingContext,
BindableColumn<T> leftColumn) {
RenderedParameterInfo parameterInfo = renderingContext.calculateParameterInfo(leftColumn);
return FragmentAndParameters.withFragment(parameterInfo.renderedPlaceHolder())
.withParameter(parameterInfo.parameterMapKey(), leftColumn.convertParameterType(value))
.build();
}
}
Original file line number Diff line number Diff line change
@@ -18,12 +18,10 @@
import java.util.function.BooleanSupplier;
import java.util.function.Supplier;

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

@Override
public <R> R accept(ConditionVisitor<T, R> visitor) {
return visitor.visit(this);
}
public abstract class AbstractNoValueCondition<T> implements RenderableCondition<T> {

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

public abstract String operator();

@Override
public FragmentAndParameters renderCondition(RenderingContext renderingContext, BindableColumn<T> leftColumn) {
return FragmentAndParameters.fromFragment(operator());
}
}
Original file line number Diff line number Diff line change
@@ -15,11 +15,17 @@
*/
package org.mybatis.dynamic.sql;

import static org.mybatis.dynamic.sql.util.StringUtilities.spaceBefore;

import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;

public abstract class AbstractSingleValueCondition<T> implements VisitableCondition<T> {
import org.mybatis.dynamic.sql.render.RenderedParameterInfo;
import org.mybatis.dynamic.sql.render.RenderingContext;
import org.mybatis.dynamic.sql.util.FragmentAndParameters;

public abstract class AbstractSingleValueCondition<T> implements RenderableCondition<T> {
protected final T value;

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

@Override
public <R> R accept(ConditionVisitor<T, R> visitor) {
return visitor.visit(this);
}

protected <S extends AbstractSingleValueCondition<T>> S filterSupport(Predicate<? super T> predicate,
Supplier<S> emptySupplier, S self) {
if (isEmpty()) {
@@ -64,4 +65,14 @@ protected <R, S extends AbstractSingleValueCondition<R>> S mapSupport(Function<?
public abstract AbstractSingleValueCondition<T> filter(Predicate<? super T> predicate);

public abstract String operator();

@Override
public FragmentAndParameters renderCondition(RenderingContext renderingContext, BindableColumn<T> leftColumn) {
RenderedParameterInfo parameterInfo = renderingContext.calculateParameterInfo(leftColumn);
String finalFragment = operator() + spaceBefore(parameterInfo.renderedPlaceHolder());

return FragmentAndParameters.withFragment(finalFragment)
.withParameter(parameterInfo.parameterMapKey(), leftColumn.convertParameterType(value()))
.build();
}
}
Original file line number Diff line number Diff line change
@@ -15,24 +15,28 @@
*/
package org.mybatis.dynamic.sql;

import org.mybatis.dynamic.sql.render.RenderingContext;
import org.mybatis.dynamic.sql.select.SelectModel;
import org.mybatis.dynamic.sql.select.render.SubQueryRenderer;
import org.mybatis.dynamic.sql.util.Buildable;
import org.mybatis.dynamic.sql.util.FragmentAndParameters;

public abstract class AbstractSubselectCondition<T> implements VisitableCondition<T> {
public abstract class AbstractSubselectCondition<T> implements RenderableCondition<T> {
private final SelectModel selectModel;

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

public SelectModel selectModel() {
return selectModel;
}
public abstract String operator();

@Override
public <R> R accept(ConditionVisitor<T, R> visitor) {
return visitor.visit(this);
public FragmentAndParameters renderCondition(RenderingContext renderingContext, BindableColumn<T> leftColumn) {
return SubQueryRenderer.withSelectModel(selectModel)
.withRenderingContext(renderingContext)
.withPrefix(operator() + " (") //$NON-NLS-1$
.withSuffix(")") //$NON-NLS-1$
.build()
.render();
}

public abstract String operator();
}
Original file line number Diff line number Diff line change
@@ -15,13 +15,19 @@
*/
package org.mybatis.dynamic.sql;

import static org.mybatis.dynamic.sql.util.StringUtilities.spaceBefore;

import java.util.function.BiFunction;
import java.util.function.BiPredicate;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;

public abstract class AbstractTwoValueCondition<T> implements VisitableCondition<T> {
import org.mybatis.dynamic.sql.render.RenderedParameterInfo;
import org.mybatis.dynamic.sql.render.RenderingContext;
import org.mybatis.dynamic.sql.util.FragmentAndParameters;

public abstract class AbstractTwoValueCondition<T> implements RenderableCondition<T> {
protected final T value1;
protected final T value2;

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

@Override
public <R> R accept(ConditionVisitor<T, R> visitor) {
return visitor.visit(this);
}

protected <S extends AbstractTwoValueCondition<T>> S filterSupport(BiPredicate<? super T, ? super T> predicate,
Supplier<S> emptySupplier, S self) {
if (isEmpty()) {
@@ -90,4 +91,20 @@ protected <R, S extends AbstractTwoValueCondition<R>> S mapSupport(Function<? su
public abstract String operator1();

public abstract String operator2();

@Override
public FragmentAndParameters renderCondition(RenderingContext renderingContext, BindableColumn<T> leftColumn) {
RenderedParameterInfo parameterInfo1 = renderingContext.calculateParameterInfo(leftColumn);
RenderedParameterInfo parameterInfo2 = renderingContext.calculateParameterInfo(leftColumn);

String finalFragment = operator1()
+ spaceBefore(parameterInfo1.renderedPlaceHolder())
+ spaceBefore(operator2())
+ spaceBefore(parameterInfo2.renderedPlaceHolder());

return FragmentAndParameters.withFragment(finalFragment)
.withParameter(parameterInfo1.parameterMapKey(), leftColumn.convertParameterType(value1()))
.withParameter(parameterInfo2.parameterMapKey(), leftColumn.convertParameterType(value2()))
.build();
}
}
Original file line number Diff line number Diff line change
@@ -21,7 +21,7 @@

public class ColumnAndConditionCriterion<T> extends SqlCriterion {
private final BindableColumn<T> column;
private final VisitableCondition<T> condition;
private final RenderableCondition<T> condition;

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

public VisitableCondition<T> condition() {
public RenderableCondition<T> condition() {
return condition;
}

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

public static class Builder<T> extends AbstractBuilder<Builder<T>> {
private @Nullable BindableColumn<T> column;
private @Nullable VisitableCondition<T> condition;
private @Nullable RenderableCondition<T> condition;

public Builder<T> withColumn(BindableColumn<T> column) {
this.column = column;
return this;
}

public Builder<T> withCondition(VisitableCondition<T> condition) {
public Builder<T> withCondition(RenderableCondition<T> condition) {
this.condition = condition;
return this;
}
30 changes: 0 additions & 30 deletions src/main/java/org/mybatis/dynamic/sql/ConditionVisitor.java

This file was deleted.

Loading