diff --git a/pom.xml b/pom.xml index 3a9b4f5ad7..440481c7a6 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.data spring-data-mongodb-parent - 1.10.0.BUILD-SNAPSHOT + 1.10.0.DATAMONGO-1424-SNAPSHOT pom Spring Data MongoDB diff --git a/spring-data-mongodb-cross-store/pom.xml b/spring-data-mongodb-cross-store/pom.xml index 6554045e11..44ba44be83 100644 --- a/spring-data-mongodb-cross-store/pom.xml +++ b/spring-data-mongodb-cross-store/pom.xml @@ -6,7 +6,7 @@ org.springframework.data spring-data-mongodb-parent - 1.10.0.BUILD-SNAPSHOT + 1.10.0.DATAMONGO-1424-SNAPSHOT ../pom.xml @@ -48,7 +48,7 @@ org.springframework.data spring-data-mongodb - 1.10.0.BUILD-SNAPSHOT + 1.10.0.DATAMONGO-1424-SNAPSHOT diff --git a/spring-data-mongodb-distribution/pom.xml b/spring-data-mongodb-distribution/pom.xml index 2d02722262..08ce7695e4 100644 --- a/spring-data-mongodb-distribution/pom.xml +++ b/spring-data-mongodb-distribution/pom.xml @@ -13,7 +13,7 @@ org.springframework.data spring-data-mongodb-parent - 1.10.0.BUILD-SNAPSHOT + 1.10.0.DATAMONGO-1424-SNAPSHOT ../pom.xml diff --git a/spring-data-mongodb-log4j/pom.xml b/spring-data-mongodb-log4j/pom.xml index ee5e3336db..474aa28ff1 100644 --- a/spring-data-mongodb-log4j/pom.xml +++ b/spring-data-mongodb-log4j/pom.xml @@ -5,7 +5,7 @@ org.springframework.data spring-data-mongodb-parent - 1.10.0.BUILD-SNAPSHOT + 1.10.0.DATAMONGO-1424-SNAPSHOT ../pom.xml diff --git a/spring-data-mongodb/pom.xml b/spring-data-mongodb/pom.xml index edfa519fad..6667b6ba27 100644 --- a/spring-data-mongodb/pom.xml +++ b/spring-data-mongodb/pom.xml @@ -11,7 +11,7 @@ org.springframework.data spring-data-mongodb-parent - 1.10.0.BUILD-SNAPSHOT + 1.10.0.DATAMONGO-1424-SNAPSHOT ../pom.xml diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/MongoRegexCreator.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/MongoRegexCreator.java index a1d85dff99..f3298a8af4 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/MongoRegexCreator.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/MongoRegexCreator.java @@ -72,7 +72,7 @@ private String prepareAndEscapeStringBeforeApplyingLikeRegex(String source, Type return source; } - if (!ObjectUtils.nullSafeEquals(Type.LIKE, type)) { + if (!ObjectUtils.nullSafeEquals(Type.LIKE, type) && !ObjectUtils.nullSafeEquals(Type.NOT_LIKE, type)) { return PUNCTATION_PATTERN.matcher(source).find() ? Pattern.quote(source) : source; } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoQueryCreator.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoQueryCreator.java index 083b778d7e..13170e1579 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoQueryCreator.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoQueryCreator.java @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 the original author or authors. + * Copyright 2010-2016 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. @@ -199,6 +199,8 @@ private Criteria from(Part part, MongoPersistentProperty property, Criteria crit case ENDING_WITH: case CONTAINING: return createContainingCriteria(part, property, criteria, parameters); + case NOT_LIKE: + return createContainingCriteria(part, property, criteria.not(), parameters); case NOT_CONTAINING: return createContainingCriteria(part, property, criteria, parameters).not(); case REGEX: diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/AbstractPersonRepositoryIntegrationTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/AbstractPersonRepositoryIntegrationTests.java index b924d81883..f34c37d821 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/AbstractPersonRepositoryIntegrationTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/AbstractPersonRepositoryIntegrationTests.java @@ -1261,4 +1261,14 @@ public void findAllByExampleShouldResolveStuffCorrectly() { assertThat(result.size(), is(2)); } + /** + * @see DATAMONGO-1424 + */ + @Test + public void findsPersonsByFirstnameNotLike() throws Exception { + + List result = repository.findByFirstnameNotLike("Bo*"); + assertThat(result.size(), is((int) (repository.count() - 1))); + assertThat(result, not(hasItem(boyd))); + } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/PersonRepository.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/PersonRepository.java index eae2c02e10..061b5ac9c1 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/PersonRepository.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/PersonRepository.java @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 the original author or authors. + * Copyright 2010-2016 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. @@ -89,6 +89,14 @@ public interface PersonRepository extends MongoRepository, Query */ List findByFirstnameLike(String firstname); + /** + * Returns all {@link Person}s with a firstname not matching the given one (*-wildcard supported). + * + * @param firstname + * @return + */ + List findByFirstnameNotLike(String firstname); + List findByFirstnameLikeOrderByLastnameAsc(String firstname, Sort sort); @Query("{'age' : { '$lt' : ?0 } }") diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/MongoQueryCreatorUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/MongoQueryCreatorUnitTests.java index 9780f32be9..a1d1c08fc3 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/MongoQueryCreatorUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/MongoQueryCreatorUnitTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2015 the original author or authors. + * Copyright 2011-2016 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. @@ -668,6 +668,62 @@ public void bindsNullValueToContainsClause() { assertThat(query, is(query(where("emailAddresses").in((Object) null)))); } + /** + * @see DATAMONGO-1424 + */ + @Test + public void notLikeShouldEscapeSourceWhenUsedWithLeadingAndTrailingWildcard() { + + PartTree tree = new PartTree("findByUsernameNotLike", User.class); + ConvertingParameterAccessor accessor = getAccessor(converter, "*fire.fight+*"); + + Query query = new MongoQueryCreator(tree, accessor, context).createQuery(); + + assertThat(query.getQueryObject(), + is(query(where("username").not().regex(".*\\Qfire.fight+\\E.*")).getQueryObject())); + } + + /** + * @see DATAMONGO-1424 + */ + @Test + public void notLikeShouldEscapeSourceWhenUsedWithLeadingWildcard() { + + PartTree tree = new PartTree("findByUsernameNotLike", User.class); + ConvertingParameterAccessor accessor = getAccessor(converter, "*steel.heart+"); + + Query query = new MongoQueryCreator(tree, accessor, context).createQuery(); + + assertThat(query.getQueryObject(), + is(query(where("username").not().regex(".*\\Qsteel.heart+\\E")).getQueryObject())); + } + + /** + * @see DATAMONGO-1424 + */ + @Test + public void notLikeShouldEscapeSourceWhenUsedWithTrailingWildcard() { + + PartTree tree = new PartTree("findByUsernameNotLike", User.class); + MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter, "cala.mity+*"), context); + Query query = creator.createQuery(); + + assertThat(query.getQueryObject(), is(query(where("username").not().regex("\\Qcala.mity+\\E.*")).getQueryObject())); + } + + /** + * @see DATAMONGO-1424 + */ + @Test + public void notLikeShouldBeTreatedCorrectlyWhenUsedWithWildcardOnly() { + + PartTree tree = new PartTree("findByUsernameNotLike", User.class); + ConvertingParameterAccessor accessor = getAccessor(converter, "*"); + + Query query = new MongoQueryCreator(tree, accessor, context).createQuery(); + assertThat(query.getQueryObject(), is(query(where("username").not().regex(".*")).getQueryObject())); + } + interface PersonRepository extends Repository { List findByLocationNearAndFirstname(Point location, Distance maxDistance, String firstname); diff --git a/src/main/asciidoc/reference/mongo-repositories.adoc b/src/main/asciidoc/reference/mongo-repositories.adoc index d78880fcff..1ceadd7afd 100644 --- a/src/main/asciidoc/reference/mongo-repositories.adoc +++ b/src/main/asciidoc/reference/mongo-repositories.adoc @@ -208,6 +208,10 @@ NOTE: Note that for version 1.0 we currently don't support referring to paramete | `findByFirstnameLike(String name)` | `{"firstname" : name} ( name as regex)` +| `NotLike`, `IsNotLike`, `EndingWith` +| `findByFirstnameNotLike(String name)` +| `{"firstname" : { "$not" : name }} ( name as regex)` + | `Containing` on String | `findByFirstnameContaining(String name)` | `{"firstname" : name} (name as regex)`