Use exact matching for IN clause with ignore case.

Prior to this change the generated pattern would have matched more entries than it should have. The behavior is now aligned to its counterpart not using the IgnoreCase flag.

Closes #4404
Original pull request: #4412
This commit is contained in:
Christoph Strobl
2023-06-13 08:26:43 +02:00
committed by Mark Paluch
parent 7e6e029352
commit d6227e52f9
4 changed files with 36 additions and 3 deletions

View File

@@ -107,7 +107,9 @@ public enum MongoRegexCreator {
* @param source
* @return
* @since 2.2.14
* @deprecated since 4.1.1
*/
@Deprecated(since = "4.1.1", forRemoval = true)
public Object toCaseInsensitiveMatch(Object source) {
return source instanceof String stringValue ? new BsonRegularExpression(Pattern.quote(stringValue), "i") : source;
}

View File

@@ -25,7 +25,7 @@ import java.util.regex.Pattern;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.bson.BsonRegularExpression;
import org.springframework.data.domain.Range;
import org.springframework.data.domain.Range.Bound;
import org.springframework.data.domain.Sort;
@@ -390,7 +390,18 @@ class MongoQueryCreator extends AbstractQueryCreator<Query, Criteria> {
Streamable<?> streamable = asStreamable(iterator.next());
if (!isSimpleComparisionPossible(part)) {
streamable = streamable.map(MongoRegexCreator.INSTANCE::toCaseInsensitiveMatch);
MatchMode matchMode = toMatchMode(part.getType());
String regexOptions = toRegexOptions(part);
streamable = streamable.map(it -> {
if (it instanceof String value) {
return new BsonRegularExpression(MongoRegexCreator.INSTANCE.toRegularExpression(value, matchMode),
regexOptions);
}
return it;
});
}
return streamable.toList();
@@ -481,6 +492,7 @@ class MongoQueryCreator extends AbstractQueryCreator<Query, Criteria> {
return MatchMode.REGEX;
case NEGATING_SIMPLE_PROPERTY:
case SIMPLE_PROPERTY:
case IN:
return MatchMode.EXACT;
default:
return MatchMode.DEFAULT;

View File

@@ -1510,9 +1510,16 @@ public abstract class AbstractPersonRepositoryIntegrationTests implements Dirtie
assertThat(result.get(0).getId().equals(bart.getId()));
}
@Test // GH-3395
@Test // GH-3395, GH-4404
void caseInSensitiveInClause() {
assertThat(repository.findByLastnameIgnoreCaseIn("bEAuFoRd", "maTTheWs")).hasSize(3);
repository.save(new Person("the-first", "The First"));
repository.save(new Person("the-first-one", "The First One"));
repository.save(new Person("the-second", "The Second"));
assertThat(repository.findByLastnameIgnoreCaseIn("tHE fIRsT")).hasSize(1);
}
@Test // GH-3395

View File

@@ -25,6 +25,7 @@ import java.lang.reflect.Method;
import java.util.List;
import java.util.regex.Pattern;
import org.bson.BsonRegularExpression;
import org.bson.Document;
import org.bson.types.ObjectId;
import org.junit.jupiter.api.BeforeEach;
@@ -273,6 +274,17 @@ class MongoQueryCreatorUnitTests {
assertThat(query).isEqualTo(query(where("firstName").regex("^dave$", "i")));
}
@Test // GH-4404
void createsQueryWithFindByInClauseHavingIgnoreCaseCorrectly() {
PartTree tree = new PartTree("findAllByFirstNameInIgnoreCase", Person.class);
MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter, List.of("da've", "carter")), context);
Query query = creator.createQuery();
assertThat(query).isEqualTo(query(where("firstName")
.in(List.of(new BsonRegularExpression("^\\Qda've\\E$", "i"), new BsonRegularExpression("^carter$", "i")))));
}
@Test // DATAMONGO-770
void createsQueryWithFindByNotIgnoreCaseCorrectly() {