Skip to content

Condition Filter and Map are now Interfaces #921

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 15 commits into from
Mar 14, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Make filter and map optional on list value conditions
  • Loading branch information
jeffgbutler committed Mar 14, 2025
commit 43fdf0651330c71c810e49a730e47efbfc28d9bb
Original file line number Diff line number Diff line change
Expand Up @@ -73,26 +73,6 @@ protected <R, S extends AbstractListValueCondition<R>> S mapSupport(Function<? s
}
}

/**
* If not empty, apply the predicate to each value in the list and return a new condition with the filtered values.
* Else returns an empty condition (this).
*
* @param predicate predicate applied to the values, if not empty
*
* @return a new condition with filtered values if renderable, otherwise an empty condition
*/
public abstract AbstractListValueCondition<T> filter(Predicate<? super T> predicate);

/**
* If not empty, apply the mapping to each value in the list return a new condition with the mapped values.
* Else return an empty condition (this).
*
* @param mapper a mapping function to apply to the values, if not empty
* @param <R> type of the new condition
* @return a new condition with mapped values if renderable, otherwise an empty condition
*/
public abstract <R> AbstractListValueCondition<R> map(Function<? super T, ? extends R> mapper);

public abstract String operator();

@Override
Expand All @@ -110,4 +90,54 @@ private FragmentAndParameters toFragmentAndParameters(T value, RenderingContext
.withParameter(parameterInfo.parameterMapKey(), leftColumn.convertParameterType(value))
.build();
}

/**
* Conditions may implement Filterable to add optionality to rendering.
*
* <p>If a condition is Filterable, then a user may add a filter to the usage of the condition that makes a decision
* whether to render the condition at runtime. Conditions that fail the filter will be dropped from the
* rendered SQL.
*
* <p>Implementations of Filterable may call
* {@link AbstractListValueCondition#filterSupport(Predicate, Function, AbstractListValueCondition, Supplier)} as
* a common implementation of the filtering algorithm.
*
* @param <T> the Java type related to the database column type
*/
public interface Filterable<T> {
/**
* If renderable and the value matches the predicate, returns this condition. Else returns a condition
* that will not render.
*
* @param predicate predicate applied to the value, if renderable
* @return this condition if renderable and the value matches the predicate, otherwise a condition
* that will not render.
*/
AbstractListValueCondition<T> filter(Predicate<? super T> predicate);
}

/**
* Conditions may implement Mappable to alter condition values or types during rendering.
*
* <p>If a condition is Mappable, then a user may add a mapper to the usage of the condition that can alter the
* values of a condition, or change that datatype.
*
* <p>Implementations of Mappable may call
* {@link AbstractListValueCondition#mapSupport(Function, Function, Supplier)} as
* a common implementation of the mapping algorithm.
*
* @param <T> the Java type related to the database column type
*/
public interface Mappable<T> {
/**
* If renderable, apply the mapping to the value and return a new condition with the new value. Else return a
* condition that will not render (this).
*
* @param mapper a mapping function to apply to the value, if renderable
* @param <R> type of the new condition
* @return a new condition with the result of applying the mapper to the value of this condition,
* if renderable, otherwise a condition that will not render.
*/
<R> AbstractListValueCondition<R> map(Function<? super T, ? extends R> mapper);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
import org.mybatis.dynamic.sql.render.RenderingContext;
import org.mybatis.dynamic.sql.util.Validator;

public class IsIn<T> extends AbstractListValueCondition<T> {
public class IsIn<T> extends AbstractListValueCondition<T>
implements AbstractListValueCondition.Filterable<T>, AbstractListValueCondition.Mappable<T>{
private static final IsIn<?> EMPTY = new IsIn<>(Collections.emptyList());

public static <T> IsIn<T> empty() {
Expand Down Expand Up @@ -56,8 +57,7 @@ public IsIn<T> filter(Predicate<? super T> predicate) {

@Override
public <R> IsIn<R> map(Function<? super T, ? extends R> mapper) {
Function<Collection<R>, IsIn<R>> constructor = IsIn::new;
return mapSupport(mapper, constructor, IsIn::empty);
return mapSupport(mapper, IsIn::new, IsIn::empty);
}

@SafeVarargs
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@
import org.mybatis.dynamic.sql.util.Validator;

public class IsInCaseInsensitive<T> extends AbstractListValueCondition<T>
implements CaseInsensitiveRenderableCondition<T> {
implements CaseInsensitiveRenderableCondition<T>, AbstractListValueCondition.Filterable<T>,
AbstractListValueCondition.Mappable<T> {
private static final IsInCaseInsensitive<?> EMPTY = new IsInCaseInsensitive<>(Collections.emptyList());

public static <T> IsInCaseInsensitive<T> empty() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@
import org.mybatis.dynamic.sql.AbstractListValueCondition;

public class IsInCaseInsensitiveWhenPresent<T> extends AbstractListValueCondition<T>
implements CaseInsensitiveRenderableCondition<T> {
implements CaseInsensitiveRenderableCondition<T>, AbstractListValueCondition.Filterable<T>,
AbstractListValueCondition.Mappable<T> {
private static final IsInCaseInsensitiveWhenPresent<?> EMPTY =
new IsInCaseInsensitiveWhenPresent<>(Collections.emptyList());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
import org.jspecify.annotations.Nullable;
import org.mybatis.dynamic.sql.AbstractListValueCondition;

public class IsInWhenPresent<T> extends AbstractListValueCondition<T> {
public class IsInWhenPresent<T> extends AbstractListValueCondition<T>
implements AbstractListValueCondition.Filterable<T>, AbstractListValueCondition.Mappable<T>{
private static final IsInWhenPresent<?> EMPTY = new IsInWhenPresent<>(Collections.emptyList());

public static <T> IsInWhenPresent<T> empty() {
Expand All @@ -48,17 +49,9 @@ public IsInWhenPresent<T> filter(Predicate<? super T> predicate) {
return filterSupport(predicate, IsInWhenPresent::new, this, IsInWhenPresent::empty);
}

/**
* If not empty, apply the mapping to each value in the list return a new condition with the mapped values.
* Else return an empty condition (this).
*
* @param mapper a mapping function to apply to the values, if not empty
* @param <R> type of the new condition
* @return a new condition with mapped values if renderable, otherwise an empty condition
*/
@Override
public <R> IsInWhenPresent<R> map(Function<? super T, ? extends R> mapper) {
Function<Collection<R>, IsInWhenPresent<R>> constructor = IsInWhenPresent::new;
return mapSupport(mapper, constructor, IsInWhenPresent::empty);
return mapSupport(mapper, IsInWhenPresent::new, IsInWhenPresent::empty);
}

@SafeVarargs
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
import org.mybatis.dynamic.sql.render.RenderingContext;
import org.mybatis.dynamic.sql.util.Validator;

public class IsNotIn<T> extends AbstractListValueCondition<T> {
public class IsNotIn<T> extends AbstractListValueCondition<T>
implements AbstractListValueCondition.Filterable<T>, AbstractListValueCondition.Mappable<T>{
private static final IsNotIn<?> EMPTY = new IsNotIn<>(Collections.emptyList());

public static <T> IsNotIn<T> empty() {
Expand Down Expand Up @@ -56,8 +57,7 @@ public IsNotIn<T> filter(Predicate<? super T> predicate) {

@Override
public <R> IsNotIn<R> map(Function<? super T, ? extends R> mapper) {
Function<Collection<R>, IsNotIn<R>> constructor = IsNotIn::new;
return mapSupport(mapper, constructor, IsNotIn::empty);
return mapSupport(mapper, IsNotIn::new, IsNotIn::empty);
}

@SafeVarargs
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@
import org.mybatis.dynamic.sql.util.Validator;

public class IsNotInCaseInsensitive<T> extends AbstractListValueCondition<T>
implements CaseInsensitiveRenderableCondition<T> {
implements CaseInsensitiveRenderableCondition<T>, AbstractListValueCondition.Filterable<T>,
AbstractListValueCondition.Mappable<T> {
private static final IsNotInCaseInsensitive<?> EMPTY = new IsNotInCaseInsensitive<>(Collections.emptyList());

public static <T> IsNotInCaseInsensitive<T> empty() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@
import org.mybatis.dynamic.sql.AbstractListValueCondition;

public class IsNotInCaseInsensitiveWhenPresent<T> extends AbstractListValueCondition<T>
implements CaseInsensitiveRenderableCondition<T> {
implements CaseInsensitiveRenderableCondition<T>, AbstractListValueCondition.Filterable<T>,
AbstractListValueCondition.Mappable<T> {
private static final IsNotInCaseInsensitiveWhenPresent<?> EMPTY =
new IsNotInCaseInsensitiveWhenPresent<>(Collections.emptyList());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@

import org.mybatis.dynamic.sql.AbstractListValueCondition;

public class IsNotInWhenPresent<T> extends AbstractListValueCondition<T> {
public class IsNotInWhenPresent<T> extends AbstractListValueCondition<T>
implements AbstractListValueCondition.Filterable<T>, AbstractListValueCondition.Mappable<T>{
private static final IsNotInWhenPresent<?> EMPTY = new IsNotInWhenPresent<>(Collections.emptyList());

public static <T> IsNotInWhenPresent<T> empty() {
Expand All @@ -47,17 +48,9 @@ public IsNotInWhenPresent<T> filter(Predicate<? super T> predicate) {
return filterSupport(predicate, IsNotInWhenPresent::new, this, IsNotInWhenPresent::empty);
}

/**
* If not empty, apply the mapping to each value in the list return a new condition with the mapped values.
* Else return an empty condition (this).
*
* @param mapper a mapping function to apply to the values, if not empty
* @param <R> type of the new condition
* @return a new condition with mapped values if renderable, otherwise an empty condition
*/
@Override
public <R> IsNotInWhenPresent<R> map(Function<? super T, ? extends R> mapper) {
Function<Collection<R>, IsNotInWhenPresent<R>> constructor = IsNotInWhenPresent::new;
return mapSupport(mapper, constructor, IsNotInWhenPresent::empty);
return mapSupport(mapper, IsNotInWhenPresent::new, IsNotInWhenPresent::empty);
}

@SafeVarargs
Expand Down