diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/QuerydslMongoPredicateExecutor.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/QuerydslMongoPredicateExecutor.java index 7e8bffc4f..08961f17b 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/QuerydslMongoPredicateExecutor.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/QuerydslMongoPredicateExecutor.java @@ -22,23 +22,18 @@ import org.springframework.dao.IncorrectResultSizeDataAccessException; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; -import org.springframework.data.domain.Sort.Order; import org.springframework.data.mongodb.core.MongoOperations; import org.springframework.data.mongodb.repository.query.MongoEntityInformation; import org.springframework.data.querydsl.EntityPathResolver; -import org.springframework.data.querydsl.QSort; import org.springframework.data.querydsl.QuerydslPredicateExecutor; import org.springframework.data.querydsl.SimpleEntityPathResolver; -import org.springframework.data.repository.core.EntityInformation; import org.springframework.data.repository.support.PageableExecutionUtils; import org.springframework.util.Assert; import com.querydsl.core.NonUniqueResultException; import com.querydsl.core.types.EntityPath; -import com.querydsl.core.types.Expression; import com.querydsl.core.types.OrderSpecifier; import com.querydsl.core.types.Predicate; -import com.querydsl.core.types.dsl.PathBuilder; /** * MongoDB-specific {@link QuerydslPredicateExecutor} that allows execution {@link Predicate}s in various forms. @@ -50,10 +45,9 @@ import com.querydsl.core.types.dsl.PathBuilder; * @author Mark Paluch * @since 2.0 */ -public class QuerydslMongoPredicateExecutor implements QuerydslPredicateExecutor { +public class QuerydslMongoPredicateExecutor extends QuerydslPredicateExecutorSupport + implements QuerydslPredicateExecutor { - private final PathBuilder builder; - private final EntityInformation entityInformation; private final MongoOperations mongoOperations; /** @@ -80,12 +74,8 @@ public class QuerydslMongoPredicateExecutor implements QuerydslPredicateExecu public QuerydslMongoPredicateExecutor(MongoEntityInformation entityInformation, MongoOperations mongoOperations, EntityPathResolver resolver) { - Assert.notNull(resolver, "EntityPathResolver must not be null!"); - - EntityPath path = resolver.createPath(entityInformation.getJavaType()); - - this.builder = new PathBuilder(path.getType(), path.getMetadata()); - this.entityInformation = entityInformation; + super(mongoOperations.getConverter(), pathBuilderFor(resolver.createPath(entityInformation.getJavaType())), + entityInformation); this.mongoOperations = mongoOperations; } @@ -210,7 +200,7 @@ public class QuerydslMongoPredicateExecutor implements QuerydslPredicateExecu * @return */ private SpringDataMongodbQuery createQuery() { - return new SpringDataMongodbQuery<>(mongoOperations, entityInformation.getJavaType()); + return new SpringDataMongodbQuery<>(mongoOperations, typeInformation().getJavaType()); } /** @@ -235,32 +225,7 @@ public class QuerydslMongoPredicateExecutor implements QuerydslPredicateExecu */ private SpringDataMongodbQuery applySorting(SpringDataMongodbQuery query, Sort sort) { - // TODO: find better solution than instanceof check - if (sort instanceof QSort) { - - List> orderSpecifiers = ((QSort) sort).getOrderSpecifiers(); - query.orderBy(orderSpecifiers.toArray(new OrderSpecifier[orderSpecifiers.size()])); - - return query; - } - - sort.stream().map(this::toOrder).forEach(query::orderBy); - + toOrderSpecifiers(sort).forEach(query::orderBy); return query; } - - /** - * Transforms a plain {@link Order} into a Querydsl specific {@link OrderSpecifier}. - * - * @param order - * @return - */ - @SuppressWarnings({ "rawtypes", "unchecked" }) - private OrderSpecifier toOrder(Order order) { - - Expression property = builder.get(order.getProperty()); - - return new OrderSpecifier( - order.isAscending() ? com.querydsl.core.types.Order.ASC : com.querydsl.core.types.Order.DESC, property); - } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/QuerydslPredicateExecutorSupport.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/QuerydslPredicateExecutorSupport.java new file mode 100644 index 000000000..30bfbf38b --- /dev/null +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/QuerydslPredicateExecutorSupport.java @@ -0,0 +1,92 @@ +/* + * Copyright 2019 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.support; + +import java.util.List; +import java.util.stream.Collectors; + +import org.springframework.data.domain.Sort; +import org.springframework.data.domain.Sort.Order; +import org.springframework.data.mongodb.core.convert.MongoConverter; +import org.springframework.data.querydsl.QSort; +import org.springframework.data.repository.core.EntityInformation; + +import com.querydsl.core.types.EntityPath; +import com.querydsl.core.types.Expression; +import com.querydsl.core.types.OrderSpecifier; +import com.querydsl.core.types.dsl.PathBuilder; + +/** + * @author Christoph Strobl + * @since 2.2 + */ +abstract class QuerydslPredicateExecutorSupport { + + private final SpringDataMongodbSerializer serializer; + private final PathBuilder builder; + private final EntityInformation entityInformation; + + QuerydslPredicateExecutorSupport(MongoConverter converter, PathBuilder builder, + EntityInformation entityInformation) { + + this.serializer = new SpringDataMongodbSerializer(converter); + this.builder = builder; + this.entityInformation = entityInformation; + } + + protected static PathBuilder pathBuilderFor(EntityPath path) { + return new PathBuilder<>(path.getType(), path.getMetadata()); + } + + protected EntityInformation typeInformation() { + return entityInformation; + } + + protected SpringDataMongodbSerializer mongodbSerializer() { + return serializer; + } + + /** + * Transforms a plain {@link Order} into a Querydsl specific {@link OrderSpecifier}. + * + * @param order + * @return + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + protected OrderSpecifier toOrder(Order order) { + + Expression property = builder.get(order.getProperty()); + + return new OrderSpecifier( + order.isAscending() ? com.querydsl.core.types.Order.ASC : com.querydsl.core.types.Order.DESC, property); + } + + /** + * Converts the given {@link Sort} to {@link OrderSpecifier}. + * + * @param sort + * @return + */ + protected List> toOrderSpecifiers(Sort sort) { + + if (sort instanceof QSort) { + return ((QSort) sort).getOrderSpecifiers(); + } + + return sort.stream().map(this::toOrder).collect(Collectors.toList()); + } + +} diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/ReactiveQuerydslMongoPredicateExecutor.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/ReactiveQuerydslMongoPredicateExecutor.java index 807696c05..547551639 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/ReactiveQuerydslMongoPredicateExecutor.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/ReactiveQuerydslMongoPredicateExecutor.java @@ -18,36 +18,29 @@ package org.springframework.data.mongodb.repository.support; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; -import java.util.List; - import org.springframework.data.domain.Sort; -import org.springframework.data.domain.Sort.Order; import org.springframework.data.mongodb.core.ReactiveMongoOperations; import org.springframework.data.mongodb.repository.query.MongoEntityInformation; import org.springframework.data.querydsl.EntityPathResolver; -import org.springframework.data.querydsl.QSort; import org.springframework.data.querydsl.QuerydslPredicateExecutor; import org.springframework.data.querydsl.ReactiveQuerydslPredicateExecutor; import org.springframework.data.querydsl.SimpleEntityPathResolver; -import org.springframework.data.repository.core.EntityInformation; import org.springframework.util.Assert; import com.querydsl.core.types.EntityPath; -import com.querydsl.core.types.Expression; import com.querydsl.core.types.OrderSpecifier; import com.querydsl.core.types.Predicate; -import com.querydsl.core.types.dsl.PathBuilder; /** * MongoDB-specific {@link QuerydslPredicateExecutor} that allows execution {@link Predicate}s in various forms. * * @author Mark Paluch + * @author Christoph Strobl * @since 2.2 */ -public class ReactiveQuerydslMongoPredicateExecutor implements ReactiveQuerydslPredicateExecutor { +public class ReactiveQuerydslMongoPredicateExecutor extends QuerydslPredicateExecutorSupport + implements ReactiveQuerydslPredicateExecutor { - private final PathBuilder builder; - private final EntityInformation entityInformation; private final ReactiveMongoOperations mongoOperations; /** @@ -60,6 +53,7 @@ public class ReactiveQuerydslMongoPredicateExecutor implements ReactiveQueryd */ public ReactiveQuerydslMongoPredicateExecutor(MongoEntityInformation entityInformation, ReactiveMongoOperations mongoOperations) { + this(entityInformation, mongoOperations, SimpleEntityPathResolver.INSTANCE); } @@ -74,12 +68,8 @@ public class ReactiveQuerydslMongoPredicateExecutor implements ReactiveQueryd public ReactiveQuerydslMongoPredicateExecutor(MongoEntityInformation entityInformation, ReactiveMongoOperations mongoOperations, EntityPathResolver resolver) { - Assert.notNull(resolver, "EntityPathResolver must not be null!"); - - EntityPath path = resolver.createPath(entityInformation.getJavaType()); - - this.builder = new PathBuilder(path.getType(), path.getMetadata()); - this.entityInformation = entityInformation; + super(mongoOperations.getConverter(), pathBuilderFor(resolver.createPath(entityInformation.getJavaType())), + entityInformation); this.mongoOperations = mongoOperations; } @@ -185,10 +175,9 @@ public class ReactiveQuerydslMongoPredicateExecutor implements ReactiveQueryd * @return */ private ReactiveSpringDataMongodbQuery createQuery() { - SpringDataMongodbSerializer serializer = new SpringDataMongodbSerializer(mongoOperations.getConverter()); - Class javaType = entityInformation.getJavaType(); - return new ReactiveSpringDataMongodbQuery<>(serializer, mongoOperations, javaType, + Class javaType = typeInformation().getJavaType(); + return new ReactiveSpringDataMongodbQuery<>(mongodbSerializer(), mongoOperations, javaType, mongoOperations.getCollectionName(javaType)); } @@ -201,32 +190,8 @@ public class ReactiveQuerydslMongoPredicateExecutor implements ReactiveQueryd */ private ReactiveSpringDataMongodbQuery applySorting(ReactiveSpringDataMongodbQuery query, Sort sort) { - // TODO: find better solution than instanceof check - if (sort instanceof QSort) { - - List> orderSpecifiers = ((QSort) sort).getOrderSpecifiers(); - query.orderBy(orderSpecifiers.toArray(new OrderSpecifier[orderSpecifiers.size()])); - - return query; - } - - sort.stream().map(this::toOrder).forEach(query::orderBy); - + toOrderSpecifiers(sort).forEach(query::orderBy); return query; } - /** - * Transforms a plain {@link Order} into a Querydsl specific {@link OrderSpecifier}. - * - * @param order - * @return - */ - @SuppressWarnings({ "rawtypes", "unchecked" }) - private OrderSpecifier toOrder(Order order) { - - Expression property = builder.get(order.getProperty()); - - return new OrderSpecifier( - order.isAscending() ? com.querydsl.core.types.Order.ASC : com.querydsl.core.types.Order.DESC, property); - } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/ReactiveSpringDataMongodbQuery.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/ReactiveSpringDataMongodbQuery.java index 575139330..ea5d0a2b9 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/ReactiveSpringDataMongodbQuery.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/ReactiveSpringDataMongodbQuery.java @@ -29,6 +29,7 @@ import org.springframework.data.mongodb.core.query.Query; import org.springframework.lang.Nullable; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; +import org.springframework.util.StringUtils; import com.querydsl.core.JoinExpression; import com.querydsl.core.QueryMetadata; @@ -45,8 +46,8 @@ import com.querydsl.core.types.dsl.CollectionPathBase; * MongoDB query with utilizing {@link ReactiveMongoOperations} for command execution. * * @param result type - * @param concrete subtype * @author Mark Paluch + * @author Christoph Strobl * @since 2.2 */ class ReactiveSpringDataMongodbQuery extends QuerydslAbstractMongodbQuery> { @@ -56,22 +57,18 @@ class ReactiveSpringDataMongodbQuery extends QuerydslAbstractMongodbQuery find; ReactiveSpringDataMongodbQuery(ReactiveMongoOperations mongoOperations, Class entityClass) { - - super(new SpringDataMongodbSerializer(mongoOperations.getConverter())); - - this.entityClass = (Class) entityClass; - this.mongoOperations = mongoOperations; - this.find = mongoOperations.query(this.entityClass); + this(new SpringDataMongodbSerializer(mongoOperations.getConverter()), mongoOperations, entityClass, null); } ReactiveSpringDataMongodbQuery(MongodbDocumentSerializer serializer, ReactiveMongoOperations mongoOperations, - Class entityClass, String collection) { + Class entityClass, @Nullable String collection) { super(serializer); this.entityClass = (Class) entityClass; this.mongoOperations = mongoOperations; - this.find = mongoOperations.query(this.entityClass).inCollection(collection); + this.find = StringUtils.hasText(collection) ? mongoOperations.query(this.entityClass).inCollection(collection) + : mongoOperations.query(this.entityClass); } /** @@ -79,7 +76,7 @@ class ReactiveSpringDataMongodbQuery extends QuerydslAbstractMongodbQuery fetch() { + Flux fetch() { return createQuery().flatMapMany(it -> find.matching(it).all()); } @@ -89,7 +86,7 @@ class ReactiveSpringDataMongodbQuery extends QuerydslAbstractMongodbQuery fetchOne() { + Mono fetchOne() { return createQuery().flatMap(it -> find.matching(it).one()); } @@ -98,7 +95,7 @@ class ReactiveSpringDataMongodbQuery extends QuerydslAbstractMongodbQuery fetchCount() { + Mono fetchCount() { return createQuery().flatMap(it -> find.matching(it).count()); } @@ -109,7 +106,7 @@ class ReactiveSpringDataMongodbQuery extends QuerydslAbstractMongodbQuery QuerydslJoinBuilder, K, T> join(Path ref, Path target) { + QuerydslJoinBuilder, K, T> join(Path ref, Path target) { return new QuerydslJoinBuilder<>(getQueryMixin(), ref, target); } @@ -120,8 +117,9 @@ class ReactiveSpringDataMongodbQuery extends QuerydslAbstractMongodbQuery QuerydslJoinBuilder, K, T> join(CollectionPathBase ref, + QuerydslJoinBuilder, K, T> join(CollectionPathBase ref, Path target) { + return new QuerydslJoinBuilder<>(getQueryMixin(), ref, target); } @@ -132,8 +130,9 @@ class ReactiveSpringDataMongodbQuery extends QuerydslAbstractMongodbQuery QuerydslAnyEmbeddedBuilder, K> anyEmbedded( + QuerydslAnyEmbeddedBuilder, K> anyEmbedded( Path> collection, Path target) { + return new QuerydslAnyEmbeddedBuilder<>(getQueryMixin(), collection); } @@ -259,6 +258,7 @@ class ReactiveSpringDataMongodbQuery extends QuerydslAbstractMongodbQuery getIds(Class targetType, @Nullable Predicate condition) { + return createQuery(Mono.justOrEmpty(condition), null, QueryModifiers.EMPTY, Collections.emptyList()) .flatMapMany(query -> mongoOperations.findDistinct(query, "_id", targetType, Object.class)); } @@ -270,7 +270,7 @@ class ReactiveSpringDataMongodbQuery extends QuerydslAbstractMongodbQuery source; - public NoMatchException(Path source) { + NoMatchException(Path source) { this.source = source; } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/ReactiveMongoRepositoryTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/ReactiveMongoRepositoryTests.java index bdcc0dafe..6243c35e1 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/ReactiveMongoRepositoryTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/ReactiveMongoRepositoryTests.java @@ -15,7 +15,7 @@ */ package org.springframework.data.mongodb.repository; -import static org.assertj.core.api.Assertions.*; +import static org.assertj.core.api.Assertions.offset; import static org.springframework.data.domain.Sort.Direction.*; import static org.springframework.data.mongodb.test.util.Assertions.assertThat; @@ -32,14 +32,14 @@ import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.TimeUnit; import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.reactivestreams.Publisher; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.beans.factory.BeanFactory; -import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; import org.springframework.dao.IncorrectResultSizeDataAccessException; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; @@ -50,18 +50,23 @@ import org.springframework.data.geo.Distance; import org.springframework.data.geo.GeoResult; import org.springframework.data.geo.Metrics; import org.springframework.data.geo.Point; +import org.springframework.data.mongodb.config.AbstractReactiveMongoConfiguration; import org.springframework.data.mongodb.core.CollectionOptions; +import org.springframework.data.mongodb.core.ReactiveMongoOperations; import org.springframework.data.mongodb.core.ReactiveMongoTemplate; import org.springframework.data.mongodb.core.mapping.Document; import org.springframework.data.mongodb.repository.Person.Sex; import org.springframework.data.mongodb.repository.support.ReactiveMongoRepositoryFactory; import org.springframework.data.mongodb.repository.support.SimpleReactiveMongoRepository; +import org.springframework.data.mongodb.test.util.MongoTestUtils; import org.springframework.data.querydsl.ReactiveQuerydslPredicateExecutor; import org.springframework.data.repository.Repository; import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.util.ClassUtils; + +import com.mongodb.reactivestreams.client.MongoClient; +import com.mongodb.reactivestreams.client.MongoClients; /** * Test for {@link ReactiveMongoRepository} query methods. @@ -70,45 +75,74 @@ import org.springframework.util.ClassUtils; * @author Christoph Strobl */ @RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration("classpath:reactive-infrastructure.xml") -public class ReactiveMongoRepositoryTests implements BeanClassLoaderAware, BeanFactoryAware { +@ContextConfiguration +public class ReactiveMongoRepositoryTests { @Autowired ReactiveMongoTemplate template; - ReactiveMongoRepositoryFactory factory; - ClassLoader classLoader; - BeanFactory beanFactory; - ReactivePersonRepository repository; - ReactiveContactRepository contactRepository; - ReactiveCappedCollectionRepository cappedRepository; + @Autowired ReactivePersonRepository repository; + @Autowired ReactiveContactRepository contactRepository; + @Autowired ReactiveCappedCollectionRepository cappedRepository; Person dave, oliver, carter, boyd, stefan, leroi, alicia; - QPerson person = new QPerson("person"); + QPerson person = QPerson.person; - @Override - public void setBeanClassLoader(ClassLoader classLoader) { - this.classLoader = classLoader == null ? ClassUtils.getDefaultClassLoader() : classLoader; + @Configuration + static class Config extends AbstractReactiveMongoConfiguration { + + @Bean + @Override + public MongoClient reactiveMongoClient() { + return MongoClients.create(); + } + + @Override + protected String getDatabaseName() { + return "reactive"; + } + + @Bean + ReactiveMongoRepositoryFactory factory(ReactiveMongoOperations template, BeanFactory beanFactory) { + + ReactiveMongoRepositoryFactory factory = new ReactiveMongoRepositoryFactory(template); + factory.setRepositoryBaseClass(SimpleReactiveMongoRepository.class); + factory.setBeanClassLoader(beanFactory.getClass().getClassLoader()); + factory.setBeanFactory(beanFactory); + factory.setEvaluationContextProvider(QueryMethodEvaluationContextProvider.DEFAULT); + + return factory; + } + + @Bean + ReactivePersonRepository reactivePersonRepository(ReactiveMongoRepositoryFactory factory) { + return factory.getRepository(ReactivePersonRepository.class); + } + + @Bean + ReactiveContactRepository reactiveContactRepository(ReactiveMongoRepositoryFactory factory) { + return factory.getRepository(ReactiveContactRepository.class); + } + + @Bean + ReactiveCappedCollectionRepository reactiveCappedCollectionRepository(ReactiveMongoRepositoryFactory factory) { + return factory.getRepository(ReactiveCappedCollectionRepository.class); + } } - @Override - public void setBeanFactory(BeanFactory beanFactory) throws BeansException { - this.beanFactory = beanFactory; + @BeforeClass + public static void cleanDb() { + + try (MongoClient client = MongoClients.create()) { + + MongoTestUtils.createOrReplaceCollectionNow("reactive", "person", client); + MongoTestUtils.createOrReplaceCollectionNow("reactive", "capped", client); + } } @Before public void setUp() throws Exception { - factory = new ReactiveMongoRepositoryFactory(template); - factory.setRepositoryBaseClass(SimpleReactiveMongoRepository.class); - factory.setBeanClassLoader(classLoader); - factory.setBeanFactory(beanFactory); - factory.setEvaluationContextProvider(QueryMethodEvaluationContextProvider.DEFAULT); - - repository = factory.getRepository(ReactivePersonRepository.class); - contactRepository = factory.getRepository(ReactiveContactRepository.class); - cappedRepository = factory.getRepository(ReactiveCappedCollectionRepository.class); - - StepVerifier.create(repository.deleteAll()).verifyComplete(); + repository.deleteAll().as(StepVerifier::create).verifyComplete(); dave = new Person("Dave", "Matthews", 42); oliver = new Person("Oliver August", "Matthews", 4); diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/support/ReactiveQuerydslMongoPredicateExecutorIntegrationTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/support/ReactiveQuerydslMongoPredicateExecutorTests.java similarity index 86% rename from spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/support/ReactiveQuerydslMongoPredicateExecutorIntegrationTests.java rename to spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/support/ReactiveQuerydslMongoPredicateExecutorTests.java index 2fd94afe0..0ba60c8f9 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/support/ReactiveQuerydslMongoPredicateExecutorIntegrationTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/support/ReactiveQuerydslMongoPredicateExecutorTests.java @@ -22,14 +22,17 @@ import java.util.Arrays; import java.util.LinkedHashSet; import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; import org.springframework.dao.IncorrectResultSizeDataAccessException; import org.springframework.dao.PermissionDeniedDataAccessException; import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort.Direction; import org.springframework.data.mongodb.ReactiveMongoDatabaseFactory; +import org.springframework.data.mongodb.config.AbstractReactiveMongoConfiguration; import org.springframework.data.mongodb.core.ReactiveMongoOperations; import org.springframework.data.mongodb.core.ReactiveMongoTemplate; import org.springframework.data.mongodb.repository.Address; @@ -39,20 +42,24 @@ import org.springframework.data.mongodb.repository.QPerson; import org.springframework.data.mongodb.repository.QUser; import org.springframework.data.mongodb.repository.User; import org.springframework.data.mongodb.repository.query.MongoEntityInformation; +import org.springframework.data.mongodb.test.util.MongoTestUtils; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringRunner; import com.mongodb.MongoException; +import com.mongodb.reactivestreams.client.MongoClient; +import com.mongodb.reactivestreams.client.MongoClients; import com.mongodb.reactivestreams.client.MongoDatabase; /** * Tests for {@link ReactiveQuerydslMongoPredicateExecutor}. * * @author Mark Paluch + * @author Christoph Strobl */ @RunWith(SpringRunner.class) -@ContextConfiguration("classpath:reactive-infrastructure.xml") -public class ReactiveQuerydslMongoPredicateExecutorIntegrationTests { +@ContextConfiguration +public class ReactiveQuerydslMongoPredicateExecutorTests { @Autowired ReactiveMongoOperations operations; @Autowired ReactiveMongoDatabaseFactory dbFactory; @@ -62,6 +69,30 @@ public class ReactiveQuerydslMongoPredicateExecutorIntegrationTests { Person dave, oliver, carter; QPerson person; + @Configuration + static class Config extends AbstractReactiveMongoConfiguration { + + @Override + public MongoClient reactiveMongoClient() { + return MongoClients.create(); + } + + @Override + protected String getDatabaseName() { + return "reactive"; + } + } + + @BeforeClass + public static void cleanDb() { + + try (MongoClient client = MongoClients.create()) { + + MongoTestUtils.createOrReplaceCollectionNow("reactive", "person", client); + MongoTestUtils.createOrReplaceCollectionNow("reactive", "user", client); + } + } + @Before public void setup() { @@ -98,6 +129,20 @@ public class ReactiveQuerydslMongoPredicateExecutorIntegrationTests { .verifyComplete(); } + @Test // DATAMONGO-2182 + public void shouldSupportCountWithPredicate() { + + repository.count(person.firstname.eq("Dave")) // + .as(StepVerifier::create) // + .expectNext(1L) // + .verifyComplete(); + + repository.count(person.firstname.eq("Unknown")) // + .as(StepVerifier::create) // + .expectNext(0L) // + .verifyComplete(); + } + @Test // DATAMONGO-2182 public void shouldSupportFindAllWithPredicateAndSort() { diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/test/util/MongoTestUtils.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/test/util/MongoTestUtils.java index a0e834713..8bdf7e493 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/test/util/MongoTestUtils.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/test/util/MongoTestUtils.java @@ -16,6 +16,7 @@ package org.springframework.data.mongodb.test.util; import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; import org.bson.Document; @@ -81,6 +82,23 @@ public class MongoTestUtils { .then(Mono.from(database.createCollection(collectionName))); } + /** + * Create a {@link com.mongodb.client.MongoCollection} if it does not exist, or drop and recreate it if it does and + * verify operation result. + * + * @param dbName must not be {@literal null}. + * @param collectionName must not be {@literal null}. + * @param client must not be {@literal null}. + */ + public static void createOrReplaceCollectionNow(String dbName, String collectionName, + com.mongodb.reactivestreams.client.MongoClient client) { + + createOrReplaceCollection(dbName, collectionName, client) // + .as(StepVerifier::create) // + .expectNext(Success.SUCCESS) // + .verifyComplete(); + } + /** * Create a new {@link com.mongodb.MongoClient} with defaults suitable for replica set usage. * diff --git a/src/main/asciidoc/reference/reactive-mongo-repositories.adoc b/src/main/asciidoc/reference/reactive-mongo-repositories.adoc index faa022e5d..2a94956bf 100644 --- a/src/main/asciidoc/reference/reactive-mongo-repositories.adoc +++ b/src/main/asciidoc/reference/reactive-mongo-repositories.adoc @@ -132,8 +132,6 @@ It supports the following features: * <> * <> -WARNING: Reactive Repositories do not support type-safe query methods that use `Querydsl`. - [[mongodb.reactive.repositories.queries.geo-spatial]] === Geo-spatial Repository Queries @@ -203,7 +201,12 @@ public interface PersonRepository extends ReactiveMongoRepository result = repository.findAll(person.address.zipCode.eq("C0123")); ---- -`QPerson` is a class that is generated by the Java annotation post-processing tool. It is a `Predicate` that lets you write type-safe queries. Notice that there are no strings in the query other than the `C0123` value. +`QPerson` is a class that is generated by the Java annotation post-processing tool. It is a `Predicate` that lets you write type-safe queries. +Note that there are no strings in the query other than the `C0123` value. You can use the generated `Predicate` class by using the `ReactiveQuerydslPredicateExecutor` interface, which the following listing shows: +.The Gateway to Reactive Querydsl - The ReactiveQuerydslPredicateExecutor +==== [source,java] ---- public interface ReactiveQuerydslPredicateExecutor { @@ -245,9 +251,12 @@ public interface ReactiveQuerydslPredicateExecutor { Mono exists(Predicate predicate); } ---- +==== To use this in your repository implementation, add it to the list of repository interfaces from which your interface inherits, as the following example shows: +.Reactive Querydsl Respository Declaration +==== [source,java] ---- public interface PersonRepository extends ReactiveMongoRepository, ReactiveQuerydslPredicateExecutor { @@ -255,5 +264,6 @@ public interface PersonRepository extends ReactiveMongoRepository