Skip to content

Commit

Permalink
Merge pull request #754 from jeffgbutler/separate-empty-from-renderable
Browse files Browse the repository at this point in the history
Refactoring Slice - Empty Conditions
  • Loading branch information
jeffgbutler authored Mar 3, 2024
2 parents 44b79f7 + 2d52703 commit 3109ed6
Show file tree
Hide file tree
Showing 24 changed files with 190 additions and 175 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ types - which is a rare usage. Please let us know if this causes an undo hardshi
your code accordingly. ([#662](https://github.com/mybatis/mybatis-dynamic-sql/pull/662))
2. Added the ability to code a bound value in rendered SQL. This is similar to a constant, but the value is added to
the parameter map and a bind parameter marker is rendered. ([#738](https://github.com/mybatis/mybatis-dynamic-sql/pull/738))
3. Refactored the conditions to separate the concept of an empty condition from that of a renderable condition. This
will enable a future change where conditions could decide to allow rendering even if they are considered empty (such
as rendering empty lists). This change should be transparent to users unless they have implemented custom conditions.

## Release 1.5.0 - April 21, 2023

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ public final <R> Stream<R> mapValues(Function<T, R> mapper) {
}

@Override
public boolean shouldRender() {
return !values.isEmpty();
public boolean isEmpty() {
return values.isEmpty();
}

@Override
Expand All @@ -56,20 +56,20 @@ private Collection<T> applyFilter(Predicate<? super T> predicate) {

protected <S extends AbstractListValueCondition<T>> S filterSupport(Predicate<? super T> predicate,
Function<Collection<T>, S> constructor, S self, Supplier<S> emptySupplier) {
if (shouldRender()) {
if (isEmpty()) {
return self;
} else {
Collection<T> filtered = applyFilter(predicate);
return filtered.isEmpty() ? emptySupplier.get() : constructor.apply(filtered);
} else {
return self;
}
}

protected <R, S extends AbstractListValueCondition<R>> S mapSupport(Function<? super T, ? extends R> mapper,
Function<Collection<R>, S> constructor, Supplier<S> emptySupplier) {
if (shouldRender()) {
return constructor.apply(applyMapper(mapper));
} else {
if (isEmpty()) {
return emptySupplier.get();
} else {
return constructor.apply(applyMapper(mapper));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ public <R> R accept(ConditionVisitor<T, R> visitor) {

protected <S extends AbstractNoValueCondition<?>> S filterSupport(BooleanSupplier booleanSupplier,
Supplier<S> emptySupplier, S self) {
if (shouldRender()) {
return booleanSupplier.getAsBoolean() ? self : emptySupplier.get();
} else {
if (isEmpty()) {
return self;
} else {
return booleanSupplier.getAsBoolean() ? self : emptySupplier.get();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,19 +37,19 @@ public <R> R accept(ConditionVisitor<T, R> visitor) {

protected <S extends AbstractSingleValueCondition<T>> S filterSupport(Predicate<? super T> predicate,
Supplier<S> emptySupplier, S self) {
if (shouldRender()) {
return predicate.test(value) ? self : emptySupplier.get();
} else {
if (isEmpty()) {
return self;
} else {
return predicate.test(value) ? self : emptySupplier.get();
}
}

protected <R, S extends AbstractSingleValueCondition<R>> S mapSupport(Function<? super T, ? extends R> mapper,
Function<R, S> constructor, Supplier<S> emptySupplier) {
if (shouldRender()) {
return constructor.apply(mapper.apply(value));
} else {
if (isEmpty()) {
return emptySupplier.get();
} else {
return constructor.apply(mapper.apply(value));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,10 @@ public <R> R accept(ConditionVisitor<T, R> visitor) {

protected <S extends AbstractTwoValueCondition<T>> S filterSupport(BiPredicate<? super T, ? super T> predicate,
Supplier<S> emptySupplier, S self) {
if (shouldRender()) {
return predicate.test(value1, value2) ? self : emptySupplier.get();
} else {
if (isEmpty()) {
return self;
} else {
return predicate.test(value1, value2) ? self : emptySupplier.get();
}
}

Expand All @@ -59,10 +59,10 @@ protected <S extends AbstractTwoValueCondition<T>> S filterSupport(Predicate<? s

protected <R, S extends AbstractTwoValueCondition<R>> S mapSupport(Function<? super T, ? extends R> mapper1,
Function<? super T, ? extends R> mapper2, BiFunction<R, R, S> constructor, Supplier<S> emptySupplier) {
if (shouldRender()) {
return constructor.apply(mapper1.apply(value1), mapper2.apply(value2));
} else {
if (isEmpty()) {
return emptySupplier.get();
} else {
return constructor.apply(mapper1.apply(value1), mapper2.apply(value2));
}
}

Expand Down
20 changes: 16 additions & 4 deletions src/main/java/org/mybatis/dynamic/sql/VisitableCondition.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,34 @@
*/
package org.mybatis.dynamic.sql;

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

@FunctionalInterface
public interface VisitableCondition<T> {
<R> R accept(ConditionVisitor<T, R> visitor);

/**
* Subclasses can override this to inform the renderer if the condition should not be included
* in the rendered SQL. For example, IsEqualWhenPresent will not render if the value is null.
* in the rendered SQL. Typically, conditions will not render if they are empty.
*
* @return true if the condition should render.
*/
default boolean shouldRender() {
return true;
default boolean shouldRender(RenderingContext renderingContext) {
return !isEmpty();
}

/**
* Subclasses can override this to indicate whether the condition is considered empty. This is primarily used in
* map and filter operations - the map and filter functions will not be applied if the condition is empty.
*
* @return true if the condition is empty.
*/
default boolean isEmpty() {
return false;
}

/**
* This method will be called during rendering when {@link VisitableCondition#shouldRender()}
* This method will be called during rendering when {@link VisitableCondition#shouldRender(RenderingContext)}
* returns false.
*/
default void renderingSkipped() {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ private Sum(BindableColumn<T> column) {
private Sum(BindableColumn<T> column, VisitableCondition<T> condition) {
super(column);
renderer = rc -> {
Validator.assertTrue(condition.shouldRender(), "ERROR.37", "sum"); //$NON-NLS-1$ //$NON-NLS-2$
Validator.assertTrue(condition.shouldRender(rc), "ERROR.37", "sum"); //$NON-NLS-1$ //$NON-NLS-2$

DefaultConditionVisitor<T> visitor = new DefaultConditionVisitor.Builder<T>()
.withColumn(column)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@
public class IsBetween<T> extends AbstractTwoValueCondition<T> {
private static final IsBetween<?> EMPTY = new IsBetween<Object>(null, null) {
@Override
public boolean shouldRender() {
return false;
public boolean isEmpty() {
return true;
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ public class IsEqualTo<T> extends AbstractSingleValueCondition<T> {

private static final IsEqualTo<?> EMPTY = new IsEqualTo<Object>(null) {
@Override
public boolean shouldRender() {
return false;
public boolean isEmpty() {
return true;
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
public class IsGreaterThan<T> extends AbstractSingleValueCondition<T> {
private static final IsGreaterThan<?> EMPTY = new IsGreaterThan<Object>(null) {
@Override
public boolean shouldRender() {
return false;
public boolean isEmpty() {
return true;
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
public class IsGreaterThanOrEqualTo<T> extends AbstractSingleValueCondition<T> {
private static final IsGreaterThanOrEqualTo<?> EMPTY = new IsGreaterThanOrEqualTo<Object>(null) {
@Override
public boolean shouldRender() {
return false;
public boolean isEmpty() {
return true;
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
public class IsLessThan<T> extends AbstractSingleValueCondition<T> {
private static final IsLessThan<?> EMPTY = new IsLessThan<Object>(null) {
@Override
public boolean shouldRender() {
return false;
public boolean isEmpty() {
return true;
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
public class IsLessThanOrEqualTo<T> extends AbstractSingleValueCondition<T> {
private static final IsLessThanOrEqualTo<?> EMPTY = new IsLessThanOrEqualTo<Object>(null) {
@Override
public boolean shouldRender() {
return false;
public boolean isEmpty() {
return true;
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
public class IsLike<T> extends AbstractSingleValueCondition<T> {
private static final IsLike<?> EMPTY = new IsLike<Object>(null) {
@Override
public boolean shouldRender() {
return false;
public boolean isEmpty() {
return true;
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ public class IsLikeCaseInsensitive extends AbstractSingleValueCondition<String>
implements CaseInsensitiveVisitableCondition {
private static final IsLikeCaseInsensitive EMPTY = new IsLikeCaseInsensitive(null) {
@Override
public boolean shouldRender() {
return false;
public boolean isEmpty() {
return true;
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@
public class IsNotBetween<T> extends AbstractTwoValueCondition<T> {
private static final IsNotBetween<?> EMPTY = new IsNotBetween<Object>(null, null) {
@Override
public boolean shouldRender() {
return false;
public boolean isEmpty() {
return true;
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
public class IsNotEqualTo<T> extends AbstractSingleValueCondition<T> {
private static final IsNotEqualTo<?> EMPTY = new IsNotEqualTo<Object>(null) {
@Override
public boolean shouldRender() {
return false;
public boolean isEmpty() {
return true;
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
public class IsNotLike<T> extends AbstractSingleValueCondition<T> {
private static final IsNotLike<?> EMPTY = new IsNotLike<Object>(null) {
@Override
public boolean shouldRender() {
return false;
public boolean isEmpty() {
return true;
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ public class IsNotLikeCaseInsensitive extends AbstractSingleValueCondition<Strin
implements CaseInsensitiveVisitableCondition {
private static final IsNotLikeCaseInsensitive EMPTY = new IsNotLikeCaseInsensitive(null) {
@Override
public boolean shouldRender() {
return false;
public boolean isEmpty() {
return true;
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
public class IsNotNull<T> extends AbstractNoValueCondition<T> {
private static final IsNotNull<?> EMPTY = new IsNotNull<Object>() {
@Override
public boolean shouldRender() {
return false;
public boolean isEmpty() {
return true;
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
public class IsNull<T> extends AbstractNoValueCondition<T> {
private static final IsNull<?> EMPTY = new IsNull<Object>() {
@Override
public boolean shouldRender() {
return false;
public boolean isEmpty() {
return true;
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ public Optional<RenderedCriterion> render(List<AndOrCriteriaGroup> subCriteria,
}

private <T> Optional<FragmentAndParameters> renderColumnAndCondition(ColumnAndConditionCriterion<T> criterion) {
if (criterion.condition().shouldRender()) {
if (criterion.condition().shouldRender(renderingContext)) {
return Optional.of(renderCondition(criterion));
} else {
criterion.condition().renderingSkipped();
Expand Down
Loading

0 comments on commit 3109ed6

Please sign in to comment.