DATAJPA-1234 - Refactored Querydsl support to be based on fragments.
The base class for repositories is now fixed. Additional features to support Querydsl come in via QuerydslJpaPredicateExecutor which is based on the QuerydslJpaRepository. The QuerydslJpaRepository is deprecated and exists only for backward compatibility.
This commit is contained in:
committed by
Oliver Gierke
parent
70d1012ac3
commit
cbc2224ef1
@@ -23,6 +23,7 @@ import java.util.Optional;
|
||||
import javax.persistence.EntityManager;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.jpa.projection.CollectionAwareProjectionFactory;
|
||||
import org.springframework.data.jpa.provider.PersistenceProvider;
|
||||
import org.springframework.data.jpa.provider.QueryExtractor;
|
||||
@@ -30,9 +31,12 @@ import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy;
|
||||
import org.springframework.data.projection.ProjectionFactory;
|
||||
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
|
||||
import org.springframework.data.querydsl.SimpleEntityPathResolver;
|
||||
import org.springframework.data.repository.core.RepositoryInformation;
|
||||
import org.springframework.data.repository.core.RepositoryMetadata;
|
||||
import org.springframework.data.repository.core.support.RepositoryComposition;
|
||||
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;
|
||||
@@ -118,12 +122,7 @@ public class JpaRepositoryFactory extends RepositoryFactorySupport {
|
||||
*/
|
||||
@Override
|
||||
protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
|
||||
|
||||
if (isQueryDslExecutor(metadata.getRepositoryInterface())) {
|
||||
return QuerydslJpaRepository.class;
|
||||
} else {
|
||||
return SimpleJpaRepository.class;
|
||||
}
|
||||
return SimpleJpaRepository.class;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -171,4 +170,30 @@ public class JpaRepositoryFactory extends RepositoryFactorySupport {
|
||||
|
||||
return (JpaEntityInformation<T, ID>) JpaEntityInformationSupport.getEntityInformation(domainClass, entityManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RepositoryComposition.RepositoryFragments getRepositoryFragments(RepositoryMetadata metadata) {
|
||||
|
||||
RepositoryComposition.RepositoryFragments fragments = RepositoryComposition.RepositoryFragments.empty();
|
||||
|
||||
boolean isQueryDslRepository = QUERY_DSL_PRESENT
|
||||
&& QuerydslPredicateExecutor.class.isAssignableFrom(metadata.getRepositoryInterface());
|
||||
|
||||
if (isQueryDslRepository) {
|
||||
|
||||
if (metadata.isReactiveRepository()) {
|
||||
throw new InvalidDataAccessApiUsageException(
|
||||
"Cannot combine Querydsl and reactive repository support in a single interface");
|
||||
}
|
||||
|
||||
JpaEntityInformation<?, Serializable> entityInformation = getEntityInformation(metadata.getDomainType());
|
||||
|
||||
Object querydslFragment = getTargetRepositoryViaReflection(QuerydslJpaPredicateExecutor.class, entityInformation, entityManager,
|
||||
SimpleEntityPathResolver.INSTANCE, crudMethodMetadataPostProcessor.getCrudMethodMetadata());
|
||||
|
||||
fragments = fragments.append(RepositoryFragment.implemented(querydslFragment));
|
||||
}
|
||||
|
||||
return fragments;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,255 @@
|
||||
/*
|
||||
* Copyright 2008-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.jpa.repository.support;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.LockModeType;
|
||||
|
||||
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.jpa.repository.EntityGraph;
|
||||
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.support.PageableExecutionUtils;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.querydsl.core.NonUniqueResultException;
|
||||
import com.querydsl.core.types.EntityPath;
|
||||
import com.querydsl.core.types.OrderSpecifier;
|
||||
import com.querydsl.core.types.Predicate;
|
||||
import com.querydsl.core.types.dsl.PathBuilder;
|
||||
import com.querydsl.jpa.JPQLQuery;
|
||||
import com.querydsl.jpa.impl.AbstractJPAQuery;
|
||||
|
||||
/**
|
||||
* QueryDsl specific fragment for extending {@link SimpleJpaRepository} with an implementation for implementation for
|
||||
* {@link QuerydslPredicateExecutor}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
* @author Mark Paluch
|
||||
* @author Jocelyn Ntakpe
|
||||
* @author Christoph Strobl
|
||||
* @author Jens Schauder
|
||||
*/
|
||||
public class QuerydslJpaPredicateExecutor<T> implements QuerydslPredicateExecutor<T> {
|
||||
|
||||
private static final EntityPathResolver DEFAULT_ENTITY_PATH_RESOLVER = SimpleEntityPathResolver.INSTANCE;
|
||||
|
||||
private final JpaEntityInformation<T, ?> entityInformation;
|
||||
private final EntityPath<T> path;
|
||||
private final Querydsl querydsl;
|
||||
private final EntityManager entityManager;
|
||||
private final CrudMethodMetadata metadata;
|
||||
|
||||
/**
|
||||
* Creates a new {@link QuerydslJpaPredicateExecutor} from the given domain class and {@link EntityManager} and uses the
|
||||
* given {@link EntityPathResolver} to translate the domain class into an {@link EntityPath}.
|
||||
* @param entityInformation must not be {@literal null}.
|
||||
* @param entityManager must not be {@literal null}.
|
||||
* @param resolver must not be {@literal null}.
|
||||
* @param metadata maybe {@literal null}.
|
||||
*/
|
||||
public QuerydslJpaPredicateExecutor(JpaEntityInformation<T, ?> entityInformation, EntityManager entityManager,
|
||||
EntityPathResolver resolver, @Nullable CrudMethodMetadata metadata) {
|
||||
|
||||
this.entityInformation = entityInformation;
|
||||
this.metadata = metadata;
|
||||
this.path = resolver.createPath(entityInformation.getJavaType());
|
||||
this.querydsl = new Querydsl(entityManager, new PathBuilder<T>(path.getType(), path.getMetadata()));
|
||||
this.entityManager = entityManager;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.querydsl.QuerydslPredicateExecutor#findOne(com.mysema.query.types.Predicate)
|
||||
*/
|
||||
@Override
|
||||
public Optional<T> findOne(Predicate predicate) {
|
||||
|
||||
try {
|
||||
return Optional.ofNullable(createQuery(predicate).select(path).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<T> findAll(Predicate predicate) {
|
||||
return createQuery(predicate).select(path).fetch();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.querydsl.QuerydslPredicateExecutor#findAll(com.mysema.query.types.Predicate, com.mysema.query.types.OrderSpecifier<?>[])
|
||||
*/
|
||||
@Override
|
||||
public List<T> findAll(Predicate predicate, OrderSpecifier<?>... orders) {
|
||||
return executeSorted(createQuery(predicate).select(path), orders);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.querydsl.QuerydslPredicateExecutor#findAll(com.mysema.query.types.Predicate, org.springframework.data.domain.Sort)
|
||||
*/
|
||||
@Override
|
||||
public List<T> findAll(Predicate predicate, Sort sort) {
|
||||
|
||||
Assert.notNull(sort, "Sort must not be null!");
|
||||
|
||||
return executeSorted(createQuery(predicate).select(path), sort);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.querydsl.QuerydslPredicateExecutor#findAll(com.mysema.query.types.OrderSpecifier[])
|
||||
*/
|
||||
@Override
|
||||
public List<T> findAll(OrderSpecifier<?>... orders) {
|
||||
|
||||
Assert.notNull(orders, "Order specifiers must not be null!");
|
||||
|
||||
return executeSorted(createQuery(new Predicate[0]).select(path), orders);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.querydsl.QuerydslPredicateExecutor#findAll(com.querydsl.core.types.Predicate, org.springframework.data.domain.Pageable)
|
||||
*/
|
||||
@Override
|
||||
public Page<T> findAll(Predicate predicate, Pageable pageable) {
|
||||
|
||||
Assert.notNull(pageable, "Pageable must not be null!");
|
||||
|
||||
final JPQLQuery<?> countQuery = createCountQuery(predicate);
|
||||
JPQLQuery<T> query = querydsl.applyPagination(pageable, createQuery(predicate).select(path));
|
||||
|
||||
return PageableExecutionUtils.getPage(query.fetch(), pageable, countQuery::fetchCount);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.querydsl.QueryDslPredicateExecutor#count(com.mysema.query.types.Predicate)
|
||||
*/
|
||||
@Override
|
||||
public long count(Predicate predicate) {
|
||||
return createQuery(predicate).fetchCount();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.querydsl.QueryDslPredicateExecutor#exists(com.mysema.query.types.Predicate)
|
||||
*/
|
||||
@Override
|
||||
public boolean exists(Predicate predicate) {
|
||||
return createQuery(predicate).fetchCount() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link JPQLQuery} for the given {@link Predicate}.
|
||||
*
|
||||
* @param predicate
|
||||
* @return the Querydsl {@link JPQLQuery}.
|
||||
*/
|
||||
protected JPQLQuery<?> createQuery(Predicate... predicate) {
|
||||
|
||||
AbstractJPAQuery<?, ?> query = doCreateQuery(getQueryHints().withFetchGraphs(entityManager), predicate);
|
||||
|
||||
CrudMethodMetadata metadata = getRepositoryMethodMetadata();
|
||||
|
||||
if (metadata == null) {
|
||||
return query;
|
||||
}
|
||||
|
||||
LockModeType type = metadata.getLockModeType();
|
||||
return type == null ? query : query.setLockMode(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link JPQLQuery} count query for the given {@link Predicate}.
|
||||
*
|
||||
* @param predicate, can be {@literal null}.
|
||||
* @return the Querydsl count {@link JPQLQuery}.
|
||||
*/
|
||||
protected JPQLQuery<?> createCountQuery(@Nullable Predicate... predicate) {
|
||||
return doCreateQuery(getQueryHints(), predicate);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private CrudMethodMetadata getRepositoryMethodMetadata() {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link QueryHints} with the query hints based on the current {@link CrudMethodMetadata} and potential
|
||||
* {@link EntityGraph} information.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private QueryHints getQueryHints() {
|
||||
return metadata == null ? QueryHints.NoHints.INSTANCE : DefaultQueryHints.of(entityInformation, metadata);
|
||||
}
|
||||
|
||||
private AbstractJPAQuery<?, ?> doCreateQuery(QueryHints hints, @Nullable Predicate... predicate) {
|
||||
|
||||
AbstractJPAQuery<?, ?> query = querydsl.createQuery(path);
|
||||
|
||||
if (predicate != null) {
|
||||
query = query.where(predicate);
|
||||
}
|
||||
|
||||
for (Entry<String, Object> hint : hints) {
|
||||
query.setHint(hint.getKey(), hint.getValue());
|
||||
}
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the given {@link JPQLQuery} after applying the given {@link OrderSpecifier}s.
|
||||
*
|
||||
* @param query must not be {@literal null}.
|
||||
* @param orders must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
private List<T> executeSorted(JPQLQuery<T> query, OrderSpecifier<?>... orders) {
|
||||
return executeSorted(query, new QSort(orders));
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the given {@link JPQLQuery} after applying the given {@link Sort}.
|
||||
*
|
||||
* @param query must not be {@literal null}.
|
||||
* @param sort must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
private List<T> executeSorted(JPQLQuery<T> query, Sort sort) {
|
||||
return querydsl.applySorting(sort, query).fetch();
|
||||
}
|
||||
}
|
||||
@@ -47,12 +47,16 @@ import com.querydsl.jpa.impl.AbstractJPAQuery;
|
||||
* QueryDsl specific extension of {@link SimpleJpaRepository} which adds implementation for
|
||||
* {@link QuerydslPredicateExecutor}.
|
||||
*
|
||||
* @deprecated Instead of this class use {@link QuerydslJpaPredicateExecutor}
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
* @author Mark Paluch
|
||||
* @author Jocelyn Ntakpe
|
||||
* @author Christoph Strobl
|
||||
* @author Jens Schauder
|
||||
*/
|
||||
@Deprecated
|
||||
public class QuerydslJpaRepository<T, ID extends Serializable> extends SimpleJpaRepository<T, ID>
|
||||
implements QuerydslPredicateExecutor<T> {
|
||||
|
||||
|
||||
@@ -118,7 +118,7 @@ public class JpaRepositoryFactoryBeanUnitTests {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean#doCreateRepositoryFactory()
|
||||
* @see org.springframework.data.jpa.predicateExecutor.support.JpaRepositoryFactoryBean#doCreateRepositoryFactory()
|
||||
*/
|
||||
@Override
|
||||
protected RepositoryFactorySupport doCreateRepositoryFactory() {
|
||||
|
||||
@@ -50,6 +50,7 @@ import org.springframework.util.ClassUtils;
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
* @author Jens Schauder
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.Silent.class)
|
||||
public class JpaRepositoryFactoryUnitTests {
|
||||
@@ -104,9 +105,9 @@ public class JpaRepositoryFactoryUnitTests {
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the factory recognized configured repository classes that contain custom method but no custom
|
||||
* implementation could be found. Furthremore the exception has to contain the name of the repository interface as for
|
||||
* a large repository configuration it's hard to find out where this error occured.
|
||||
* Asserts that the factory recognized configured predicateExecutor classes that contain custom method but no custom
|
||||
* implementation could be found. Furthremore the exception has to contain the name of the predicateExecutor interface as for
|
||||
* a large predicateExecutor configuration it's hard to find out where this error occured.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@@ -144,21 +145,6 @@ public class JpaRepositoryFactoryUnitTests {
|
||||
repository.customMethod(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void usesQueryDslRepositoryIfInterfaceImplementsExecutor() {
|
||||
|
||||
when(entityInformation.getJavaType()).thenReturn(User.class);
|
||||
assertEquals(QuerydslJpaRepository.class,
|
||||
factory.getRepositoryBaseClass(new DefaultRepositoryMetadata(QueryDslSampleRepository.class)));
|
||||
|
||||
try {
|
||||
QueryDslSampleRepository repository = factory.getRepository(QueryDslSampleRepository.class);
|
||||
assertEquals(QuerydslJpaRepository.class, ((Advised) repository).getTargetClass());
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertThat(e.getStackTrace()[0].getClassName(), is("org.springframework.data.querydsl.SimpleEntityPathResolver"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test // DATAJPA-710, DATACMNS-542
|
||||
public void usesConfiguredRepositoryBaseClass() {
|
||||
|
||||
@@ -198,7 +184,7 @@ public class JpaRepositoryFactoryUnitTests {
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of the custom repository interface.
|
||||
* Implementation of the custom predicateExecutor interface.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,317 @@
|
||||
/*
|
||||
* Copyright 2008-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.jpa.repository.support;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.PersistenceContext;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.dao.IncorrectResultSizeDataAccessException;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.domain.Sort.Direction;
|
||||
import org.springframework.data.domain.Sort.Order;
|
||||
import org.springframework.data.jpa.domain.sample.Address;
|
||||
import org.springframework.data.jpa.domain.sample.QUser;
|
||||
import org.springframework.data.jpa.domain.sample.Role;
|
||||
import org.springframework.data.jpa.domain.sample.User;
|
||||
import org.springframework.data.querydsl.QPageRequest;
|
||||
import org.springframework.data.querydsl.QSort;
|
||||
import org.springframework.data.querydsl.SimpleEntityPathResolver;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import com.querydsl.core.types.Predicate;
|
||||
import com.querydsl.core.types.dsl.BooleanExpression;
|
||||
import com.querydsl.core.types.dsl.PathBuilder;
|
||||
import com.querydsl.core.types.dsl.PathBuilderFactory;
|
||||
|
||||
/**
|
||||
* Integration test for {@link QuerydslJpaPredicateExecutor}.
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
* @author Mark Paluch
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration({ "classpath:infrastructure.xml" })
|
||||
@Transactional
|
||||
public class QuerydslJpaPredicateExecutorUnitTests {
|
||||
|
||||
@PersistenceContext EntityManager em;
|
||||
|
||||
QuerydslJpaPredicateExecutor<User> predicateExecutor;
|
||||
QUser user = new QUser("user");
|
||||
User dave, carter, oliver;
|
||||
Role adminRole;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
JpaEntityInformation<User, Integer> information = new JpaMetamodelEntityInformation<>(User.class,
|
||||
em.getMetamodel());
|
||||
|
||||
SimpleJpaRepository<User, Integer> repository = new SimpleJpaRepository<>(information, em);
|
||||
dave = repository.save(new User("Dave", "Matthews", "dave@matthews.com"));
|
||||
carter = repository.save(new User("Carter", "Beauford", "carter@beauford.com"));
|
||||
oliver = repository.save(new User("Oliver", "matthews", "oliver@matthews.com"));
|
||||
adminRole = em.merge(new Role("admin"));
|
||||
|
||||
this.predicateExecutor = new QuerydslJpaPredicateExecutor<>(information, em, SimpleEntityPathResolver.INSTANCE, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void executesPredicatesCorrectly() throws Exception {
|
||||
|
||||
BooleanExpression isCalledDave = user.firstname.eq("Dave");
|
||||
BooleanExpression isBeauford = user.lastname.eq("Beauford");
|
||||
|
||||
List<User> result = predicateExecutor.findAll(isCalledDave.or(isBeauford));
|
||||
|
||||
assertThat(result).containsExactlyInAnyOrder(carter, dave);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void executesStringBasedPredicatesCorrectly() throws Exception {
|
||||
|
||||
PathBuilder<User> builder = new PathBuilderFactory().create(User.class);
|
||||
|
||||
BooleanExpression isCalledDave = builder.getString("firstname").eq("Dave");
|
||||
BooleanExpression isBeauford = builder.getString("lastname").eq("Beauford");
|
||||
|
||||
List<User> result = predicateExecutor.findAll(isCalledDave.or(isBeauford));
|
||||
|
||||
assertThat(result).containsExactlyInAnyOrder(carter, dave);
|
||||
}
|
||||
|
||||
@Test // DATAJPA-243
|
||||
public void considersSortingProvidedThroughPageable() {
|
||||
|
||||
Predicate lastnameContainsE = user.lastname.contains("e");
|
||||
|
||||
Page<User> result = predicateExecutor.findAll(lastnameContainsE, PageRequest.of(0, 1, Direction.ASC, "lastname"));
|
||||
|
||||
assertThat(result).containsExactly(carter);
|
||||
|
||||
result = predicateExecutor.findAll(lastnameContainsE, PageRequest.of(0, 2, Direction.DESC, "lastname"));
|
||||
|
||||
assertThat(result).containsExactly(oliver, dave);
|
||||
}
|
||||
|
||||
@Test // DATAJPA-296
|
||||
public void appliesIgnoreCaseOrdering() {
|
||||
|
||||
Sort sort = Sort.by(new Order(Direction.DESC, "lastname").ignoreCase(), new Order(Direction.ASC, "firstname"));
|
||||
|
||||
Page<User> result = predicateExecutor.findAll(user.lastname.contains("e"), PageRequest.of(0, 2, sort));
|
||||
|
||||
assertThat(result.getContent()).containsExactly(dave, oliver);
|
||||
}
|
||||
|
||||
@Test // DATAJPA-427
|
||||
public void findBySpecificationWithSortByPluralAssociationPropertyInPageableShouldUseSortNullValuesLast() {
|
||||
|
||||
oliver.getColleagues().add(dave);
|
||||
dave.getColleagues().add(oliver);
|
||||
|
||||
QUser user = QUser.user;
|
||||
|
||||
Page<User> page = predicateExecutor.findAll(user.firstname.isNotNull(),
|
||||
PageRequest.of(0, 10, Sort.by(Sort.Direction.ASC, "colleagues.firstname")));
|
||||
|
||||
assertThat(page.getContent()).hasSize(3).contains(oliver, dave, carter);
|
||||
}
|
||||
|
||||
@Test // DATAJPA-427
|
||||
public void findBySpecificationWithSortBySingularAssociationPropertyInPageableShouldUseSortNullValuesLast() {
|
||||
|
||||
oliver.setManager(dave);
|
||||
dave.setManager(carter);
|
||||
|
||||
QUser user = QUser.user;
|
||||
|
||||
Page<User> page = predicateExecutor.findAll(user.firstname.isNotNull(),
|
||||
PageRequest.of(0, 10, Sort.by(Sort.Direction.ASC, "manager.firstname")));
|
||||
|
||||
assertThat(page.getContent()).hasSize(3).contains(dave, oliver, carter);
|
||||
}
|
||||
|
||||
@Test // DATAJPA-427
|
||||
public void findBySpecificationWithSortBySingularPropertyInPageableShouldUseSortNullValuesFirst() {
|
||||
|
||||
QUser user = QUser.user;
|
||||
|
||||
Page<User> page = predicateExecutor.findAll(user.firstname.isNotNull(),
|
||||
PageRequest.of(0, 10, Sort.by(Sort.Direction.ASC, "firstname")));
|
||||
|
||||
assertThat(page.getContent()).containsExactly(carter, dave, oliver);
|
||||
}
|
||||
|
||||
@Test // DATAJPA-427
|
||||
public void findBySpecificationWithSortByOrderIgnoreCaseBySingularPropertyInPageableShouldUseSortNullValuesFirst() {
|
||||
|
||||
QUser user = QUser.user;
|
||||
|
||||
Page<User> page = predicateExecutor.findAll(user.firstname.isNotNull(),
|
||||
PageRequest.of(0, 10, Sort.by(new Order(Sort.Direction.ASC, "firstname").ignoreCase())));
|
||||
|
||||
assertThat(page.getContent()).containsExactly(carter, dave, oliver);
|
||||
}
|
||||
|
||||
@Test // DATAJPA-427
|
||||
public void findBySpecificationWithSortByNestedEmbeddedPropertyInPageableShouldUseSortNullValuesFirst() {
|
||||
|
||||
oliver.setAddress(new Address("Germany", "Saarbrücken", "HaveItYourWay", "123"));
|
||||
|
||||
QUser user = QUser.user;
|
||||
|
||||
Page<User> page = predicateExecutor.findAll(user.firstname.isNotNull(),
|
||||
PageRequest.of(0, 10, Sort.by(Sort.Direction.ASC, "address.streetName")));
|
||||
|
||||
assertThat(page.getContent()).containsExactly(dave, carter, oliver);
|
||||
}
|
||||
|
||||
@Test // DATAJPA-12
|
||||
public void findBySpecificationWithSortByQueryDslOrderSpecifierWithQPageRequestAndQSort() {
|
||||
|
||||
QUser user = QUser.user;
|
||||
|
||||
Page<User> page = predicateExecutor.findAll(user.firstname.isNotNull(),
|
||||
new QPageRequest(0, 10, new QSort(user.firstname.asc())));
|
||||
|
||||
assertThat(page.getContent()).containsExactly(carter, dave, oliver);
|
||||
}
|
||||
|
||||
@Test // DATAJPA-12
|
||||
public void findBySpecificationWithSortByQueryDslOrderSpecifierWithQPageRequest() {
|
||||
|
||||
QUser user = QUser.user;
|
||||
|
||||
Page<User> page = predicateExecutor.findAll(user.firstname.isNotNull(), new QPageRequest(0, 10, user.firstname.asc()));
|
||||
|
||||
assertThat(page.getContent()).containsExactly(carter, dave, oliver);
|
||||
}
|
||||
|
||||
@Test // DATAJPA-12
|
||||
public void findBySpecificationWithSortByQueryDslOrderSpecifierForAssociationShouldGenerateLeftJoinWithQPageRequest() {
|
||||
|
||||
oliver.setManager(dave);
|
||||
dave.setManager(carter);
|
||||
|
||||
QUser user = QUser.user;
|
||||
|
||||
Page<User> page = predicateExecutor.findAll(user.firstname.isNotNull(),
|
||||
new QPageRequest(0, 10, user.manager.firstname.asc()));
|
||||
|
||||
assertThat(page.getContent()).containsExactly(carter, dave, oliver);
|
||||
}
|
||||
|
||||
@Test // DATAJPA-500, DATAJPA-635
|
||||
public void sortByNestedEmbeddedAttribute() {
|
||||
|
||||
carter.setAddress(new Address("U", "Z", "Y", "41"));
|
||||
dave.setAddress(new Address("U", "A", "Y", "41"));
|
||||
oliver.setAddress(new Address("G", "D", "X", "42"));
|
||||
|
||||
List<User> users = predicateExecutor.findAll(QUser.user.address.streetName.asc());
|
||||
|
||||
assertThat(users).hasSize(3).contains(dave, oliver, carter);
|
||||
}
|
||||
|
||||
@Test // DATAJPA-566, DATAJPA-635
|
||||
public void shouldSupportSortByOperatorWithDateExpressions() {
|
||||
|
||||
carter.setDateOfBirth(new LocalDate(2000, 2, 1).toDate());
|
||||
dave.setDateOfBirth(new LocalDate(2000, 1, 1).toDate());
|
||||
oliver.setDateOfBirth(new LocalDate(2003, 5, 1).toDate());
|
||||
|
||||
List<User> users = predicateExecutor.findAll(QUser.user.dateOfBirth.yearMonth().asc());
|
||||
|
||||
assertThat(users).containsExactly(dave, carter, oliver);
|
||||
}
|
||||
|
||||
@Test // DATAJPA-665
|
||||
public void shouldSupportExistsWithPredicate() throws Exception {
|
||||
|
||||
assertThat(predicateExecutor.exists(user.firstname.eq("Dave"))).isEqualTo(true);
|
||||
assertThat(predicateExecutor.exists(user.firstname.eq("Unknown"))).isEqualTo(false);
|
||||
assertThat(predicateExecutor.exists((Predicate) null)).isEqualTo(true);
|
||||
}
|
||||
|
||||
@Test // DATAJPA-679
|
||||
public void shouldSupportFindAllWithPredicateAndSort() {
|
||||
|
||||
List<User> users = predicateExecutor.findAll(user.dateOfBirth.isNull(), Sort.by(Direction.ASC, "firstname"));
|
||||
|
||||
assertThat(users).contains(carter, dave, oliver);
|
||||
}
|
||||
|
||||
@Test // DATAJPA-585
|
||||
public void worksWithUnpagedPageable() {
|
||||
assertThat(predicateExecutor.findAll(user.dateOfBirth.isNull(), Pageable.unpaged()).getContent()).hasSize(3);
|
||||
}
|
||||
|
||||
@Test // DATAJPA-912
|
||||
public void pageableQueryReportsTotalFromResult() {
|
||||
|
||||
Page<User> firstPage = predicateExecutor.findAll(user.dateOfBirth.isNull(), PageRequest.of(0, 10));
|
||||
assertThat(firstPage.getContent()).hasSize(3);
|
||||
assertThat(firstPage.getTotalElements()).isEqualTo(3L);
|
||||
|
||||
Page<User> secondPage = predicateExecutor.findAll(user.dateOfBirth.isNull(), PageRequest.of(1, 2));
|
||||
assertThat(secondPage.getContent()).hasSize(1);
|
||||
assertThat(secondPage.getTotalElements()).isEqualTo(3L);
|
||||
}
|
||||
|
||||
@Test // DATAJPA-912
|
||||
public void pageableQueryReportsTotalFromCount() {
|
||||
|
||||
Page<User> firstPage = predicateExecutor.findAll(user.dateOfBirth.isNull(), PageRequest.of(0, 3));
|
||||
assertThat(firstPage.getContent()).hasSize(3);
|
||||
assertThat(firstPage.getTotalElements()).isEqualTo(3L);
|
||||
|
||||
Page<User> secondPage = predicateExecutor.findAll(user.dateOfBirth.isNull(), PageRequest.of(10, 10));
|
||||
assertThat(secondPage.getContent()).hasSize(0);
|
||||
assertThat(secondPage.getTotalElements()).isEqualTo(3L);
|
||||
}
|
||||
|
||||
@Test // DATAJPA-1115
|
||||
public void findOneWithPredicateReturnsResultCorrectly() {
|
||||
assertThat(predicateExecutor.findOne(user.eq(dave))).contains(dave);
|
||||
}
|
||||
|
||||
@Test // DATAJPA-1115
|
||||
public void findOneWithPredicateReturnsOptionalEmptyWhenNoDataFound() {
|
||||
assertThat(predicateExecutor.findOne(user.firstname.eq("batman"))).isNotPresent();
|
||||
}
|
||||
|
||||
@Test(expected = IncorrectResultSizeDataAccessException.class) // DATAJPA-1115
|
||||
public void findOneWithPredicateThrowsExceptionForNonUniqueResults() {
|
||||
predicateExecutor.findOne(user.emailAddress.contains("com"));
|
||||
}
|
||||
}
|
||||
@@ -32,7 +32,7 @@ import org.springframework.transaction.TransactionException;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
|
||||
/**
|
||||
* Integration test for transactional behaviour of repository operations.
|
||||
* Integration test for transactional behaviour of predicateExecutor operations.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user