diff --git a/CHANGELOG.md b/CHANGELOG.md index cec9f683f..c65f2c09c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -82,6 +82,8 @@ Runtime behavior changes: 2. We have updated the "ParameterTypeConverter" used in Spring applications to maintain compatibility with Spring's "Converter" interface. The primary change is that the framework will no longer call a type converter if the input value is null. This should simplify the coding of converters and foster reuse with existing Spring converters. +3. The "map" method on the "WhenPresent" conditions will accept a mapper function that may return a null value. The + conditions will now properly handle this outcome ### Other important changes: diff --git a/pom.xml b/pom.xml index cad1ea0b9..2f37f9c03 100644 --- a/pom.xml +++ b/pom.xml @@ -76,6 +76,8 @@ pom.xml,src/main/java,src/main/kotlin src/test/java,src/test/kotlin + + http://localhost:9000 official 1.20.6 diff --git a/src/main/java/org/mybatis/dynamic/sql/AbstractListValueCondition.java b/src/main/java/org/mybatis/dynamic/sql/AbstractListValueCondition.java index 41c6a56e2..e178c6bf3 100644 --- a/src/main/java/org/mybatis/dynamic/sql/AbstractListValueCondition.java +++ b/src/main/java/org/mybatis/dynamic/sql/AbstractListValueCondition.java @@ -23,6 +23,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import org.jspecify.annotations.NonNull; import org.mybatis.dynamic.sql.render.RenderedParameterInfo; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.util.FragmentAndParameters; @@ -113,7 +114,7 @@ public interface Filterable { * @return this condition if renderable and the value matches the predicate, otherwise a condition * that will not render. */ - AbstractListValueCondition filter(Predicate predicate); + AbstractListValueCondition filter(Predicate predicate); } /** @@ -138,6 +139,6 @@ public interface Mappable { * @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. */ - AbstractListValueCondition map(Function mapper); + AbstractListValueCondition map(Function mapper); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/AbstractNoValueCondition.java b/src/main/java/org/mybatis/dynamic/sql/AbstractNoValueCondition.java index 20e6251d6..71daa7763 100644 --- a/src/main/java/org/mybatis/dynamic/sql/AbstractNoValueCondition.java +++ b/src/main/java/org/mybatis/dynamic/sql/AbstractNoValueCondition.java @@ -60,7 +60,8 @@ public interface Filterable { * @param * condition type - not used except for compilation compliance * - * @return this condition if renderable and the supplier returns true, otherwise a condition that will not render. + * @return this condition if renderable and the supplier returns true, otherwise a condition that will not + * render. */ AbstractNoValueCondition filter(BooleanSupplier booleanSupplier); } diff --git a/src/main/java/org/mybatis/dynamic/sql/AbstractSingleValueCondition.java b/src/main/java/org/mybatis/dynamic/sql/AbstractSingleValueCondition.java index c16dbf08c..eb56eef39 100644 --- a/src/main/java/org/mybatis/dynamic/sql/AbstractSingleValueCondition.java +++ b/src/main/java/org/mybatis/dynamic/sql/AbstractSingleValueCondition.java @@ -21,6 +21,7 @@ import java.util.function.Predicate; import java.util.function.Supplier; +import org.jspecify.annotations.NonNull; import org.mybatis.dynamic.sql.render.RenderedParameterInfo; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.util.FragmentAndParameters; @@ -88,7 +89,7 @@ public interface Filterable { * @return this condition if renderable and the value matches the predicate, otherwise a condition * that will not render. */ - AbstractSingleValueCondition filter(Predicate predicate); + AbstractSingleValueCondition filter(Predicate predicate); } /** @@ -113,6 +114,6 @@ public interface Mappable { * @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. */ - AbstractSingleValueCondition map(Function mapper); + AbstractSingleValueCondition map(Function mapper); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/AbstractTwoValueCondition.java b/src/main/java/org/mybatis/dynamic/sql/AbstractTwoValueCondition.java index 6cceff16e..d409ffbb8 100644 --- a/src/main/java/org/mybatis/dynamic/sql/AbstractTwoValueCondition.java +++ b/src/main/java/org/mybatis/dynamic/sql/AbstractTwoValueCondition.java @@ -23,6 +23,7 @@ import java.util.function.Predicate; import java.util.function.Supplier; +import org.jspecify.annotations.NonNull; import org.mybatis.dynamic.sql.render.RenderedParameterInfo; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.util.FragmentAndParameters; @@ -110,7 +111,7 @@ public interface Filterable { * @return this condition if renderable and the values match the predicate, otherwise a condition * that will not render. */ - AbstractTwoValueCondition filter(BiPredicate predicate); + AbstractTwoValueCondition filter(BiPredicate predicate); /** * If renderable and both values match the predicate, returns this condition. Else returns a condition @@ -121,7 +122,7 @@ public interface Filterable { * @return this condition if renderable and the values match the predicate, otherwise a condition * that will not render. */ - AbstractTwoValueCondition filter(Predicate predicate); + AbstractTwoValueCondition filter(Predicate predicate); } /** @@ -147,8 +148,8 @@ public interface Mappable { * @return a new condition with the result of applying the mappers to the values of this condition, * if renderable, otherwise a condition that will not render. */ - AbstractTwoValueCondition map(Function mapper1, - Function mapper2); + AbstractTwoValueCondition map(Function mapper1, + Function mapper2); /** * If renderable, apply the mapping to both values and return a new condition with the new values. Else return a @@ -159,6 +160,6 @@ AbstractTwoValueCondition map(Function mapper1, * @return a new condition with the result of applying the mappers to the values of this condition, * if renderable, otherwise a condition that will not render. */ - AbstractTwoValueCondition map(Function mapper); + AbstractTwoValueCondition map(Function mapper); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java b/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java index 2f365de1e..9790633b0 100644 --- a/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java +++ b/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java @@ -21,6 +21,7 @@ import java.util.Objects; import java.util.function.Supplier; +import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.delete.DeleteDSL; import org.mybatis.dynamic.sql.delete.DeleteModel; @@ -62,14 +63,18 @@ import org.mybatis.dynamic.sql.util.Buildable; import org.mybatis.dynamic.sql.where.WhereDSL; import org.mybatis.dynamic.sql.where.condition.IsBetween; +import org.mybatis.dynamic.sql.where.condition.IsBetweenWhenPresent; import org.mybatis.dynamic.sql.where.condition.IsEqualTo; import org.mybatis.dynamic.sql.where.condition.IsEqualToColumn; +import org.mybatis.dynamic.sql.where.condition.IsEqualToWhenPresent; import org.mybatis.dynamic.sql.where.condition.IsEqualToWithSubselect; import org.mybatis.dynamic.sql.where.condition.IsGreaterThan; import org.mybatis.dynamic.sql.where.condition.IsGreaterThanColumn; import org.mybatis.dynamic.sql.where.condition.IsGreaterThanOrEqualTo; import org.mybatis.dynamic.sql.where.condition.IsGreaterThanOrEqualToColumn; +import org.mybatis.dynamic.sql.where.condition.IsGreaterThanOrEqualToWhenPresent; import org.mybatis.dynamic.sql.where.condition.IsGreaterThanOrEqualToWithSubselect; +import org.mybatis.dynamic.sql.where.condition.IsGreaterThanWhenPresent; import org.mybatis.dynamic.sql.where.condition.IsGreaterThanWithSubselect; import org.mybatis.dynamic.sql.where.condition.IsIn; import org.mybatis.dynamic.sql.where.condition.IsInCaseInsensitive; @@ -80,13 +85,19 @@ import org.mybatis.dynamic.sql.where.condition.IsLessThanColumn; import org.mybatis.dynamic.sql.where.condition.IsLessThanOrEqualTo; import org.mybatis.dynamic.sql.where.condition.IsLessThanOrEqualToColumn; +import org.mybatis.dynamic.sql.where.condition.IsLessThanOrEqualToWhenPresent; import org.mybatis.dynamic.sql.where.condition.IsLessThanOrEqualToWithSubselect; +import org.mybatis.dynamic.sql.where.condition.IsLessThanWhenPresent; import org.mybatis.dynamic.sql.where.condition.IsLessThanWithSubselect; import org.mybatis.dynamic.sql.where.condition.IsLike; import org.mybatis.dynamic.sql.where.condition.IsLikeCaseInsensitive; +import org.mybatis.dynamic.sql.where.condition.IsLikeCaseInsensitiveWhenPresent; +import org.mybatis.dynamic.sql.where.condition.IsLikeWhenPresent; import org.mybatis.dynamic.sql.where.condition.IsNotBetween; +import org.mybatis.dynamic.sql.where.condition.IsNotBetweenWhenPresent; import org.mybatis.dynamic.sql.where.condition.IsNotEqualTo; import org.mybatis.dynamic.sql.where.condition.IsNotEqualToColumn; +import org.mybatis.dynamic.sql.where.condition.IsNotEqualToWhenPresent; import org.mybatis.dynamic.sql.where.condition.IsNotEqualToWithSubselect; import org.mybatis.dynamic.sql.where.condition.IsNotIn; import org.mybatis.dynamic.sql.where.condition.IsNotInCaseInsensitive; @@ -95,6 +106,8 @@ import org.mybatis.dynamic.sql.where.condition.IsNotInWithSubselect; import org.mybatis.dynamic.sql.where.condition.IsNotLike; import org.mybatis.dynamic.sql.where.condition.IsNotLikeCaseInsensitive; +import org.mybatis.dynamic.sql.where.condition.IsNotLikeCaseInsensitiveWhenPresent; +import org.mybatis.dynamic.sql.where.condition.IsNotLikeWhenPresent; import org.mybatis.dynamic.sql.where.condition.IsNotNull; import org.mybatis.dynamic.sql.where.condition.IsNull; @@ -634,11 +647,11 @@ static IsEqualToColumn isEqualTo(BasicColumn column) { return IsEqualToColumn.of(column); } - static IsEqualTo isEqualToWhenPresent(@Nullable T value) { - return value == null ? IsEqualTo.empty() : IsEqualTo.of(value); + static IsEqualToWhenPresent isEqualToWhenPresent(@Nullable T value) { + return IsEqualToWhenPresent.of(value); } - static IsEqualTo isEqualToWhenPresent(Supplier<@Nullable T> valueSupplier) { + static IsEqualToWhenPresent isEqualToWhenPresent(Supplier<@Nullable T> valueSupplier) { return isEqualToWhenPresent(valueSupplier.get()); } @@ -658,11 +671,11 @@ static IsNotEqualToColumn isNotEqualTo(BasicColumn column) { return IsNotEqualToColumn.of(column); } - static IsNotEqualTo isNotEqualToWhenPresent(@Nullable T value) { - return value == null ? IsNotEqualTo.empty() : IsNotEqualTo.of(value); + static IsNotEqualToWhenPresent isNotEqualToWhenPresent(@Nullable T value) { + return IsNotEqualToWhenPresent.of(value); } - static IsNotEqualTo isNotEqualToWhenPresent(Supplier<@Nullable T> valueSupplier) { + static IsNotEqualToWhenPresent isNotEqualToWhenPresent(Supplier<@Nullable T> valueSupplier) { return isNotEqualToWhenPresent(valueSupplier.get()); } @@ -682,11 +695,11 @@ static IsGreaterThanColumn isGreaterThan(BasicColumn column) { return IsGreaterThanColumn.of(column); } - static IsGreaterThan isGreaterThanWhenPresent(@Nullable T value) { - return value == null ? IsGreaterThan.empty() : IsGreaterThan.of(value); + static IsGreaterThanWhenPresent isGreaterThanWhenPresent(@Nullable T value) { + return IsGreaterThanWhenPresent.of(value); } - static IsGreaterThan isGreaterThanWhenPresent(Supplier<@Nullable T> valueSupplier) { + static IsGreaterThanWhenPresent isGreaterThanWhenPresent(Supplier<@Nullable T> valueSupplier) { return isGreaterThanWhenPresent(valueSupplier.get()); } @@ -707,11 +720,12 @@ static IsGreaterThanOrEqualToColumn isGreaterThanOrEqualTo(BasicColumn co return IsGreaterThanOrEqualToColumn.of(column); } - static IsGreaterThanOrEqualTo isGreaterThanOrEqualToWhenPresent(@Nullable T value) { - return value == null ? IsGreaterThanOrEqualTo.empty() : IsGreaterThanOrEqualTo.of(value); + static IsGreaterThanOrEqualToWhenPresent isGreaterThanOrEqualToWhenPresent(@Nullable T value) { + return IsGreaterThanOrEqualToWhenPresent.of(value); } - static IsGreaterThanOrEqualTo isGreaterThanOrEqualToWhenPresent(Supplier<@Nullable T> valueSupplier) { + static IsGreaterThanOrEqualToWhenPresent isGreaterThanOrEqualToWhenPresent( + Supplier<@Nullable T> valueSupplier) { return isGreaterThanOrEqualToWhenPresent(valueSupplier.get()); } @@ -731,11 +745,11 @@ static IsLessThanColumn isLessThan(BasicColumn column) { return IsLessThanColumn.of(column); } - static IsLessThan isLessThanWhenPresent(@Nullable T value) { - return value == null ? IsLessThan.empty() : IsLessThan.of(value); + static IsLessThanWhenPresent isLessThanWhenPresent(@Nullable T value) { + return IsLessThanWhenPresent.of(value); } - static IsLessThan isLessThanWhenPresent(Supplier<@Nullable T> valueSupplier) { + static IsLessThanWhenPresent isLessThanWhenPresent(Supplier<@Nullable T> valueSupplier) { return isLessThanWhenPresent(valueSupplier.get()); } @@ -755,20 +769,20 @@ static IsLessThanOrEqualToColumn isLessThanOrEqualTo(BasicColumn column) return IsLessThanOrEqualToColumn.of(column); } - static IsLessThanOrEqualTo isLessThanOrEqualToWhenPresent(@Nullable T value) { - return value == null ? IsLessThanOrEqualTo.empty() : IsLessThanOrEqualTo.of(value); + static IsLessThanOrEqualToWhenPresent isLessThanOrEqualToWhenPresent(@Nullable T value) { + return IsLessThanOrEqualToWhenPresent.of(value); } - static IsLessThanOrEqualTo isLessThanOrEqualToWhenPresent(Supplier<@Nullable T> valueSupplier) { + static IsLessThanOrEqualToWhenPresent isLessThanOrEqualToWhenPresent(Supplier<@Nullable T> valueSupplier) { return isLessThanOrEqualToWhenPresent(valueSupplier.get()); } @SafeVarargs - static IsIn isIn(T... values) { + static IsIn isIn(@NonNull T... values) { return IsIn.of(values); } - static IsIn isIn(Collection values) { + static IsIn isIn(Collection<@NonNull T> values) { return IsIn.of(values); } @@ -782,15 +796,15 @@ static IsInWhenPresent isInWhenPresent(@Nullable T... values) { } static IsInWhenPresent isInWhenPresent(@Nullable Collection<@Nullable T> values) { - return values == null ? IsInWhenPresent.empty() : IsInWhenPresent.of(values); + return IsInWhenPresent.of(values); } @SafeVarargs - static IsNotIn isNotIn(T... values) { + static IsNotIn isNotIn(@NonNull T... values) { return IsNotIn.of(values); } - static IsNotIn isNotIn(Collection values) { + static IsNotIn isNotIn(Collection<@NonNull T> values) { return IsNotIn.of(values); } @@ -804,22 +818,22 @@ static IsNotInWhenPresent isNotInWhenPresent(@Nullable T... values) { } static IsNotInWhenPresent isNotInWhenPresent(@Nullable Collection<@Nullable T> values) { - return values == null ? IsNotInWhenPresent.empty() : IsNotInWhenPresent.of(values); + return IsNotInWhenPresent.of(values); } static IsBetween.Builder isBetween(T value1) { return IsBetween.isBetween(value1); } - static IsBetween.Builder isBetween(Supplier valueSupplier1) { + static IsBetween.Builder isBetween(Supplier<@NonNull T> valueSupplier1) { return isBetween(valueSupplier1.get()); } - static IsBetween.WhenPresentBuilder isBetweenWhenPresent(@Nullable T value1) { - return IsBetween.isBetweenWhenPresent(value1); + static IsBetweenWhenPresent.Builder isBetweenWhenPresent(@Nullable T value1) { + return IsBetweenWhenPresent.isBetweenWhenPresent(value1); } - static IsBetween.WhenPresentBuilder isBetweenWhenPresent(Supplier<@Nullable T> valueSupplier1) { + static IsBetweenWhenPresent.Builder isBetweenWhenPresent(Supplier<@Nullable T> valueSupplier1) { return isBetweenWhenPresent(valueSupplier1.get()); } @@ -827,15 +841,15 @@ static IsNotBetween.Builder isNotBetween(T value1) { return IsNotBetween.isNotBetween(value1); } - static IsNotBetween.Builder isNotBetween(Supplier valueSupplier1) { + static IsNotBetween.Builder isNotBetween(Supplier<@NonNull T> valueSupplier1) { return isNotBetween(valueSupplier1.get()); } - static IsNotBetween.WhenPresentBuilder isNotBetweenWhenPresent(@Nullable T value1) { - return IsNotBetween.isNotBetweenWhenPresent(value1); + static IsNotBetweenWhenPresent.Builder isNotBetweenWhenPresent(@Nullable T value1) { + return IsNotBetweenWhenPresent.isNotBetweenWhenPresent(value1); } - static IsNotBetween.WhenPresentBuilder isNotBetweenWhenPresent(Supplier<@Nullable T> valueSupplier1) { + static IsNotBetweenWhenPresent.Builder isNotBetweenWhenPresent(Supplier<@Nullable T> valueSupplier1) { return isNotBetweenWhenPresent(valueSupplier1.get()); } @@ -848,11 +862,11 @@ static IsLike isLike(Supplier valueSupplier) { return isLike(valueSupplier.get()); } - static IsLike isLikeWhenPresent(@Nullable T value) { - return value == null ? IsLike.empty() : IsLike.of(value); + static IsLikeWhenPresent isLikeWhenPresent(@Nullable T value) { + return IsLikeWhenPresent.of(value); } - static IsLike isLikeWhenPresent(Supplier<@Nullable T> valueSupplier) { + static IsLikeWhenPresent isLikeWhenPresent(Supplier<@Nullable T> valueSupplier) { return isLikeWhenPresent(valueSupplier.get()); } @@ -864,11 +878,11 @@ static IsNotLike isNotLike(Supplier valueSupplier) { return isNotLike(valueSupplier.get()); } - static IsNotLike isNotLikeWhenPresent(@Nullable T value) { - return value == null ? IsNotLike.empty() : IsNotLike.of(value); + static IsNotLikeWhenPresent isNotLikeWhenPresent(@Nullable T value) { + return IsNotLikeWhenPresent.of(value); } - static IsNotLike isNotLikeWhenPresent(Supplier<@Nullable T> valueSupplier) { + static IsNotLikeWhenPresent isNotLikeWhenPresent(Supplier<@Nullable T> valueSupplier) { return isNotLikeWhenPresent(valueSupplier.get()); } @@ -890,11 +904,12 @@ static IsLikeCaseInsensitive isLikeCaseInsensitive(Supplier valu return isLikeCaseInsensitive(valueSupplier.get()); } - static IsLikeCaseInsensitive isLikeCaseInsensitiveWhenPresent(@Nullable String value) { - return value == null ? IsLikeCaseInsensitive.empty() : IsLikeCaseInsensitive.of(value); + static IsLikeCaseInsensitiveWhenPresent isLikeCaseInsensitiveWhenPresent(@Nullable String value) { + return IsLikeCaseInsensitiveWhenPresent.of(value); } - static IsLikeCaseInsensitive isLikeCaseInsensitiveWhenPresent(Supplier<@Nullable String> valueSupplier) { + static IsLikeCaseInsensitiveWhenPresent isLikeCaseInsensitiveWhenPresent( + Supplier<@Nullable String> valueSupplier) { return isLikeCaseInsensitiveWhenPresent(valueSupplier.get()); } @@ -906,11 +921,11 @@ static IsNotLikeCaseInsensitive isNotLikeCaseInsensitive(Supplier isNotLikeCaseInsensitiveWhenPresent(@Nullable String value) { - return value == null ? IsNotLikeCaseInsensitive.empty() : IsNotLikeCaseInsensitive.of(value); + static IsNotLikeCaseInsensitiveWhenPresent isNotLikeCaseInsensitiveWhenPresent(@Nullable String value) { + return IsNotLikeCaseInsensitiveWhenPresent.of(value); } - static IsNotLikeCaseInsensitive isNotLikeCaseInsensitiveWhenPresent( + static IsNotLikeCaseInsensitiveWhenPresent isNotLikeCaseInsensitiveWhenPresent( Supplier<@Nullable String> valueSupplier) { return isNotLikeCaseInsensitiveWhenPresent(valueSupplier.get()); } @@ -929,7 +944,7 @@ static IsInCaseInsensitiveWhenPresent isInCaseInsensitiveWhenPresent(@Nu static IsInCaseInsensitiveWhenPresent isInCaseInsensitiveWhenPresent( @Nullable Collection<@Nullable String> values) { - return values == null ? IsInCaseInsensitiveWhenPresent.empty() : IsInCaseInsensitiveWhenPresent.of(values); + return IsInCaseInsensitiveWhenPresent.of(values); } static IsNotInCaseInsensitive isNotInCaseInsensitive(String... values) { @@ -946,8 +961,7 @@ static IsNotInCaseInsensitiveWhenPresent isNotInCaseInsensitiveWhenPrese static IsNotInCaseInsensitiveWhenPresent isNotInCaseInsensitiveWhenPresent( @Nullable Collection<@Nullable String> values) { - return values == null ? IsNotInCaseInsensitiveWhenPresent.empty() : - IsNotInCaseInsensitiveWhenPresent.of(values); + return IsNotInCaseInsensitiveWhenPresent.of(values); } // order by support diff --git a/src/main/java/org/mybatis/dynamic/sql/delete/DeleteDSL.java b/src/main/java/org/mybatis/dynamic/sql/delete/DeleteDSL.java index 3724e5395..aeebc5498 100644 --- a/src/main/java/org/mybatis/dynamic/sql/delete/DeleteDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/delete/DeleteDSL.java @@ -120,7 +120,7 @@ public DeleteDSL limit(long limit) { return limitWhenPresent(limit); } - public DeleteDSL limitWhenPresent(Long limit) { + public DeleteDSL limitWhenPresent(@Nullable Long limit) { return DeleteDSL.this.limitWhenPresent(limit); } diff --git a/src/main/java/org/mybatis/dynamic/sql/update/UpdateDSL.java b/src/main/java/org/mybatis/dynamic/sql/update/UpdateDSL.java index f33bbc074..fbac97595 100644 --- a/src/main/java/org/mybatis/dynamic/sql/update/UpdateDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/update/UpdateDSL.java @@ -202,7 +202,7 @@ public UpdateDSL limit(long limit) { return limitWhenPresent(limit); } - public UpdateDSL limitWhenPresent(Long limit) { + public UpdateDSL limitWhenPresent(@Nullable Long limit) { return UpdateDSL.this.limitWhenPresent(limit); } diff --git a/src/main/java/org/mybatis/dynamic/sql/util/mybatis3/CommonSelectMapper.java b/src/main/java/org/mybatis/dynamic/sql/util/mybatis3/CommonSelectMapper.java index 1faa0bd05..8f0f350ee 100644 --- a/src/main/java/org/mybatis/dynamic/sql/util/mybatis3/CommonSelectMapper.java +++ b/src/main/java/org/mybatis/dynamic/sql/util/mybatis3/CommonSelectMapper.java @@ -22,6 +22,7 @@ import java.util.function.Function; import org.apache.ibatis.annotations.SelectProvider; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.select.render.SelectStatementProvider; import org.mybatis.dynamic.sql.util.SqlProviderAdapter; @@ -49,7 +50,7 @@ public interface CommonSelectMapper { /** * Select a single row as a Map of values. The row may have any number of columns. * The Map key will be the column name as returned from the - * database (may be aliased if an alias is specified in the select statement). Map entries will be + * database (the key will be aliased if an alias is specified in the select statement). Map entries will be * of data types determined by the JDBC driver. MyBatis will call ResultSet.getObject() to retrieve * values from the ResultSet. Reference your JDBC driver documentation to learn about type mappings * for your specific database. @@ -58,7 +59,7 @@ public interface CommonSelectMapper { * @return A Map containing the row values. */ @SelectProvider(type = SqlProviderAdapter.class, method = "select") - Map selectOneMappedRow(SelectStatementProvider selectStatement); + @Nullable Map selectOneMappedRow(SelectStatementProvider selectStatement); /** * Select a single row of values and then convert the values to a custom type. This is similar @@ -74,16 +75,17 @@ public interface CommonSelectMapper { * @param the datatype of the converted object * @return the converted object */ - default R selectOne(SelectStatementProvider selectStatement, + default @Nullable R selectOne(SelectStatementProvider selectStatement, Function, R> rowMapper) { - return rowMapper.apply(selectOneMappedRow(selectStatement)); + var result = selectOneMappedRow(selectStatement); + return result == null ? null : rowMapper.apply(result); } /** * Select any number of rows and return a List of Maps containing row values (one Map for each row returned). * The rows may have any number of columns. * The Map key will be the column name as returned from the - * database (may be aliased if an alias is specified in the select statement). Map entries will be + * database (the key will be aliased if an alias is specified in the select statement). Map entries will be * of data types determined by the JDBC driver. MyBatis will call ResultSet.getObject() to retrieve * values from the ResultSet. Reference your JDBC driver documentation to learn about type mappings * for your specific database. @@ -122,7 +124,7 @@ default List selectMany(SelectStatementProvider selectStatement, * column is null */ @SelectProvider(type = SqlProviderAdapter.class, method = "select") - BigDecimal selectOneBigDecimal(SelectStatementProvider selectStatement); + @Nullable BigDecimal selectOneBigDecimal(SelectStatementProvider selectStatement); /** * Retrieve a single {@link java.math.BigDecimal} from a result set. The result set must have @@ -157,7 +159,7 @@ default List selectMany(SelectStatementProvider selectStatement, * column is null */ @SelectProvider(type = SqlProviderAdapter.class, method = "select") - Double selectOneDouble(SelectStatementProvider selectStatement); + @Nullable Double selectOneDouble(SelectStatementProvider selectStatement); /** * Retrieve a single {@link java.lang.Double} from a result set. The result set must have @@ -192,7 +194,7 @@ default List selectMany(SelectStatementProvider selectStatement, * column is null */ @SelectProvider(type = SqlProviderAdapter.class, method = "select") - Integer selectOneInteger(SelectStatementProvider selectStatement); + @Nullable Integer selectOneInteger(SelectStatementProvider selectStatement); /** * Retrieve a single {@link java.lang.Integer} from a result set. The result set must have @@ -227,7 +229,7 @@ default List selectMany(SelectStatementProvider selectStatement, * column is null */ @SelectProvider(type = SqlProviderAdapter.class, method = "select") - Long selectOneLong(SelectStatementProvider selectStatement); + @Nullable Long selectOneLong(SelectStatementProvider selectStatement); /** * Retrieve a single {@link java.lang.Long} from a result set. The result set must have @@ -262,7 +264,7 @@ default List selectMany(SelectStatementProvider selectStatement, * column is null */ @SelectProvider(type = SqlProviderAdapter.class, method = "select") - String selectOneString(SelectStatementProvider selectStatement); + @Nullable String selectOneString(SelectStatementProvider selectStatement); /** * Retrieve a single {@link java.lang.String} from a result set. The result set must have diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/AndGatherer.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/AndGatherer.java index 8a587262a..c9514f3fa 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/AndGatherer.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/AndGatherer.java @@ -17,6 +17,8 @@ import java.util.function.Supplier; +import org.jspecify.annotations.NonNull; + /** * Utility class supporting the "and" part of a between condition. This class supports builders, so it is mutable. * @@ -38,7 +40,7 @@ public R and(T value2) { return build(value2); } - public R and(Supplier valueSupplier2) { + public R and(Supplier<@NonNull T> valueSupplier2) { return and(valueSupplier2.get()); } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsBetween.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsBetween.java index 0e6700fb0..0f7fcd66a 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsBetween.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsBetween.java @@ -20,10 +20,10 @@ import java.util.function.Function; import java.util.function.Predicate; -import org.jspecify.annotations.Nullable; +import org.jspecify.annotations.NonNull; import org.mybatis.dynamic.sql.AbstractTwoValueCondition; -public class IsBetween extends AbstractTwoValueCondition +public class IsBetween extends AbstractTwoValueCondition<@NonNull T> implements AbstractTwoValueCondition.Filterable, AbstractTwoValueCondition.Mappable { private static final IsBetween EMPTY = new IsBetween(-1, -1) { @Override @@ -63,22 +63,23 @@ public String operator2() { } @Override - public IsBetween filter(BiPredicate predicate) { + public IsBetween filter(BiPredicate predicate) { return filterSupport(predicate, IsBetween::empty, this); } @Override - public IsBetween filter(Predicate predicate) { + public IsBetween filter(Predicate predicate) { return filterSupport(predicate, IsBetween::empty, this); } @Override - public IsBetween map(Function mapper1, Function mapper2) { + public IsBetween map(Function mapper1, + Function mapper2) { return mapSupport(mapper1, mapper2, IsBetween::new, IsBetween::empty); } @Override - public IsBetween map(Function mapper) { + public IsBetween map(Function mapper) { return map(mapper, mapper); } @@ -86,10 +87,6 @@ public static Builder isBetween(T value1) { return new Builder<>(value1); } - public static WhenPresentBuilder isBetweenWhenPresent(@Nullable T value1) { - return new WhenPresentBuilder<>(value1); - } - public static class Builder extends AndGatherer> { private Builder(T value1) { super(value1); @@ -100,19 +97,4 @@ protected IsBetween build(T value2) { return new IsBetween<>(value1, value2); } } - - public static class WhenPresentBuilder extends AndWhenPresentGatherer> { - private WhenPresentBuilder(@Nullable T value1) { - super(value1); - } - - @Override - protected IsBetween build(@Nullable T value2) { - if (value1 == null || value2 == null) { - return empty(); - } else { - return new IsBetween<>(value1, value2); - } - } - } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsBetweenWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsBetweenWhenPresent.java new file mode 100644 index 000000000..bc9c12d37 --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsBetweenWhenPresent.java @@ -0,0 +1,109 @@ +/* + * Copyright 2016-2025 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.where.condition; + +import java.util.NoSuchElementException; +import java.util.function.BiPredicate; +import java.util.function.Function; +import java.util.function.Predicate; + +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; +import org.mybatis.dynamic.sql.AbstractTwoValueCondition; + +public class IsBetweenWhenPresent extends AbstractTwoValueCondition + implements AbstractTwoValueCondition.Filterable, AbstractTwoValueCondition.Mappable { + private static final IsBetweenWhenPresent EMPTY = new IsBetweenWhenPresent(-1, -1) { + @Override + public Object value1() { + throw new NoSuchElementException("No value present"); //$NON-NLS-1$ + } + + @Override + public Object value2() { + throw new NoSuchElementException("No value present"); //$NON-NLS-1$ + } + + @Override + public boolean isEmpty() { + return true; + } + }; + + public static IsBetweenWhenPresent empty() { + @SuppressWarnings("unchecked") + IsBetweenWhenPresent t = (IsBetweenWhenPresent) EMPTY; + return t; + } + + protected IsBetweenWhenPresent(T value1, T value2) { + super(value1, value2); + } + + @Override + public String operator1() { + return "between"; //$NON-NLS-1$ + } + + @Override + public String operator2() { + return "and"; //$NON-NLS-1$ + } + + @Override + public IsBetweenWhenPresent filter(BiPredicate predicate) { + return filterSupport(predicate, IsBetweenWhenPresent::empty, this); + } + + @Override + public IsBetweenWhenPresent filter(Predicate predicate) { + return filterSupport(predicate, IsBetweenWhenPresent::empty, this); + } + + @Override + public IsBetweenWhenPresent map(Function mapper1, + Function mapper2) { + return mapSupport(mapper1, mapper2, IsBetweenWhenPresent::of, IsBetweenWhenPresent::empty); + } + + @Override + public IsBetweenWhenPresent map(Function mapper) { + return map(mapper, mapper); + } + + public static IsBetweenWhenPresent of(@Nullable T value1, @Nullable T value2) { + if (value1 == null || value2 == null) { + return empty(); + } else { + return new IsBetweenWhenPresent<>(value1, value2); + } + } + + public static Builder isBetweenWhenPresent(@Nullable T value1) { + return new Builder<>(value1); + } + + public static class Builder extends AndWhenPresentGatherer> { + private Builder(@Nullable T value1) { + super(value1); + } + + @Override + protected IsBetweenWhenPresent build(@Nullable T value2) { + return of(value1, value2); + } + } +} diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsEqualTo.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsEqualTo.java index 51e6e4d47..db8548f61 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsEqualTo.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsEqualTo.java @@ -19,6 +19,7 @@ import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; import org.mybatis.dynamic.sql.AbstractSingleValueCondition; public class IsEqualTo extends AbstractSingleValueCondition @@ -56,12 +57,12 @@ public static IsEqualTo of(T value) { } @Override - public IsEqualTo filter(Predicate predicate) { + public IsEqualTo filter(Predicate predicate) { return filterSupport(predicate, IsEqualTo::empty, this); } @Override - public IsEqualTo map(Function mapper) { + public IsEqualTo map(Function mapper) { return mapSupport(mapper, IsEqualTo::new, IsEqualTo::empty); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsEqualToWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsEqualToWhenPresent.java new file mode 100644 index 000000000..2dd8c746d --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsEqualToWhenPresent.java @@ -0,0 +1,73 @@ +/* + * Copyright 2016-2025 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.where.condition; + +import java.util.NoSuchElementException; +import java.util.function.Function; +import java.util.function.Predicate; + +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; +import org.mybatis.dynamic.sql.AbstractSingleValueCondition; + +public class IsEqualToWhenPresent extends AbstractSingleValueCondition + implements AbstractSingleValueCondition.Filterable, AbstractSingleValueCondition.Mappable { + + private static final IsEqualToWhenPresent EMPTY = new IsEqualToWhenPresent(-1) { + @Override + public Object value() { + throw new NoSuchElementException("No value present"); //$NON-NLS-1$ + } + + @Override + public boolean isEmpty() { + return true; + } + }; + + public static IsEqualToWhenPresent empty() { + @SuppressWarnings("unchecked") + IsEqualToWhenPresent t = (IsEqualToWhenPresent) EMPTY; + return t; + } + + protected IsEqualToWhenPresent(T value) { + super(value); + } + + @Override + public String operator() { + return "="; //$NON-NLS-1$ + } + + public static IsEqualToWhenPresent of(@Nullable T value) { + if (value == null) { + return empty(); + } else { + return new IsEqualToWhenPresent<>(value); + } + } + + @Override + public IsEqualToWhenPresent filter(Predicate predicate) { + return filterSupport(predicate, IsEqualToWhenPresent::empty, this); + } + + @Override + public IsEqualToWhenPresent map(Function mapper) { + return mapSupport(mapper, IsEqualToWhenPresent::of, IsEqualToWhenPresent::empty); + } +} diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThan.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThan.java index 93be70911..577a400f2 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThan.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThan.java @@ -19,6 +19,7 @@ import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; import org.mybatis.dynamic.sql.AbstractSingleValueCondition; public class IsGreaterThan extends AbstractSingleValueCondition @@ -55,12 +56,12 @@ public static IsGreaterThan of(T value) { } @Override - public IsGreaterThan filter(Predicate predicate) { + public IsGreaterThan filter(Predicate predicate) { return filterSupport(predicate, IsGreaterThan::empty, this); } @Override - public IsGreaterThan map(Function mapper) { + public IsGreaterThan map(Function mapper) { return mapSupport(mapper, IsGreaterThan::new, IsGreaterThan::empty); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanOrEqualTo.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanOrEqualTo.java index 8373bf352..5fb4bd0d4 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanOrEqualTo.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanOrEqualTo.java @@ -19,6 +19,7 @@ import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; import org.mybatis.dynamic.sql.AbstractSingleValueCondition; public class IsGreaterThanOrEqualTo extends AbstractSingleValueCondition @@ -55,12 +56,12 @@ public static IsGreaterThanOrEqualTo of(T value) { } @Override - public IsGreaterThanOrEqualTo filter(Predicate predicate) { + public IsGreaterThanOrEqualTo filter(Predicate predicate) { return filterSupport(predicate, IsGreaterThanOrEqualTo::empty, this); } @Override - public IsGreaterThanOrEqualTo map(Function mapper) { + public IsGreaterThanOrEqualTo map(Function mapper) { return mapSupport(mapper, IsGreaterThanOrEqualTo::new, IsGreaterThanOrEqualTo::empty); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanOrEqualToWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanOrEqualToWhenPresent.java new file mode 100644 index 000000000..01f895dc9 --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanOrEqualToWhenPresent.java @@ -0,0 +1,73 @@ +/* + * Copyright 2016-2025 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.where.condition; + +import java.util.NoSuchElementException; +import java.util.function.Function; +import java.util.function.Predicate; + +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; +import org.mybatis.dynamic.sql.AbstractSingleValueCondition; + +public class IsGreaterThanOrEqualToWhenPresent extends AbstractSingleValueCondition + implements AbstractSingleValueCondition.Filterable, AbstractSingleValueCondition.Mappable { + private static final IsGreaterThanOrEqualToWhenPresent EMPTY = + new IsGreaterThanOrEqualToWhenPresent(-1) { + @Override + public Object value() { + throw new NoSuchElementException("No value present"); //$NON-NLS-1$ + } + + @Override + public boolean isEmpty() { + return true; + } + }; + + public static IsGreaterThanOrEqualToWhenPresent empty() { + @SuppressWarnings("unchecked") + IsGreaterThanOrEqualToWhenPresent t = (IsGreaterThanOrEqualToWhenPresent) EMPTY; + return t; + } + + protected IsGreaterThanOrEqualToWhenPresent(T value) { + super(value); + } + + @Override + public String operator() { + return ">="; //$NON-NLS-1$ + } + + public static IsGreaterThanOrEqualToWhenPresent of(@Nullable T value) { + if (value == null) { + return empty(); + } else { + return new IsGreaterThanOrEqualToWhenPresent<>(value); + } + } + + @Override + public IsGreaterThanOrEqualToWhenPresent filter(Predicate predicate) { + return filterSupport(predicate, IsGreaterThanOrEqualToWhenPresent::empty, this); + } + + @Override + public IsGreaterThanOrEqualToWhenPresent map(Function mapper) { + return mapSupport(mapper, IsGreaterThanOrEqualToWhenPresent::of, IsGreaterThanOrEqualToWhenPresent::empty); + } +} diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanWhenPresent.java new file mode 100644 index 000000000..779a15596 --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanWhenPresent.java @@ -0,0 +1,72 @@ +/* + * Copyright 2016-2025 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.where.condition; + +import java.util.NoSuchElementException; +import java.util.function.Function; +import java.util.function.Predicate; + +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; +import org.mybatis.dynamic.sql.AbstractSingleValueCondition; + +public class IsGreaterThanWhenPresent extends AbstractSingleValueCondition + implements AbstractSingleValueCondition.Filterable, AbstractSingleValueCondition.Mappable { + private static final IsGreaterThanWhenPresent EMPTY = new IsGreaterThanWhenPresent(-1) { + @Override + public Object value() { + throw new NoSuchElementException("No value present"); //$NON-NLS-1$ + } + + @Override + public boolean isEmpty() { + return true; + } + }; + + public static IsGreaterThanWhenPresent empty() { + @SuppressWarnings("unchecked") + IsGreaterThanWhenPresent t = (IsGreaterThanWhenPresent) EMPTY; + return t; + } + + protected IsGreaterThanWhenPresent(T value) { + super(value); + } + + @Override + public String operator() { + return ">"; //$NON-NLS-1$ + } + + public static IsGreaterThanWhenPresent of(@Nullable T value) { + if (value == null) { + return empty(); + } else { + return new IsGreaterThanWhenPresent<>(value); + } + } + + @Override + public IsGreaterThanWhenPresent filter(Predicate predicate) { + return filterSupport(predicate, IsGreaterThanWhenPresent::empty, this); + } + + @Override + public IsGreaterThanWhenPresent map(Function mapper) { + return mapSupport(mapper, IsGreaterThanWhenPresent::of, IsGreaterThanWhenPresent::empty); + } +} diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsIn.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsIn.java index 8beeacc8d..67072dc8a 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsIn.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsIn.java @@ -21,12 +21,13 @@ import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; import org.mybatis.dynamic.sql.AbstractListValueCondition; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.util.Validator; public class IsIn extends AbstractListValueCondition - implements AbstractListValueCondition.Filterable, AbstractListValueCondition.Mappable{ + implements AbstractListValueCondition.Filterable, AbstractListValueCondition.Mappable { private static final IsIn EMPTY = new IsIn<>(Collections.emptyList()); public static IsIn empty() { @@ -51,12 +52,12 @@ public String operator() { } @Override - public IsIn filter(Predicate predicate) { + public IsIn filter(Predicate predicate) { return filterSupport(predicate, IsIn::new, this, IsIn::empty); } @Override - public IsIn map(Function mapper) { + public IsIn map(Function mapper) { return mapSupport(mapper, IsIn::new, IsIn::empty); } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java index bc8bfbdf9..d26a9c30f 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java @@ -21,6 +21,7 @@ import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; import org.mybatis.dynamic.sql.AbstractListValueCondition; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.util.StringUtilities; @@ -53,20 +54,21 @@ public String operator() { } @Override - public IsInCaseInsensitive filter(Predicate predicate) { + public IsInCaseInsensitive filter(Predicate predicate) { return filterSupport(predicate, IsInCaseInsensitive::new, this, IsInCaseInsensitive::empty); } @Override - public IsInCaseInsensitive map(Function mapper) { + public IsInCaseInsensitive map(Function mapper) { return mapSupport(mapper, IsInCaseInsensitive::new, IsInCaseInsensitive::empty); } - public static IsInCaseInsensitive of(String... values) { + @SafeVarargs + public static IsInCaseInsensitive of(T... values) { return of(Arrays.asList(values)); } - public static IsInCaseInsensitive of(Collection values) { + public static IsInCaseInsensitive of(Collection values) { return new IsInCaseInsensitive<>(values); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java index fee942f7d..6b4c1e1cd 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java @@ -18,10 +18,11 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.function.Function; import java.util.Objects; +import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.AbstractListValueCondition; import org.mybatis.dynamic.sql.util.StringUtilities; @@ -48,21 +49,26 @@ public String operator() { } @Override - public IsInCaseInsensitiveWhenPresent filter(Predicate predicate) { + public IsInCaseInsensitiveWhenPresent filter(Predicate predicate) { return filterSupport(predicate, IsInCaseInsensitiveWhenPresent::new, this, IsInCaseInsensitiveWhenPresent::empty); } @Override - public IsInCaseInsensitiveWhenPresent map(Function mapper) { + public IsInCaseInsensitiveWhenPresent map(Function mapper) { return mapSupport(mapper, IsInCaseInsensitiveWhenPresent::new, IsInCaseInsensitiveWhenPresent::empty); } - public static IsInCaseInsensitiveWhenPresent of(@Nullable String... values) { + @SafeVarargs + public static IsInCaseInsensitiveWhenPresent of(@Nullable T... values) { return of(Arrays.asList(values)); } - public static IsInCaseInsensitiveWhenPresent of(Collection<@Nullable String> values) { - return new IsInCaseInsensitiveWhenPresent<>(values); + public static IsInCaseInsensitiveWhenPresent of(@Nullable Collection<@Nullable T> values) { + if (values == null) { + return empty(); + } else { + return new IsInCaseInsensitiveWhenPresent<>(values); + } } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInWhenPresent.java index 5c431fea3..abacd2690 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInWhenPresent.java @@ -22,11 +22,12 @@ import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.AbstractListValueCondition; public class IsInWhenPresent extends AbstractListValueCondition - implements AbstractListValueCondition.Filterable, AbstractListValueCondition.Mappable{ + implements AbstractListValueCondition.Filterable, AbstractListValueCondition.Mappable { private static final IsInWhenPresent EMPTY = new IsInWhenPresent<>(Collections.emptyList()); public static IsInWhenPresent empty() { @@ -45,13 +46,13 @@ public String operator() { } @Override - public IsInWhenPresent filter(Predicate predicate) { + public IsInWhenPresent filter(Predicate predicate) { return filterSupport(predicate, IsInWhenPresent::new, this, IsInWhenPresent::empty); } @Override - public IsInWhenPresent map(Function mapper) { - return mapSupport(mapper, IsInWhenPresent::new, IsInWhenPresent::empty); + public IsInWhenPresent map(Function mapper) { + return mapSupport(mapper, IsInWhenPresent::of, IsInWhenPresent::empty); } @SafeVarargs @@ -59,7 +60,11 @@ public static IsInWhenPresent of(@Nullable T... values) { return of(Arrays.asList(values)); } - public static IsInWhenPresent of(Collection<@Nullable T> values) { - return new IsInWhenPresent<>(values); + public static IsInWhenPresent of(@Nullable Collection<@Nullable T> values) { + if (values == null) { + return empty(); + } else { + return new IsInWhenPresent<>(values); + } } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThan.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThan.java index 3ed383fbd..ffe66bd97 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThan.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThan.java @@ -19,6 +19,7 @@ import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; import org.mybatis.dynamic.sql.AbstractSingleValueCondition; public class IsLessThan extends AbstractSingleValueCondition @@ -56,12 +57,12 @@ public static IsLessThan of(T value) { } @Override - public IsLessThan filter(Predicate predicate) { + public IsLessThan filter(Predicate predicate) { return filterSupport(predicate, IsLessThan::empty, this); } @Override - public IsLessThan map(Function mapper) { + public IsLessThan map(Function mapper) { return mapSupport(mapper, IsLessThan::new, IsLessThan::empty); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanOrEqualTo.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanOrEqualTo.java index 1b92e0c40..a73707e3e 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanOrEqualTo.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanOrEqualTo.java @@ -19,6 +19,7 @@ import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; import org.mybatis.dynamic.sql.AbstractSingleValueCondition; public class IsLessThanOrEqualTo extends AbstractSingleValueCondition @@ -55,12 +56,12 @@ public static IsLessThanOrEqualTo of(T value) { } @Override - public IsLessThanOrEqualTo filter(Predicate predicate) { + public IsLessThanOrEqualTo filter(Predicate predicate) { return filterSupport(predicate, IsLessThanOrEqualTo::empty, this); } @Override - public IsLessThanOrEqualTo map(Function mapper) { + public IsLessThanOrEqualTo map(Function mapper) { return mapSupport(mapper, IsLessThanOrEqualTo::new, IsLessThanOrEqualTo::empty); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanOrEqualToWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanOrEqualToWhenPresent.java new file mode 100644 index 000000000..d944b7a45 --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanOrEqualToWhenPresent.java @@ -0,0 +1,72 @@ +/* + * Copyright 2016-2025 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.where.condition; + +import java.util.NoSuchElementException; +import java.util.function.Function; +import java.util.function.Predicate; + +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; +import org.mybatis.dynamic.sql.AbstractSingleValueCondition; + +public class IsLessThanOrEqualToWhenPresent extends AbstractSingleValueCondition + implements AbstractSingleValueCondition.Filterable, AbstractSingleValueCondition.Mappable { + private static final IsLessThanOrEqualToWhenPresent EMPTY = new IsLessThanOrEqualToWhenPresent(-1) { + @Override + public Object value() { + throw new NoSuchElementException("No value present"); //$NON-NLS-1$ + } + + @Override + public boolean isEmpty() { + return true; + } + }; + + public static IsLessThanOrEqualToWhenPresent empty() { + @SuppressWarnings("unchecked") + IsLessThanOrEqualToWhenPresent t = (IsLessThanOrEqualToWhenPresent) EMPTY; + return t; + } + + protected IsLessThanOrEqualToWhenPresent(T value) { + super(value); + } + + @Override + public String operator() { + return "<="; //$NON-NLS-1$ + } + + public static IsLessThanOrEqualToWhenPresent of(@Nullable T value) { + if (value == null) { + return empty(); + } else { + return new IsLessThanOrEqualToWhenPresent<>(value); + } + } + + @Override + public IsLessThanOrEqualToWhenPresent filter(Predicate predicate) { + return filterSupport(predicate, IsLessThanOrEqualToWhenPresent::empty, this); + } + + @Override + public IsLessThanOrEqualToWhenPresent map(Function mapper) { + return mapSupport(mapper, IsLessThanOrEqualToWhenPresent::of, IsLessThanOrEqualToWhenPresent::empty); + } +} diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanWhenPresent.java new file mode 100644 index 000000000..830bf788c --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanWhenPresent.java @@ -0,0 +1,73 @@ +/* + * Copyright 2016-2025 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.where.condition; + +import java.util.NoSuchElementException; +import java.util.function.Function; +import java.util.function.Predicate; + +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; +import org.mybatis.dynamic.sql.AbstractSingleValueCondition; + +public class IsLessThanWhenPresent extends AbstractSingleValueCondition + implements AbstractSingleValueCondition.Filterable, AbstractSingleValueCondition.Mappable { + + private static final IsLessThanWhenPresent EMPTY = new IsLessThanWhenPresent(-1) { + @Override + public Object value() { + throw new NoSuchElementException("No value present"); //$NON-NLS-1$ + } + + @Override + public boolean isEmpty() { + return true; + } + }; + + public static IsLessThanWhenPresent empty() { + @SuppressWarnings("unchecked") + IsLessThanWhenPresent t = (IsLessThanWhenPresent) EMPTY; + return t; + } + + protected IsLessThanWhenPresent(T value) { + super(value); + } + + @Override + public String operator() { + return "<"; //$NON-NLS-1$ + } + + public static IsLessThanWhenPresent of(@Nullable T value) { + if (value == null) { + return empty(); + } else { + return new IsLessThanWhenPresent<>(value); + } + } + + @Override + public IsLessThanWhenPresent filter(Predicate predicate) { + return filterSupport(predicate, IsLessThanWhenPresent::empty, this); + } + + @Override + public IsLessThanWhenPresent map(Function mapper) { + return mapSupport(mapper, IsLessThanWhenPresent::of, IsLessThanWhenPresent::empty); + } +} diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLike.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLike.java index e738bda4c..f2d2a419a 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLike.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLike.java @@ -19,6 +19,7 @@ import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; import org.mybatis.dynamic.sql.AbstractSingleValueCondition; public class IsLike extends AbstractSingleValueCondition @@ -56,12 +57,12 @@ public static IsLike of(T value) { } @Override - public IsLike filter(Predicate predicate) { + public IsLike filter(Predicate predicate) { return filterSupport(predicate, IsLike::empty, this); } @Override - public IsLike map(Function mapper) { + public IsLike map(Function mapper) { return mapSupport(mapper, IsLike::new, IsLike::empty); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitive.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitive.java index e4d31c126..43525e287 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitive.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitive.java @@ -19,6 +19,7 @@ import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; import org.mybatis.dynamic.sql.AbstractSingleValueCondition; import org.mybatis.dynamic.sql.util.StringUtilities; @@ -53,16 +54,16 @@ public String operator() { } @Override - public IsLikeCaseInsensitive filter(Predicate predicate) { + public IsLikeCaseInsensitive filter(Predicate predicate) { return filterSupport(predicate, IsLikeCaseInsensitive::empty, this); } @Override - public IsLikeCaseInsensitive map(Function mapper) { + public IsLikeCaseInsensitive map(Function mapper) { return mapSupport(mapper, IsLikeCaseInsensitive::new, IsLikeCaseInsensitive::empty); } - public static IsLikeCaseInsensitive of(String value) { + public static IsLikeCaseInsensitive of(T value) { return new IsLikeCaseInsensitive<>(value); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitiveWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitiveWhenPresent.java new file mode 100644 index 000000000..60307625f --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitiveWhenPresent.java @@ -0,0 +1,75 @@ +/* + * Copyright 2016-2025 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.where.condition; + +import java.util.NoSuchElementException; +import java.util.function.Function; +import java.util.function.Predicate; + +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; +import org.mybatis.dynamic.sql.AbstractSingleValueCondition; +import org.mybatis.dynamic.sql.util.StringUtilities; + +public class IsLikeCaseInsensitiveWhenPresent extends AbstractSingleValueCondition + implements CaseInsensitiveRenderableCondition, AbstractSingleValueCondition.Filterable, + AbstractSingleValueCondition.Mappable { + private static final IsLikeCaseInsensitiveWhenPresent EMPTY = + new IsLikeCaseInsensitiveWhenPresent<>("") { //$NON-NLS-1$ + @Override + public String value() { + throw new NoSuchElementException("No value present"); //$NON-NLS-1$ + } + + @Override + public boolean isEmpty() { + return true; + } + }; + + public static IsLikeCaseInsensitiveWhenPresent empty() { + @SuppressWarnings("unchecked") + IsLikeCaseInsensitiveWhenPresent t = (IsLikeCaseInsensitiveWhenPresent) EMPTY; + return t; + } + + protected IsLikeCaseInsensitiveWhenPresent(T value) { + super(StringUtilities.upperCaseIfPossible(value)); + } + + @Override + public String operator() { + return "like"; //$NON-NLS-1$ + } + + @Override + public IsLikeCaseInsensitiveWhenPresent filter(Predicate predicate) { + return filterSupport(predicate, IsLikeCaseInsensitiveWhenPresent::empty, this); + } + + @Override + public IsLikeCaseInsensitiveWhenPresent map(Function mapper) { + return mapSupport(mapper, IsLikeCaseInsensitiveWhenPresent::of, IsLikeCaseInsensitiveWhenPresent::empty); + } + + public static IsLikeCaseInsensitiveWhenPresent of(@Nullable T value) { + if (value == null) { + return empty(); + } else { + return new IsLikeCaseInsensitiveWhenPresent<>(value); + } + } +} diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeWhenPresent.java new file mode 100644 index 000000000..fc20722a2 --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeWhenPresent.java @@ -0,0 +1,73 @@ +/* + * Copyright 2016-2025 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.where.condition; + +import java.util.NoSuchElementException; +import java.util.function.Function; +import java.util.function.Predicate; + +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; +import org.mybatis.dynamic.sql.AbstractSingleValueCondition; + +public class IsLikeWhenPresent extends AbstractSingleValueCondition + implements AbstractSingleValueCondition.Filterable, AbstractSingleValueCondition.Mappable { + + private static final IsLikeWhenPresent EMPTY = new IsLikeWhenPresent(-1) { + @Override + public Object value() { + throw new NoSuchElementException("No value present"); //$NON-NLS-1$ + } + + @Override + public boolean isEmpty() { + return true; + } + }; + + public static IsLikeWhenPresent empty() { + @SuppressWarnings("unchecked") + IsLikeWhenPresent t = (IsLikeWhenPresent) EMPTY; + return t; + } + + protected IsLikeWhenPresent(T value) { + super(value); + } + + @Override + public String operator() { + return "like"; //$NON-NLS-1$ + } + + public static IsLikeWhenPresent of(@Nullable T value) { + if (value == null) { + return empty(); + } else { + return new IsLikeWhenPresent<>(value); + } + } + + @Override + public IsLikeWhenPresent filter(Predicate predicate) { + return filterSupport(predicate, IsLikeWhenPresent::empty, this); + } + + @Override + public IsLikeWhenPresent map(Function mapper) { + return mapSupport(mapper, IsLikeWhenPresent::of, IsLikeWhenPresent::empty); + } +} diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotBetween.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotBetween.java index 6a515d4ac..b3d0d59ff 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotBetween.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotBetween.java @@ -20,7 +20,7 @@ import java.util.function.Function; import java.util.function.Predicate; -import org.jspecify.annotations.Nullable; +import org.jspecify.annotations.NonNull; import org.mybatis.dynamic.sql.AbstractTwoValueCondition; public class IsNotBetween extends AbstractTwoValueCondition @@ -63,23 +63,23 @@ public String operator2() { } @Override - public IsNotBetween filter(BiPredicate predicate) { + public IsNotBetween filter(BiPredicate predicate) { return filterSupport(predicate, IsNotBetween::empty, this); } @Override - public IsNotBetween filter(Predicate predicate) { + public IsNotBetween filter(Predicate predicate) { return filterSupport(predicate, IsNotBetween::empty, this); } @Override - public IsNotBetween map(Function mapper1, - Function mapper2) { + public IsNotBetween map(Function mapper1, + Function mapper2) { return mapSupport(mapper1, mapper2, IsNotBetween::new, IsNotBetween::empty); } @Override - public IsNotBetween map(Function mapper) { + public IsNotBetween map(Function mapper) { return map(mapper, mapper); } @@ -87,10 +87,6 @@ public static Builder isNotBetween(T value1) { return new Builder<>(value1); } - public static WhenPresentBuilder isNotBetweenWhenPresent(@Nullable T value1) { - return new WhenPresentBuilder<>(value1); - } - public static class Builder extends AndGatherer> { private Builder(T value1) { @@ -102,20 +98,4 @@ protected IsNotBetween build(T value2) { return new IsNotBetween<>(value1, value2); } } - - public static class WhenPresentBuilder extends AndWhenPresentGatherer> { - - private WhenPresentBuilder(@Nullable T value1) { - super(value1); - } - - @Override - protected IsNotBetween build(@Nullable T value2) { - if (value1 == null || value2 == null) { - return empty(); - } else { - return new IsNotBetween<>(value1, value2); - } - } - } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotBetweenWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotBetweenWhenPresent.java new file mode 100644 index 000000000..3c9c8fc9f --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotBetweenWhenPresent.java @@ -0,0 +1,110 @@ +/* + * Copyright 2016-2025 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.where.condition; + +import java.util.NoSuchElementException; +import java.util.function.BiPredicate; +import java.util.function.Function; +import java.util.function.Predicate; + +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; +import org.mybatis.dynamic.sql.AbstractTwoValueCondition; + +public class IsNotBetweenWhenPresent extends AbstractTwoValueCondition + implements AbstractTwoValueCondition.Filterable, AbstractTwoValueCondition.Mappable { + private static final IsNotBetweenWhenPresent EMPTY = new IsNotBetweenWhenPresent(-1, -1) { + @Override + public Object value1() { + throw new NoSuchElementException("No value present"); //$NON-NLS-1$ + } + + @Override + public Object value2() { + throw new NoSuchElementException("No value present"); //$NON-NLS-1$ + } + + @Override + public boolean isEmpty() { + return true; + } + }; + + public static IsNotBetweenWhenPresent empty() { + @SuppressWarnings("unchecked") + IsNotBetweenWhenPresent t = (IsNotBetweenWhenPresent) EMPTY; + return t; + } + + protected IsNotBetweenWhenPresent(T value1, T value2) { + super(value1, value2); + } + + @Override + public String operator1() { + return "not between"; //$NON-NLS-1$ + } + + @Override + public String operator2() { + return "and"; //$NON-NLS-1$ + } + + @Override + public IsNotBetweenWhenPresent filter(BiPredicate predicate) { + return filterSupport(predicate, IsNotBetweenWhenPresent::empty, this); + } + + @Override + public IsNotBetweenWhenPresent filter(Predicate predicate) { + return filterSupport(predicate, IsNotBetweenWhenPresent::empty, this); + } + + @Override + public IsNotBetweenWhenPresent map(Function mapper1, + Function mapper2) { + return mapSupport(mapper1, mapper2, IsNotBetweenWhenPresent::of, IsNotBetweenWhenPresent::empty); + } + + @Override + public IsNotBetweenWhenPresent map(Function mapper) { + return map(mapper, mapper); + } + + public static IsNotBetweenWhenPresent of(@Nullable T value1, @Nullable T value2) { + if (value1 == null || value2 == null) { + return empty(); + } else { + return new IsNotBetweenWhenPresent<>(value1, value2); + } + } + + public static Builder isNotBetweenWhenPresent(@Nullable T value1) { + return new Builder<>(value1); + } + + public static class Builder extends AndWhenPresentGatherer> { + + private Builder(@Nullable T value1) { + super(value1); + } + + @Override + protected IsNotBetweenWhenPresent build(@Nullable T value2) { + return of(value1, value2); + } + } +} diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotEqualTo.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotEqualTo.java index 39070c2e8..fc0292070 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotEqualTo.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotEqualTo.java @@ -19,6 +19,7 @@ import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; import org.mybatis.dynamic.sql.AbstractSingleValueCondition; public class IsNotEqualTo extends AbstractSingleValueCondition @@ -55,12 +56,12 @@ public static IsNotEqualTo of(T value) { } @Override - public IsNotEqualTo filter(Predicate predicate) { + public IsNotEqualTo filter(Predicate predicate) { return filterSupport(predicate, IsNotEqualTo::empty, this); } @Override - public IsNotEqualTo map(Function mapper) { + public IsNotEqualTo map(Function mapper) { return mapSupport(mapper, IsNotEqualTo::new, IsNotEqualTo::empty); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotEqualToWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotEqualToWhenPresent.java new file mode 100644 index 000000000..1fff2d9ba --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotEqualToWhenPresent.java @@ -0,0 +1,72 @@ +/* + * Copyright 2016-2025 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.where.condition; + +import java.util.NoSuchElementException; +import java.util.function.Function; +import java.util.function.Predicate; + +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; +import org.mybatis.dynamic.sql.AbstractSingleValueCondition; + +public class IsNotEqualToWhenPresent extends AbstractSingleValueCondition + implements AbstractSingleValueCondition.Filterable, AbstractSingleValueCondition.Mappable { + private static final IsNotEqualToWhenPresent EMPTY = new IsNotEqualToWhenPresent(-1) { + @Override + public Object value() { + throw new NoSuchElementException("No value present"); //$NON-NLS-1$ + } + + @Override + public boolean isEmpty() { + return true; + } + }; + + public static IsNotEqualToWhenPresent empty() { + @SuppressWarnings("unchecked") + IsNotEqualToWhenPresent t = (IsNotEqualToWhenPresent) EMPTY; + return t; + } + + protected IsNotEqualToWhenPresent(T value) { + super(value); + } + + @Override + public String operator() { + return "<>"; //$NON-NLS-1$ + } + + public static IsNotEqualToWhenPresent of(@Nullable T value) { + if (value == null) { + return empty(); + } else { + return new IsNotEqualToWhenPresent<>(value); + } + } + + @Override + public IsNotEqualToWhenPresent filter(Predicate predicate) { + return filterSupport(predicate, IsNotEqualToWhenPresent::empty, this); + } + + @Override + public IsNotEqualToWhenPresent map(Function mapper) { + return mapSupport(mapper, IsNotEqualToWhenPresent::of, IsNotEqualToWhenPresent::empty); + } +} diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotIn.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotIn.java index 33f5d14c7..af6c248f4 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotIn.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotIn.java @@ -21,12 +21,13 @@ import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; import org.mybatis.dynamic.sql.AbstractListValueCondition; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.util.Validator; public class IsNotIn extends AbstractListValueCondition - implements AbstractListValueCondition.Filterable, AbstractListValueCondition.Mappable{ + implements AbstractListValueCondition.Filterable, AbstractListValueCondition.Mappable { private static final IsNotIn EMPTY = new IsNotIn<>(Collections.emptyList()); public static IsNotIn empty() { @@ -51,12 +52,12 @@ public String operator() { } @Override - public IsNotIn filter(Predicate predicate) { + public IsNotIn filter(Predicate predicate) { return filterSupport(predicate, IsNotIn::new, this, IsNotIn::empty); } @Override - public IsNotIn map(Function mapper) { + public IsNotIn map(Function mapper) { return mapSupport(mapper, IsNotIn::new, IsNotIn::empty); } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java index 4486d1df7..98a9ca9db 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java @@ -21,6 +21,7 @@ import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; import org.mybatis.dynamic.sql.AbstractListValueCondition; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.util.StringUtilities; @@ -53,20 +54,21 @@ public String operator() { } @Override - public IsNotInCaseInsensitive filter(Predicate predicate) { + public IsNotInCaseInsensitive filter(Predicate predicate) { return filterSupport(predicate, IsNotInCaseInsensitive::new, this, IsNotInCaseInsensitive::empty); } @Override - public IsNotInCaseInsensitive map(Function mapper) { + public IsNotInCaseInsensitive map(Function mapper) { return mapSupport(mapper, IsNotInCaseInsensitive::new, IsNotInCaseInsensitive::empty); } - public static IsNotInCaseInsensitive of(String... values) { + @SafeVarargs + public static IsNotInCaseInsensitive of(T... values) { return of(Arrays.asList(values)); } - public static IsNotInCaseInsensitive of(Collection values) { + public static IsNotInCaseInsensitive of(Collection values) { return new IsNotInCaseInsensitive<>(values); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java index 992a231eb..6852c67fd 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java @@ -18,10 +18,11 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.function.Function; import java.util.Objects; +import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.AbstractListValueCondition; import org.mybatis.dynamic.sql.util.StringUtilities; @@ -48,21 +49,26 @@ public String operator() { } @Override - public IsNotInCaseInsensitiveWhenPresent filter(Predicate predicate) { + public IsNotInCaseInsensitiveWhenPresent filter(Predicate predicate) { return filterSupport(predicate, IsNotInCaseInsensitiveWhenPresent::new, this, IsNotInCaseInsensitiveWhenPresent::empty); } @Override - public IsNotInCaseInsensitiveWhenPresent map(Function mapper) { + public IsNotInCaseInsensitiveWhenPresent map(Function mapper) { return mapSupport(mapper, IsNotInCaseInsensitiveWhenPresent::new, IsNotInCaseInsensitiveWhenPresent::empty); } - public static IsNotInCaseInsensitiveWhenPresent of(@Nullable String... values) { + @SafeVarargs + public static IsNotInCaseInsensitiveWhenPresent of(@Nullable T... values) { return of(Arrays.asList(values)); } - public static IsNotInCaseInsensitiveWhenPresent of(Collection<@Nullable String> values) { - return new IsNotInCaseInsensitiveWhenPresent<>(values); + public static IsNotInCaseInsensitiveWhenPresent of(@Nullable Collection<@Nullable T> values) { + if (values == null) { + return empty(); + } else { + return new IsNotInCaseInsensitiveWhenPresent<>(values); + } } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInWhenPresent.java index ddc8e5470..33efb1782 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInWhenPresent.java @@ -22,10 +22,12 @@ import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.AbstractListValueCondition; public class IsNotInWhenPresent extends AbstractListValueCondition - implements AbstractListValueCondition.Filterable, AbstractListValueCondition.Mappable{ + implements AbstractListValueCondition.Filterable, AbstractListValueCondition.Mappable { private static final IsNotInWhenPresent EMPTY = new IsNotInWhenPresent<>(Collections.emptyList()); public static IsNotInWhenPresent empty() { @@ -44,21 +46,25 @@ public String operator() { } @Override - public IsNotInWhenPresent filter(Predicate predicate) { + public IsNotInWhenPresent filter(Predicate predicate) { return filterSupport(predicate, IsNotInWhenPresent::new, this, IsNotInWhenPresent::empty); } @Override - public IsNotInWhenPresent map(Function mapper) { + public IsNotInWhenPresent map(Function mapper) { return mapSupport(mapper, IsNotInWhenPresent::new, IsNotInWhenPresent::empty); } @SafeVarargs - public static IsNotInWhenPresent of(T... values) { + public static IsNotInWhenPresent of(@Nullable T... values) { return of(Arrays.asList(values)); } - public static IsNotInWhenPresent of(Collection values) { - return new IsNotInWhenPresent<>(values); + public static IsNotInWhenPresent of(@Nullable Collection<@Nullable T> values) { + if (values == null) { + return empty(); + } else { + return new IsNotInWhenPresent<>(values); + } } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLike.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLike.java index a62dc3e9e..b5b82d675 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLike.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLike.java @@ -19,6 +19,7 @@ import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; import org.mybatis.dynamic.sql.AbstractSingleValueCondition; public class IsNotLike extends AbstractSingleValueCondition @@ -55,12 +56,12 @@ public static IsNotLike of(T value) { } @Override - public IsNotLike filter(Predicate predicate) { + public IsNotLike filter(Predicate predicate) { return filterSupport(predicate, IsNotLike::empty, this); } @Override - public IsNotLike map(Function mapper) { + public IsNotLike map(Function mapper) { return mapSupport(mapper, IsNotLike::new, IsNotLike::empty); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitive.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitive.java index 715a19a8d..1604deb3b 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitive.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitive.java @@ -19,6 +19,7 @@ import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; import org.mybatis.dynamic.sql.AbstractSingleValueCondition; import org.mybatis.dynamic.sql.util.StringUtilities; @@ -53,16 +54,16 @@ public String operator() { } @Override - public IsNotLikeCaseInsensitive filter(Predicate predicate) { + public IsNotLikeCaseInsensitive filter(Predicate predicate) { return filterSupport(predicate, IsNotLikeCaseInsensitive::empty, this); } @Override - public IsNotLikeCaseInsensitive map(Function mapper) { + public IsNotLikeCaseInsensitive map(Function mapper) { return mapSupport(mapper, IsNotLikeCaseInsensitive::new, IsNotLikeCaseInsensitive::empty); } - public static IsNotLikeCaseInsensitive of(String value) { + public static IsNotLikeCaseInsensitive of(T value) { return new IsNotLikeCaseInsensitive<>(value); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitiveWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitiveWhenPresent.java new file mode 100644 index 000000000..cc0b04549 --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitiveWhenPresent.java @@ -0,0 +1,75 @@ +/* + * Copyright 2016-2025 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.where.condition; + +import java.util.NoSuchElementException; +import java.util.function.Function; +import java.util.function.Predicate; + +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; +import org.mybatis.dynamic.sql.AbstractSingleValueCondition; +import org.mybatis.dynamic.sql.util.StringUtilities; + +public class IsNotLikeCaseInsensitiveWhenPresent extends AbstractSingleValueCondition + implements CaseInsensitiveRenderableCondition, AbstractSingleValueCondition.Filterable, + AbstractSingleValueCondition.Mappable { + private static final IsNotLikeCaseInsensitiveWhenPresent EMPTY = + new IsNotLikeCaseInsensitiveWhenPresent<>("") { //$NON-NLS-1$ + @Override + public String value() { + throw new NoSuchElementException("No value present"); //$NON-NLS-1$ + } + + @Override + public boolean isEmpty() { + return true; + } + }; + + public static IsNotLikeCaseInsensitiveWhenPresent empty() { + @SuppressWarnings("unchecked") + IsNotLikeCaseInsensitiveWhenPresent t = (IsNotLikeCaseInsensitiveWhenPresent) EMPTY; + return t; + } + + protected IsNotLikeCaseInsensitiveWhenPresent(T value) { + super(StringUtilities.upperCaseIfPossible(value)); + } + + @Override + public String operator() { + return "not like"; //$NON-NLS-1$ + } + + @Override + public IsNotLikeCaseInsensitiveWhenPresent filter(Predicate predicate) { + return filterSupport(predicate, IsNotLikeCaseInsensitiveWhenPresent::empty, this); + } + + @Override + public IsNotLikeCaseInsensitiveWhenPresent map(Function mapper) { + return mapSupport(mapper, IsNotLikeCaseInsensitiveWhenPresent::of, IsNotLikeCaseInsensitiveWhenPresent::empty); + } + + public static IsNotLikeCaseInsensitiveWhenPresent of(@Nullable T value) { + if (value == null) { + return empty(); + } else { + return new IsNotLikeCaseInsensitiveWhenPresent<>(value); + } + } +} diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeWhenPresent.java new file mode 100644 index 000000000..a3571b0ee --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeWhenPresent.java @@ -0,0 +1,72 @@ +/* + * Copyright 2016-2025 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.where.condition; + +import java.util.NoSuchElementException; +import java.util.function.Function; +import java.util.function.Predicate; + +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; +import org.mybatis.dynamic.sql.AbstractSingleValueCondition; + +public class IsNotLikeWhenPresent extends AbstractSingleValueCondition + implements AbstractSingleValueCondition.Filterable, AbstractSingleValueCondition.Mappable { + private static final IsNotLikeWhenPresent EMPTY = new IsNotLikeWhenPresent(-1) { + @Override + public Object value() { + throw new NoSuchElementException("No value present"); //$NON-NLS-1$ + } + + @Override + public boolean isEmpty() { + return true; + } + }; + + public static IsNotLikeWhenPresent empty() { + @SuppressWarnings("unchecked") + IsNotLikeWhenPresent t = (IsNotLikeWhenPresent) EMPTY; + return t; + } + + protected IsNotLikeWhenPresent(T value) { + super(value); + } + + @Override + public String operator() { + return "not like"; //$NON-NLS-1$ + } + + public static IsNotLikeWhenPresent of(@Nullable T value) { + if (value == null) { + return empty(); + } else { + return new IsNotLikeWhenPresent<>(value); + } + } + + @Override + public IsNotLikeWhenPresent filter(Predicate predicate) { + return filterSupport(predicate, IsNotLikeWhenPresent::empty, this); + } + + @Override + public IsNotLikeWhenPresent map(Function mapper) { + return mapSupport(mapper, IsNotLikeWhenPresent::of, IsNotLikeWhenPresent::empty); + } +} diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/SqlElements.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/SqlElements.kt index 530c962ed..f648496d0 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/SqlElements.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/SqlElements.kt @@ -51,14 +51,18 @@ import org.mybatis.dynamic.sql.util.kotlin.GroupingCriteriaReceiver import org.mybatis.dynamic.sql.util.kotlin.KotlinSubQueryBuilder import org.mybatis.dynamic.sql.util.kotlin.invalidIfNull import org.mybatis.dynamic.sql.where.condition.IsBetween +import org.mybatis.dynamic.sql.where.condition.IsBetweenWhenPresent import org.mybatis.dynamic.sql.where.condition.IsEqualTo import org.mybatis.dynamic.sql.where.condition.IsEqualToColumn +import org.mybatis.dynamic.sql.where.condition.IsEqualToWhenPresent import org.mybatis.dynamic.sql.where.condition.IsEqualToWithSubselect import org.mybatis.dynamic.sql.where.condition.IsGreaterThan import org.mybatis.dynamic.sql.where.condition.IsGreaterThanColumn import org.mybatis.dynamic.sql.where.condition.IsGreaterThanOrEqualTo import org.mybatis.dynamic.sql.where.condition.IsGreaterThanOrEqualToColumn +import org.mybatis.dynamic.sql.where.condition.IsGreaterThanOrEqualToWhenPresent import org.mybatis.dynamic.sql.where.condition.IsGreaterThanOrEqualToWithSubselect +import org.mybatis.dynamic.sql.where.condition.IsGreaterThanWhenPresent import org.mybatis.dynamic.sql.where.condition.IsGreaterThanWithSubselect import org.mybatis.dynamic.sql.where.condition.IsIn import org.mybatis.dynamic.sql.where.condition.IsInCaseInsensitive @@ -69,13 +73,19 @@ import org.mybatis.dynamic.sql.where.condition.IsLessThan import org.mybatis.dynamic.sql.where.condition.IsLessThanColumn import org.mybatis.dynamic.sql.where.condition.IsLessThanOrEqualTo import org.mybatis.dynamic.sql.where.condition.IsLessThanOrEqualToColumn +import org.mybatis.dynamic.sql.where.condition.IsLessThanOrEqualToWhenPresent import org.mybatis.dynamic.sql.where.condition.IsLessThanOrEqualToWithSubselect +import org.mybatis.dynamic.sql.where.condition.IsLessThanWhenPresent import org.mybatis.dynamic.sql.where.condition.IsLessThanWithSubselect import org.mybatis.dynamic.sql.where.condition.IsLike import org.mybatis.dynamic.sql.where.condition.IsLikeCaseInsensitive +import org.mybatis.dynamic.sql.where.condition.IsLikeCaseInsensitiveWhenPresent +import org.mybatis.dynamic.sql.where.condition.IsLikeWhenPresent import org.mybatis.dynamic.sql.where.condition.IsNotBetween +import org.mybatis.dynamic.sql.where.condition.IsNotBetweenWhenPresent import org.mybatis.dynamic.sql.where.condition.IsNotEqualTo import org.mybatis.dynamic.sql.where.condition.IsNotEqualToColumn +import org.mybatis.dynamic.sql.where.condition.IsNotEqualToWhenPresent import org.mybatis.dynamic.sql.where.condition.IsNotEqualToWithSubselect import org.mybatis.dynamic.sql.where.condition.IsNotIn import org.mybatis.dynamic.sql.where.condition.IsNotInCaseInsensitive @@ -84,6 +94,8 @@ import org.mybatis.dynamic.sql.where.condition.IsNotInWhenPresent import org.mybatis.dynamic.sql.where.condition.IsNotInWithSubselect import org.mybatis.dynamic.sql.where.condition.IsNotLike import org.mybatis.dynamic.sql.where.condition.IsNotLikeCaseInsensitive +import org.mybatis.dynamic.sql.where.condition.IsNotLikeCaseInsensitiveWhenPresent +import org.mybatis.dynamic.sql.where.condition.IsNotLikeWhenPresent import org.mybatis.dynamic.sql.where.condition.IsNotNull import org.mybatis.dynamic.sql.where.condition.IsNull @@ -216,7 +228,7 @@ fun isEqualTo(subQuery: KotlinSubQueryBuilder.() -> Unit): IsEqualToWi fun isEqualTo(column: BasicColumn): IsEqualToColumn = SqlBuilder.isEqualTo(column) -fun isEqualToWhenPresent(value: T?): IsEqualTo = SqlBuilder.isEqualToWhenPresent(value) +fun isEqualToWhenPresent(value: T?): IsEqualToWhenPresent = SqlBuilder.isEqualToWhenPresent(value) fun isNotEqualTo(value: T): IsNotEqualTo = SqlBuilder.isNotEqualTo(value) @@ -225,7 +237,8 @@ fun isNotEqualTo(subQuery: KotlinSubQueryBuilder.() -> Unit): IsNotEqu fun isNotEqualTo(column: BasicColumn): IsNotEqualToColumn = SqlBuilder.isNotEqualTo(column) -fun isNotEqualToWhenPresent(value: T?): IsNotEqualTo = SqlBuilder.isNotEqualToWhenPresent(value) +fun isNotEqualToWhenPresent(value: T?): IsNotEqualToWhenPresent = + SqlBuilder.isNotEqualToWhenPresent(value) fun isGreaterThan(value: T): IsGreaterThan = SqlBuilder.isGreaterThan(value) @@ -234,7 +247,8 @@ fun isGreaterThan(subQuery: KotlinSubQueryBuilder.() -> Unit): IsGreat fun isGreaterThan(column: BasicColumn): IsGreaterThanColumn = SqlBuilder.isGreaterThan(column) -fun isGreaterThanWhenPresent(value: T?): IsGreaterThan = SqlBuilder.isGreaterThanWhenPresent(value) +fun isGreaterThanWhenPresent(value: T?): IsGreaterThanWhenPresent = + SqlBuilder.isGreaterThanWhenPresent(value) fun isGreaterThanOrEqualTo(value: T): IsGreaterThanOrEqualTo = SqlBuilder.isGreaterThanOrEqualTo(value) @@ -244,7 +258,7 @@ fun isGreaterThanOrEqualTo(subQuery: KotlinSubQueryBuilder.() -> Unit) fun isGreaterThanOrEqualTo(column: BasicColumn): IsGreaterThanOrEqualToColumn = SqlBuilder.isGreaterThanOrEqualTo(column) -fun isGreaterThanOrEqualToWhenPresent(value: T?): IsGreaterThanOrEqualTo = +fun isGreaterThanOrEqualToWhenPresent(value: T?): IsGreaterThanOrEqualToWhenPresent = SqlBuilder.isGreaterThanOrEqualToWhenPresent(value) fun isLessThan(value: T): IsLessThan = SqlBuilder.isLessThan(value) @@ -254,7 +268,7 @@ fun isLessThan(subQuery: KotlinSubQueryBuilder.() -> Unit): IsLessThan fun isLessThan(column: BasicColumn): IsLessThanColumn = SqlBuilder.isLessThan(column) -fun isLessThanWhenPresent(value: T?): IsLessThan = SqlBuilder.isLessThanWhenPresent(value) +fun isLessThanWhenPresent(value: T?): IsLessThanWhenPresent = SqlBuilder.isLessThanWhenPresent(value) fun isLessThanOrEqualTo(value: T): IsLessThanOrEqualTo = SqlBuilder.isLessThanOrEqualTo(value) @@ -263,7 +277,7 @@ fun isLessThanOrEqualTo(subQuery: KotlinSubQueryBuilder.() -> Unit): I fun isLessThanOrEqualTo(column: BasicColumn): IsLessThanOrEqualToColumn = SqlBuilder.isLessThanOrEqualTo(column) -fun isLessThanOrEqualToWhenPresent(value: T?): IsLessThanOrEqualTo = +fun isLessThanOrEqualToWhenPresent(value: T?): IsLessThanOrEqualToWhenPresent = SqlBuilder.isLessThanOrEqualToWhenPresent(value) fun isIn(vararg values: T): IsIn = isIn(values.asList()) @@ -312,11 +326,11 @@ fun isNotBetweenWhenPresent(value1: T?): NotBetweenWhenPresentBuilder< // for string columns, but generic for columns with type handlers fun isLike(value: T): IsLike = SqlBuilder.isLike(value) -fun isLikeWhenPresent(value: T?): IsLike = SqlBuilder.isLikeWhenPresent(value) +fun isLikeWhenPresent(value: T?): IsLikeWhenPresent = SqlBuilder.isLikeWhenPresent(value) fun isNotLike(value: T): IsNotLike = SqlBuilder.isNotLike(value) -fun isNotLikeWhenPresent(value: T?): IsNotLike = SqlBuilder.isNotLikeWhenPresent(value) +fun isNotLikeWhenPresent(value: T?): IsNotLikeWhenPresent = SqlBuilder.isNotLikeWhenPresent(value) // shortcuts for booleans fun isTrue(): IsEqualTo = isEqualTo(true) @@ -326,12 +340,12 @@ fun isFalse(): IsEqualTo = isEqualTo(false) // conditions for strings only fun isLikeCaseInsensitive(value: String): IsLikeCaseInsensitive = SqlBuilder.isLikeCaseInsensitive(value) -fun isLikeCaseInsensitiveWhenPresent(value: String?): IsLikeCaseInsensitive = +fun isLikeCaseInsensitiveWhenPresent(value: String?): IsLikeCaseInsensitiveWhenPresent = SqlBuilder.isLikeCaseInsensitiveWhenPresent(value) fun isNotLikeCaseInsensitive(value: String): IsNotLikeCaseInsensitive = SqlBuilder.isNotLikeCaseInsensitive(value) -fun isNotLikeCaseInsensitiveWhenPresent(value: String?): IsNotLikeCaseInsensitive = +fun isNotLikeCaseInsensitiveWhenPresent(value: String?): IsNotLikeCaseInsensitiveWhenPresent = SqlBuilder.isNotLikeCaseInsensitiveWhenPresent(value) fun isInCaseInsensitive(vararg values: String): IsInCaseInsensitive = isInCaseInsensitive(values.asList()) @@ -400,7 +414,7 @@ class BetweenBuilder(private val value1: T) { } class BetweenWhenPresentBuilder(private val value1: T?) { - fun and(value2: T?): IsBetween { + fun and(value2: T?): IsBetweenWhenPresent { return SqlBuilder.isBetweenWhenPresent(value1).and(value2) } } @@ -410,7 +424,7 @@ class NotBetweenBuilder(private val value1: T) { } class NotBetweenWhenPresentBuilder(private val value1: T?) { - fun and(value2: T?): IsNotBetween { + fun and(value2: T?): IsNotBetweenWhenPresent { return SqlBuilder.isNotBetweenWhenPresent(value1).and(value2) } } diff --git a/src/site/markdown/docs/conditions.md b/src/site/markdown/docs/conditions.md index 2e266e22b..438249400 100644 --- a/src/site/markdown/docs/conditions.md +++ b/src/site/markdown/docs/conditions.md @@ -166,8 +166,8 @@ table lists the optional conditions and shows how to use them: | Null | where(id, isNull().filter(BooleanSupplier) | The condition will render if BooleanSupplier.getAsBoolean() returns true | ### "When Present" Condition Builders -The library supplies several methods that supply conditions to be used in the common case of checking for null -values. The table below lists the rendering rules for each of these "when present" condition builder methods. +The library supplies conditions for use in the common case of checking for null +values. The table below lists the rendering rules for each of these "when present" conditions. | Condition | Example | Rendering Rules | |---------------------------|---------------------------------------------------|---------------------------------------------------------------| @@ -184,14 +184,20 @@ values. The table below lists the rendering rules for each of these "when presen | Not Like | where(id, isNotLikeWhenPresent(x)) | The condition will render if x is non-null | | Not Like Case Insensitive | where(id, isNotLikeCaseInsensitiveWhenPresent(x)) | The condition will render if x is non-null | -Note that these methods simply apply a "NotNull" filter to a condition. For example: +With our adoption of JSpecify, it is now considered a misuse of the library to pass a null value into a condition +unless the condition is one of the "when present" conditions. If you previously wrote code like this: ```java -// the following two lines are functionally equivalent -... where (id, isEqualToWhenPresent(x)) ... ... where (id, isEqualTo(x).filter(Objects::nonNull)) ... ``` +Starting in version 2.0.0 of the library, you will now see IDE warnings related to nullability. You should change it +to this: + +```java +... where (id, isEqualToWhenPresent(x)) ... +``` + ### Optionality with the "In" Conditions Optionality with the "in" and "not in" conditions is a bit more complex than the other types of conditions. The rules are different for the base conditions ("isIn", "isNotIn", etc.) and the "when present" conditions ("isInWhenPresent", diff --git a/src/test/java/examples/animal/data/AnimalDataTest.java b/src/test/java/examples/animal/data/AnimalDataTest.java index a883b4bd2..1ea44184c 100644 --- a/src/test/java/examples/animal/data/AnimalDataTest.java +++ b/src/test/java/examples/animal/data/AnimalDataTest.java @@ -33,7 +33,6 @@ import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Optional; import org.apache.ibatis.datasource.unpooled.UnpooledDataSource; @@ -717,7 +716,7 @@ void testInConditionWithEventuallyEmptyListForceRendering() { SelectModel selectModel = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isInWhenPresent(inValues).filter(Objects::nonNull).filter(i -> i != 22)) + .where(id, isInWhenPresent(inValues).filter(i -> i != 22)) .build(); assertThatExceptionOfType(NonRenderingWhereClauseException.class).isThrownBy(() -> @@ -744,7 +743,7 @@ void testInCaseSensitiveCondition() { SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(animalName, isInCaseInsensitive("yellow-bellied marmot", "verbet", null)) + .where(animalName, isInCaseInsensitiveWhenPresent("yellow-bellied marmot", "verbet", null)) .build() .render(RenderingStrategies.MYBATIS3); @@ -792,12 +791,13 @@ void testNotInCaseSensitiveConditionWithNull() { SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(animalName, isNotInCaseInsensitive((String)null)) + .where(animalName, isNotInCaseInsensitiveWhenPresent((String) null)) + .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) .build() .render(RenderingStrategies.MYBATIS3); List animals = mapper.selectMany(selectStatement); - assertThat(animals).isEmpty(); + assertThat(animals).hasSize(65); } } @@ -825,7 +825,7 @@ void testNotInConditionWithEventuallyEmptyListForceRendering() { SelectModel selectModel = select(id, animalName, bodyWeight, brainWeight) .from(animalData) .where(id, isNotInWhenPresent(null, 22, null) - .filter(Objects::nonNull).filter(i -> i != 22)) + .filter(i -> i != 22)) .build(); assertThatExceptionOfType(NonRenderingWhereClauseException.class).isThrownBy(() -> diff --git a/src/test/java/examples/animal/data/CommonSelectMapperTest.java b/src/test/java/examples/animal/data/CommonSelectMapperTest.java index 863df85e6..380d888f7 100644 --- a/src/test/java/examples/animal/data/CommonSelectMapperTest.java +++ b/src/test/java/examples/animal/data/CommonSelectMapperTest.java @@ -106,6 +106,7 @@ void testGeneralSelectOneWithRowMapper() { AnimalData animal = mapper.selectOne(selectStatement, rowMapper); + assertThat(animal).isNotNull(); assertThat(animal.getId()).isEqualTo(1); assertThat(animal.getAnimalName()).isEqualTo("Lesser short-tailed shrew"); assertThat(animal.getBodyWeight()).isEqualTo(0.14); @@ -113,6 +114,21 @@ void testGeneralSelectOneWithRowMapper() { } } + @Test + void testGeneralSelectOneWithRowMapperAndNullRow() { + try (SqlSession sqlSession = sqlSessionFactory.openSession()) { + CommonSelectMapper mapper = sqlSession.getMapper(CommonSelectMapper.class); + SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) + .from(animalData) + .where(id, isEqualTo(-237)) + .build() + .render(RenderingStrategies.MYBATIS3); + + AnimalData animal = mapper.selectOne(selectStatement, rowMapper); + assertThat(animal).isNull(); + } + } + @Test void testGeneralSelectMany() { try (SqlSession sqlSession = sqlSessionFactory.openSession()) { diff --git a/src/test/java/examples/animal/data/OptionalConditionsWithPredicatesAnimalDataTest.java b/src/test/java/examples/animal/data/OptionalConditionsWithPredicatesAnimalDataTest.java index a46190941..89d349825 100644 --- a/src/test/java/examples/animal/data/OptionalConditionsWithPredicatesAnimalDataTest.java +++ b/src/test/java/examples/animal/data/OptionalConditionsWithPredicatesAnimalDataTest.java @@ -30,7 +30,6 @@ import java.sql.Connection; import java.sql.DriverManager; import java.util.List; -import java.util.Objects; import org.apache.ibatis.datasource.unpooled.UnpooledDataSource; import org.apache.ibatis.jdbc.ScriptRunner; @@ -44,7 +43,6 @@ import org.junit.jupiter.api.Test; import org.mybatis.dynamic.sql.render.RenderingStrategies; import org.mybatis.dynamic.sql.select.render.SelectStatementProvider; -import org.mybatis.dynamic.sql.util.Predicates; class OptionalConditionsWithPredicatesAnimalDataTest { @@ -78,7 +76,7 @@ void testAllIgnored() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isGreaterThan(NULL_INTEGER).filter(Objects::nonNull)) // the where clause should not render + .where(id, isGreaterThanWhenPresent(NULL_INTEGER)) // the where clause should not render .orderBy(id) .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) .build() @@ -93,26 +91,6 @@ void testAllIgnored() { } } - @Test - void testSelectByNull() { - // this method demonstrates that ignoring the null value warning will still work - try (SqlSession sqlSession = sqlSessionFactory.openSession()) { - AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); - SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) - .from(animalData) - .where(id, isGreaterThan(NULL_INTEGER)) // should be an IDE warning about passing null to a nonnull method - .orderBy(id) - .build() - .render(RenderingStrategies.MYBATIS3); - List animals = mapper.selectMany(selectStatement); - assertAll( - () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id > #{parameters.p1,jdbcType=INTEGER} order by id"), - () -> assertThat(selectStatement.getParameters()).containsEntry("p1", null), - () -> assertThat(animals).isEmpty() - ); - } - } - @Test void testIgnoredBetweenRendered() { try (SqlSession sqlSession = sqlSessionFactory.openSession()) { @@ -120,8 +98,8 @@ void testIgnoredBetweenRendered() { SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) .where(id, isEqualTo(3)) - .and(id, isNotEqualTo(NULL_INTEGER).filter(Objects::nonNull)) - .or(id, isEqualTo(4).filter(Objects::nonNull)) + .and(id, isNotEqualToWhenPresent(NULL_INTEGER)) + .or(id, isEqualTo(4)) .orderBy(id) .build() .render(RenderingStrategies.MYBATIS3); @@ -141,9 +119,9 @@ void testIgnoredInWhere() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isLessThan(NULL_INTEGER).filter(Objects::nonNull)) - .and(id, isEqualTo(3).filter(Objects::nonNull)) - .or(id, isEqualTo(4).filter(Objects::nonNull)) + .where(id, isLessThanWhenPresent(NULL_INTEGER)) + .and(id, isEqualTo(3)) + .or(id, isEqualTo(4)) .orderBy(id) .build() .render(RenderingStrategies.MYBATIS3); @@ -163,10 +141,10 @@ void testManyIgnored() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isLessThan(NULL_INTEGER).filter(Objects::nonNull), and(id, isGreaterThanOrEqualTo(NULL_INTEGER).filter(Objects::nonNull))) - .and(id, isEqualTo(NULL_INTEGER).filter(Objects::nonNull), or(id, isEqualTo(3), and(id, isLessThan(NULL_INTEGER).filter(Objects::nonNull)))) - .or(id, isEqualTo(4).filter(Objects::nonNull), and(id, isGreaterThanOrEqualTo(NULL_INTEGER).filter(Objects::nonNull))) - .and(id, isNotEqualTo(NULL_INTEGER).filter(Objects::nonNull)) + .where(id, isLessThanWhenPresent(NULL_INTEGER), and(id, isGreaterThanOrEqualToWhenPresent(NULL_INTEGER))) + .and(id, isEqualToWhenPresent(NULL_INTEGER), or(id, isEqualTo(3), and(id, isLessThanWhenPresent(NULL_INTEGER)))) + .or(id, isEqualTo(4), and(id, isGreaterThanOrEqualToWhenPresent(NULL_INTEGER))) + .and(id, isNotEqualToWhenPresent(NULL_INTEGER)) .orderBy(id) .build() .render(RenderingStrategies.MYBATIS3); @@ -186,8 +164,8 @@ void testIgnoredInitialWhere() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isLessThan(NULL_INTEGER).filter(Objects::nonNull), and(id, isEqualTo(3).filter(Objects::nonNull))) - .or(id, isEqualTo(4).filter(Objects::nonNull)) + .where(id, isLessThanWhenPresent(NULL_INTEGER), and(id, isEqualTo(3))) + .or(id, isEqualTo(4)) .orderBy(id) .build() .render(RenderingStrategies.MYBATIS3); @@ -207,7 +185,7 @@ void testEqualWhenWithValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isEqualTo(4).filter(Objects::nonNull)) + .where(id, isEqualTo(4)) .orderBy(id) .build() .render(RenderingStrategies.MYBATIS3); @@ -226,7 +204,7 @@ void testEqualWhenWithoutValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isEqualTo(NULL_INTEGER).filter(Objects::nonNull)) + .where(id, isEqualToWhenPresent(NULL_INTEGER)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -246,7 +224,7 @@ void testNotEqualWhenWithValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isNotEqualTo(4).filter(Objects::nonNull)) + .where(id, isNotEqualTo(4)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -266,7 +244,7 @@ void testNotEqualWhenWithoutValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isNotEqualTo(NULL_INTEGER).filter(Objects::nonNull)) + .where(id, isNotEqualToWhenPresent(NULL_INTEGER)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -286,7 +264,7 @@ void testGreaterThanWhenWithValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isGreaterThan(4).filter(Objects::nonNull)) + .where(id, isGreaterThan(4)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -306,7 +284,7 @@ void testGreaterThanWhenWithoutValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isGreaterThan(NULL_INTEGER).filter(Objects::nonNull)) + .where(id, isGreaterThanWhenPresent(NULL_INTEGER)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -326,7 +304,7 @@ void testGreaterThanOrEqualToWhenWithValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isGreaterThanOrEqualTo(4).filter(Objects::nonNull)) + .where(id, isGreaterThanOrEqualTo(4)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -346,7 +324,7 @@ void testGreaterThanOrEqualToWhenWithoutValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isGreaterThanOrEqualTo(NULL_INTEGER).filter(Objects::nonNull)) + .where(id, isGreaterThanOrEqualToWhenPresent(NULL_INTEGER)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -366,7 +344,7 @@ void testLessThanWhenWithValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isLessThan(4).filter(Objects::nonNull)) + .where(id, isLessThan(4)) .orderBy(id) .build() .render(RenderingStrategies.MYBATIS3); @@ -385,7 +363,7 @@ void testLessThanWhenWithoutValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isLessThan(NULL_INTEGER).filter(Objects::nonNull)) + .where(id, isLessThanWhenPresent(NULL_INTEGER)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -405,7 +383,7 @@ void testLessThanOrEqualToWhenWithValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isLessThanOrEqualTo(4).filter(Objects::nonNull)) + .where(id, isLessThanOrEqualTo(4)) .orderBy(id) .build() .render(RenderingStrategies.MYBATIS3); @@ -424,7 +402,7 @@ void testLessThanOrEqualToWhenWithoutValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isLessThanOrEqualTo(NULL_INTEGER).filter(Objects::nonNull)) + .where(id, isLessThanOrEqualToWhenPresent(NULL_INTEGER)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -463,7 +441,7 @@ void testIsInWhenWithSomeValues() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isIn(3, NULL_INTEGER, 5).filter(Objects::nonNull).map(i -> i + 3)) + .where(id, isInWhenPresent(3, NULL_INTEGER, 5).map(i -> i + 3)) .orderBy(id) .build() .render(RenderingStrategies.MYBATIS3); @@ -502,8 +480,7 @@ void testValueStreamTransformer() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(animalName, isIn(" Mouse", " ", null, "", "Musk shrew ") - .filter(Objects::nonNull) + .where(animalName, isInWhenPresent(" Mouse", " ", null, "", "Musk shrew ") .map(String::trim) .filter(not(String::isEmpty))) .orderBy(id) @@ -583,7 +560,7 @@ void testIsNotInWhenWithSomeValues() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isNotIn(3, NULL_INTEGER, 5).filter(Objects::nonNull)) + .where(id, isNotInWhenPresent(3, NULL_INTEGER, 5)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -643,7 +620,7 @@ void testIsBetweenWhenWithValues() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isBetween(3).and(6).filter(Predicates.bothPresent())) + .where(id, isBetween(3).and(6)) .orderBy(id) .build() .render(RenderingStrategies.MYBATIS3); @@ -662,7 +639,7 @@ void testIsBetweenWhenWithFirstMissing() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isBetween(NULL_INTEGER).and(6).filter(Predicates.bothPresent())) + .where(id, isBetweenWhenPresent(NULL_INTEGER).and(6)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -682,7 +659,7 @@ void testIsBetweenWhenWithSecondMissing() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isBetween(3).and(NULL_INTEGER).filter(Predicates.bothPresent())) + .where(id, isBetweenWhenPresent(3).and(NULL_INTEGER)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -702,7 +679,7 @@ void testIsBetweenWhenWithBothMissing() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isBetween(NULL_INTEGER).and(NULL_INTEGER).filter(Predicates.bothPresent())) + .where(id, isBetweenWhenPresent(NULL_INTEGER).and(NULL_INTEGER)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -722,7 +699,7 @@ void testIsNotBetweenWhenWithValues() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isNotBetween(3).and(6).filter(Predicates.bothPresent())) + .where(id, isNotBetween(3).and(6)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -742,7 +719,7 @@ void testIsNotBetweenWhenWithFirstMissing() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isNotBetween(NULL_INTEGER).and(6).filter(Predicates.bothPresent())) + .where(id, isNotBetweenWhenPresent(NULL_INTEGER).and(6)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -762,7 +739,7 @@ void testIsNotBetweenWhenWithSecondMissing() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isNotBetween(3).and(NULL_INTEGER).filter(Predicates.bothPresent())) + .where(id, isNotBetweenWhenPresent(3).and(NULL_INTEGER)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -782,7 +759,7 @@ void testIsNotBetweenWhenWithBothMissing() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(id, isNotBetween(NULL_INTEGER).and(NULL_INTEGER).filter(Predicates.bothPresent())) + .where(id, isNotBetweenWhenPresent(NULL_INTEGER).and(NULL_INTEGER)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -802,7 +779,7 @@ void testIsLikeWhenWithValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(animalName, isLike("%mole").filter(Objects::nonNull)) + .where(animalName, isLike("%mole")) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -822,7 +799,7 @@ void testIsLikeWhenWithoutValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(animalName, isLike((String) null).filter(Objects::nonNull)) + .where(animalName, isLikeWhenPresent((String) null)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -842,7 +819,7 @@ void testIsLikeCaseInsensitiveWhenWithValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(animalName, isLikeCaseInsensitive("%MoLe").filter(Objects::nonNull)) + .where(animalName, isLikeCaseInsensitive("%MoLe")) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -862,7 +839,7 @@ void testIsLikeCaseInsensitiveWhenWithoutValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(animalName, isLikeCaseInsensitive((String) null).filter(Objects::nonNull)) + .where(animalName, isLikeCaseInsensitiveWhenPresent((String) null)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -882,7 +859,7 @@ void testIsNotLikeWhenWithValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(animalName, isNotLike("%mole").filter(Objects::nonNull)) + .where(animalName, isNotLike("%mole")) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -902,7 +879,7 @@ void testIsNotLikeWhenWithoutValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(animalName, isNotLike((String) null).filter(Objects::nonNull)) + .where(animalName, isNotLikeWhenPresent((String) null)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -922,7 +899,7 @@ void testIsNotLikeCaseInsensitiveWhenWithValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(animalName, isNotLikeCaseInsensitive("%MoLe").filter(Objects::nonNull)) + .where(animalName, isNotLikeCaseInsensitive("%MoLe")) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() @@ -942,7 +919,7 @@ void testIsNotLikeCaseInsensitiveWhenWithoutValue() { AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) .from(animalData) - .where(animalName, isNotLikeCaseInsensitive((String) null).filter(Objects::nonNull)) + .where(animalName, isNotLikeCaseInsensitiveWhenPresent((String) null)) .and(id, isLessThanOrEqualTo(10)) .orderBy(id) .build() diff --git a/src/test/java/examples/complexquery/ComplexQueryTest.java b/src/test/java/examples/complexquery/ComplexQueryTest.java index fca43c133..3912040cb 100644 --- a/src/test/java/examples/complexquery/ComplexQueryTest.java +++ b/src/test/java/examples/complexquery/ComplexQueryTest.java @@ -22,8 +22,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mybatis.dynamic.sql.SqlBuilder.*; -import java.util.Objects; - +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.mybatis.dynamic.sql.render.RenderingStrategies; import org.mybatis.dynamic.sql.select.QueryExpressionDSL; @@ -107,18 +106,17 @@ void testAllNull() { assertThat(selectStatement.getParameters()).containsEntry("p1", 50L); } - SelectStatementProvider search(Integer targetId, String fName, String lName) { + SelectStatementProvider search(@Nullable Integer targetId, @Nullable String fName, @Nullable String lName) { QueryExpressionDSL.QueryExpressionWhereBuilder builder = select(id, firstName, lastName) .from(person) .where() .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)); if (targetId != null) { - builder - .and(id, isEqualTo(targetId)); + builder.and(id, isEqualTo(targetId)); } else { builder - .and(firstName, isLike(fName).filter(Objects::nonNull).map(s -> "%" + s + "%")) + .and(firstName, isLikeWhenPresent(fName).map(s -> "%" + s + "%")) .and(lastName, isLikeWhenPresent(lName).map(this::addWildcards)); } diff --git a/src/test/java/examples/emptywhere/EmptyWhereTest.java b/src/test/java/examples/emptywhere/EmptyWhereTest.java index 4c02f4f66..fd699da23 100644 --- a/src/test/java/examples/emptywhere/EmptyWhereTest.java +++ b/src/test/java/examples/emptywhere/EmptyWhereTest.java @@ -20,7 +20,8 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mybatis.dynamic.sql.SqlBuilder.*; -import java.util.*; +import java.util.List; +import java.util.Optional; import java.util.stream.Stream; import org.junit.jupiter.api.Test; @@ -93,8 +94,8 @@ void testDeleteThreeConditions() { DeleteDSL.DeleteWhereBuilder builder = deleteFrom(person) .where(id, isEqualTo(3)); - builder.and(firstName, isEqualTo(fName).filter(Objects::nonNull)); - builder.and(PersonDynamicSqlSupport.lastName, isEqualTo(lName).filter(Objects::nonNull)); + builder.and(firstName, isEqualTo(fName)); + builder.and(PersonDynamicSqlSupport.lastName, isEqualTo(lName)); DeleteStatementProvider deleteStatement = builder.build().render(RenderingStrategies.MYBATIS3); @@ -112,8 +113,8 @@ void testDeleteVariations(Variation variation) { DeleteDSL.DeleteWhereBuilder builder = deleteFrom(person) .where(); - builder.and(firstName, isEqualTo(variation.firstName).filter(Objects::nonNull)); - builder.or(PersonDynamicSqlSupport.lastName, isEqualTo(variation.lastName).filter(Objects::nonNull)); + builder.and(firstName, isEqualToWhenPresent(variation.firstName)); + builder.or(PersonDynamicSqlSupport.lastName, isEqualToWhenPresent(variation.lastName)); builder.configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)); DeleteStatementProvider deleteStatement = builder.build().render(RenderingStrategies.MYBATIS3); @@ -132,8 +133,8 @@ void testSelectThreeConditions() { .from(person) .where(id, isEqualTo(3)); - builder.and(firstName, isEqualTo(fName).filter(Objects::nonNull)); - builder.and(PersonDynamicSqlSupport.lastName, isEqualTo(lName).filter(Objects::nonNull)); + builder.and(firstName, isEqualTo(fName)); + builder.and(PersonDynamicSqlSupport.lastName, isEqualTo(lName)); SelectStatementProvider selectStatement = builder.build().render(RenderingStrategies.MYBATIS3); @@ -153,8 +154,8 @@ void testSelectVariations(Variation variation) { .from(person) .where(); - builder.and(firstName, isEqualTo(variation.firstName).filter(Objects::nonNull)); - builder.or(PersonDynamicSqlSupport.lastName, isEqualTo(variation.lastName).filter(Objects::nonNull)); + builder.and(firstName, isEqualToWhenPresent(variation.firstName)); + builder.or(PersonDynamicSqlSupport.lastName, isEqualToWhenPresent(variation.lastName)); builder.configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)); SelectStatementProvider selectStatement = builder.build().render(RenderingStrategies.MYBATIS3); @@ -173,8 +174,8 @@ void testJoinThreeConditions() { .from(person).join(order).on(person.id, isEqualTo(order.personId)) .where(id, isEqualTo(3)); - builder.and(firstName, isEqualTo(fName).filter(Objects::nonNull)); - builder.and(PersonDynamicSqlSupport.lastName, isEqualTo(lName).filter(Objects::nonNull)); + builder.and(firstName, isEqualTo(fName)); + builder.and(PersonDynamicSqlSupport.lastName, isEqualTo(lName)); SelectStatementProvider selectStatement = builder.build().render(RenderingStrategies.MYBATIS3); @@ -195,8 +196,8 @@ void testJoinVariations(Variation variation) { .from(person).join(order).on(person.id, isEqualTo(order.personId)) .where(); - builder.and(firstName, isEqualTo(variation.firstName).filter(Objects::nonNull)); - builder.or(PersonDynamicSqlSupport.lastName, isEqualTo(variation.lastName).filter(Objects::nonNull)); + builder.and(firstName, isEqualToWhenPresent(variation.firstName)); + builder.or(PersonDynamicSqlSupport.lastName, isEqualToWhenPresent(variation.lastName)); builder.configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)); SelectStatementProvider selectStatement = builder.build().render(RenderingStrategies.MYBATIS3); @@ -218,8 +219,8 @@ void testUpdateThreeConditions() { .set(id).equalTo(3) .where(id, isEqualTo(3)); - builder.and(firstName, isEqualTo(fName).filter(Objects::nonNull)); - builder.and(PersonDynamicSqlSupport.lastName, isEqualTo(lName).filter(Objects::nonNull)); + builder.and(firstName, isEqualTo(fName)); + builder.and(PersonDynamicSqlSupport.lastName, isEqualTo(lName)); UpdateStatementProvider updateStatement = builder.build().render(RenderingStrategies.MYBATIS3); @@ -239,8 +240,8 @@ void testUpdateVariations(Variation variation) { .set(id).equalTo(3) .where(); - builder.and(firstName, isEqualTo(variation.firstName).filter(Objects::nonNull)); - builder.or(PersonDynamicSqlSupport.lastName, isEqualTo(variation.lastName).filter(Objects::nonNull)); + builder.and(firstName, isEqualToWhenPresent(variation.firstName)); + builder.or(PersonDynamicSqlSupport.lastName, isEqualToWhenPresent(variation.lastName)); builder.configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)); UpdateStatementProvider updateStatement = builder.build().render(RenderingStrategies.MYBATIS3); @@ -259,8 +260,8 @@ void testWhereThreeConditions() { WhereDSL.StandaloneWhereFinisher builder = where(id, isEqualTo(3)); - builder.and(firstName, isEqualTo(fName).filter(Objects::nonNull)); - builder.and(PersonDynamicSqlSupport.lastName, isEqualTo(lName).filter(Objects::nonNull)); + builder.and(firstName, isEqualTo(fName)); + builder.and(PersonDynamicSqlSupport.lastName, isEqualTo(lName)); Optional whereClause = builder.build().render(RenderingStrategies.MYBATIS3); @@ -278,8 +279,8 @@ void testWhereThreeConditions() { void testWhereVariations(Variation variation) { WhereDSL.StandaloneWhereFinisher builder = where(); - builder.and(firstName, isEqualTo(variation.firstName).filter(Objects::nonNull)); - builder.or(PersonDynamicSqlSupport.lastName, isEqualTo(variation.lastName).filter(Objects::nonNull)); + builder.and(firstName, isEqualToWhenPresent(variation.firstName)); + builder.or(PersonDynamicSqlSupport.lastName, isEqualToWhenPresent(variation.lastName)); builder.configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)); Optional whereClause = builder.build().render(RenderingStrategies.MYBATIS3); diff --git a/src/test/java/examples/simple/PersonMapperTest.java b/src/test/java/examples/simple/PersonMapperTest.java index 7aed9182d..acbda68ad 100644 --- a/src/test/java/examples/simple/PersonMapperTest.java +++ b/src/test/java/examples/simple/PersonMapperTest.java @@ -36,7 +36,6 @@ import java.util.Collection; import java.util.Date; import java.util.List; -import java.util.Objects; import java.util.Optional; import org.apache.ibatis.datasource.unpooled.UnpooledDataSource; @@ -146,7 +145,7 @@ void testSelectWithTypeConversionAndFilterAndNull() { PersonMapper mapper = session.getMapper(PersonMapper.class); List rows = mapper.select(c -> - c.where(id, isEqualTo((String) null).filter(Objects::nonNull).map(Integer::parseInt)) + c.where(id, isEqualToWhenPresent((String) null).map(Integer::parseInt)) .or(occupation, isNull())); assertThat(rows).hasSize(2); diff --git a/src/test/java/issues/gh105/Issue105Test.java b/src/test/java/issues/gh105/Issue105Test.java index 8fb16f22d..c12f4fde9 100644 --- a/src/test/java/issues/gh105/Issue105Test.java +++ b/src/test/java/issues/gh105/Issue105Test.java @@ -19,12 +19,9 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mybatis.dynamic.sql.SqlBuilder.*; -import java.util.Objects; - import org.junit.jupiter.api.Test; import org.mybatis.dynamic.sql.render.RenderingStrategies; import org.mybatis.dynamic.sql.select.render.SelectStatementProvider; -import org.mybatis.dynamic.sql.util.Predicates; class Issue105Test { @@ -35,8 +32,8 @@ void testFuzzyLikeBothPresent() { SelectStatementProvider selectStatement = select(id, firstName, lastName) .from(person) - .where(firstName, isLike(fName).filter(Objects::nonNull).map(s -> "%" + s + "%")) - .and(lastName, isLike(lName).filter(Objects::nonNull).map(s -> "%" + s + "%")) + .where(firstName, isLike(fName).map(s -> "%" + s + "%")) + .and(lastName, isLike(lName).map(s -> "%" + s + "%")) .build() .render(RenderingStrategies.MYBATIS3); @@ -57,8 +54,8 @@ void testFuzzyLikeFirstNameNull() { SelectStatementProvider selectStatement = select(id, firstName, lastName) .from(person) - .where(firstName, isLike(fName).filter(Objects::nonNull).map(SearchUtils::addWildcards)) - .and(lastName, isLike(lName).filter(Objects::nonNull).map(SearchUtils::addWildcards)) + .where(firstName, isLikeWhenPresent(fName).map(SearchUtils::addWildcards)) + .and(lastName, isLike(lName).map(SearchUtils::addWildcards)) .build() .render(RenderingStrategies.MYBATIS3); @@ -77,8 +74,8 @@ void testFuzzyLikeLastNameNull() { SelectStatementProvider selectStatement = select(id, firstName, lastName) .from(person) - .where(firstName, isLike(fName).filter(Objects::nonNull).map(SearchUtils::addWildcards)) - .and(lastName, isLike(lName).filter(Objects::nonNull).map(SearchUtils::addWildcards)) + .where(firstName, isLike(fName).map(SearchUtils::addWildcards)) + .and(lastName, isLikeWhenPresent(lName).map(SearchUtils::addWildcards)) .build() .render(RenderingStrategies.MYBATIS3); @@ -97,8 +94,8 @@ void testFuzzyLikeBothNull() { SelectStatementProvider selectStatement = select(id, firstName, lastName) .from(person) - .where(firstName, isLike(fName).filter(Objects::nonNull).map(SearchUtils::addWildcards)) - .and(lastName, isLike(lName).filter(Objects::nonNull).map(SearchUtils::addWildcards)) + .where(firstName, isLikeWhenPresent(fName).map(SearchUtils::addWildcards)) + .and(lastName, isLikeWhenPresent(lName).map(SearchUtils::addWildcards)) .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) .build() .render(RenderingStrategies.MYBATIS3); @@ -522,22 +519,6 @@ void testNotLikeWhenPresentTransform() { assertThat(selectStatement.getParameters()).containsEntry("p1", "%fred%"); } - @Test - void testBetweenTransformWithNull() { - - SelectStatementProvider selectStatement = select(id, firstName, lastName) - .from(person) - .where(age, isBetween(1).and((Integer) null).filter(Predicates.bothPresent()).map(i1 -> i1 + 1, i2 -> i2 + 2)) - .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) - .build() - .render(RenderingStrategies.MYBATIS3); - - String expected = "select person_id, first_name, last_name" - + " from Person"; - - assertThat(selectStatement.getSelectStatement()).isEqualTo(expected); - } - @Test void testBetweenWhenPresentTransformWithNull() { @@ -554,22 +535,6 @@ void testBetweenWhenPresentTransformWithNull() { assertThat(selectStatement.getSelectStatement()).isEqualTo(expected); } - @Test - void testEqualTransformWithNull() { - - SelectStatementProvider selectStatement = select(id, firstName, lastName) - .from(person) - .where(age, isEqualTo((Integer) null).filter(Objects::nonNull).map(i -> i + 1)) - .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) - .build() - .render(RenderingStrategies.MYBATIS3); - - String expected = "select person_id, first_name, last_name" - + " from Person"; - - assertThat(selectStatement.getSelectStatement()).isEqualTo(expected); - } - @Test void testEqualWhenPresentTransformWithNull() { @@ -586,38 +551,6 @@ void testEqualWhenPresentTransformWithNull() { assertThat(selectStatement.getSelectStatement()).isEqualTo(expected); } - @Test - void testGreaterThanTransformWithNull() { - - SelectStatementProvider selectStatement = select(id, firstName, lastName) - .from(person) - .where(age, isGreaterThan((Integer) null).filter(Objects::nonNull).map(i -> i + 1)) - .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) - .build() - .render(RenderingStrategies.MYBATIS3); - - String expected = "select person_id, first_name, last_name" - + " from Person"; - - assertThat(selectStatement.getSelectStatement()).isEqualTo(expected); - } - - @Test - void testGreaterThanOrEqualTransformWithNull() { - - SelectStatementProvider selectStatement = select(id, firstName, lastName) - .from(person) - .where(age, isGreaterThanOrEqualTo((Integer) null).filter(Objects::nonNull).map(i -> i + 1)) - .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) - .build() - .render(RenderingStrategies.MYBATIS3); - - String expected = "select person_id, first_name, last_name" - + " from Person"; - - assertThat(selectStatement.getSelectStatement()).isEqualTo(expected); - } - @Test void testGreaterThanOrEqualWhenPresentTransformWithNull() { @@ -650,38 +583,6 @@ void testGreaterThanWhenPresentTransformWithNull() { assertThat(selectStatement.getSelectStatement()).isEqualTo(expected); } - @Test - void testLessThanTransformWithNull() { - - SelectStatementProvider selectStatement = select(id, firstName, lastName) - .from(person) - .where(age, isLessThan((Integer) null).filter(Objects::nonNull).map(i -> i + 1)) - .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) - .build() - .render(RenderingStrategies.MYBATIS3); - - String expected = "select person_id, first_name, last_name" - + " from Person"; - - assertThat(selectStatement.getSelectStatement()).isEqualTo(expected); - } - - @Test - void testLessThanOrEqualTransformWithNull() { - - SelectStatementProvider selectStatement = select(id, firstName, lastName) - .from(person) - .where(age, isLessThanOrEqualTo((Integer) null).filter(Objects::nonNull).map(i -> i + 1)) - .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) - .build() - .render(RenderingStrategies.MYBATIS3); - - String expected = "select person_id, first_name, last_name" - + " from Person"; - - assertThat(selectStatement.getSelectStatement()).isEqualTo(expected); - } - @Test void testLessThanOrEqualWhenPresentTransformWithNull() { @@ -714,38 +615,6 @@ void testLessThanWhenPresentTransformWithNull() { assertThat(selectStatement.getSelectStatement()).isEqualTo(expected); } - @Test - void testLikeTransformWithNull() { - - SelectStatementProvider selectStatement = select(id, firstName, lastName) - .from(person) - .where(firstName, isLike((String) null).filter(Objects::nonNull).map(SearchUtils::addWildcards)) - .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) - .build() - .render(RenderingStrategies.MYBATIS3); - - String expected = "select person_id, first_name, last_name" - + " from Person"; - - assertThat(selectStatement.getSelectStatement()).isEqualTo(expected); - } - - @Test - void testLikeCaseInsensitiveTransformWithNull() { - - SelectStatementProvider selectStatement = select(id, firstName, lastName) - .from(person) - .where(firstName, isLikeCaseInsensitive((String) null).filter(Objects::nonNull).map(SearchUtils::addWildcards)) - .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) - .build() - .render(RenderingStrategies.MYBATIS3); - - String expected = "select person_id, first_name, last_name" - + " from Person"; - - assertThat(selectStatement.getSelectStatement()).isEqualTo(expected); - } - @Test void testLikeCaseInsensitiveWhenPresentTransformWithNull() { @@ -783,7 +652,7 @@ void testNotBetweenTransformWithNull() { SelectStatementProvider selectStatement = select(id, firstName, lastName) .from(person) - .where(age, isNotBetween((Integer) null).and(10).filter(Predicates.bothPresent()).map(i1 -> i1 + 1, i2 -> i2 + 2)) + .where(age, isNotBetweenWhenPresent((Integer) null).and(10).map(i1 -> i1 + 1, i2 -> i2 + 2)) .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) .build() .render(RenderingStrategies.MYBATIS3); @@ -810,22 +679,6 @@ void testNotBetweenWhenPresentTransformWithNull() { assertThat(selectStatement.getSelectStatement()).isEqualTo(expected); } - @Test - void testNotEqualTransformWithNull() { - - SelectStatementProvider selectStatement = select(id, firstName, lastName) - .from(person) - .where(age, isNotEqualTo((Integer) null).filter(Objects::nonNull).map(i -> i + 1)) - .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) - .build() - .render(RenderingStrategies.MYBATIS3); - - String expected = "select person_id, first_name, last_name" - + " from Person"; - - assertThat(selectStatement.getSelectStatement()).isEqualTo(expected); - } - @Test void testNotEqualWhenPresentTransformWithNull() { @@ -842,38 +695,6 @@ void testNotEqualWhenPresentTransformWithNull() { assertThat(selectStatement.getSelectStatement()).isEqualTo(expected); } - @Test - void testNotLikeTransformWithNull() { - - SelectStatementProvider selectStatement = select(id, firstName, lastName) - .from(person) - .where(firstName, isNotLike((String) null).filter(Objects::nonNull).map(SearchUtils::addWildcards)) - .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) - .build() - .render(RenderingStrategies.MYBATIS3); - - String expected = "select person_id, first_name, last_name" - + " from Person"; - - assertThat(selectStatement.getSelectStatement()).isEqualTo(expected); - } - - @Test - void testNotLikeCaseInsensitiveTransformWithNull() { - - SelectStatementProvider selectStatement = select(id, firstName, lastName) - .from(person) - .where(firstName, isNotLikeCaseInsensitive((String) null).filter(Objects::nonNull).map(SearchUtils::addWildcards)) - .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) - .build() - .render(RenderingStrategies.MYBATIS3); - - String expected = "select person_id, first_name, last_name" - + " from Person"; - - assertThat(selectStatement.getSelectStatement()).isEqualTo(expected); - } - @Test void testNotLikeCaseInsensitiveWhenPresentTransformWithNull() { diff --git a/src/test/java/org/mybatis/dynamic/sql/util/PredicatesTest.java b/src/test/java/org/mybatis/dynamic/sql/util/PredicatesTest.java new file mode 100644 index 000000000..950af088a --- /dev/null +++ b/src/test/java/org/mybatis/dynamic/sql/util/PredicatesTest.java @@ -0,0 +1,42 @@ +/* + * Copyright 2016-2025 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.util; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +class PredicatesTest { + @Test + void testFirstNull() { + assertThat(Predicates.bothPresent().test(null, 1)).isFalse(); + } + + @Test + void testSecondNull() { + assertThat(Predicates.bothPresent().test(1, null)).isFalse(); + } + + @Test + void testBothNull() { + assertThat(Predicates.bothPresent().test(null, null)).isFalse(); + } + + @Test + void testNeitherNull() { + assertThat(Predicates.bothPresent().test(1, 1)).isTrue(); + } +} diff --git a/src/test/java/org/mybatis/dynamic/sql/where/condition/FilterAndMapTest.java b/src/test/java/org/mybatis/dynamic/sql/where/condition/FilterAndMapTest.java index bd2e56fbb..7ea071e87 100644 --- a/src/test/java/org/mybatis/dynamic/sql/where/condition/FilterAndMapTest.java +++ b/src/test/java/org/mybatis/dynamic/sql/where/condition/FilterAndMapTest.java @@ -20,9 +20,12 @@ import java.util.List; import java.util.NoSuchElementException; -import java.util.Objects; +import java.util.function.Predicate; +import java.util.stream.Stream; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; import org.mybatis.dynamic.sql.SqlBuilder; class FilterAndMapTest { @@ -33,17 +36,9 @@ void testTypeConversion() { assertThat(cond.value()).isEqualTo(1); } - @Test - void testTypeConversionWithNullThrowsException() { - var cond = SqlBuilder.isEqualTo((String) null); - assertThatExceptionOfType(NumberFormatException.class).isThrownBy(() -> - cond.map(Integer::parseInt) - ); - } - @Test void testTypeConversionWithNullAndFilterDoesNotThrowException() { - var cond = SqlBuilder.isEqualTo((String) null).filter(Objects::nonNull).map(Integer::parseInt); + var cond = SqlBuilder.isEqualToWhenPresent((String) null).map(Integer::parseInt); assertThat(cond.isEmpty()).isTrue(); } @@ -479,17 +474,17 @@ void testBetweenUnRenderableFilterShouldReturnSameObject() { @Test void testBetweenUnRenderableFirstNullFilterShouldReturnSameObject() { - IsBetween cond = SqlBuilder.isBetween((Integer) null).and(4).filter(Objects::nonNull); + IsBetweenWhenPresent cond = SqlBuilder.isBetweenWhenPresent((Integer) null).and(4); assertThat(cond.isEmpty()).isTrue(); - IsBetween filtered = cond.filter(v -> true); + IsBetweenWhenPresent filtered = cond.filter(v -> true); assertThat(cond).isSameAs(filtered); } @Test void testBetweenUnRenderableSecondNullFilterShouldReturnSameObject() { - IsBetween cond = SqlBuilder.isBetween(3).and((Integer) null).filter(Objects::nonNull); + IsBetweenWhenPresent cond = SqlBuilder.isBetweenWhenPresent(3).and((Integer) null); assertThat(cond.isEmpty()).isTrue(); - IsBetween filtered = cond.filter(v -> true); + IsBetweenWhenPresent filtered = cond.filter(v -> true); assertThat(cond).isSameAs(filtered); } @@ -501,6 +496,46 @@ void testBetweenMapWithSingleMapper() { assertThat(cond.value2()).isEqualTo(4); } + @Test + void testBetweenWhenPresentFilterWithBiPredicate() { + IsBetweenWhenPresent cond = SqlBuilder.isBetweenWhenPresent("3").and("4") + .map(Integer::parseInt) + .filter((v1, v2) -> true); + assertThat(cond.isEmpty()).isFalse(); + assertThat(cond.value1()).isEqualTo(3); + assertThat(cond.value2()).isEqualTo(4); + } + + @Test + void testNotBetweenWhenPresentFilterWithBiPredicate() { + IsNotBetweenWhenPresent cond = SqlBuilder.isNotBetweenWhenPresent("3").and("4") + .map(Integer::parseInt) + .filter((v1, v2) -> true); + assertThat(cond.isEmpty()).isFalse(); + assertThat(cond.value1()).isEqualTo(3); + assertThat(cond.value2()).isEqualTo(4); + } + + @ParameterizedTest + @MethodSource("testBetweenFilterVariations") + void testBetweenFilterVariations(FilterVariation variation) { + IsBetween cond = SqlBuilder.isBetween("4").and("6") + .map(Integer::parseInt) + .filter(variation.predicate); + assertThat(cond.isEmpty()).isEqualTo(variation.empty); + } + + private record FilterVariation(Predicate predicate, boolean empty) {} + + private static Stream testBetweenFilterVariations() { + return Stream.of( + new FilterVariation(v -> v == 4, true), + new FilterVariation(v -> v == 6, true), + new FilterVariation(v -> v == 1, true), + new FilterVariation(v -> v % 2 == 0, false) + ); + } + @Test void testNotBetweenUnRenderableFilterShouldReturnSameObject() { IsNotBetween cond = SqlBuilder.isNotBetween(3).and(4).filter((i1, i2) -> false); @@ -511,17 +546,17 @@ void testNotBetweenUnRenderableFilterShouldReturnSameObject() { @Test void testNotBetweenUnRenderableFirstNullFilterShouldReturnSameObject() { - IsNotBetween cond = SqlBuilder.isNotBetween((Integer) null).and(4).filter(Objects::nonNull); + IsNotBetweenWhenPresent cond = SqlBuilder.isNotBetweenWhenPresent((Integer) null).and(4); assertThat(cond.isEmpty()).isTrue(); - IsNotBetween filtered = cond.filter(v -> true); + IsNotBetweenWhenPresent filtered = cond.filter(v -> true); assertThat(cond).isSameAs(filtered); } @Test void testNotBetweenUnRenderableSecondNullFilterShouldReturnSameObject() { - IsNotBetween cond = SqlBuilder.isNotBetween(3).and((Integer) null).filter(Objects::nonNull); + IsNotBetweenWhenPresent cond = SqlBuilder.isNotBetweenWhenPresent(3).and((Integer) null); assertThat(cond.isEmpty()).isTrue(); - IsNotBetween filtered = cond.filter(v -> true); + IsNotBetweenWhenPresent filtered = cond.filter(v -> true); assertThat(cond).isSameAs(filtered); } @@ -533,6 +568,24 @@ void testNotBetweenMapWithSingleMapper() { assertThat(cond.value2()).isEqualTo(4); } + @Test + void testBetweenFilterToEmpty() { + var cond = SqlBuilder.isBetween("3").and("4").map(Integer::parseInt) + .filter((i1, i2) -> false); + assertThat(cond.isEmpty()).isTrue(); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value1); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value2); + } + + @Test + void testNotBetweenFilterToEmpty() { + var cond = SqlBuilder.isNotBetween("3").and("4").map(Integer::parseInt) + .filter((i1, i2) -> false); + assertThat(cond.isEmpty()).isTrue(); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value1); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value2); + } + @Test void testMappingAnEmptyListCondition() { var cond = SqlBuilder.isNotIn("Fred", "Wilma"); diff --git a/src/test/java/org/mybatis/dynamic/sql/where/condition/NullContractTest.java b/src/test/java/org/mybatis/dynamic/sql/where/condition/NullContractTest.java new file mode 100644 index 000000000..cd55d9e52 --- /dev/null +++ b/src/test/java/org/mybatis/dynamic/sql/where/condition/NullContractTest.java @@ -0,0 +1,546 @@ +/* + * Copyright 2016-2025 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.where.condition; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; + +import java.util.NoSuchElementException; + +import org.junit.jupiter.api.Test; +import org.mybatis.dynamic.sql.SqlBuilder; + +/** + * This set of tests verifies that the library handles null values in conditions as expected. + * + *

In version 2.0, we adopted JSpecify which brought several issues to light. + * In general, the library does not support passing null values into methods unless the method + * is a "whenPresent" method. However, from the beginning the library has handled null values in conditions + * by placing a null into the generated parameter map. We consider this a misuse of the library, but we are + * keeping that behavior for compatibility. + * + *

In a future version, we will stop supporting this misuse. + * + *

This set of tests should be the only tests in the library that verify this behavior. All other tests + * should use the library properly. + */ +class NullContractTest { + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsBetween() { + IsBetween nullCond = SqlBuilder.isBetween((Integer) null).and((Integer) null); + assertThat(nullCond.isEmpty()).isFalse(); + + IsBetween cond = SqlBuilder.isBetween(1).and(10); + IsBetween filtered = cond.filter(i -> i >= 1); + IsBetween mapped = filtered.map(i -> null); + assertThat(mapped.isEmpty()).isFalse(); + + mapped = filtered.map(v1 -> null, v2 -> null); + assertThat(mapped.isEmpty()).isFalse(); + assertThat(mapped.value1()).isNull(); + assertThat(mapped.value2()).isNull(); + } + + @Test + void testIsBetweenWhenPresent() { + IsBetweenWhenPresent nullCond = SqlBuilder.isBetweenWhenPresent((Integer) null).and((Integer) null); + assertThat(nullCond.isEmpty()).isTrue(); + + IsBetweenWhenPresent cond = SqlBuilder.isBetweenWhenPresent(1).and(10); + IsBetweenWhenPresent filtered = cond.filter(i -> i == 1); + IsBetweenWhenPresent mapped = filtered.map(i -> null); + assertThat(mapped.isEmpty()).isTrue(); + + mapped = filtered.map(v1 -> null, v2 -> null); + assertThat(mapped.isEmpty()).isTrue(); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(mapped::value1); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(mapped::value2); + } + + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsEqualTo() { + IsEqualTo nullCond = SqlBuilder.isEqualTo((Integer) null); // should be an IDE warning + assertThat(nullCond.isEmpty()).isFalse(); + + IsEqualTo cond = SqlBuilder.isEqualTo(1); + IsEqualTo filtered = cond.filter(i -> i == 1); + IsEqualTo mapped = filtered.map(i -> null); // should be an IDE warning + assertThat(mapped.isEmpty()).isFalse(); + assertThat(mapped.value()).isNull(); + } + + @Test + void testIsEqualToWhenPresent() { + IsEqualToWhenPresent nullCond = SqlBuilder.isEqualToWhenPresent((Integer) null); + assertThat(nullCond.isEmpty()).isTrue(); + + IsEqualToWhenPresent cond = SqlBuilder.isEqualToWhenPresent(1); + IsEqualToWhenPresent filtered = cond.filter(i -> i == 1); + IsEqualToWhenPresent mapped = filtered.map(i -> null); + assertThat(mapped.isEmpty()).isTrue(); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(mapped::value); + } + + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsGreaterThan() { + IsGreaterThan nullCond = SqlBuilder.isGreaterThan((Integer) null); // should be an IDE warning + assertThat(nullCond.isEmpty()).isFalse(); + + IsGreaterThan cond = SqlBuilder.isGreaterThan(1); + IsGreaterThan filtered = cond.filter(i -> i == 1); + IsGreaterThan mapped = filtered.map(i -> null); // should be an IDE warning + assertThat(mapped.isEmpty()).isFalse(); + assertThat(mapped.value()).isNull(); + } + + @Test + void testIsGreaterThanWhenPresent() { + IsGreaterThanWhenPresent nullCond = SqlBuilder.isGreaterThanWhenPresent((Integer) null); + assertThat(nullCond.isEmpty()).isTrue(); + + IsGreaterThanWhenPresent cond = SqlBuilder.isGreaterThanWhenPresent(1); + IsGreaterThanWhenPresent filtered = cond.filter(i -> i == 1); + IsGreaterThanWhenPresent mapped = filtered.map(i -> null); + assertThat(mapped.isEmpty()).isTrue(); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(mapped::value); + } + + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsGreaterThanOrEqualTo() { + IsGreaterThanOrEqualTo nullCond = SqlBuilder.isGreaterThanOrEqualTo((Integer) null); // should be an IDE warning + assertThat(nullCond.isEmpty()).isFalse(); + + IsGreaterThanOrEqualTo cond = SqlBuilder.isGreaterThanOrEqualTo(1); + IsGreaterThanOrEqualTo filtered = cond.filter(i -> i == 1); + IsGreaterThanOrEqualTo mapped = filtered.map(i -> null); // should be an IDE warning + assertThat(mapped.isEmpty()).isFalse(); + assertThat(mapped.value()).isNull(); + } + + @Test + void testIsGreaterThanOrEqualToWhenPresent() { + IsGreaterThanOrEqualToWhenPresent nullCond = SqlBuilder.isGreaterThanOrEqualToWhenPresent((Integer) null); + assertThat(nullCond.isEmpty()).isTrue(); + + IsGreaterThanOrEqualToWhenPresent cond = SqlBuilder.isGreaterThanOrEqualToWhenPresent(1); + IsGreaterThanOrEqualToWhenPresent filtered = cond.filter(i -> i == 1); + IsGreaterThanOrEqualToWhenPresent mapped = filtered.map(i -> null); + assertThat(mapped.isEmpty()).isTrue(); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(mapped::value); + } + + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsLessThan() { + IsLessThan nullCond = SqlBuilder.isLessThan((Integer) null); // should be an IDE warning + assertThat(nullCond.isEmpty()).isFalse(); + + IsLessThan cond = SqlBuilder.isLessThan(1); + IsLessThan filtered = cond.filter(i -> i == 1); + IsLessThan mapped = filtered.map(i -> null); // should be an IDE warning + assertThat(mapped.isEmpty()).isFalse(); + assertThat(mapped.value()).isNull(); + } + + @Test + void testIsLessThanWhenPresent() { + IsLessThanWhenPresent nullCond = SqlBuilder.isLessThanWhenPresent((Integer) null); + assertThat(nullCond.isEmpty()).isTrue(); + + IsLessThanWhenPresent cond = SqlBuilder.isLessThanWhenPresent(1); + IsLessThanWhenPresent filtered = cond.filter(i -> i == 1); + IsLessThanWhenPresent mapped = filtered.map(i -> null); + assertThat(mapped.isEmpty()).isTrue(); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(mapped::value); + } + + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsLessThanOrEqualTo() { + IsLessThanOrEqualTo nullCond = SqlBuilder.isLessThanOrEqualTo((Integer) null); // should be an IDE warning + assertThat(nullCond.isEmpty()).isFalse(); + + IsLessThanOrEqualTo cond = SqlBuilder.isLessThanOrEqualTo(1); + IsLessThanOrEqualTo filtered = cond.filter(i -> i == 1); + IsLessThanOrEqualTo mapped = filtered.map(i -> null); // should be an IDE warning + assertThat(mapped.isEmpty()).isFalse(); + assertThat(mapped.value()).isNull(); + } + + @Test + void testIsLessThanOrEqualToWhenPresent() { + IsLessThanOrEqualToWhenPresent nullCond = SqlBuilder.isLessThanOrEqualToWhenPresent((Integer) null); + assertThat(nullCond.isEmpty()).isTrue(); + + IsLessThanOrEqualToWhenPresent cond = SqlBuilder.isLessThanOrEqualToWhenPresent(1); + IsLessThanOrEqualToWhenPresent filtered = cond.filter(i -> i == 1); + IsLessThanOrEqualToWhenPresent mapped = filtered.map(i -> null); + assertThat(mapped.isEmpty()).isTrue(); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(mapped::value); + } + + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsNotBetween() { + IsNotBetween nullCond = SqlBuilder.isNotBetween((Integer) null).and((Integer) null); + assertThat(nullCond.isEmpty()).isFalse(); + + IsNotBetween cond = SqlBuilder.isNotBetween(1).and(10); + IsNotBetween filtered = cond.filter(i -> i >= 1); + IsNotBetween mapped = filtered.map(i -> null); + assertThat(mapped.isEmpty()).isFalse(); + + mapped = filtered.map(v1 -> null, v2 -> null); + assertThat(mapped.isEmpty()).isFalse(); + assertThat(mapped.value1()).isNull(); + assertThat(mapped.value2()).isNull(); + } + + @Test + void testIsNotBetweenWhenPresent() { + IsNotBetweenWhenPresent nullCond = SqlBuilder.isNotBetweenWhenPresent((Integer) null).and((Integer) null); + assertThat(nullCond.isEmpty()).isTrue(); + + IsNotBetweenWhenPresent cond = SqlBuilder.isNotBetweenWhenPresent(1).and(10); + IsNotBetweenWhenPresent filtered = cond.filter(i -> i == 1); + IsNotBetweenWhenPresent mapped = filtered.map(i -> null); + assertThat(mapped.isEmpty()).isTrue(); + + mapped = filtered.map(v1 -> null, v2 -> null); + assertThat(mapped.isEmpty()).isTrue(); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(mapped::value1); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(mapped::value2); + } + + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsNotEqualTo() { + IsNotEqualTo nullCond = SqlBuilder.isNotEqualTo((Integer) null); // should be an IDE warning + assertThat(nullCond.isEmpty()).isFalse(); + + IsNotEqualTo cond = SqlBuilder.isNotEqualTo(1); + IsNotEqualTo filtered = cond.filter(i -> i == 1); + IsNotEqualTo mapped = filtered.map(i -> null); // should be an IDE warning + assertThat(mapped.isEmpty()).isFalse(); + assertThat(mapped.value()).isNull(); + } + + @Test + void testIsNotEqualToWhenPresent() { + IsNotEqualToWhenPresent nullCond = SqlBuilder.isNotEqualToWhenPresent((Integer) null); + assertThat(nullCond.isEmpty()).isTrue(); + + IsNotEqualToWhenPresent cond = SqlBuilder.isNotEqualToWhenPresent(1); + IsNotEqualToWhenPresent filtered = cond.filter(i -> i == 1); + IsNotEqualToWhenPresent mapped = filtered.map(i -> null); + assertThat(mapped.isEmpty()).isTrue(); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(mapped::value); + } + + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsLike() { + IsLike nullCond = SqlBuilder.isLike((String) null); // should be an IDE warning + assertThat(nullCond.isEmpty()).isFalse(); + + IsLike cond = SqlBuilder.isLike("fred"); + IsLike filtered = cond.filter(i -> i.equals("fred")); + IsLike mapped = filtered.map(i -> null); // should be an IDE warning + assertThat(mapped.isEmpty()).isFalse(); + assertThat(mapped.value()).isNull(); + } + + @Test + void testIsLikeWhenPresent() { + IsLikeWhenPresent nullCond = SqlBuilder.isLikeWhenPresent((String) null); + assertThat(nullCond.isEmpty()).isTrue(); + + IsLikeWhenPresent cond = SqlBuilder.isLikeWhenPresent("fred"); + IsLikeWhenPresent filtered = cond.filter(i -> i.equals("fred")); + IsLikeWhenPresent mapped = filtered.map(i -> null); + assertThat(mapped.isEmpty()).isTrue(); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(mapped::value); + } + + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsLikeCaseInsensitive() { + IsLikeCaseInsensitive nullCond = SqlBuilder.isLikeCaseInsensitive((String) null); // should be an IDE warning + assertThat(nullCond.isEmpty()).isFalse(); + + IsLikeCaseInsensitive cond = SqlBuilder.isLikeCaseInsensitive("fred"); + IsLikeCaseInsensitive filtered = cond.filter(i -> i.equals("FRED")); + IsLikeCaseInsensitive mapped = filtered.map(i -> null); // should be an IDE warning + assertThat(mapped.isEmpty()).isFalse(); + assertThat(mapped.value()).isNull(); + } + + @Test + void testIsLikeCaseInsensitiveWhenPresent() { + IsLikeCaseInsensitiveWhenPresent nullCond = SqlBuilder.isLikeCaseInsensitiveWhenPresent((String) null); + assertThat(nullCond.isEmpty()).isTrue(); + + IsLikeCaseInsensitiveWhenPresent cond = SqlBuilder.isLikeCaseInsensitiveWhenPresent("fred"); + IsLikeCaseInsensitiveWhenPresent filtered = cond.filter(i -> i.equals("fred")); + IsLikeCaseInsensitiveWhenPresent mapped = filtered.map(i -> null); + assertThat(mapped.isEmpty()).isTrue(); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(mapped::value); + } + + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsNotLike() { + IsNotLike nullCond = SqlBuilder.isNotLike((String) null); // should be an IDE warning + assertThat(nullCond.isEmpty()).isFalse(); + + IsNotLike cond = SqlBuilder.isNotLike("fred"); + IsNotLike filtered = cond.filter(i -> i.equals("fred")); + IsNotLike mapped = filtered.map(i -> null); // should be an IDE warning + assertThat(mapped.isEmpty()).isFalse(); + assertThat(mapped.value()).isNull(); + } + + @Test + void testIsNotLikeWhenPresent() { + IsNotLikeWhenPresent nullCond = SqlBuilder.isNotLikeWhenPresent((String) null); + assertThat(nullCond.isEmpty()).isTrue(); + + IsNotLikeWhenPresent cond = SqlBuilder.isNotLikeWhenPresent("fred"); + IsNotLikeWhenPresent filtered = cond.filter(i -> i.equals("fred")); + IsNotLikeWhenPresent mapped = filtered.map(i -> null); + assertThat(mapped.isEmpty()).isTrue(); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(mapped::value); + } + + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsNotLikeCaseInsensitive() { + IsNotLikeCaseInsensitive nullCond = SqlBuilder.isNotLikeCaseInsensitive((String) null); // should be an IDE warning + assertThat(nullCond.isEmpty()).isFalse(); + + IsNotLikeCaseInsensitive cond = SqlBuilder.isNotLikeCaseInsensitive("fred"); + IsNotLikeCaseInsensitive filtered = cond.filter(i -> i.equals("FRED")); + IsNotLikeCaseInsensitive mapped = filtered.map(i -> null); // should be an IDE warning + assertThat(mapped.isEmpty()).isFalse(); + assertThat(mapped.value()).isNull(); + } + + @Test + void testIsNotLikeCaseInsensitiveWhenPresent() { + IsNotLikeCaseInsensitiveWhenPresent nullCond = SqlBuilder.isNotLikeCaseInsensitiveWhenPresent((String) null); + assertThat(nullCond.isEmpty()).isTrue(); + + IsNotLikeCaseInsensitiveWhenPresent cond = SqlBuilder.isNotLikeCaseInsensitiveWhenPresent("fred"); + IsNotLikeCaseInsensitiveWhenPresent filtered = cond.filter(i -> i.equals("FRED")); + IsNotLikeCaseInsensitiveWhenPresent mapped = filtered.map(i -> null); + assertThat(mapped.isEmpty()).isTrue(); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(mapped::value); + } + + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsIn() { + IsIn nullCond = SqlBuilder.isIn((Integer) null); // should be an IDE warning + assertThat(nullCond.isEmpty()).isFalse(); + + IsIn cond = SqlBuilder.isIn(1); + IsIn filtered = cond.filter(i -> i == 1); + IsIn mapped = filtered.map(i -> null); // should be an IDE warning + assertThat(mapped.isEmpty()).isFalse(); + assertThat(mapped.values().toList()).containsExactly((Integer) null); + } + + @Test + void testIsInWhenPresent() { + IsInWhenPresent nullCond = SqlBuilder.isInWhenPresent((Integer) null); + assertThat(nullCond.isEmpty()).isTrue(); + + IsInWhenPresent cond = SqlBuilder.isInWhenPresent(1); + IsInWhenPresent filtered = cond.filter(i -> i == 1); + IsInWhenPresent mapped = filtered.map(i -> null); + assertThat(mapped.isEmpty()).isTrue(); + assertThat(mapped.values().toList()).isEmpty(); + } + + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsInCaseInsensitive() { + IsInCaseInsensitive nullCond = SqlBuilder.isInCaseInsensitive((String) null); // should be an IDE warning + assertThat(nullCond.isEmpty()).isFalse(); + + IsInCaseInsensitive cond = SqlBuilder.isInCaseInsensitive("fred"); + IsInCaseInsensitive filtered = cond.filter(i -> i.equals("FRED")); + IsInCaseInsensitive mapped = filtered.map(i -> null); // should be an IDE warning + assertThat(mapped.isEmpty()).isFalse(); + assertThat(mapped.values().toList()).containsExactly((String) null); + } + + @Test + void testIsInCaseInsensitiveWhenPresent() { + IsInCaseInsensitiveWhenPresent nullCond = SqlBuilder.isInCaseInsensitiveWhenPresent((String) null); + assertThat(nullCond.isEmpty()).isTrue(); + + IsInCaseInsensitiveWhenPresent cond = SqlBuilder.isInCaseInsensitiveWhenPresent("fred"); + IsInCaseInsensitiveWhenPresent filtered = cond.filter(i -> i.equals("FRED")); + IsInCaseInsensitiveWhenPresent mapped = filtered.map(i -> null); + assertThat(mapped.isEmpty()).isTrue(); + assertThat(mapped.values().toList()).isEmpty(); + } + + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsNotIn() { + IsNotIn nullCond = SqlBuilder.isNotIn((Integer) null); // should be an IDE warning + assertThat(nullCond.isEmpty()).isFalse(); + + IsNotIn cond = SqlBuilder.isNotIn(1); + IsNotIn filtered = cond.filter(i -> i == 1); + IsNotIn mapped = filtered.map(i -> null); // should be an IDE warning + assertThat(mapped.isEmpty()).isFalse(); + assertThat(mapped.values().toList()).containsExactly((Integer) null); + } + + @Test + void testIsNotInWhenPresent() { + IsNotInWhenPresent nullCond = SqlBuilder.isNotInWhenPresent((Integer) null); + assertThat(nullCond.isEmpty()).isTrue(); + + IsNotInWhenPresent cond = SqlBuilder.isNotInWhenPresent(1); + IsNotInWhenPresent filtered = cond.filter(i -> i == 1); + IsNotInWhenPresent mapped = filtered.map(i -> null); + assertThat(mapped.isEmpty()).isTrue(); + assertThat(mapped.values().toList()).isEmpty(); + } + + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsNotInCaseInsensitive() { + IsNotInCaseInsensitive nullCond = SqlBuilder.isNotInCaseInsensitive((String) null); // should be an IDE warning + assertThat(nullCond.isEmpty()).isFalse(); + + IsNotInCaseInsensitive cond = SqlBuilder.isNotInCaseInsensitive("fred"); + IsNotInCaseInsensitive filtered = cond.filter(i -> i.equals("FRED")); + IsNotInCaseInsensitive mapped = filtered.map(i -> null); // should be an IDE warning + assertThat(mapped.isEmpty()).isFalse(); + assertThat(mapped.values().toList()).containsExactly((String) null); + } + + @Test + void testIsNotInCaseInsensitiveWhenPresent() { + IsNotInCaseInsensitiveWhenPresent nullCond = SqlBuilder.isNotInCaseInsensitiveWhenPresent((String) null); + assertThat(nullCond.isEmpty()).isTrue(); + + IsNotInCaseInsensitiveWhenPresent cond = SqlBuilder.isNotInCaseInsensitiveWhenPresent("fred"); + IsNotInCaseInsensitiveWhenPresent filtered = cond.filter(i -> i.equals("FRED")); + IsNotInCaseInsensitiveWhenPresent mapped = filtered.map(i -> null); + assertThat(mapped.isEmpty()).isTrue(); + assertThat(mapped.values().toList()).isEmpty(); + } + + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsBetweenNull() { + IsBetween cond = SqlBuilder.isBetween(() -> (Integer) null).and(() -> null); + assertThat(cond.value1()).isNull(); + assertThat(cond.value2()).isNull(); + assertThat(cond.isEmpty()).isFalse(); + } + + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsNotBetweenNull() { + IsNotBetween cond = SqlBuilder.isNotBetween(() -> (Integer) null).and(() -> null); + assertThat(cond.value1()).isNull(); + assertThat(cond.value2()).isNull(); + assertThat(cond.isEmpty()).isFalse(); + } + + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsNotEqualToNull() { + IsNotEqualTo cond = SqlBuilder.isNotEqualTo(() -> (Integer) null); + assertThat(cond.value()).isNull(); + assertThat(cond.isEmpty()).isFalse(); + } + + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsGreaterThanNull() { + IsGreaterThan cond = SqlBuilder.isGreaterThan(() -> (Integer) null); + assertThat(cond.value()).isNull(); + assertThat(cond.isEmpty()).isFalse(); + } + + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsGreaterThanOrEqualToNull() { + IsGreaterThanOrEqualTo cond = SqlBuilder.isGreaterThanOrEqualTo(() -> (Integer) null); + assertThat(cond.value()).isNull(); + assertThat(cond.isEmpty()).isFalse(); + } + + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsLessThanNull() { + IsLessThan cond = SqlBuilder.isLessThan(() -> (Integer) null); + assertThat(cond.value()).isNull(); + assertThat(cond.isEmpty()).isFalse(); + } + + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsLessThanOrEqualToNull() { + IsLessThanOrEqualTo cond = SqlBuilder.isLessThanOrEqualTo(() -> (Integer) null); + assertThat(cond.value()).isNull(); + assertThat(cond.isEmpty()).isFalse(); + } + + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsLikeNull() { + IsLike cond = SqlBuilder.isLike(() -> null); + assertThat(cond.value()).isNull(); + assertThat(cond.isEmpty()).isFalse(); + } + + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsLikeCaseInsensitiveNull() { + IsLikeCaseInsensitive cond = SqlBuilder.isLikeCaseInsensitive(() -> null); + assertThat(cond.value()).isNull(); + assertThat(cond.isEmpty()).isFalse(); + } + + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsNotLikeNull() { + IsNotLike cond = SqlBuilder.isNotLike(() -> null); + assertThat(cond.value()).isNull(); + assertThat(cond.isEmpty()).isFalse(); + } + + @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing + @Test + void testIsNotLikeCaseInsensitiveNull() { + IsNotLikeCaseInsensitive cond = SqlBuilder.isNotLikeCaseInsensitive(() -> null); + assertThat(cond.value()).isNull(); + assertThat(cond.isEmpty()).isFalse(); + } +} diff --git a/src/test/java/org/mybatis/dynamic/sql/where/condition/SupplierTest.java b/src/test/java/org/mybatis/dynamic/sql/where/condition/SupplierTest.java index b85a7f412..113c60321 100644 --- a/src/test/java/org/mybatis/dynamic/sql/where/condition/SupplierTest.java +++ b/src/test/java/org/mybatis/dynamic/sql/where/condition/SupplierTest.java @@ -34,17 +34,9 @@ void testIsBetween() { assertThat(cond.isEmpty()).isFalse(); } - @Test - void testIsBetweenNull() { - IsBetween cond = SqlBuilder.isBetween(() -> (Integer) null).and(() -> null); - assertThat(cond.value1()).isNull(); - assertThat(cond.value2()).isNull(); - assertThat(cond.isEmpty()).isFalse(); - } - @Test void testIsBetweenWhenPresent() { - IsBetween cond = SqlBuilder.isBetweenWhenPresent(() -> 3).and(() -> 4); + IsBetweenWhenPresent cond = SqlBuilder.isBetweenWhenPresent(() -> 3).and(() -> 4); assertThat(cond.value1()).isEqualTo(3); assertThat(cond.value2()).isEqualTo(4); assertThat(cond.isEmpty()).isFalse(); @@ -52,7 +44,7 @@ void testIsBetweenWhenPresent() { @Test void testIsBetweenWhenPresentNull() { - IsBetween cond = SqlBuilder.isBetweenWhenPresent(() -> (Integer) null).and(() -> null); + IsBetweenWhenPresent cond = SqlBuilder.isBetweenWhenPresent(() -> (Integer) null).and(() -> null); assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value1); assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value2); assertThat(cond.isEmpty()).isTrue(); @@ -66,17 +58,9 @@ void testIsNotBetween() { assertThat(cond.isEmpty()).isFalse(); } - @Test - void testIsNotBetweenNull() { - IsNotBetween cond = SqlBuilder.isNotBetween(() -> (Integer) null).and(() -> null); - assertThat(cond.value1()).isNull(); - assertThat(cond.value2()).isNull(); - assertThat(cond.isEmpty()).isFalse(); - } - @Test void testIsNotBetweenWhenPresent() { - IsNotBetween cond = SqlBuilder.isNotBetweenWhenPresent(() -> 3).and(() -> 4); + IsNotBetweenWhenPresent cond = SqlBuilder.isNotBetweenWhenPresent(() -> 3).and(() -> 4); assertThat(cond.value1()).isEqualTo(3); assertThat(cond.value2()).isEqualTo(4); assertThat(cond.isEmpty()).isFalse(); @@ -84,7 +68,7 @@ void testIsNotBetweenWhenPresent() { @Test void testIsNotBetweenWhenPresentNull() { - IsNotBetween cond = SqlBuilder.isNotBetweenWhenPresent(() -> (Integer) null).and(() -> null); + IsNotBetweenWhenPresent cond = SqlBuilder.isNotBetweenWhenPresent(() -> (Integer) null).and(() -> null); assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value1); assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value2); assertThat(cond.isEmpty()).isTrue(); @@ -92,14 +76,14 @@ void testIsNotBetweenWhenPresentNull() { @Test void testIsEqualToWhenPresent() { - IsEqualTo cond = SqlBuilder.isEqualToWhenPresent(() -> 3); + IsEqualToWhenPresent cond = SqlBuilder.isEqualToWhenPresent(() -> 3); assertThat(cond.value()).isEqualTo(3); assertThat(cond.isEmpty()).isFalse(); } @Test void testIsEqualToWhenPresentNull() { - IsEqualTo cond = SqlBuilder.isEqualToWhenPresent(() -> null); + IsEqualToWhenPresent cond = SqlBuilder.isEqualToWhenPresent(() -> null); assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value); assertThat(cond.isEmpty()).isTrue(); } @@ -111,23 +95,16 @@ void testIsNotEqualTo() { assertThat(cond.isEmpty()).isFalse(); } - @Test - void testIsNotEqualToNull() { - IsNotEqualTo cond = SqlBuilder.isNotEqualTo(() -> (Integer) null); - assertThat(cond.value()).isNull(); - assertThat(cond.isEmpty()).isFalse(); - } - @Test void testIsNotEqualToWhenPresent() { - IsNotEqualTo cond = SqlBuilder.isNotEqualToWhenPresent(() -> 3); + IsNotEqualToWhenPresent cond = SqlBuilder.isNotEqualToWhenPresent(() -> 3); assertThat(cond.value()).isEqualTo(3); assertThat(cond.isEmpty()).isFalse(); } @Test void testIsNotEqualToWhenPresentNull() { - IsNotEqualTo cond = SqlBuilder.isNotEqualToWhenPresent(() -> null); + IsNotEqualToWhenPresent cond = SqlBuilder.isNotEqualToWhenPresent(() -> null); assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value); assertThat(cond.isEmpty()).isTrue(); } @@ -139,23 +116,16 @@ void testIsGreaterThan() { assertThat(cond.isEmpty()).isFalse(); } - @Test - void testIsGreaterThanNull() { - IsGreaterThan cond = SqlBuilder.isGreaterThan(() -> (Integer) null); - assertThat(cond.value()).isNull(); - assertThat(cond.isEmpty()).isFalse(); - } - @Test void testIsGreaterThanWhenPresent() { - IsGreaterThan cond = SqlBuilder.isGreaterThanWhenPresent(() -> 3); + IsGreaterThanWhenPresent cond = SqlBuilder.isGreaterThanWhenPresent(() -> 3); assertThat(cond.value()).isEqualTo(3); assertThat(cond.isEmpty()).isFalse(); } @Test void testIsGreaterThanWhenPresentNull() { - IsGreaterThan cond = SqlBuilder.isGreaterThanWhenPresent(() -> null); + IsGreaterThanWhenPresent cond = SqlBuilder.isGreaterThanWhenPresent(() -> null); assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value); assertThat(cond.isEmpty()).isTrue(); } @@ -167,23 +137,16 @@ void testIsGreaterThanOrEqualTo() { assertThat(cond.isEmpty()).isFalse(); } - @Test - void testIsGreaterThanOrEqualToNull() { - IsGreaterThanOrEqualTo cond = SqlBuilder.isGreaterThanOrEqualTo(() -> (Integer) null); - assertThat(cond.value()).isNull(); - assertThat(cond.isEmpty()).isFalse(); - } - @Test void testIsGreaterThanOrEqualToWhenPresent() { - IsGreaterThanOrEqualTo cond = SqlBuilder.isGreaterThanOrEqualToWhenPresent(() -> 3); + IsGreaterThanOrEqualToWhenPresent cond = SqlBuilder.isGreaterThanOrEqualToWhenPresent(() -> 3); assertThat(cond.value()).isEqualTo(3); assertThat(cond.isEmpty()).isFalse(); } @Test void testIsGreaterThanOrEqualToWhenPresentNull() { - IsGreaterThanOrEqualTo cond = SqlBuilder.isGreaterThanOrEqualToWhenPresent(() -> null); + IsGreaterThanOrEqualToWhenPresent cond = SqlBuilder.isGreaterThanOrEqualToWhenPresent(() -> null); assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value); assertThat(cond.isEmpty()).isTrue(); } @@ -195,23 +158,16 @@ void testIsLessThan() { assertThat(cond.isEmpty()).isFalse(); } - @Test - void testIsLessThanNull() { - IsLessThan cond = SqlBuilder.isLessThan(() -> (Integer) null); - assertThat(cond.value()).isNull(); - assertThat(cond.isEmpty()).isFalse(); - } - @Test void testIsLessThanWhenPresent() { - IsLessThan cond = SqlBuilder.isLessThanWhenPresent(() -> 3); + IsLessThanWhenPresent cond = SqlBuilder.isLessThanWhenPresent(() -> 3); assertThat(cond.value()).isEqualTo(3); assertThat(cond.isEmpty()).isFalse(); } @Test void testIsLessThanWhenPresentNull() { - IsLessThan cond = SqlBuilder.isLessThanWhenPresent(() -> null); + IsLessThanWhenPresent cond = SqlBuilder.isLessThanWhenPresent(() -> null); assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value); assertThat(cond.isEmpty()).isTrue(); } @@ -223,23 +179,16 @@ void testIsLessThanOrEqualTo() { assertThat(cond.isEmpty()).isFalse(); } - @Test - void testIsLessThanOrEqualToNull() { - IsLessThanOrEqualTo cond = SqlBuilder.isLessThanOrEqualTo(() -> (Integer) null); - assertThat(cond.value()).isNull(); - assertThat(cond.isEmpty()).isFalse(); - } - @Test void testIsLessThanOrEqualToWhenPresent() { - IsLessThanOrEqualTo cond = SqlBuilder.isLessThanOrEqualToWhenPresent(() -> 3); + IsLessThanOrEqualToWhenPresent cond = SqlBuilder.isLessThanOrEqualToWhenPresent(() -> 3); assertThat(cond.value()).isEqualTo(3); assertThat(cond.isEmpty()).isFalse(); } @Test void testIsLessThanOrEqualToWhenPresentNull() { - IsLessThanOrEqualTo cond = SqlBuilder.isLessThanOrEqualToWhenPresent(() -> null); + IsLessThanOrEqualToWhenPresent cond = SqlBuilder.isLessThanOrEqualToWhenPresent(() -> null); assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value); assertThat(cond.isEmpty()).isTrue(); } @@ -251,13 +200,6 @@ void testIsLike() { assertThat(cond.isEmpty()).isFalse(); } - @Test - void testIsLikeNull() { - IsLike cond = SqlBuilder.isLike(() -> null); - assertThat(cond.value()).isNull(); - assertThat(cond.isEmpty()).isFalse(); - } - @Test void testIsLikeCaseInsensitive() { IsLikeCaseInsensitive cond = SqlBuilder.isLikeCaseInsensitive(() -> "%f%"); @@ -265,37 +207,30 @@ void testIsLikeCaseInsensitive() { assertThat(cond.isEmpty()).isFalse(); } - @Test - void testIsLikeCaseInsensitiveNull() { - IsLikeCaseInsensitive cond = SqlBuilder.isLikeCaseInsensitive(() -> null); - assertThat(cond.value()).isNull(); - assertThat(cond.isEmpty()).isFalse(); - } - @Test void testIsLikeCaseInsensitiveWhenPresent() { - IsLikeCaseInsensitive cond = SqlBuilder.isLikeCaseInsensitiveWhenPresent(() -> "%f%"); + IsLikeCaseInsensitiveWhenPresent cond = SqlBuilder.isLikeCaseInsensitiveWhenPresent(() -> "%f%"); assertThat(cond.value()).isEqualTo("%F%"); assertThat(cond.isEmpty()).isFalse(); } @Test void testIsLikeCaseInsensitiveWhenPresentNull() { - IsLikeCaseInsensitive cond = SqlBuilder.isLikeCaseInsensitiveWhenPresent(() -> null); + IsLikeCaseInsensitiveWhenPresent cond = SqlBuilder.isLikeCaseInsensitiveWhenPresent(() -> null); assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value); assertThat(cond.isEmpty()).isTrue(); } @Test void testIsLikeWhenPresent() { - IsLike cond = SqlBuilder.isLikeWhenPresent(() -> "%F%"); + IsLikeWhenPresent cond = SqlBuilder.isLikeWhenPresent(() -> "%F%"); assertThat(cond.value()).isEqualTo("%F%"); assertThat(cond.isEmpty()).isFalse(); } @Test void testIsLikeWhenPresentNull() { - IsLike cond = SqlBuilder.isLikeWhenPresent(() -> null); + IsLikeWhenPresent cond = SqlBuilder.isLikeWhenPresent(() -> null); assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value); assertThat(cond.isEmpty()).isTrue(); } @@ -307,23 +242,16 @@ void testIsNotLike() { assertThat(cond.isEmpty()).isFalse(); } - @Test - void testIsNotLikeNull() { - IsNotLike cond = SqlBuilder.isNotLike(() -> null); - assertThat(cond.value()).isNull(); - assertThat(cond.isEmpty()).isFalse(); - } - @Test void testIsNotLikeWhenPresent() { - IsNotLike cond = SqlBuilder.isNotLikeWhenPresent(() -> "%F%"); + IsNotLikeWhenPresent cond = SqlBuilder.isNotLikeWhenPresent(() -> "%F%"); assertThat(cond.value()).isEqualTo("%F%"); assertThat(cond.isEmpty()).isFalse(); } @Test void testIsNotLikeWhenPresentNull() { - IsNotLike cond = SqlBuilder.isNotLikeWhenPresent(() -> null); + IsNotLikeWhenPresent cond = SqlBuilder.isNotLikeWhenPresent(() -> null); assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value); assertThat(cond.isEmpty()).isTrue(); } @@ -335,23 +263,16 @@ void testIsNotLikeCaseInsensitive() { assertThat(cond.isEmpty()).isFalse(); } - @Test - void testIsNotLikeCaseInsensitiveNull() { - IsNotLikeCaseInsensitive cond = SqlBuilder.isNotLikeCaseInsensitive(() -> null); - assertThat(cond.value()).isNull(); - assertThat(cond.isEmpty()).isFalse(); - } - @Test void testIsNotLikeCaseInsensitiveWhenPresent() { - IsNotLikeCaseInsensitive cond = SqlBuilder.isNotLikeCaseInsensitiveWhenPresent(() -> "%f%"); + IsNotLikeCaseInsensitiveWhenPresent cond = SqlBuilder.isNotLikeCaseInsensitiveWhenPresent(() -> "%f%"); assertThat(cond.value()).isEqualTo("%F%"); assertThat(cond.isEmpty()).isFalse(); } @Test void testIsNotLikeCaseInsensitiveWhenPresentNull() { - IsNotLikeCaseInsensitive cond = SqlBuilder.isNotLikeCaseInsensitiveWhenPresent(() -> null); + IsNotLikeCaseInsensitiveWhenPresent cond = SqlBuilder.isNotLikeCaseInsensitiveWhenPresent(() -> null); assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value); assertThat(cond.isEmpty()).isTrue(); } diff --git a/src/test/java/org/mybatis/dynamic/sql/where/render/OptionalCriterionRenderTest.java b/src/test/java/org/mybatis/dynamic/sql/where/render/OptionalCriterionRenderTest.java index 1e6e56a92..48bd36755 100644 --- a/src/test/java/org/mybatis/dynamic/sql/where/render/OptionalCriterionRenderTest.java +++ b/src/test/java/org/mybatis/dynamic/sql/where/render/OptionalCriterionRenderTest.java @@ -19,7 +19,6 @@ import static org.assertj.core.api.Assertions.entry; import static org.mybatis.dynamic.sql.SqlBuilder.*; -import java.util.Objects; import java.util.Optional; import org.junit.jupiter.api.Test; @@ -35,21 +34,7 @@ class OptionalCriterionRenderTest { @Test void testNoRenderableCriteria() { - Integer nullId = null; - - Optional whereClause = where(id, isEqualToWhenPresent(nullId)) - .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) - .build() - .render(RenderingStrategies.SPRING_NAMED_PARAMETER); - - assertThat(whereClause).isEmpty(); - } - - @Test - void testNoRenderableCriteriaWithIf() { - Integer nullId = null; - - Optional whereClause = where(id, isEqualTo(nullId).filter(Objects::nonNull)) + Optional whereClause = where(id, isEqualToWhenPresent((Integer) null)) .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) .build() .render(RenderingStrategies.SPRING_NAMED_PARAMETER); @@ -103,10 +88,8 @@ void testEnabledIsNotNull() { @Test void testOneRenderableCriteriaBeforeNull() { - String nullFirstName = null; - Optional whereClause = where(id, isEqualToWhenPresent(22)) - .and(firstName, isEqualToWhenPresent(nullFirstName)) + .and(firstName, isEqualToWhenPresent((String) null)) .build() .render(RenderingStrategies.SPRING_NAMED_PARAMETER); @@ -118,9 +101,7 @@ void testOneRenderableCriteriaBeforeNull() { @Test void testOneRenderableCriteriaBeforeNull2() { - String nullFirstName = null; - - Optional whereClause = where(id, isEqualToWhenPresent(22), and(firstName, isEqualToWhenPresent(nullFirstName))) + Optional whereClause = where(id, isEqualToWhenPresent(22), and(firstName, isEqualToWhenPresent((String) null))) .build() .render(RenderingStrategies.SPRING_NAMED_PARAMETER); @@ -132,9 +113,7 @@ void testOneRenderableCriteriaBeforeNull2() { @Test void testOneRenderableCriteriaAfterNull() { - Integer nullId = null; - - Optional whereClause = where(id, isEqualToWhenPresent(nullId)) + Optional whereClause = where(id, isEqualToWhenPresent((Integer) null)) .and(firstName, isEqualToWhenPresent("fred")) .build() .render(RenderingStrategies.SPRING_NAMED_PARAMETER); @@ -147,9 +126,7 @@ void testOneRenderableCriteriaAfterNull() { @Test void testOneRenderableCriteriaAfterNull2() { - Integer nullId = null; - - Optional whereClause = where(id, isEqualToWhenPresent(nullId), and(firstName, isEqualToWhenPresent("fred"))) + Optional whereClause = where(id, isEqualToWhenPresent((Integer) null), and(firstName, isEqualToWhenPresent("fred"))) .build() .render(RenderingStrategies.SPRING_NAMED_PARAMETER); @@ -161,9 +138,7 @@ void testOneRenderableCriteriaAfterNull2() { @Test void testOverrideFirstConnector() { - Integer nullId = null; - - Optional whereClause = where(id, isEqualToWhenPresent(nullId), and(firstName, isEqualToWhenPresent("fred")), or(lastName, isEqualTo("flintstone"))) + Optional whereClause = where(id, isEqualToWhenPresent((Integer) null), and(firstName, isEqualToWhenPresent("fred")), or(lastName, isEqualTo("flintstone"))) .build() .render(RenderingStrategies.SPRING_NAMED_PARAMETER); @@ -306,10 +281,8 @@ void testWhereExistsAndAnd() { @Test void testCollapsingCriteriaGroup1() { - String name1 = null; - Optional whereClause = where( - group(firstName, isEqualToWhenPresent(name1)), or(lastName, isEqualToWhenPresent(name1))) + group(firstName, isEqualToWhenPresent((String) null)), or(lastName, isEqualToWhenPresent((String) null))) .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) .build() .render(RenderingStrategies.SPRING_NAMED_PARAMETER); @@ -319,10 +292,8 @@ void testCollapsingCriteriaGroup1() { @Test void testCollapsingCriteriaGroup2() { - String name1 = null; - Optional whereClause = where( - group(firstName, isEqualTo("Fred")), or(lastName, isEqualToWhenPresent(name1))) + group(firstName, isEqualTo("Fred")), or(lastName, isEqualToWhenPresent((String) null))) .build() .render(RenderingStrategies.SPRING_NAMED_PARAMETER); @@ -336,10 +307,8 @@ void testCollapsingCriteriaGroup2() { @Test void testCollapsingCriteriaGroup3() { - String name1 = null; - Optional whereClause = where( - group(firstName, isEqualTo("Fred")), or(lastName, isEqualToWhenPresent(name1)), or(firstName, isEqualTo("Betty"))) + group(firstName, isEqualTo("Fred")), or(lastName, isEqualToWhenPresent((String) null)), or(firstName, isEqualTo("Betty"))) .build() .render(RenderingStrategies.SPRING_NAMED_PARAMETER); diff --git a/src/test/kotlin/examples/kotlin/mybatis3/mariadb/KIsLikeEscape.kt b/src/test/kotlin/examples/kotlin/mybatis3/mariadb/KIsLikeEscape.kt index b47f09110..6746dc03e 100644 --- a/src/test/kotlin/examples/kotlin/mybatis3/mariadb/KIsLikeEscape.kt +++ b/src/test/kotlin/examples/kotlin/mybatis3/mariadb/KIsLikeEscape.kt @@ -1,3 +1,18 @@ +/* + * Copyright 2016-2025 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 examples.kotlin.mybatis3.mariadb import java.util.function.Predicate