Browse Source

DATAMONGO-2072 - Support Range in repository between queries.

We now support o.s.d.domain.Range as method parameter for between queries. This allows more fine grained control over the inclusion/exclusion of the upper/lower bounds. Up till now between required 2 parameters which had been strictly bound to excluding bounds using $gt and $lt.

Original pull request: #645.
pull/651/head
Christoph Strobl 7 years ago committed by Mark Paluch
parent
commit
5b47648f49
  1. 48
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoQueryCreator.java
  2. 11
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/MongoQueryCreatorUnitTests.java
  3. 6
      src/main/asciidoc/reference/mongo-repositories.adoc

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

@ -26,6 +26,7 @@ import java.util.regex.Pattern;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Range; import org.springframework.data.domain.Range;
import org.springframework.data.domain.Range.Bound;
import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort;
import org.springframework.data.geo.Distance; import org.springframework.data.geo.Distance;
import org.springframework.data.geo.Metrics; import org.springframework.data.geo.Metrics;
@ -42,7 +43,6 @@ import org.springframework.data.mongodb.core.query.CriteriaDefinition;
import org.springframework.data.mongodb.core.query.MongoRegexCreator; import org.springframework.data.mongodb.core.query.MongoRegexCreator;
import org.springframework.data.mongodb.core.query.MongoRegexCreator.MatchMode; import org.springframework.data.mongodb.core.query.MongoRegexCreator.MatchMode;
import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.repository.query.ConvertingParameterAccessor.PotentiallyConvertingIterator;
import org.springframework.data.repository.query.parser.AbstractQueryCreator; import org.springframework.data.repository.query.parser.AbstractQueryCreator;
import org.springframework.data.repository.query.parser.Part; import org.springframework.data.repository.query.parser.Part;
import org.springframework.data.repository.query.parser.Part.IgnoreCaseType; import org.springframework.data.repository.query.parser.Part.IgnoreCaseType;
@ -187,7 +187,7 @@ class MongoQueryCreator extends AbstractQueryCreator<Query, Criteria> {
case LESS_THAN_EQUAL: case LESS_THAN_EQUAL:
return criteria.lte(parameters.next()); return criteria.lte(parameters.next());
case BETWEEN: case BETWEEN:
return criteria.gt(parameters.next()).lt(parameters.next()); return computeBetweenPart(criteria, parameters.next(), parameters);
case IS_NOT_NULL: case IS_NOT_NULL:
return criteria.ne(null); return criteria.ne(null);
case IS_NULL: case IS_NULL:
@ -418,6 +418,50 @@ class MongoQueryCreator extends AbstractQueryCreator<Query, Criteria> {
return false; return false;
} }
/**
* Compute a {@link Type#BETWEEN} typed {@link Part} using {@link Criteria#gt(Object) $gt},
* {@link Criteria#gte(Object) $gte}, {@link Criteria#lt(Object) $lt} and {@link Criteria#lte(Object) $lte}. <br />
* In case the given {@literal value} is actually a {@link Range} the lower and upper bounds of the {@link Range} are
* used according to their {@link Bound#isInclusive() inclusion} definition. Otherwise the {@literal value} is used
* for {@literal $gt} and {@link Iterator#next() parameters.next()} as {@literal $lt}.
*
* @param criteria must not be {@literal null}.
* @param value current value. Must not be {@literal null}.
* @param parameters must not be {@literal null}.
* @return
* @since 2.2
*/
private static Criteria computeBetweenPart(Criteria criteria, Object value, Iterator<Object> parameters) {
if (!(value instanceof Range)) {
return criteria.gt(value).lt(parameters.next());
}
Range<?> range = (Range<?>) value;
Optional<?> min = range.getLowerBound().getValue();
Optional<?> max = range.getUpperBound().getValue();
min.ifPresent(it -> {
if (range.getLowerBound().isInclusive()) {
criteria.gte(it);
} else {
criteria.gt(it);
}
});
max.ifPresent(it -> {
if (range.getUpperBound().isInclusive()) {
criteria.lte(it);
} else {
criteria.lt(it);
}
});
return criteria;
}
private static MatchMode toMatchMode(Type type) { private static MatchMode toMatchMode(Type type) {
switch (type) { switch (type) {

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

@ -32,6 +32,7 @@ import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.rules.ExpectedException; import org.junit.rules.ExpectedException;
import org.springframework.data.domain.Range; import org.springframework.data.domain.Range;
import org.springframework.data.domain.Range.Bound;
import org.springframework.data.geo.Distance; import org.springframework.data.geo.Distance;
import org.springframework.data.geo.Metrics; import org.springframework.data.geo.Metrics;
import org.springframework.data.geo.Point; import org.springframework.data.geo.Point;
@ -648,6 +649,16 @@ public class MongoQueryCreatorUnitTests {
assertThat(creator.createQuery()).isEqualTo(query(where("firstName").regex(".*", "iu"))); assertThat(creator.createQuery()).isEqualTo(query(where("firstName").regex(".*", "iu")));
} }
@Test // DATAMONGO-2071
public void betweenShouldAllowSingleRageParameter() {
PartTree tree = new PartTree("findByAgeBetween", Person.class);
MongoQueryCreator creator = new MongoQueryCreator(tree,
getAccessor(converter, Range.of(Bound.exclusive(10), Bound.exclusive(11))), context);
assertThat(creator.createQuery()).isEqualTo(query(where("age").gt(10).lt(11)));
}
interface PersonRepository extends Repository<Person, Long> { interface PersonRepository extends Repository<Person, Long> {
List<Person> findByLocationNearAndFirstname(Point location, Distance maxDistance, String firstname); List<Person> findByLocationNearAndFirstname(Point location, Distance maxDistance, String firstname);

6
src/main/asciidoc/reference/mongo-repositories.adoc

@ -188,8 +188,10 @@ The following table shows the keywords that are supported for query methods:
| `{"age" : {"$lte" : age}}` | `{"age" : {"$lte" : age}}`
| `Between` | `Between`
| `findByAgeBetween(int from, int to)` | `findByAgeBetween(int from, int to)` +
| `{"age" : {"$gt" : from, "$lt" : to}}` `findByAgeBetween(Range<Integer> range)`
| `{"age" : {"$gt" : from, "$lt" : to}}` +
lower / upper bounds (`$gt` / `$gte` & `$lt` / `$lte`) according to `Range`
| `In` | `In`
| `findByAgeIn(Collection ages)` | `findByAgeIn(Collection ages)`

Loading…
Cancel
Save