From a2fec6a935acb1bc04f00d1364ac41b40bedfc99 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Sun, 6 Apr 2025 18:16:55 -0400 Subject: [PATCH 01/11] Properly handle nullability in the when present conditions --- .../org/mybatis/dynamic/sql/SqlBuilder.java | 108 +++-- .../sql/where/condition/AndGatherer.java | 4 +- .../sql/where/condition/IsBetween.java | 20 - .../where/condition/IsBetweenWhenPresent.java | 108 +++++ .../where/condition/IsEqualToWhenPresent.java | 72 +++ .../IsGreaterThanOrEqualToWhenPresent.java | 71 +++ .../condition/IsGreaterThanWhenPresent.java | 71 +++ .../where/condition/IsInCaseInsensitive.java | 5 +- .../IsInCaseInsensitiveWhenPresent.java | 13 +- .../sql/where/condition/IsInWhenPresent.java | 12 +- .../IsLessThanOrEqualToWhenPresent.java | 71 +++ .../condition/IsLessThanWhenPresent.java | 72 +++ .../condition/IsLikeCaseInsensitive.java | 2 +- .../IsLikeCaseInsensitiveWhenPresent.java | 73 +++ .../where/condition/IsLikeWhenPresent.java | 72 +++ .../sql/where/condition/IsNotBetween.java | 21 - .../condition/IsNotBetweenWhenPresent.java | 109 +++++ .../condition/IsNotEqualToWhenPresent.java | 71 +++ .../condition/IsNotInCaseInsensitive.java | 5 +- .../IsNotInCaseInsensitiveWhenPresent.java | 13 +- .../where/condition/IsNotInWhenPresent.java | 13 +- .../condition/IsNotLikeCaseInsensitive.java | 2 +- .../IsNotLikeCaseInsensitiveWhenPresent.java | 73 +++ .../where/condition/IsNotLikeWhenPresent.java | 71 +++ .../sql/util/kotlin/elements/SqlElements.kt | 38 +- .../sql/where/condition/NullContractTest.java | 441 ++++++++++++++++++ .../sql/where/condition/SupplierTest.java | 48 +- 27 files changed, 1532 insertions(+), 147 deletions(-) create mode 100644 src/main/java/org/mybatis/dynamic/sql/where/condition/IsBetweenWhenPresent.java create mode 100644 src/main/java/org/mybatis/dynamic/sql/where/condition/IsEqualToWhenPresent.java create mode 100644 src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanOrEqualToWhenPresent.java create mode 100644 src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanWhenPresent.java create mode 100644 src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanOrEqualToWhenPresent.java create mode 100644 src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanWhenPresent.java create mode 100644 src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitiveWhenPresent.java create mode 100644 src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeWhenPresent.java create mode 100644 src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotBetweenWhenPresent.java create mode 100644 src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotEqualToWhenPresent.java create mode 100644 src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitiveWhenPresent.java create mode 100644 src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeWhenPresent.java create mode 100644 src/test/java/org/mybatis/dynamic/sql/where/condition/NullContractTest.java 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/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..fab5e70f6 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,7 +20,6 @@ import java.util.function.Function; import java.util.function.Predicate; -import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.AbstractTwoValueCondition; public class IsBetween extends AbstractTwoValueCondition @@ -86,10 +85,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 +95,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..8c23cdfbb --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsBetweenWhenPresent.java @@ -0,0 +1,108 @@ +/* + * 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.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 IsBetweenWhenPresent.of(value1, value2); + } + } +} 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..f06489076 --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsEqualToWhenPresent.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.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/IsGreaterThanOrEqualToWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanOrEqualToWhenPresent.java new file mode 100644 index 000000000..89e8cda4f --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanOrEqualToWhenPresent.java @@ -0,0 +1,71 @@ +/* + * 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.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..175b5fcf6 --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanWhenPresent.java @@ -0,0 +1,71 @@ +/* + * 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.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/IsInCaseInsensitive.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java index bc8bfbdf9..3e2a22d2a 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 @@ -62,11 +62,12 @@ 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..ac3ce2787 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 @@ -54,15 +54,20 @@ public IsInCaseInsensitiveWhenPresent filter(Predicate predicate) } @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 || values.isEmpty()) { + 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..1ec8185ee 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 @@ -50,8 +50,8 @@ public IsInWhenPresent filter(Predicate predicate) { } @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 +59,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 || values.isEmpty()) { + return empty(); + } else { + return new IsInWhenPresent<>(values); + } } } 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..3cdc8ff39 --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanOrEqualToWhenPresent.java @@ -0,0 +1,71 @@ +/* + * 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.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..78a07f9a2 --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanWhenPresent.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.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/IsLikeCaseInsensitive.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitive.java index e4d31c126..ffdc2bc7d 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 @@ -62,7 +62,7 @@ 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..89ab9b038 --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitiveWhenPresent.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.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..a69e55356 --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeWhenPresent.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.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..836e3c741 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,6 @@ import java.util.function.Function; import java.util.function.Predicate; -import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.AbstractTwoValueCondition; public class IsNotBetween extends AbstractTwoValueCondition @@ -87,10 +86,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 +97,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..23b6507d5 --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotBetweenWhenPresent.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.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 IsNotBetweenWhenPresent.of(value1, value2); + } + } +} 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..07ab3f6cf --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotEqualToWhenPresent.java @@ -0,0 +1,71 @@ +/* + * 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.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/IsNotInCaseInsensitive.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java index 4486d1df7..2bc802ab8 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 @@ -62,11 +62,12 @@ 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..82d9d6e27 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 @@ -54,15 +54,20 @@ public IsNotInCaseInsensitiveWhenPresent filter(Predicate predicat } @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 || values.isEmpty()) { + 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..ed4b27389 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,6 +22,7 @@ import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.AbstractListValueCondition; public class IsNotInWhenPresent extends AbstractListValueCondition @@ -49,16 +50,20 @@ public IsNotInWhenPresent filter(Predicate predicate) { } @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 || values.isEmpty()) { + return empty(); + } else { + return new IsNotInWhenPresent<>(values); + } } } 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..6bd943227 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 @@ -62,7 +62,7 @@ public IsNotLikeCaseInsensitive map(Function mapp 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..891525295 --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitiveWhenPresent.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.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..d018c9062 --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeWhenPresent.java @@ -0,0 +1,71 @@ +/* + * 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.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/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..35f0440d8 --- /dev/null +++ b/src/test/java/org/mybatis/dynamic/sql/where/condition/NullContractTest.java @@ -0,0 +1,441 @@ +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. + */ +public 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();; + } +} 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..c2bf40ddf 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 @@ -44,7 +44,7 @@ void testIsBetweenNull() { @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 +52,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(); @@ -76,7 +76,7 @@ void testIsNotBetweenNull() { @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 +84,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 +92,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(); } @@ -120,14 +120,14 @@ void testIsNotEqualToNull() { @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(); } @@ -148,14 +148,14 @@ void testIsGreaterThanNull() { @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(); } @@ -176,14 +176,14 @@ void testIsGreaterThanOrEqualToNull() { @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(); } @@ -204,14 +204,14 @@ void testIsLessThanNull() { @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(); } @@ -232,14 +232,14 @@ void testIsLessThanOrEqualToNull() { @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(); } @@ -274,28 +274,28 @@ void testIsLikeCaseInsensitiveNull() { @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(); } @@ -316,14 +316,14 @@ void testIsNotLikeNull() { @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(); } @@ -344,14 +344,14 @@ void testIsNotLikeCaseInsensitiveNull() { @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(); } From d1771e82ab9177dca387c3060d9e839c48e80a8c Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Sun, 6 Apr 2025 18:19:37 -0400 Subject: [PATCH 02/11] Checkstyle --- .../dynamic/sql/where/condition/NullContractTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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 index 35f0440d8..6ea7b2909 100644 --- a/src/test/java/org/mybatis/dynamic/sql/where/condition/NullContractTest.java +++ b/src/test/java/org/mybatis/dynamic/sql/where/condition/NullContractTest.java @@ -361,7 +361,7 @@ void testIsInWhenPresent() { IsInWhenPresent filtered = cond.filter(i -> i == 1); IsInWhenPresent mapped = filtered.map(i -> null); assertThat(mapped.isEmpty()).isTrue(); - assertThat(mapped.values().toList()).isEmpty();; + assertThat(mapped.values().toList()).isEmpty(); } @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing @@ -386,7 +386,7 @@ void testIsInCaseInsensitiveWhenPresent() { IsInCaseInsensitiveWhenPresent filtered = cond.filter(i -> i.equals("FRED")); IsInCaseInsensitiveWhenPresent mapped = filtered.map(i -> null); assertThat(mapped.isEmpty()).isTrue(); - assertThat(mapped.values().toList()).isEmpty();; + assertThat(mapped.values().toList()).isEmpty(); } @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing @@ -411,7 +411,7 @@ void testIsNotInWhenPresent() { IsNotInWhenPresent filtered = cond.filter(i -> i == 1); IsNotInWhenPresent mapped = filtered.map(i -> null); assertThat(mapped.isEmpty()).isTrue(); - assertThat(mapped.values().toList()).isEmpty();; + assertThat(mapped.values().toList()).isEmpty(); } @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing @@ -436,6 +436,6 @@ void testIsNotInCaseInsensitiveWhenPresent() { IsNotInCaseInsensitiveWhenPresent filtered = cond.filter(i -> i.equals("FRED")); IsNotInCaseInsensitiveWhenPresent mapped = filtered.map(i -> null); assertThat(mapped.isEmpty()).isTrue(); - assertThat(mapped.values().toList()).isEmpty();; + assertThat(mapped.values().toList()).isEmpty(); } } From ee2ccbf6c0e3f7c4a2b1f408351af28ff4a58682 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 7 Apr 2025 10:32:22 -0400 Subject: [PATCH 03/11] Add missing jSpecify annotations --- src/main/java/org/mybatis/dynamic/sql/delete/DeleteDSL.java | 2 +- src/main/java/org/mybatis/dynamic/sql/update/UpdateDSL.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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); } From 6315e94d65638b82d311a2214013e9c702285c1d Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 7 Apr 2025 10:43:12 -0400 Subject: [PATCH 04/11] Properly handle null row in sommon select mapper --- .../sql/util/mybatis3/CommonSelectMapper.java | 18 ++++++++++-------- .../animal/data/CommonSelectMapperTest.java | 16 ++++++++++++++++ 2 files changed, 26 insertions(+), 8 deletions(-) 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..789538fed 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; @@ -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,9 +75,10 @@ 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); } /** @@ -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/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()) { From 37fa65f2339ca2cf31a32b706c4b0d9506ebfd80 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 7 Apr 2025 10:50:44 -0400 Subject: [PATCH 05/11] Documentation --- .../mybatis/dynamic/sql/util/mybatis3/CommonSelectMapper.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 789538fed..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 @@ -50,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. @@ -85,7 +85,7 @@ public interface CommonSelectMapper { * 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. From 26c973a6dfd9846975f0aa2d9afa2f10b2d38c07 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 7 Apr 2025 10:52:32 -0400 Subject: [PATCH 06/11] Fully denote the nullability of filter and map methods. Also fix al the tests that were, essentially, misuses of the library. --- .../sql/AbstractListValueCondition.java | 5 +- .../sql/AbstractSingleValueCondition.java | 5 +- .../sql/AbstractTwoValueCondition.java | 11 +- .../sql/where/condition/IsBetween.java | 12 +- .../where/condition/IsBetweenWhenPresent.java | 11 +- .../sql/where/condition/IsEqualTo.java | 5 +- .../where/condition/IsEqualToWhenPresent.java | 5 +- .../sql/where/condition/IsGreaterThan.java | 5 +- .../condition/IsGreaterThanOrEqualTo.java | 5 +- .../IsGreaterThanOrEqualToWhenPresent.java | 5 +- .../condition/IsGreaterThanWhenPresent.java | 5 +- .../dynamic/sql/where/condition/IsIn.java | 5 +- .../where/condition/IsInCaseInsensitive.java | 5 +- .../IsInCaseInsensitiveWhenPresent.java | 7 +- .../sql/where/condition/IsInWhenPresent.java | 7 +- .../sql/where/condition/IsLessThan.java | 5 +- .../where/condition/IsLessThanOrEqualTo.java | 5 +- .../IsLessThanOrEqualToWhenPresent.java | 5 +- .../condition/IsLessThanWhenPresent.java | 5 +- .../dynamic/sql/where/condition/IsLike.java | 5 +- .../condition/IsLikeCaseInsensitive.java | 5 +- .../IsLikeCaseInsensitiveWhenPresent.java | 5 +- .../where/condition/IsLikeWhenPresent.java | 5 +- .../sql/where/condition/IsNotBetween.java | 11 +- .../condition/IsNotBetweenWhenPresent.java | 11 +- .../sql/where/condition/IsNotEqualTo.java | 5 +- .../condition/IsNotEqualToWhenPresent.java | 5 +- .../dynamic/sql/where/condition/IsNotIn.java | 5 +- .../condition/IsNotInCaseInsensitive.java | 5 +- .../IsNotInCaseInsensitiveWhenPresent.java | 7 +- .../where/condition/IsNotInWhenPresent.java | 7 +- .../sql/where/condition/IsNotLike.java | 5 +- .../condition/IsNotLikeCaseInsensitive.java | 5 +- .../IsNotLikeCaseInsensitiveWhenPresent.java | 5 +- .../where/condition/IsNotLikeWhenPresent.java | 5 +- ...onditionsWithPredicatesAnimalDataTest.java | 109 +++++++----------- .../complexquery/ComplexQueryTest.java | 10 +- .../examples/emptywhere/EmptyWhereTest.java | 43 +++---- .../examples/simple/PersonMapperTest.java | 3 +- src/test/java/issues/gh105/Issue105Test.java | 43 ++++--- .../sql/where/condition/FilterAndMapTest.java | 27 ++--- .../sql/where/condition/NullContractTest.java | 90 +++++++++++++++ .../sql/where/condition/SupplierTest.java | 79 ------------- .../render/OptionalCriterionRenderTest.java | 3 +- 44 files changed, 315 insertions(+), 306 deletions(-) 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/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/where/condition/IsBetween.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsBetween.java index fab5e70f6..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,9 +20,10 @@ import java.util.function.Function; import java.util.function.Predicate; +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 @@ -62,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); } 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 index 8c23cdfbb..a3eb2a91e 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsBetweenWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsBetweenWhenPresent.java @@ -20,6 +20,7 @@ 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; @@ -63,23 +64,23 @@ public String operator2() { } @Override - public IsBetweenWhenPresent filter(BiPredicate predicate) { + public IsBetweenWhenPresent filter(BiPredicate predicate) { return filterSupport(predicate, IsBetweenWhenPresent::empty, this); } @Override - public IsBetweenWhenPresent filter(Predicate predicate) { + public IsBetweenWhenPresent filter(Predicate predicate) { return filterSupport(predicate, IsBetweenWhenPresent::empty, this); } @Override - public IsBetweenWhenPresent map(Function mapper1, - Function mapper2) { + public IsBetweenWhenPresent map(Function mapper1, + Function mapper2) { return mapSupport(mapper1, mapper2, IsBetweenWhenPresent::of, IsBetweenWhenPresent::empty); } @Override - public IsBetweenWhenPresent map(Function mapper) { + public IsBetweenWhenPresent map(Function mapper) { return map(mapper, mapper); } 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 index f06489076..2dd8c746d 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsEqualToWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsEqualToWhenPresent.java @@ -19,6 +19,7 @@ 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; @@ -61,12 +62,12 @@ public static IsEqualToWhenPresent of(@Nullable T value) { } @Override - public IsEqualToWhenPresent filter(Predicate predicate) { + public IsEqualToWhenPresent filter(Predicate predicate) { return filterSupport(predicate, IsEqualToWhenPresent::empty, this); } @Override - public IsEqualToWhenPresent map(Function mapper) { + 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 index 89e8cda4f..825b5c6cf 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanOrEqualToWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanOrEqualToWhenPresent.java @@ -19,6 +19,7 @@ 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; @@ -60,12 +61,12 @@ public static IsGreaterThanOrEqualToWhenPresent of(@Nullable T value) { } @Override - public IsGreaterThanOrEqualToWhenPresent filter(Predicate predicate) { + public IsGreaterThanOrEqualToWhenPresent filter(Predicate predicate) { return filterSupport(predicate, IsGreaterThanOrEqualToWhenPresent::empty, this); } @Override - public IsGreaterThanOrEqualToWhenPresent map(Function mapper) { + 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 index 175b5fcf6..779a15596 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanWhenPresent.java @@ -19,6 +19,7 @@ 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; @@ -60,12 +61,12 @@ public static IsGreaterThanWhenPresent of(@Nullable T value) { } @Override - public IsGreaterThanWhenPresent filter(Predicate predicate) { + public IsGreaterThanWhenPresent filter(Predicate predicate) { return filterSupport(predicate, IsGreaterThanWhenPresent::empty, this); } @Override - public IsGreaterThanWhenPresent map(Function mapper) { + 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..886980610 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,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.Validator; @@ -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 3e2a22d2a..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,12 +54,12 @@ 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); } 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 ac3ce2787..934df359b 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 @@ -22,6 +22,7 @@ import java.util.Objects; 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,13 +49,13 @@ 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); } @@ -64,7 +65,7 @@ public static IsInCaseInsensitiveWhenPresent of(@Nullable T... values) { } public static IsInCaseInsensitiveWhenPresent of(@Nullable Collection<@Nullable T> values) { - if (values == null || values.isEmpty()) { + 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 1ec8185ee..2dec62d72 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,6 +22,7 @@ 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; @@ -45,12 +46,12 @@ 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) { + public IsInWhenPresent map(Function mapper) { return mapSupport(mapper, IsInWhenPresent::of, IsInWhenPresent::empty); } @@ -60,7 +61,7 @@ public static IsInWhenPresent of(@Nullable T... values) { } public static IsInWhenPresent of(@Nullable Collection<@Nullable T> values) { - if (values == null || values.isEmpty()) { + 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 index 3cdc8ff39..d944b7a45 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanOrEqualToWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanOrEqualToWhenPresent.java @@ -19,6 +19,7 @@ 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; @@ -60,12 +61,12 @@ public static IsLessThanOrEqualToWhenPresent of(@Nullable T value) { } @Override - public IsLessThanOrEqualToWhenPresent filter(Predicate predicate) { + public IsLessThanOrEqualToWhenPresent filter(Predicate predicate) { return filterSupport(predicate, IsLessThanOrEqualToWhenPresent::empty, this); } @Override - public IsLessThanOrEqualToWhenPresent map(Function mapper) { + 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 index 78a07f9a2..830bf788c 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanWhenPresent.java @@ -19,6 +19,7 @@ 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; @@ -61,12 +62,12 @@ public static IsLessThanWhenPresent of(@Nullable T value) { } @Override - public IsLessThanWhenPresent filter(Predicate predicate) { + public IsLessThanWhenPresent filter(Predicate predicate) { return filterSupport(predicate, IsLessThanWhenPresent::empty, this); } @Override - public IsLessThanWhenPresent map(Function mapper) { + 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 ffdc2bc7d..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,12 +54,12 @@ 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); } 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 index 89ab9b038..bebbff30d 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitiveWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitiveWhenPresent.java @@ -19,6 +19,7 @@ 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; @@ -54,12 +55,12 @@ public String operator() { } @Override - public IsLikeCaseInsensitiveWhenPresent filter(Predicate predicate) { + public IsLikeCaseInsensitiveWhenPresent filter(Predicate predicate) { return filterSupport(predicate, IsLikeCaseInsensitiveWhenPresent::empty, this); } @Override - public IsLikeCaseInsensitiveWhenPresent map(Function mapper) { + public IsLikeCaseInsensitiveWhenPresent map(Function mapper) { return mapSupport(mapper, IsLikeCaseInsensitiveWhenPresent::of, IsLikeCaseInsensitiveWhenPresent::empty); } 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 index a69e55356..fc20722a2 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeWhenPresent.java @@ -19,6 +19,7 @@ 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; @@ -61,12 +62,12 @@ public static IsLikeWhenPresent of(@Nullable T value) { } @Override - public IsLikeWhenPresent filter(Predicate predicate) { + public IsLikeWhenPresent filter(Predicate predicate) { return filterSupport(predicate, IsLikeWhenPresent::empty, this); } @Override - public IsLikeWhenPresent map(Function mapper) { + 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 836e3c741..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,6 +20,7 @@ import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; import org.mybatis.dynamic.sql.AbstractTwoValueCondition; public class IsNotBetween extends AbstractTwoValueCondition @@ -62,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); } 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 index 23b6507d5..cb9860384 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotBetweenWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotBetweenWhenPresent.java @@ -20,6 +20,7 @@ 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; @@ -63,23 +64,23 @@ public String operator2() { } @Override - public IsNotBetweenWhenPresent filter(BiPredicate predicate) { + public IsNotBetweenWhenPresent filter(BiPredicate predicate) { return filterSupport(predicate, IsNotBetweenWhenPresent::empty, this); } @Override - public IsNotBetweenWhenPresent filter(Predicate predicate) { + public IsNotBetweenWhenPresent filter(Predicate predicate) { return filterSupport(predicate, IsNotBetweenWhenPresent::empty, this); } @Override - public IsNotBetweenWhenPresent map(Function mapper1, - Function mapper2) { + public IsNotBetweenWhenPresent map(Function mapper1, + Function mapper2) { return mapSupport(mapper1, mapper2, IsNotBetweenWhenPresent::of, IsNotBetweenWhenPresent::empty); } @Override - public IsNotBetweenWhenPresent map(Function mapper) { + public IsNotBetweenWhenPresent map(Function mapper) { return map(mapper, mapper); } 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 index 07ab3f6cf..1fff2d9ba 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotEqualToWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotEqualToWhenPresent.java @@ -19,6 +19,7 @@ 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; @@ -60,12 +61,12 @@ public static IsNotEqualToWhenPresent of(@Nullable T value) { } @Override - public IsNotEqualToWhenPresent filter(Predicate predicate) { + public IsNotEqualToWhenPresent filter(Predicate predicate) { return filterSupport(predicate, IsNotEqualToWhenPresent::empty, this); } @Override - public IsNotEqualToWhenPresent map(Function mapper) { + 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..f6c70d180 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,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.Validator; @@ -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 2bc802ab8..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,12 +54,12 @@ 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); } 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 82d9d6e27..5646168c1 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 @@ -22,6 +22,7 @@ import java.util.Objects; 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,13 +49,13 @@ 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); } @@ -64,7 +65,7 @@ public static IsNotInCaseInsensitiveWhenPresent of(@Nullable T... values) } public static IsNotInCaseInsensitiveWhenPresent of(@Nullable Collection<@Nullable T> values) { - if (values == null || values.isEmpty()) { + 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 ed4b27389..375f7d69b 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,6 +22,7 @@ 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; @@ -45,12 +46,12 @@ 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); } @@ -60,7 +61,7 @@ public static IsNotInWhenPresent of(@Nullable T... values) { } public static IsNotInWhenPresent of(@Nullable Collection<@Nullable T> values) { - if (values == null || values.isEmpty()) { + 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 6bd943227..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,12 +54,12 @@ 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); } 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 index 891525295..e1e17f9da 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitiveWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitiveWhenPresent.java @@ -19,6 +19,7 @@ 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; @@ -54,12 +55,12 @@ public String operator() { } @Override - public IsNotLikeCaseInsensitiveWhenPresent filter(Predicate predicate) { + public IsNotLikeCaseInsensitiveWhenPresent filter(Predicate predicate) { return filterSupport(predicate, IsNotLikeCaseInsensitiveWhenPresent::empty, this); } @Override - public IsNotLikeCaseInsensitiveWhenPresent map(Function mapper) { + public IsNotLikeCaseInsensitiveWhenPresent map(Function mapper) { return mapSupport(mapper, IsNotLikeCaseInsensitiveWhenPresent::of, IsNotLikeCaseInsensitiveWhenPresent::empty); } 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 index d018c9062..a3571b0ee 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeWhenPresent.java @@ -19,6 +19,7 @@ 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; @@ -60,12 +61,12 @@ public static IsNotLikeWhenPresent of(@Nullable T value) { } @Override - public IsNotLikeWhenPresent filter(Predicate predicate) { + public IsNotLikeWhenPresent filter(Predicate predicate) { return filterSupport(predicate, IsNotLikeWhenPresent::empty, this); } @Override - public IsNotLikeWhenPresent map(Function mapper) { + public IsNotLikeWhenPresent map(Function mapper) { return mapSupport(mapper, IsNotLikeWhenPresent::of, IsNotLikeWhenPresent::empty); } } 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..81ecb79c2 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); @@ -527,7 +524,7 @@ 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)) + .where(age, isBetweenWhenPresent(1).and((Integer) null).map(i1 -> i1 + 1, i2 -> i2 + 2)) .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) .build() .render(RenderingStrategies.MYBATIS3); @@ -559,7 +556,7 @@ void testEqualTransformWithNull() { SelectStatementProvider selectStatement = select(id, firstName, lastName) .from(person) - .where(age, isEqualTo((Integer) null).filter(Objects::nonNull).map(i -> i + 1)) + .where(age, isEqualToWhenPresent((Integer) null).map(i -> i + 1)) .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) .build() .render(RenderingStrategies.MYBATIS3); @@ -591,7 +588,7 @@ void testGreaterThanTransformWithNull() { SelectStatementProvider selectStatement = select(id, firstName, lastName) .from(person) - .where(age, isGreaterThan((Integer) null).filter(Objects::nonNull).map(i -> i + 1)) + .where(age, isGreaterThanWhenPresent((Integer) null).map(i -> i + 1)) .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) .build() .render(RenderingStrategies.MYBATIS3); @@ -607,7 +604,7 @@ void testGreaterThanOrEqualTransformWithNull() { SelectStatementProvider selectStatement = select(id, firstName, lastName) .from(person) - .where(age, isGreaterThanOrEqualTo((Integer) null).filter(Objects::nonNull).map(i -> i + 1)) + .where(age, isGreaterThanOrEqualToWhenPresent((Integer) null).map(i -> i + 1)) .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) .build() .render(RenderingStrategies.MYBATIS3); @@ -655,7 +652,7 @@ void testLessThanTransformWithNull() { SelectStatementProvider selectStatement = select(id, firstName, lastName) .from(person) - .where(age, isLessThan((Integer) null).filter(Objects::nonNull).map(i -> i + 1)) + .where(age, isLessThanWhenPresent((Integer) null).map(i -> i + 1)) .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) .build() .render(RenderingStrategies.MYBATIS3); @@ -671,7 +668,7 @@ void testLessThanOrEqualTransformWithNull() { SelectStatementProvider selectStatement = select(id, firstName, lastName) .from(person) - .where(age, isLessThanOrEqualTo((Integer) null).filter(Objects::nonNull).map(i -> i + 1)) + .where(age, isLessThanOrEqualToWhenPresent((Integer) null).map(i -> i + 1)) .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) .build() .render(RenderingStrategies.MYBATIS3); @@ -719,7 +716,7 @@ void testLikeTransformWithNull() { SelectStatementProvider selectStatement = select(id, firstName, lastName) .from(person) - .where(firstName, isLike((String) null).filter(Objects::nonNull).map(SearchUtils::addWildcards)) + .where(firstName, isLikeWhenPresent((String) null).map(SearchUtils::addWildcards)) .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) .build() .render(RenderingStrategies.MYBATIS3); @@ -735,7 +732,7 @@ void testLikeCaseInsensitiveTransformWithNull() { SelectStatementProvider selectStatement = select(id, firstName, lastName) .from(person) - .where(firstName, isLikeCaseInsensitive((String) null).filter(Objects::nonNull).map(SearchUtils::addWildcards)) + .where(firstName, isLikeCaseInsensitiveWhenPresent((String) null).map(SearchUtils::addWildcards)) .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) .build() .render(RenderingStrategies.MYBATIS3); @@ -783,7 +780,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); @@ -815,7 +812,7 @@ void testNotEqualTransformWithNull() { SelectStatementProvider selectStatement = select(id, firstName, lastName) .from(person) - .where(age, isNotEqualTo((Integer) null).filter(Objects::nonNull).map(i -> i + 1)) + .where(age, isNotEqualToWhenPresent((Integer) null).map(i -> i + 1)) .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) .build() .render(RenderingStrategies.MYBATIS3); @@ -847,7 +844,7 @@ void testNotLikeTransformWithNull() { SelectStatementProvider selectStatement = select(id, firstName, lastName) .from(person) - .where(firstName, isNotLike((String) null).filter(Objects::nonNull).map(SearchUtils::addWildcards)) + .where(firstName, isNotLikeWhenPresent((String) null).map(SearchUtils::addWildcards)) .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) .build() .render(RenderingStrategies.MYBATIS3); @@ -863,7 +860,7 @@ void testNotLikeCaseInsensitiveTransformWithNull() { SelectStatementProvider selectStatement = select(id, firstName, lastName) .from(person) - .where(firstName, isNotLikeCaseInsensitive((String) null).filter(Objects::nonNull).map(SearchUtils::addWildcards)) + .where(firstName, isNotLikeCaseInsensitiveWhenPresent((String) null).map(SearchUtils::addWildcards)) .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) .build() .render(RenderingStrategies.MYBATIS3); 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..a3bb3d620 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,7 +20,6 @@ import java.util.List; import java.util.NoSuchElementException; -import java.util.Objects; import org.junit.jupiter.api.Test; import org.mybatis.dynamic.sql.SqlBuilder; @@ -33,17 +32,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 +470,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); } @@ -511,17 +502,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); } 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 index 6ea7b2909..ed7d4e01c 100644 --- a/src/test/java/org/mybatis/dynamic/sql/where/condition/NullContractTest.java +++ b/src/test/java/org/mybatis/dynamic/sql/where/condition/NullContractTest.java @@ -438,4 +438,94 @@ void testIsNotInCaseInsensitiveWhenPresent() { 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 c2bf40ddf..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,14 +34,6 @@ 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() { IsBetweenWhenPresent cond = SqlBuilder.isBetweenWhenPresent(() -> 3).and(() -> 4); @@ -66,14 +58,6 @@ 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() { IsNotBetweenWhenPresent cond = SqlBuilder.isNotBetweenWhenPresent(() -> 3).and(() -> 4); @@ -111,13 +95,6 @@ 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() { IsNotEqualToWhenPresent cond = SqlBuilder.isNotEqualToWhenPresent(() -> 3); @@ -139,13 +116,6 @@ 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() { IsGreaterThanWhenPresent cond = SqlBuilder.isGreaterThanWhenPresent(() -> 3); @@ -167,13 +137,6 @@ 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() { IsGreaterThanOrEqualToWhenPresent cond = SqlBuilder.isGreaterThanOrEqualToWhenPresent(() -> 3); @@ -195,13 +158,6 @@ 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() { IsLessThanWhenPresent cond = SqlBuilder.isLessThanWhenPresent(() -> 3); @@ -223,13 +179,6 @@ 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() { IsLessThanOrEqualToWhenPresent cond = SqlBuilder.isLessThanOrEqualToWhenPresent(() -> 3); @@ -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,13 +207,6 @@ 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() { IsLikeCaseInsensitiveWhenPresent cond = SqlBuilder.isLikeCaseInsensitiveWhenPresent(() -> "%f%"); @@ -307,13 +242,6 @@ 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() { IsNotLikeWhenPresent cond = SqlBuilder.isNotLikeWhenPresent(() -> "%F%"); @@ -335,13 +263,6 @@ 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() { IsNotLikeCaseInsensitiveWhenPresent cond = SqlBuilder.isNotLikeCaseInsensitiveWhenPresent(() -> "%f%"); 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..25ea36a3e 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; @@ -49,7 +48,7 @@ void testNoRenderableCriteria() { void testNoRenderableCriteriaWithIf() { Integer nullId = null; - Optional whereClause = where(id, isEqualTo(nullId).filter(Objects::nonNull)) + Optional whereClause = where(id, isEqualToWhenPresent(nullId)) .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) .build() .render(RenderingStrategies.SPRING_NAMED_PARAMETER); From 384c758b0b865033d44df8eb8ad87470be64fcdd Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 7 Apr 2025 11:34:55 -0400 Subject: [PATCH 07/11] Licensing --- .../sql/where/condition/NullContractTest.java | 15 +++++++++++++++ .../kotlin/mybatis3/mariadb/KIsLikeEscape.kt | 15 +++++++++++++++ 2 files changed, 30 insertions(+) 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 index ed7d4e01c..17b96973e 100644 --- a/src/test/java/org/mybatis/dynamic/sql/where/condition/NullContractTest.java +++ b/src/test/java/org/mybatis/dynamic/sql/where/condition/NullContractTest.java @@ -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 org.mybatis.dynamic.sql.where.condition; import static org.assertj.core.api.Assertions.assertThat; 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 From a781f6ae35d62b0cbf992eb9ceccd5d8ed44ecd1 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 7 Apr 2025 12:36:02 -0400 Subject: [PATCH 08/11] Sonar should talk to localhost by default --- pom.xml | 2 ++ 1 file changed, 2 insertions(+) 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 From 428fc915dd94cfe8e162d75b2e0c4fb22698769f Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 7 Apr 2025 12:36:27 -0400 Subject: [PATCH 09/11] Checkstyle --- .../java/org/mybatis/dynamic/sql/AbstractNoValueCondition.java | 3 ++- .../sql/where/condition/IsGreaterThanOrEqualToWhenPresent.java | 3 ++- .../java/org/mybatis/dynamic/sql/where/condition/IsIn.java | 2 +- .../sql/where/condition/IsInCaseInsensitiveWhenPresent.java | 2 +- .../mybatis/dynamic/sql/where/condition/IsInWhenPresent.java | 2 +- .../sql/where/condition/IsLikeCaseInsensitiveWhenPresent.java | 3 ++- .../java/org/mybatis/dynamic/sql/where/condition/IsNotIn.java | 2 +- .../sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java | 2 +- .../dynamic/sql/where/condition/IsNotInWhenPresent.java | 2 +- .../where/condition/IsNotLikeCaseInsensitiveWhenPresent.java | 3 ++- 10 files changed, 14 insertions(+), 10 deletions(-) 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/where/condition/IsGreaterThanOrEqualToWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanOrEqualToWhenPresent.java index 825b5c6cf..01f895dc9 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanOrEqualToWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanOrEqualToWhenPresent.java @@ -25,7 +25,8 @@ public class IsGreaterThanOrEqualToWhenPresent extends AbstractSingleValueCondition implements AbstractSingleValueCondition.Filterable, AbstractSingleValueCondition.Mappable { - private static final IsGreaterThanOrEqualToWhenPresent EMPTY = new IsGreaterThanOrEqualToWhenPresent(-1) { + private static final IsGreaterThanOrEqualToWhenPresent EMPTY = + new IsGreaterThanOrEqualToWhenPresent(-1) { @Override public Object value() { throw new NoSuchElementException("No value present"); //$NON-NLS-1$ 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 886980610..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 @@ -27,7 +27,7 @@ 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() { 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 934df359b..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,8 +18,8 @@ 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; 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 2dec62d72..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 @@ -27,7 +27,7 @@ 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() { 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 index bebbff30d..60307625f 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitiveWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitiveWhenPresent.java @@ -27,7 +27,8 @@ public class IsLikeCaseInsensitiveWhenPresent extends AbstractSingleValueCondition implements CaseInsensitiveRenderableCondition, AbstractSingleValueCondition.Filterable, AbstractSingleValueCondition.Mappable { - private static final IsLikeCaseInsensitiveWhenPresent EMPTY = new IsLikeCaseInsensitiveWhenPresent<>("") { //$NON-NLS-1$ + private static final IsLikeCaseInsensitiveWhenPresent EMPTY = + new IsLikeCaseInsensitiveWhenPresent<>("") { //$NON-NLS-1$ @Override public String value() { throw new NoSuchElementException("No value present"); //$NON-NLS-1$ 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 f6c70d180..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 @@ -27,7 +27,7 @@ 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() { 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 5646168c1..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,8 +18,8 @@ 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; 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 375f7d69b..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 @@ -27,7 +27,7 @@ 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() { 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 index e1e17f9da..cc0b04549 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitiveWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitiveWhenPresent.java @@ -27,7 +27,8 @@ public class IsNotLikeCaseInsensitiveWhenPresent extends AbstractSingleValueCondition implements CaseInsensitiveRenderableCondition, AbstractSingleValueCondition.Filterable, AbstractSingleValueCondition.Mappable { - private static final IsNotLikeCaseInsensitiveWhenPresent EMPTY = new IsNotLikeCaseInsensitiveWhenPresent<>("") { //$NON-NLS-1$ + private static final IsNotLikeCaseInsensitiveWhenPresent EMPTY = + new IsNotLikeCaseInsensitiveWhenPresent<>("") { //$NON-NLS-1$ @Override public String value() { throw new NoSuchElementException("No value present"); //$NON-NLS-1$ From 42a905c88d19f83859c94e663351be1ad0fc11d8 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 7 Apr 2025 15:27:34 -0400 Subject: [PATCH 10/11] Checkstyle, Sonar, Coverage, etc. --- .../where/condition/IsBetweenWhenPresent.java | 2 +- .../condition/IsNotBetweenWhenPresent.java | 2 +- .../examples/animal/data/AnimalDataTest.java | 12 +- src/test/java/issues/gh105/Issue105Test.java | 176 ------------------ .../dynamic/sql/util/PredicatesTest.java | 42 +++++ .../sql/where/condition/FilterAndMapTest.java | 62 ++++++ .../sql/where/condition/NullContractTest.java | 2 +- .../render/OptionalCriterionRenderTest.java | 48 +---- 8 files changed, 122 insertions(+), 224 deletions(-) create mode 100644 src/test/java/org/mybatis/dynamic/sql/util/PredicatesTest.java 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 index a3eb2a91e..bc9c12d37 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsBetweenWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsBetweenWhenPresent.java @@ -103,7 +103,7 @@ private Builder(@Nullable T value1) { @Override protected IsBetweenWhenPresent build(@Nullable T value2) { - return IsBetweenWhenPresent.of(value1, value2); + return of(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 index cb9860384..3c9c8fc9f 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotBetweenWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotBetweenWhenPresent.java @@ -104,7 +104,7 @@ private Builder(@Nullable T value1) { @Override protected IsNotBetweenWhenPresent build(@Nullable T value2) { - return IsNotBetweenWhenPresent.of(value1, value2); + return of(value1, value2); } } } 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/issues/gh105/Issue105Test.java b/src/test/java/issues/gh105/Issue105Test.java index 81ecb79c2..c12f4fde9 100644 --- a/src/test/java/issues/gh105/Issue105Test.java +++ b/src/test/java/issues/gh105/Issue105Test.java @@ -519,22 +519,6 @@ void testNotLikeWhenPresentTransform() { assertThat(selectStatement.getParameters()).containsEntry("p1", "%fred%"); } - @Test - void testBetweenTransformWithNull() { - - SelectStatementProvider selectStatement = select(id, firstName, lastName) - .from(person) - .where(age, isBetweenWhenPresent(1).and((Integer) null).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() { @@ -551,22 +535,6 @@ void testBetweenWhenPresentTransformWithNull() { assertThat(selectStatement.getSelectStatement()).isEqualTo(expected); } - @Test - void testEqualTransformWithNull() { - - SelectStatementProvider selectStatement = select(id, firstName, lastName) - .from(person) - .where(age, isEqualToWhenPresent((Integer) null).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() { @@ -583,38 +551,6 @@ void testEqualWhenPresentTransformWithNull() { assertThat(selectStatement.getSelectStatement()).isEqualTo(expected); } - @Test - void testGreaterThanTransformWithNull() { - - SelectStatementProvider selectStatement = select(id, firstName, lastName) - .from(person) - .where(age, isGreaterThanWhenPresent((Integer) null).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, isGreaterThanOrEqualToWhenPresent((Integer) null).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() { @@ -647,38 +583,6 @@ void testGreaterThanWhenPresentTransformWithNull() { assertThat(selectStatement.getSelectStatement()).isEqualTo(expected); } - @Test - void testLessThanTransformWithNull() { - - SelectStatementProvider selectStatement = select(id, firstName, lastName) - .from(person) - .where(age, isLessThanWhenPresent((Integer) null).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, isLessThanOrEqualToWhenPresent((Integer) null).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() { @@ -711,38 +615,6 @@ void testLessThanWhenPresentTransformWithNull() { assertThat(selectStatement.getSelectStatement()).isEqualTo(expected); } - @Test - void testLikeTransformWithNull() { - - SelectStatementProvider selectStatement = select(id, firstName, lastName) - .from(person) - .where(firstName, isLikeWhenPresent((String) null).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, isLikeCaseInsensitiveWhenPresent((String) null).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() { @@ -807,22 +679,6 @@ void testNotBetweenWhenPresentTransformWithNull() { assertThat(selectStatement.getSelectStatement()).isEqualTo(expected); } - @Test - void testNotEqualTransformWithNull() { - - SelectStatementProvider selectStatement = select(id, firstName, lastName) - .from(person) - .where(age, isNotEqualToWhenPresent((Integer) null).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() { @@ -839,38 +695,6 @@ void testNotEqualWhenPresentTransformWithNull() { assertThat(selectStatement.getSelectStatement()).isEqualTo(expected); } - @Test - void testNotLikeTransformWithNull() { - - SelectStatementProvider selectStatement = select(id, firstName, lastName) - .from(person) - .where(firstName, isNotLikeWhenPresent((String) null).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, isNotLikeCaseInsensitiveWhenPresent((String) null).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 a3bb3d620..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,8 +20,12 @@ import java.util.List; import java.util.NoSuchElementException; +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 { @@ -492,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); @@ -524,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 index 17b96973e..cd55d9e52 100644 --- a/src/test/java/org/mybatis/dynamic/sql/where/condition/NullContractTest.java +++ b/src/test/java/org/mybatis/dynamic/sql/where/condition/NullContractTest.java @@ -37,7 +37,7 @@ *

This set of tests should be the only tests in the library that verify this behavior. All other tests * should use the library properly. */ -public class NullContractTest { +class NullContractTest { @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing @Test void testIsBetween() { 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 25ea36a3e..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 @@ -34,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, isEqualToWhenPresent(nullId)) + Optional whereClause = where(id, isEqualToWhenPresent((Integer) null)) .configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true)) .build() .render(RenderingStrategies.SPRING_NAMED_PARAMETER); @@ -102,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); @@ -117,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); @@ -131,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); @@ -146,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); @@ -160,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); @@ -305,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); @@ -318,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); @@ -335,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); From b3b3b7d8f9cc26aa86f5b36bdef1dd28bf917dba Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 7 Apr 2025 15:38:09 -0400 Subject: [PATCH 11/11] Documentation --- CHANGELOG.md | 2 ++ src/site/markdown/docs/conditions.md | 16 +++++++++++----- 2 files changed, 13 insertions(+), 5 deletions(-) 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/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",