From 734869059418bacda5ceb556e876322b40ad336f Mon Sep 17 00:00:00 2001 From: Tom Hombergs Date: Wed, 18 Jul 2018 21:27:39 +0200 Subject: [PATCH] DATAJPA-1163 - Evaluate expression "#{#entityName}" in count queries. SpEL expressions based on the entityName are now supported in count queries. Original pull request: #283. --- .../query/AbstractStringBasedJpaQuery.java | 5 ++++- .../query/ExpressionBasedStringQuery.java | 14 ++++++++++++++ .../query/SimpleJpaQueryUnitTests.java | 17 +++++++++++++++++ .../jpa/repository/sample/UserRepository.java | 4 ++++ 4 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/springframework/data/jpa/repository/query/AbstractStringBasedJpaQuery.java b/src/main/java/org/springframework/data/jpa/repository/query/AbstractStringBasedJpaQuery.java index b457c33a1..3cb07f457 100644 --- a/src/main/java/org/springframework/data/jpa/repository/query/AbstractStringBasedJpaQuery.java +++ b/src/main/java/org/springframework/data/jpa/repository/query/AbstractStringBasedJpaQuery.java @@ -34,6 +34,7 @@ import org.springframework.util.Assert; * @author Oliver Gierke * @author Thomas Darimont * @author Jens Schauder + * @author Tom Hombergs */ abstract class AbstractStringBasedJpaQuery extends AbstractJpaQuery { @@ -63,7 +64,9 @@ abstract class AbstractStringBasedJpaQuery extends AbstractJpaQuery { this.evaluationContextProvider = evaluationContextProvider; this.query = new ExpressionBasedStringQuery(queryString, method.getEntityInformation(), parser); - this.countQuery = query.deriveCountQuery(method.getCountQuery(), method.getCountQueryProjection()); + + DeclaredQuery countQuery = query.deriveCountQuery(method.getCountQuery(), method.getCountQueryProjection()); + this.countQuery = ExpressionBasedStringQuery.from(countQuery, method.getEntityInformation(), parser); this.parser = parser; diff --git a/src/main/java/org/springframework/data/jpa/repository/query/ExpressionBasedStringQuery.java b/src/main/java/org/springframework/data/jpa/repository/query/ExpressionBasedStringQuery.java index 8074788ef..a7d867456 100644 --- a/src/main/java/org/springframework/data/jpa/repository/query/ExpressionBasedStringQuery.java +++ b/src/main/java/org/springframework/data/jpa/repository/query/ExpressionBasedStringQuery.java @@ -34,6 +34,7 @@ import org.springframework.util.Assert; * * @author Thomas Darimont * @author Oliver Gierke + * @author Tom Hombergs */ class ExpressionBasedStringQuery extends StringQuery { @@ -59,6 +60,19 @@ class ExpressionBasedStringQuery extends StringQuery { super(renderQueryIfExpressionOrReturnQuery(query, metadata, parser)); } + /** + * Creates an {@link ExpressionBasedStringQuery} from a given {@link DeclaredQuery}. + * + * @param query the original query. Must not be {@literal null}. + * @param metadata the {@link JpaEntityMetadata} for the given entity. Must not be {@literal null}. + * @param parser Parser for resolving SpEL expressions. Must not be {@literal null}. + * @return A query supporting SpEL expressions. + */ + public static ExpressionBasedStringQuery from(DeclaredQuery query, JpaEntityMetadata metadata, + SpelExpressionParser parser) { + return new ExpressionBasedStringQuery(query.getQueryString(), metadata, parser); + } + /** * @param query, the query expression potentially containing a SpEL expression. Must not be {@literal null}.} * @param metadata the {@link JpaEntityMetadata} for the given entity. Must not be {@literal null}. diff --git a/src/test/java/org/springframework/data/jpa/repository/query/SimpleJpaQueryUnitTests.java b/src/test/java/org/springframework/data/jpa/repository/query/SimpleJpaQueryUnitTests.java index 2a92cd1d2..d6633dea6 100644 --- a/src/test/java/org/springframework/data/jpa/repository/query/SimpleJpaQueryUnitTests.java +++ b/src/test/java/org/springframework/data/jpa/repository/query/SimpleJpaQueryUnitTests.java @@ -62,6 +62,7 @@ import org.springframework.expression.spel.standard.SpelExpressionParser; * @author Oliver Gierke * @author Thomas Darimont * @author Jens Schauder + * @author Tom Hombergs */ @RunWith(MockitoJUnitRunner.Silent.class) public class SimpleJpaQueryUnitTests { @@ -233,6 +234,22 @@ public class SimpleJpaQueryUnitTests { .isThrownBy(() -> createJpaQuery(illegalMethod)); } + @Test // DATAJPA-1163 + public void resolvesExpressionInCountQuery() throws Exception { + + when(em.createQuery(Mockito.anyString())).thenReturn(query); + + Method method = UserRepository.class.getMethod("findAllWithExpressionInCountQuery", Pageable.class); + JpaQueryMethod queryMethod = new JpaQueryMethod(method, metadata, factory, extractor); + + AbstractJpaQuery jpaQuery = new SimpleJpaQuery(queryMethod, em, "select u from User u", EVALUATION_CONTEXT_PROVIDER, + PARSER); + jpaQuery.createCountQuery(new Object[] { PageRequest.of(1, 10) }); + + verify(em).createQuery(eq("select u from User u")); + verify(em).createQuery(eq("select count(u.id) from User u"), eq(Long.class)); + } + private AbstractJpaQuery createJpaQuery(Method method) { JpaQueryMethod queryMethod = new JpaQueryMethod(method, metadata, factory, extractor); diff --git a/src/test/java/org/springframework/data/jpa/repository/sample/UserRepository.java b/src/test/java/org/springframework/data/jpa/repository/sample/UserRepository.java index f33c0222b..417882bfc 100644 --- a/src/test/java/org/springframework/data/jpa/repository/sample/UserRepository.java +++ b/src/test/java/org/springframework/data/jpa/repository/sample/UserRepository.java @@ -556,6 +556,10 @@ public interface UserRepository // DATAJPA-1334 List findByNamedQueryWithConstructorExpression(); + // DATAJPA-1163 + @Query(value = "select u from #{#entityName} u", countQuery = "select count(u.id) from #{#entityName} u") + List findAllWithExpressionInCountQuery(Pageable pageable); + interface RolesAndFirstname { String getFirstname();