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 a1d85dff9..f3298a8af 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 @@ public enum MongoRegexCreator { 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 315ac7a80..9c5de69ae 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 @@ class MongoQueryCreator extends AbstractQueryCreator { 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.not(), parameters); 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 ae2c22e5b..bdd9a1eca 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 @@ -1296,4 +1296,15 @@ public abstract class AbstractPersonRepositoryIntegrationTests { assertThat(result, not(hasItem(carter))); } + /* + * @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 6874dc62f..f9f2f1fbb 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. @@ -91,6 +91,14 @@ public interface PersonRepository extends MongoRepository, Query List findByFirstnameNotContains(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); List findBySkillsContains(List skills); 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 2fe220b73..71dc7316b 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. @@ -669,6 +669,62 @@ public class MongoQueryCreatorUnitTests { 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 e484731b7..eaf2697d7 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)`