Browse Source

DATAMONGO-2030 - Reinstantiate existsBy queries for reactive repositories.

We now support existsBy queries for reactive repositories to align with blocking repository support. ExistsBy support got lost during merging and is now back in place.

Extract boolean flag counting into BooleanUtil.
pull/590/head
Mark Paluch 8 years ago
parent
commit
8b8eb3cfe5
  1. 13
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AbstractReactiveMongoQuery.java
  2. 48
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/BooleanUtil.java
  3. 9
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/ReactivePartTreeMongoQuery.java
  4. 38
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/ReactiveStringBasedMongoQuery.java
  5. 20
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/StringBasedMongoQuery.java
  6. 7
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/ReactiveMongoRepositoryTests.java
  7. 11
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/ReactiveStringBasedMongoQueryUnitTests.java

13
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AbstractReactiveMongoQuery.java

@ -15,10 +15,10 @@ @@ -15,10 +15,10 @@
*/
package org.springframework.data.mongodb.repository.query;
import org.bson.Document;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.bson.Document;
import org.reactivestreams.Publisher;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.convert.EntityInstantiators;
@ -36,7 +36,6 @@ import org.springframework.data.mongodb.repository.query.ReactiveMongoQueryExecu @@ -36,7 +36,6 @@ import org.springframework.data.mongodb.repository.query.ReactiveMongoQueryExecu
import org.springframework.data.repository.query.ParameterAccessor;
import org.springframework.data.repository.query.RepositoryQuery;
import org.springframework.data.repository.query.ResultProcessor;
import org.springframework.data.repository.query.ReturnedType;
import org.springframework.util.Assert;
/**
@ -152,6 +151,8 @@ public abstract class AbstractReactiveMongoQuery implements RepositoryQuery { @@ -152,6 +151,8 @@ public abstract class AbstractReactiveMongoQuery implements RepositoryQuery {
return (q, t, c) -> operation.matching(q.with(accessor.getPageable())).all();
} else if (isCountQuery()) {
return (q, t, c) -> operation.matching(q).count();
} else if (isExistsQuery()) {
return (q, t, c) -> operation.matching(q).exists();
} else {
return (q, t, c) -> {
@ -223,6 +224,14 @@ public abstract class AbstractReactiveMongoQuery implements RepositoryQuery { @@ -223,6 +224,14 @@ public abstract class AbstractReactiveMongoQuery implements RepositoryQuery {
*/
protected abstract boolean isCountQuery();
/**
* Returns whether the query should get an exists projection applied.
*
* @return
* @since 2.0.9
*/
protected abstract boolean isExistsQuery();
/**
* Return weather the query should delete matching documents.
*

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

@ -0,0 +1,48 @@ @@ -0,0 +1,48 @@
/*
* Copyright 2018 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mongodb.repository.query;
import lombok.experimental.UtilityClass;
/**
* Utility class containing methods to interact with boolean values.
*
* @author Mark Paluch
* @since 2.0.9
*/
@UtilityClass
class BooleanUtil {
/**
* Count the number of {@literal true} values.
*
* @param values
* @return the number of values that are {@literal true}.
*/
static int countBooleanTrueValues(boolean... values) {
int count = 0;
for (boolean value : values) {
if (value) {
count++;
}
}
return count;
}
}

9
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/ReactivePartTreeMongoQuery.java

@ -134,6 +134,15 @@ public class ReactivePartTreeMongoQuery extends AbstractReactiveMongoQuery { @@ -134,6 +134,15 @@ public class ReactivePartTreeMongoQuery extends AbstractReactiveMongoQuery {
return tree.isCountProjection();
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.repository.query.AbstractReactiveMongoQuery#isExistsQuery()
*/
@Override
protected boolean isExistsQuery() {
return tree.isExistsProjection();
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.repository.query.AbstractReactiveMongoQuery#isDeleteQuery()

38
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/ReactiveStringBasedMongoQuery.java

@ -28,7 +28,6 @@ import org.springframework.data.mongodb.repository.query.ExpressionEvaluatingPar @@ -28,7 +28,6 @@ import org.springframework.data.mongodb.repository.query.ExpressionEvaluatingPar
import org.springframework.data.mongodb.repository.query.StringBasedMongoQuery.ParameterBinding;
import org.springframework.data.mongodb.repository.query.StringBasedMongoQuery.ParameterBindingParser;
import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
import org.springframework.data.spel.EvaluationContextProvider;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.util.Assert;
@ -41,13 +40,14 @@ import org.springframework.util.Assert; @@ -41,13 +40,14 @@ import org.springframework.util.Assert;
*/
public class ReactiveStringBasedMongoQuery extends AbstractReactiveMongoQuery {
private static final String COUND_AND_DELETE = "Manually defined query for %s cannot be both a count and delete query at the same time!";
private static final String COUNT_EXISTS_AND_DELETE = "Manually defined query for %s cannot be a count and exists or delete query at the same time!";
private static final Logger LOG = LoggerFactory.getLogger(ReactiveStringBasedMongoQuery.class);
private static final ParameterBindingParser BINDING_PARSER = ParameterBindingParser.INSTANCE;
private final String query;
private final String fieldSpec;
private final boolean isCountQuery;
private final boolean isExistsQuery;
private final boolean isDeleteQuery;
private final List<ParameterBinding> queryParameterBindings;
private final List<ParameterBinding> fieldSpecParameterBindings;
@ -93,11 +93,23 @@ public class ReactiveStringBasedMongoQuery extends AbstractReactiveMongoQuery { @@ -93,11 +93,23 @@ public class ReactiveStringBasedMongoQuery extends AbstractReactiveMongoQuery {
this.fieldSpec = BINDING_PARSER.parseAndCollectParameterBindingsFromQueryIntoBindings(
method.getFieldSpecification(), this.fieldSpecParameterBindings);
this.isCountQuery = method.hasAnnotatedQuery() ? method.getQueryAnnotation().count() : false;
this.isDeleteQuery = method.hasAnnotatedQuery() ? method.getQueryAnnotation().delete() : false;
if (method.hasAnnotatedQuery()) {
if (isCountQuery && isDeleteQuery) {
throw new IllegalArgumentException(String.format(COUND_AND_DELETE, method));
org.springframework.data.mongodb.repository.Query queryAnnotation = method.getQueryAnnotation();
this.isCountQuery = queryAnnotation.count();
this.isExistsQuery = queryAnnotation.exists();
this.isDeleteQuery = queryAnnotation.delete();
if (hasAmbiguousProjectionFlags(this.isCountQuery, this.isExistsQuery, this.isDeleteQuery)) {
throw new IllegalArgumentException(String.format(COUNT_EXISTS_AND_DELETE, method));
}
} else {
this.isCountQuery = false;
this.isExistsQuery = false;
this.isDeleteQuery = false;
}
this.parameterBinder = new ExpressionEvaluatingParameterBinder(expressionParser, evaluationContextProvider);
@ -133,6 +145,15 @@ public class ReactiveStringBasedMongoQuery extends AbstractReactiveMongoQuery { @@ -133,6 +145,15 @@ public class ReactiveStringBasedMongoQuery extends AbstractReactiveMongoQuery {
return isCountQuery;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.repository.query.AbstractReactiveMongoQuery#isExistsQuery()
*/
@Override
protected boolean isExistsQuery() {
return isExistsQuery;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.repository.query.AbstractReactiveMongoQuery#isDeleteQuery()
@ -151,4 +172,9 @@ public class ReactiveStringBasedMongoQuery extends AbstractReactiveMongoQuery { @@ -151,4 +172,9 @@ public class ReactiveStringBasedMongoQuery extends AbstractReactiveMongoQuery {
return false;
}
private static boolean hasAmbiguousProjectionFlags(boolean isCountQuery, boolean isExistsQuery,
boolean isDeleteQuery) {
return BooleanUtil.countBooleanTrueValues(isCountQuery, isExistsQuery, isDeleteQuery) > 1;
}
}

20
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/StringBasedMongoQuery.java

@ -170,11 +170,6 @@ public class StringBasedMongoQuery extends AbstractMongoQuery { @@ -170,11 +170,6 @@ public class StringBasedMongoQuery extends AbstractMongoQuery {
return this.isDeleteQuery;
}
private static boolean hasAmbiguousProjectionFlags(boolean isCountQuery, boolean isExistsQuery,
boolean isDeleteQuery) {
return countBooleanValues(isCountQuery, isExistsQuery, isDeleteQuery) > 1;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.repository.query.AbstractMongoQuery#isLimiting()
@ -184,18 +179,9 @@ public class StringBasedMongoQuery extends AbstractMongoQuery { @@ -184,18 +179,9 @@ public class StringBasedMongoQuery extends AbstractMongoQuery {
return false;
}
private static int countBooleanValues(boolean... values) {
int count = 0;
for (boolean value : values) {
if (value) {
count++;
}
}
return count;
private static boolean hasAmbiguousProjectionFlags(boolean isCountQuery, boolean isExistsQuery,
boolean isDeleteQuery) {
return BooleanUtil.countBooleanTrueValues(isCountQuery, isExistsQuery, isDeleteQuery) > 1;
}
/**

7
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/ReactiveMongoRepositoryTests.java

@ -309,6 +309,11 @@ public class ReactiveMongoRepositoryTests implements BeanClassLoaderAware, BeanF @@ -309,6 +309,11 @@ public class ReactiveMongoRepositoryTests implements BeanClassLoaderAware, BeanF
StepVerifier.create(repository.findFirstByLastname(dave.getLastname())).expectNextCount(1).verifyComplete();
}
@Test // DATAMONGO-2030
public void shouldReturnExistsBy() {
StepVerifier.create(repository.existsByLastname(dave.getLastname())).expectNext(true).verifyComplete();
}
@Test // DATAMONGO-1979
public void findAppliesAnnotatedSort() {
@ -353,6 +358,8 @@ public class ReactiveMongoRepositoryTests implements BeanClassLoaderAware, BeanF @@ -353,6 +358,8 @@ public class ReactiveMongoRepositoryTests implements BeanClassLoaderAware, BeanF
Flux<Person> findPersonByLocationNear(Point point, Distance maxDistance);
Mono<Boolean> existsByLastname(String lastname);
Mono<Person> findFirstByLastname(String lastname);
@Query(sort = "{ age : -1 }")

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

@ -122,6 +122,14 @@ public class ReactiveStringBasedMongoQueryUnitTests { @@ -122,6 +122,14 @@ public class ReactiveStringBasedMongoQueryUnitTests {
createQueryForMethod("invalidMethod", String.class);
}
@Test // DATAMONGO-2030
public void shouldSupportExistsProjection() throws Exception {
ReactiveStringBasedMongoQuery mongoQuery = createQueryForMethod("existsByLastname", String.class);
assertThat(mongoQuery.isExistsQuery(), is(true));
}
@Test // DATAMONGO-1444
public void shouldSupportFindByParameterizedCriteriaAndFields() throws Exception {
@ -260,5 +268,8 @@ public class ReactiveStringBasedMongoQueryUnitTests { @@ -260,5 +268,8 @@ public class ReactiveStringBasedMongoQueryUnitTests {
@Query("{'id':?#{ [0] ? { $exists :true} : [1] }, 'foo':42, 'bar': ?#{ [0] ? { $exists :false} : [1] }}")
Flux<Person> findByQueryWithExpressionAndMultipleNestedObjects(boolean param0, String param1, String param2);
@Query(value = "{ 'lastname' : ?0 }", exists = true)
Mono<Boolean> existsByLastname(String lastname);
}
}

Loading…
Cancel
Save