From 7526f3bd2ed36157241bf2e1caea9f7e3498f5c1 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Wed, 31 May 2017 10:26:47 +0200 Subject: [PATCH] DATAMONGO-1702 - Adopt to composable repositories. Deprecate QuerydslMongoRepository, introduce QuerydslMongoPredicateExecutor instead without extending SimpleMongoRepository. Use RepositoryFragments to mix in requested repository aspects. Original pull request: #480. --- .../support/MongoRepositoryFactory.java | 39 ++- .../QuerydslMongoPredicateExecutor.java | 270 ++++++++++++++++++ .../support/QuerydslMongoRepository.java | 267 +---------------- .../repository/custom/ComposedRepository.java | 26 ++ ...ComposedRepositoryImplementationTests.java | 49 ++++ .../repository/custom/RepositoryMixin.java | 24 ++ .../custom/RepositoryMixinImpl.java | 27 ++ ...ngoPredicateExecutorIntegrationTests.java} | 10 +- 8 files changed, 435 insertions(+), 277 deletions(-) create mode 100644 spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/QuerydslMongoPredicateExecutor.java create mode 100644 spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/custom/ComposedRepository.java create mode 100644 spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/custom/ComposedRepositoryImplementationTests.java create mode 100644 spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/custom/RepositoryMixin.java create mode 100644 spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/custom/RepositoryMixinImpl.java rename spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/support/{QueryDslMongoRepositoryIntegrationTests.java => QuerydslMongoPredicateExecutorIntegrationTests.java} (91%) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/MongoRepositoryFactory.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/MongoRepositoryFactory.java index 53fb544bb..c91f5c5df 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/MongoRepositoryFactory.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/MongoRepositoryFactory.java @@ -36,13 +36,13 @@ import org.springframework.data.querydsl.QuerydslPredicateExecutor; import org.springframework.data.repository.core.NamedQueries; import org.springframework.data.repository.core.RepositoryInformation; import org.springframework.data.repository.core.RepositoryMetadata; +import org.springframework.data.repository.core.support.RepositoryComposition.RepositoryFragments; import org.springframework.data.repository.core.support.RepositoryFactorySupport; +import org.springframework.data.repository.core.support.RepositoryFragment; import org.springframework.data.repository.query.EvaluationContextProvider; import org.springframework.data.repository.query.QueryLookupStrategy; import org.springframework.data.repository.query.QueryLookupStrategy.Key; import org.springframework.data.repository.query.RepositoryQuery; -import org.springframework.data.repository.reactive.ReactiveCrudRepository; -import org.springframework.data.repository.reactive.RxJava1CrudRepository; import org.springframework.data.repository.util.QueryExecutionConverters; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.util.Assert; @@ -88,25 +88,36 @@ public class MongoRepositoryFactory extends RepositoryFactorySupport { */ @Override protected Class getRepositoryBaseClass(RepositoryMetadata metadata) { + return SimpleMongoRepository.class; + } - boolean isReactiveRepository = (PROJECT_REACTOR_PRESENT - && ReactiveCrudRepository.class.isAssignableFrom(metadata.getRepositoryInterface())) - || (RXJAVA_OBSERVABLE_PRESENT - && RxJava1CrudRepository.class.isAssignableFrom(metadata.getRepositoryInterface())); + /* + * (non-Javadoc) + * @see org.springframework.data.repository.core.support.RepositoryFactorySupport#getRepositoryFragments(org.springframework.data.repository.core.RepositoryMetadata) + */ + @Override + protected RepositoryFragments getRepositoryFragments(RepositoryMetadata metadata) { + + RepositoryFragments fragments = RepositoryFragments.empty(); boolean isQueryDslRepository = QUERY_DSL_PRESENT && QuerydslPredicateExecutor.class.isAssignableFrom(metadata.getRepositoryInterface()); - if (isReactiveRepository) { + if (isQueryDslRepository) { - if (isQueryDslRepository) { + if (metadata.isReactiveRepository()) { throw new InvalidDataAccessApiUsageException( - "Cannot combine Querydsl and reactive repository in one interface"); + "Cannot combine Querydsl and reactive repository support in a single interface"); } - return SimpleReactiveMongoRepository.class; + + MongoEntityInformation entityInformation = getEntityInformation(metadata.getDomainType(), + metadata); + + fragments = fragments.append(RepositoryFragment.implemented( + getTargetRepositoryViaReflection(QuerydslMongoPredicateExecutor.class, entityInformation, operations))); } - return isQueryDslRepository ? QuerydslMongoRepository.class : SimpleMongoRepository.class; + return fragments; } /* @@ -140,16 +151,16 @@ public class MongoRepositoryFactory extends RepositoryFactorySupport { } private MongoEntityInformation getEntityInformation(Class domainClass, - RepositoryInformation information) { + RepositoryMetadata metadata) { MongoPersistentEntity entity = mappingContext.getRequiredPersistentEntity(domainClass); return MongoEntityInformationSupport. entityInformationFor(entity, - information != null ? information.getIdType() : null); + metadata != null ? metadata.getIdType() : null); } /** * {@link QueryLookupStrategy} to create {@link PartTreeMongoQuery} instances. - * + * * @author Oliver Gierke * @author Thomas Darimont */ 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 new file mode 100644 index 000000000..4e3a7608d --- /dev/null +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/QuerydslMongoPredicateExecutor.java @@ -0,0 +1,270 @@ +/* + * Copyright 2017 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.Optional; + +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; +import com.querydsl.mongodb.AbstractMongodbQuery; + +/** + * MongoDB-specific {@link QuerydslPredicateExecutor} that allows execution {@link Predicate}s in various forms. + * + * @author Oliver Gierke + * @author Thomas Darimont + * @author Mark Paluch + * @author Christoph Strobl + * @author Mark Paluch + * @since 2.0 + */ +public class QuerydslMongoPredicateExecutor implements QuerydslPredicateExecutor { + + private final PathBuilder builder; + private final EntityInformation entityInformation; + private final MongoOperations mongoOperations; + + /** + * Creates a new {@link QuerydslMongoPredicateExecutor} for the given {@link MongoEntityInformation} and + * {@link MongoTemplate}. Uses the {@link SimpleEntityPathResolver} to create an {@link EntityPath} for the given + * domain class. + * + * @param entityInformation must not be {@literal null}. + * @param mongoOperations must not be {@literal null}. + */ + public QuerydslMongoPredicateExecutor(MongoEntityInformation entityInformation, + MongoOperations mongoOperations) { + this(entityInformation, mongoOperations, SimpleEntityPathResolver.INSTANCE); + } + + /** + * Creates a new {@link QuerydslMongoPredicateExecutor} for the given {@link MongoEntityInformation}, + * {@link MongoTemplate} and {@link EntityPathResolver}. + * + * @param entityInformation must not be {@literal null}. + * @param mongoOperations must not be {@literal null}. + * @param resolver must not be {@literal null}. + */ + 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; + this.mongoOperations = mongoOperations; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.querydsl.QuerydslPredicateExecutor#findById(com.querydsl.core.types.Predicate) + */ + @Override + public Optional findOne(Predicate predicate) { + + Assert.notNull(predicate, "Predicate must not be null!"); + + try { + return Optional.ofNullable(createQueryFor(predicate).fetchOne()); + } catch (NonUniqueResultException ex) { + throw new IncorrectResultSizeDataAccessException(ex.getMessage(), 1, ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.querydsl.QueryDslPredicateExecutor#findAll(com.mysema.query.types.Predicate) + */ + @Override + public List findAll(Predicate predicate) { + + Assert.notNull(predicate, "Predicate must not be null!"); + + return createQueryFor(predicate).fetchResults().getResults(); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.querydsl.QueryDslPredicateExecutor#findAll(com.mysema.query.types.Predicate, com.mysema.query.types.OrderSpecifier[]) + */ + @Override + public List findAll(Predicate predicate, OrderSpecifier... orders) { + + Assert.notNull(predicate, "Predicate must not be null!"); + Assert.notNull(orders, "Order specifiers must not be null!"); + + return createQueryFor(predicate).orderBy(orders).fetchResults().getResults(); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.querydsl.QueryDslPredicateExecutor#findAll(com.mysema.query.types.Predicate, org.springframework.data.domain.Sort) + */ + @Override + public List findAll(Predicate predicate, Sort sort) { + + Assert.notNull(predicate, "Predicate must not be null!"); + Assert.notNull(sort, "Sort must not be null!"); + + return applySorting(createQueryFor(predicate), sort).fetchResults().getResults(); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.querydsl.QueryDslPredicateExecutor#findAll(com.mysema.query.types.OrderSpecifier[]) + */ + @Override + public Iterable findAll(OrderSpecifier... orders) { + + Assert.notNull(orders, "Order specifiers must not be null!"); + + return createQuery().orderBy(orders).fetchResults().getResults(); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.querydsl.QueryDslPredicateExecutor#findAll(com.mysema.query.types.Predicate, org.springframework.data.domain.Pageable) + */ + @Override + public Page findAll(Predicate predicate, Pageable pageable) { + + Assert.notNull(predicate, "Predicate must not be null!"); + Assert.notNull(pageable, "Pageable must not be null!"); + + AbstractMongodbQuery> query = createQueryFor(predicate); + + return PageableExecutionUtils.getPage(applyPagination(query, pageable).fetchResults().getResults(), pageable, + () -> createQueryFor(predicate).fetchCount()); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.querydsl.QueryDslPredicateExecutor#count(com.mysema.query.types.Predicate) + */ + @Override + public long count(Predicate predicate) { + + Assert.notNull(predicate, "Predicate must not be null!"); + + return createQueryFor(predicate).fetchCount(); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.querydsl.QueryDslPredicateExecutor#exists(com.mysema.query.types.Predicate) + */ + @Override + public boolean exists(Predicate predicate) { + + Assert.notNull(predicate, "Predicate must not be null!"); + + return createQueryFor(predicate).fetchCount() > 0; + } + + /** + * Creates a {@link MongodbQuery} for the given {@link Predicate}. + * + * @param predicate + * @return + */ + private AbstractMongodbQuery> createQueryFor(Predicate predicate) { + return createQuery().where(predicate); + } + + /** + * Creates a {@link MongodbQuery}. + * + * @return + */ + private AbstractMongodbQuery> createQuery() { + return new SpringDataMongodbQuery(mongoOperations, entityInformation.getJavaType()); + } + + /** + * Applies the given {@link Pageable} to the given {@link MongodbQuery}. + * + * @param query + * @param pageable + * @return + */ + private AbstractMongodbQuery> applyPagination( + AbstractMongodbQuery> query, Pageable pageable) { + + query = query.offset(pageable.getOffset()).limit(pageable.getPageSize()); + return applySorting(query, pageable.getSort()); + } + + /** + * Applies the given {@link Sort} to the given {@link MongodbQuery}. + * + * @param query + * @param sort + * @return + */ + private AbstractMongodbQuery> applySorting( + AbstractMongodbQuery> 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(it -> query.orderBy(it)); + + 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/QuerydslMongoRepository.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/QuerydslMongoRepository.java index a11667e5d..bdffe0ed9 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/QuerydslMongoRepository.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/QuerydslMongoRepository.java @@ -16,33 +16,13 @@ package org.springframework.data.mongodb.repository.support; import java.io.Serializable; -import java.util.List; -import java.util.Optional; -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.core.MongoTemplate; 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.core.EntityMetadata; -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; -import com.querydsl.mongodb.AbstractMongodbQuery; /** * Special Querydsl based repository implementation that allows execution {@link Predicate}s in various forms. @@ -51,249 +31,20 @@ import com.querydsl.mongodb.AbstractMongodbQuery; * @author Thomas Darimont * @author Mark Paluch * @author Christoph Strobl + * @deprecated since 2.0. Querydsl execution is now linked via composable repositories and no longer requires to be a + * subclass of {@link SimpleMongoRepository}. Use {@link QuerydslMongoPredicateExecutor} for standalone + * Querydsl {@link Predicate} execution. */ -public class QuerydslMongoRepository extends SimpleMongoRepository +@Deprecated +public class QuerydslMongoRepository extends QuerydslMongoPredicateExecutor implements QuerydslPredicateExecutor { - private final PathBuilder builder; - private final EntityInformation entityInformation; - private final MongoOperations mongoOperations; - - /** - * Creates a new {@link QuerydslMongoRepository} for the given {@link EntityMetadata} and {@link MongoTemplate}. Uses - * the {@link SimpleEntityPathResolver} to create an {@link EntityPath} for the given domain class. - * - * @param entityInformation must not be {@literal null}. - * @param mongoOperations must not be {@literal null}. - */ - public QuerydslMongoRepository(MongoEntityInformation entityInformation, MongoOperations mongoOperations) { - this(entityInformation, mongoOperations, SimpleEntityPathResolver.INSTANCE); - } - - /** - * Creates a new {@link QuerydslMongoRepository} for the given {@link MongoEntityInformation}, {@link MongoTemplate} - * and {@link EntityPathResolver}. - * - * @param entityInformation must not be {@literal null}. - * @param mongoOperations must not be {@literal null}. - * @param resolver must not be {@literal null}. - */ - public QuerydslMongoRepository(MongoEntityInformation entityInformation, MongoOperations mongoOperations, - EntityPathResolver resolver) { - + public QuerydslMongoRepository(MongoEntityInformation entityInformation, MongoOperations mongoOperations) { super(entityInformation, mongoOperations); - - 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; - this.mongoOperations = mongoOperations; } - /* - * (non-Javadoc) - * @see org.springframework.data.querydsl.QuerydslPredicateExecutor#findById(com.querydsl.core.types.Predicate) - */ - @Override - public Optional findOne(Predicate predicate) { - - Assert.notNull(predicate, "Predicate must not be null!"); - - try { - return Optional.ofNullable(createQueryFor(predicate).fetchOne()); - } catch (NonUniqueResultException ex) { - throw new IncorrectResultSizeDataAccessException(ex.getMessage(), 1, ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.querydsl.QueryDslPredicateExecutor#findAll(com.mysema.query.types.Predicate) - */ - @Override - public List findAll(Predicate predicate) { - - Assert.notNull(predicate, "Predicate must not be null!"); - - return createQueryFor(predicate).fetchResults().getResults(); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.querydsl.QueryDslPredicateExecutor#findAll(com.mysema.query.types.Predicate, com.mysema.query.types.OrderSpecifier[]) - */ - @Override - public List findAll(Predicate predicate, OrderSpecifier... orders) { - - Assert.notNull(predicate, "Predicate must not be null!"); - Assert.notNull(orders, "Order specifiers must not be null!"); - - return createQueryFor(predicate).orderBy(orders).fetchResults().getResults(); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.querydsl.QueryDslPredicateExecutor#findAll(com.mysema.query.types.Predicate, org.springframework.data.domain.Sort) - */ - @Override - public List findAll(Predicate predicate, Sort sort) { - - Assert.notNull(predicate, "Predicate must not be null!"); - Assert.notNull(sort, "Sort must not be null!"); - - return applySorting(createQueryFor(predicate), sort).fetchResults().getResults(); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.querydsl.QueryDslPredicateExecutor#findAll(com.mysema.query.types.OrderSpecifier[]) - */ - @Override - public Iterable findAll(OrderSpecifier... orders) { - - Assert.notNull(orders, "Order specifiers must not be null!"); - - return createQuery().orderBy(orders).fetchResults().getResults(); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.querydsl.QueryDslPredicateExecutor#findAll(com.mysema.query.types.Predicate, org.springframework.data.domain.Pageable) - */ - @Override - public Page findAll(Predicate predicate, Pageable pageable) { - - Assert.notNull(predicate, "Predicate must not be null!"); - Assert.notNull(pageable, "Pageable must not be null!"); - - AbstractMongodbQuery> query = createQueryFor(predicate); - - return PageableExecutionUtils.getPage(applyPagination(query, pageable).fetchResults().getResults(), pageable, - () -> createQueryFor(predicate).fetchCount()); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.mongodb.repository.support.SimpleMongoRepository#findAll(org.springframework.data.domain.Pageable) - */ - @Override - public Page findAll(Pageable pageable) { - - Assert.notNull(pageable, "Pageable must not be null!"); - - AbstractMongodbQuery> query = createQuery(); - - return PageableExecutionUtils.getPage(applyPagination(query, pageable).fetchResults().getResults(), pageable, - () -> createQuery().fetchCount()); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.mongodb.repository.support.SimpleMongoRepository#findAll(org.springframework.data.domain.Sort) - */ - @Override - public List findAll(Sort sort) { - - Assert.notNull(sort, "Sort must not be null!"); - - return applySorting(createQuery(), sort).fetchResults().getResults(); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.querydsl.QueryDslPredicateExecutor#count(com.mysema.query.types.Predicate) - */ - @Override - public long count(Predicate predicate) { - - Assert.notNull(predicate, "Predicate must not be null!"); - - return createQueryFor(predicate).fetchCount(); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.querydsl.QueryDslPredicateExecutor#exists(com.mysema.query.types.Predicate) - */ - @Override - public boolean exists(Predicate predicate) { - - Assert.notNull(predicate, "Predicate must not be null!"); - - return createQueryFor(predicate).fetchCount() > 0; - } - - /** - * Creates a {@link MongodbQuery} for the given {@link Predicate}. - * - * @param predicate - * @return - */ - private AbstractMongodbQuery> createQueryFor(Predicate predicate) { - return createQuery().where(predicate); - } - - /** - * Creates a {@link MongodbQuery}. - * - * @return - */ - private AbstractMongodbQuery> createQuery() { - return new SpringDataMongodbQuery(mongoOperations, entityInformation.getJavaType()); - } - - /** - * Applies the given {@link Pageable} to the given {@link MongodbQuery}. - * - * @param query - * @param pageable - * @return - */ - private AbstractMongodbQuery> applyPagination( - AbstractMongodbQuery> query, Pageable pageable) { - - query = query.offset(pageable.getOffset()).limit(pageable.getPageSize()); - return applySorting(query, pageable.getSort()); - } - - /** - * Applies the given {@link Sort} to the given {@link MongodbQuery}. - * - * @param query - * @param sort - * @return - */ - private AbstractMongodbQuery> applySorting( - AbstractMongodbQuery> 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(it -> query.orderBy(it)); - - 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); + public QuerydslMongoRepository(MongoEntityInformation entityInformation, MongoOperations mongoOperations, + EntityPathResolver resolver) { + super(entityInformation, mongoOperations, resolver); } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/custom/ComposedRepository.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/custom/ComposedRepository.java new file mode 100644 index 000000000..6365229b1 --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/custom/ComposedRepository.java @@ -0,0 +1,26 @@ +/* + * Copyright 2017 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.custom; + +import org.springframework.data.mongodb.core.User; +import org.springframework.data.repository.Repository; + +/** + * @author Mark Paluch + */ +public interface ComposedRepository extends Repository, RepositoryMixin { + +} diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/custom/ComposedRepositoryImplementationTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/custom/ComposedRepositoryImplementationTests.java new file mode 100644 index 000000000..f4e429b2a --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/custom/ComposedRepositoryImplementationTests.java @@ -0,0 +1,49 @@ +/* + * Copyright 2017 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.custom; + +import static org.assertj.core.api.Assertions.*; + +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.context.annotation.ImportResource; +import org.springframework.data.mongodb.repository.config.EnableMongoRepositories; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +/** + * Integration tests for composed Repository implementations. + * + * @author Mark Paluch + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration +public class ComposedRepositoryImplementationTests { + + @Configuration + @EnableMongoRepositories + @ImportResource("classpath:infrastructure.xml") + static class Config {} + + @Autowired ComposedRepository composedRepository; + + @Test // DATAMONGO-1702 + public void shouldExecuteMethodOnCustomRepositoryImplementation() { + assertThat(composedRepository.getFoo()).isEqualTo("foo"); + } +} diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/custom/RepositoryMixin.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/custom/RepositoryMixin.java new file mode 100644 index 000000000..8196b549e --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/custom/RepositoryMixin.java @@ -0,0 +1,24 @@ +/* + * Copyright 2017 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.custom; + +/** + * @author Mark Paluch + */ +public interface RepositoryMixin { + + String getFoo(); +} diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/custom/RepositoryMixinImpl.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/custom/RepositoryMixinImpl.java new file mode 100644 index 000000000..9e95dbf41 --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/custom/RepositoryMixinImpl.java @@ -0,0 +1,27 @@ +/* + * Copyright 2017 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.custom; + +/** + * @author Mark Paluch + */ +public class RepositoryMixinImpl implements RepositoryMixin { + + @Override + public String getFoo() { + return "foo"; + } +} diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/support/QueryDslMongoRepositoryIntegrationTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/support/QuerydslMongoPredicateExecutorIntegrationTests.java similarity index 91% rename from spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/support/QueryDslMongoRepositoryIntegrationTests.java rename to spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/support/QuerydslMongoPredicateExecutorIntegrationTests.java index ccf562b6c..27bb91ef9 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/support/QueryDslMongoRepositoryIntegrationTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/support/QuerydslMongoPredicateExecutorIntegrationTests.java @@ -35,7 +35,7 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; /** - * Integration test for {@link QuerydslMongoRepository}. + * Integration test for {@link QuerydslMongoPredicateExecutor}. * * @author Thomas Darimont * @author Mark Paluch @@ -44,10 +44,10 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @ContextConfiguration( locations = "/org/springframework/data/mongodb/repository/PersonRepositoryIntegrationTests-context.xml") @RunWith(SpringJUnit4ClassRunner.class) -public class QueryDslMongoRepositoryIntegrationTests { +public class QuerydslMongoPredicateExecutorIntegrationTests { @Autowired MongoOperations operations; - QuerydslMongoRepository repository; + QuerydslMongoPredicateExecutor repository; Person dave, oliver, carter; QPerson person; @@ -57,7 +57,7 @@ public class QueryDslMongoRepositoryIntegrationTests { MongoRepositoryFactory factory = new MongoRepositoryFactory(operations); MongoEntityInformation entityInformation = factory.getEntityInformation(Person.class); - repository = new QuerydslMongoRepository<>(entityInformation, operations); + repository = new QuerydslMongoPredicateExecutor(entityInformation, operations); operations.dropCollection(Person.class); @@ -67,7 +67,7 @@ public class QueryDslMongoRepositoryIntegrationTests { person = new QPerson("person"); - repository.saveAll(Arrays.asList(oliver, dave, carter)); + operations.insertAll(Arrays.asList(oliver, dave, carter)); } @Test // DATAMONGO-1146