Browse Source

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
3.4.x
Christoph Strobl 3 years ago committed by Mark Paluch
parent
commit
746199fb28
No known key found for this signature in database
GPG Key ID: 4406B84C1661DCD1
  1. 2
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/MongoRegexCreator.java
  2. 16
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoQueryCreator.java
  3. 9
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/AbstractPersonRepositoryIntegrationTests.java
  4. 12
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/MongoQueryCreatorUnitTests.java

2
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/MongoRegexCreator.java

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

16
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoQueryCreator.java

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

9
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/AbstractPersonRepositoryIntegrationTests.java

@ -1451,9 +1451,16 @@ public abstract class AbstractPersonRepositoryIntegrationTests implements Dirtie
assertThat(result.get(0).getId().equals(bart.getId())); assertThat(result.get(0).getId().equals(bart.getId()));
} }
@Test // GH-3395 @Test // GH-3395, GH-4404
void caseInSensitiveInClause() { void caseInSensitiveInClause() {
assertThat(repository.findByLastnameIgnoreCaseIn("bEAuFoRd", "maTTheWs")).hasSize(3); 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 @Test // GH-3395

12
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/MongoQueryCreatorUnitTests.java

@ -25,6 +25,7 @@ import java.lang.reflect.Method;
import java.util.List; import java.util.List;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.bson.BsonRegularExpression;
import org.bson.Document; import org.bson.Document;
import org.bson.types.ObjectId; import org.bson.types.ObjectId;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
@ -277,6 +278,17 @@ class MongoQueryCreatorUnitTests {
assertThat(query).isEqualTo(query(where("firstName").regex("^dave$", "i"))); 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 @Test // DATAMONGO-770
void createsQueryWithFindByNotIgnoreCaseCorrectly() { void createsQueryWithFindByNotIgnoreCaseCorrectly() {

Loading…
Cancel
Save