Skip to content

Commit a309d99

Browse files
authored
Merge pull request #923 from jeffgbutler/fix-case-insensitive-conditions
Improve case insensitive conditions
2 parents ea3b0a8 + c8480cc commit a309d99

9 files changed

+34
-123
lines changed

src/main/java/org/mybatis/dynamic/sql/util/StringUtilities.java

+8-10
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,6 @@
1515
*/
1616
package org.mybatis.dynamic.sql.util;
1717

18-
import java.util.function.Function;
19-
20-
import org.jspecify.annotations.Nullable;
21-
2218
public interface StringUtilities {
2319

2420
static String spaceAfter(String in) {
@@ -29,10 +25,6 @@ static String spaceBefore(String in) {
2925
return " " + in; //$NON-NLS-1$
3026
}
3127

32-
static @Nullable String safelyUpperCase(@Nullable String s) {
33-
return s == null ? null : s.toUpperCase();
34-
}
35-
3628
static String toCamelCase(String inputString) {
3729
StringBuilder sb = new StringBuilder();
3830

@@ -62,7 +54,13 @@ static String formatConstantForSQL(String in) {
6254
return "'" + escaped + "'"; //$NON-NLS-1$ //$NON-NLS-2$
6355
}
6456

65-
static Function<String, String> mapToUpperCase(Function<String, String> f) {
66-
return f.andThen(String::toUpperCase);
57+
static <T> T upperCaseIfPossible(T value) {
58+
if (value instanceof String) {
59+
@SuppressWarnings("unchecked")
60+
T t = (T) ((String) value).toUpperCase();
61+
return t;
62+
}
63+
64+
return value;
6765
}
6866
}

src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java

+2-16
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public static <T> IsInCaseInsensitive<T> empty() {
3838
}
3939

4040
protected IsInCaseInsensitive(Collection<T> values) {
41-
super(values);
41+
super(values.stream().map(StringUtilities::upperCaseIfPossible).toList());
4242
}
4343

4444
@Override
@@ -57,19 +57,6 @@ public IsInCaseInsensitive<T> filter(Predicate<? super T> predicate) {
5757
return filterSupport(predicate, IsInCaseInsensitive::new, this, IsInCaseInsensitive::empty);
5858
}
5959

60-
/**
61-
* If renderable, apply the mapping to the value and return a new condition with the new value. Else return a
62-
* condition that will not render (this).
63-
*
64-
* <p>This function DOES NOT automatically transform values to uppercase, so it potentially creates a
65-
* case-sensitive query. For String conditions you can use {@link StringUtilities#mapToUpperCase(Function)}
66-
* to add an uppercase transform after your mapping function.
67-
*
68-
* @param mapper a mapping function to apply to the value, if renderable
69-
* @param <R> type of the new condition
70-
* @return a new condition with the result of applying the mapper to the value of this condition,
71-
* if renderable, otherwise a condition that will not render.
72-
*/
7360
@Override
7461
public <R> IsInCaseInsensitive<R> map(Function<? super T, ? extends R> mapper) {
7562
return mapSupport(mapper, IsInCaseInsensitive::new, IsInCaseInsensitive::empty);
@@ -80,7 +67,6 @@ public static IsInCaseInsensitive<String> of(String... values) {
8067
}
8168

8269
public static IsInCaseInsensitive<String> of(Collection<String> values) {
83-
// Keep the null safe upper case utility for backwards compatibility in case someone passes in a null
84-
return new IsInCaseInsensitive<>(values.stream().map(StringUtilities::safelyUpperCase).toList());
70+
return new IsInCaseInsensitive<>(values);
8571
}
8672
}

src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java

+2-16
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public static <T> IsInCaseInsensitiveWhenPresent<T> empty() {
3939
}
4040

4141
protected IsInCaseInsensitiveWhenPresent(Collection<T> values) {
42-
super(values);
42+
super(values.stream().filter(Objects::nonNull).map(StringUtilities::upperCaseIfPossible).toList());
4343
}
4444

4545
@Override
@@ -53,19 +53,6 @@ public IsInCaseInsensitiveWhenPresent<T> filter(Predicate<? super T> predicate)
5353
IsInCaseInsensitiveWhenPresent::empty);
5454
}
5555

56-
/**
57-
* If renderable, apply the mapping to the value and return a new condition with the new value. Else return a
58-
* condition that will not render (this).
59-
*
60-
* <p>This function DOES NOT automatically transform values to uppercase, so it potentially creates a
61-
* case-sensitive query. For String conditions you can use {@link StringUtilities#mapToUpperCase(Function)}
62-
* to add an uppercase transform after your mapping function.
63-
*
64-
* @param mapper a mapping function to apply to the value, if renderable
65-
* @param <R> type of the new condition
66-
* @return a new condition with the result of applying the mapper to the value of this condition,
67-
* if renderable, otherwise a condition that will not render.
68-
*/
6956
@Override
7057
public <R> IsInCaseInsensitiveWhenPresent<R> map(Function<? super T, ? extends R> mapper) {
7158
return mapSupport(mapper, IsInCaseInsensitiveWhenPresent::new, IsInCaseInsensitiveWhenPresent::empty);
@@ -76,7 +63,6 @@ public static IsInCaseInsensitiveWhenPresent<String> of(@Nullable String... valu
7663
}
7764

7865
public static IsInCaseInsensitiveWhenPresent<String> of(Collection<@Nullable String> values) {
79-
return new IsInCaseInsensitiveWhenPresent<>(
80-
values.stream().filter(Objects::nonNull).map(String::toUpperCase).toList());
66+
return new IsInCaseInsensitiveWhenPresent<>(values);
8167
}
8268
}

src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitive.java

+2-16
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public static <T> IsLikeCaseInsensitive<T> empty() {
4444
}
4545

4646
protected IsLikeCaseInsensitive(T value) {
47-
super(value);
47+
super(StringUtilities.upperCaseIfPossible(value));
4848
}
4949

5050
@Override
@@ -57,26 +57,12 @@ public IsLikeCaseInsensitive<T> filter(Predicate<? super T> predicate) {
5757
return filterSupport(predicate, IsLikeCaseInsensitive::empty, this);
5858
}
5959

60-
/**
61-
* If renderable, apply the mapping to the value and return a new condition with the new value. Else return a
62-
* condition that will not render (this).
63-
*
64-
* <p>This function DOES NOT automatically transform values to uppercase, so it potentially creates a
65-
* case-sensitive query. For String conditions you can use {@link StringUtilities#mapToUpperCase(Function)}
66-
* to add an uppercase transform after your mapping function.
67-
*
68-
* @param mapper a mapping function to apply to the value, if renderable
69-
* @param <R> type of the new condition
70-
* @return a new condition with the result of applying the mapper to the value of this condition,
71-
* if renderable, otherwise a condition that will not render.
72-
*/
7360
@Override
7461
public <R> IsLikeCaseInsensitive<R> map(Function<? super T, ? extends R> mapper) {
7562
return mapSupport(mapper, IsLikeCaseInsensitive::new, IsLikeCaseInsensitive::empty);
7663
}
7764

7865
public static IsLikeCaseInsensitive<String> of(String value) {
79-
// Keep the null safe upper case utility for backwards compatibility in case someone passes in a null
80-
return new IsLikeCaseInsensitive<>(StringUtilities.safelyUpperCase(value));
66+
return new IsLikeCaseInsensitive<>(value);
8167
}
8268
}

src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java

+2-16
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public static <T> IsNotInCaseInsensitive<T> empty() {
3838
}
3939

4040
protected IsNotInCaseInsensitive(Collection<T> values) {
41-
super(values);
41+
super(values.stream().map(StringUtilities::upperCaseIfPossible).toList());
4242
}
4343

4444
@Override
@@ -57,19 +57,6 @@ public IsNotInCaseInsensitive<T> filter(Predicate<? super T> predicate) {
5757
return filterSupport(predicate, IsNotInCaseInsensitive::new, this, IsNotInCaseInsensitive::empty);
5858
}
5959

60-
/**
61-
* If renderable, apply the mapping to the value and return a new condition with the new value. Else return a
62-
* condition that will not render (this).
63-
*
64-
* <p>This function DOES NOT automatically transform values to uppercase, so it potentially creates a
65-
* case-sensitive query. For String conditions you can use {@link StringUtilities#mapToUpperCase(Function)}
66-
* to add an uppercase transform after your mapping function.
67-
*
68-
* @param mapper a mapping function to apply to the value, if renderable
69-
* @param <R> type of the new condition
70-
* @return a new condition with the result of applying the mapper to the value of this condition,
71-
* if renderable, otherwise a condition that will not render.
72-
*/
7360
@Override
7461
public <R> IsNotInCaseInsensitive<R> map(Function<? super T, ? extends R> mapper) {
7562
return mapSupport(mapper, IsNotInCaseInsensitive::new, IsNotInCaseInsensitive::empty);
@@ -80,7 +67,6 @@ public static IsNotInCaseInsensitive<String> of(String... values) {
8067
}
8168

8269
public static IsNotInCaseInsensitive<String> of(Collection<String> values) {
83-
// Keep the null safe upper case utility for backwards compatibility in case someone passes in a null
84-
return new IsNotInCaseInsensitive<>(values.stream().map(StringUtilities::safelyUpperCase).toList());
70+
return new IsNotInCaseInsensitive<>(values);
8571
}
8672
}

src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java

+2-16
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public static <T> IsNotInCaseInsensitiveWhenPresent<T> empty() {
3939
}
4040

4141
protected IsNotInCaseInsensitiveWhenPresent(Collection<T> values) {
42-
super(values);
42+
super(values.stream().filter(Objects::nonNull).map(StringUtilities::upperCaseIfPossible).toList());
4343
}
4444

4545
@Override
@@ -53,19 +53,6 @@ public IsNotInCaseInsensitiveWhenPresent<T> filter(Predicate<? super T> predicat
5353
this, IsNotInCaseInsensitiveWhenPresent::empty);
5454
}
5555

56-
/**
57-
* If renderable, apply the mapping to the value and return a new condition with the new value. Else return a
58-
* condition that will not render (this).
59-
*
60-
* <p>This function DOES NOT automatically transform values to uppercase, so it potentially creates a
61-
* case-sensitive query. For String conditions you can use {@link StringUtilities#mapToUpperCase(Function)}
62-
* to add an uppercase transform after your mapping function.
63-
*
64-
* @param mapper a mapping function to apply to the value, if renderable
65-
* @param <R> type of the new condition
66-
* @return a new condition with the result of applying the mapper to the value of this condition,
67-
* if renderable, otherwise a condition that will not render.
68-
*/
6956
@Override
7057
public <R> IsNotInCaseInsensitiveWhenPresent<R> map(Function<? super T, ? extends R> mapper) {
7158
return mapSupport(mapper, IsNotInCaseInsensitiveWhenPresent::new, IsNotInCaseInsensitiveWhenPresent::empty);
@@ -76,7 +63,6 @@ public static IsNotInCaseInsensitiveWhenPresent<String> of(@Nullable String... v
7663
}
7764

7865
public static IsNotInCaseInsensitiveWhenPresent<String> of(Collection<@Nullable String> values) {
79-
return new IsNotInCaseInsensitiveWhenPresent<>(
80-
values.stream().filter(Objects::nonNull).map(String::toUpperCase).toList());
66+
return new IsNotInCaseInsensitiveWhenPresent<>(values);
8167
}
8268
}

src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitive.java

+2-16
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public static <T> IsNotLikeCaseInsensitive<T> empty() {
4444
}
4545

4646
protected IsNotLikeCaseInsensitive(T value) {
47-
super(value);
47+
super(StringUtilities.upperCaseIfPossible(value));
4848
}
4949

5050
@Override
@@ -57,26 +57,12 @@ public IsNotLikeCaseInsensitive<T> filter(Predicate<? super T> predicate) {
5757
return filterSupport(predicate, IsNotLikeCaseInsensitive::empty, this);
5858
}
5959

60-
/**
61-
* If renderable, apply the mapping to the value and return a new condition with the new value. Else return a
62-
* condition that will not render (this).
63-
*
64-
* <p>This function DOES NOT automatically transform values to uppercase, so it potentially creates a
65-
* case-sensitive query. For String conditions you can use {@link StringUtilities#mapToUpperCase(Function)}
66-
* to add an uppercase transform after your mapping function.
67-
*
68-
* @param mapper a mapping function to apply to the value, if renderable
69-
* @param <R> type of the new condition
70-
* @return a new condition with the result of applying the mapper to the value of this condition,
71-
* if renderable, otherwise a condition that will not render.
72-
*/
7360
@Override
7461
public <R> IsNotLikeCaseInsensitive<R> map(Function<? super T, ? extends R> mapper) {
7562
return mapSupport(mapper, IsNotLikeCaseInsensitive::new, IsNotLikeCaseInsensitive::empty);
7663
}
7764

7865
public static IsNotLikeCaseInsensitive<String> of(String value) {
79-
// Keep the null safe upper case utility for backwards compatibility in case someone passes in a null
80-
return new IsNotLikeCaseInsensitive<>(StringUtilities.safelyUpperCase(value));
66+
return new IsNotLikeCaseInsensitive<>(value);
8167
}
8268
}

src/test/java/org/mybatis/dynamic/sql/util/StringUtilitiesTest.java

+12
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,16 @@ void testNumeric() {
3838
String input = "USER%NAME%3";
3939
assertThat(StringUtilities.toCamelCase(input)).isEqualTo("userName3");
4040
}
41+
42+
@Test
43+
void testUpperCaseInteger() {
44+
Integer i = StringUtilities.upperCaseIfPossible(3);
45+
assertThat(i).isEqualTo(3);
46+
}
47+
48+
@Test
49+
void testUpperCaseString() {
50+
String i = StringUtilities.upperCaseIfPossible("fred");
51+
assertThat(i).isEqualTo("FRED");
52+
}
4153
}

src/test/java/org/mybatis/dynamic/sql/where/condition/FilterAndMapTest.java

+2-17
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424

2525
import org.junit.jupiter.api.Test;
2626
import org.mybatis.dynamic.sql.SqlBuilder;
27-
import org.mybatis.dynamic.sql.util.StringUtilities;
2827

2928
class FilterAndMapTest {
3029
@Test
@@ -543,31 +542,17 @@ void testMappingAnEmptyListCondition() {
543542
assertThat(filtered).isSameAs(mapped);
544543
}
545544

546-
@Test
547-
void testIsInCaseInsensitiveWhenPresentMap() {
548-
var cond = SqlBuilder.isInCaseInsensitiveWhenPresent("Fred", "Wilma");
549-
var mapped = cond.map(s -> s + " Flintstone");
550-
assertThat(mapped.values().toList()).containsExactly("FRED Flintstone", "WILMA Flintstone");
551-
}
552-
553545
@Test
554546
void testIsInCaseInsensitiveWhenPresentMapCaseInsensitive() {
555547
var cond = SqlBuilder.isInCaseInsensitiveWhenPresent("Fred", "Wilma");
556-
var mapped = cond.map(StringUtilities.mapToUpperCase(s -> s + " Flintstone"));
557-
assertThat(mapped.values().toList()).containsExactly("FRED FLINTSTONE", "WILMA FLINTSTONE");
558-
}
559-
560-
@Test
561-
void testIsNotInCaseInsensitiveWhenPresentMap() {
562-
var cond = SqlBuilder.isNotInCaseInsensitiveWhenPresent("Fred", "Wilma");
563548
var mapped = cond.map(s -> s + " Flintstone");
564-
assertThat(mapped.values().toList()).containsExactly("FRED Flintstone", "WILMA Flintstone");
549+
assertThat(mapped.values().toList()).containsExactly("FRED FLINTSTONE", "WILMA FLINTSTONE");
565550
}
566551

567552
@Test
568553
void testIsNotInCaseInsensitiveWhenPresentMapCaseInsensitive() {
569554
var cond = SqlBuilder.isNotInCaseInsensitiveWhenPresent("Fred", "Wilma");
570-
var mapped = cond.map(StringUtilities.mapToUpperCase(s -> s + " Flintstone"));
555+
var mapped = cond.map(s -> s + " Flintstone");
571556
assertThat(mapped.values().toList()).containsExactly("FRED FLINTSTONE", "WILMA FLINTSTONE");
572557
}
573558
}

0 commit comments

Comments
 (0)