Skip to content

Commit e1fe724

Browse files
committed
Consider GROUP BY count queries in AOT repository fragments.
We now properly consider results of GROUP BY count queries returning potentially multiple rows, a count for each group instead of enforcing a single result item. Closes #4096
1 parent 0999b95 commit e1fe724

File tree

3 files changed

+28
-3
lines changed

3 files changed

+28
-3
lines changed

spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/aot/AotRepositoryFragmentSupport.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,14 @@
1515
*/
1616
package org.springframework.data.jpa.repository.aot;
1717

18+
import jakarta.persistence.Query;
1819
import jakarta.persistence.Tuple;
1920

2021
import java.lang.reflect.Array;
2122
import java.lang.reflect.Method;
2223
import java.util.ArrayList;
2324
import java.util.Collection;
25+
import java.util.List;
2426
import java.util.Optional;
2527
import java.util.function.UnaryOperator;
2628
import java.util.stream.Stream;
@@ -167,6 +169,24 @@ protected String rewriteQuery(DeclaredQuery query, Sort sort, Class<?> returnedT
167169
return source;
168170
}
169171

172+
protected long getCount(Query query) {
173+
174+
List<?> totals = query.getResultList();
175+
176+
if (totals.size() == 1) {
177+
Object result = totals.get(0);
178+
179+
if (result instanceof Number n) {
180+
return n.longValue();
181+
}
182+
183+
return CONVERSION_SERVICE.convert(result, Long.class);
184+
}
185+
186+
// group by count
187+
return totals.size();
188+
}
189+
170190
protected <T> @Nullable T convertOne(@Nullable Object result, boolean nativeQuery, Class<T> projection) {
171191

172192
if (result == null) {

spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/aot/JpaCodeBlocks.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ public CodeBlock build() {
226226
builder.add(createQuery(true, countQueryVariableName, countQueryStringNameVariableName, queryRewriterName,
227227
queries.count(), null, pageable,
228228
queryHints ? this.queryHints : MergedAnnotation.missing(), null, Long.class));
229-
builder.addStatement("return ($T) $L.getSingleResult()", Long.class, countQueryVariableName);
229+
builder.addStatement("return getCount($L)", countQueryVariableName);
230230

231231
// end control flow does not work well with lambdas
232232
builder.unindent();

spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/UserRepositoryTests.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,7 @@ void testPreventsCascadingRolePersisting() {
418418
* Tests cascading on {@literal merge} operation.
419419
*/
420420
@Test
421-
void testMergingCascadesCollegueas() {
421+
void testMergingCascadesColleagues() {
422422

423423
firstUser.addColleague(secondUser);
424424
flushTestUsers();
@@ -752,13 +752,18 @@ void findsUsersBySpringDataNamedQuery() {
752752
assertThat(repository.findBySpringDataNamedQuery("Gierke")).containsOnly(firstUser);
753753
}
754754

755-
@Test // DATADOC-86
755+
@Test // DATADOC-86, GH-4096
756756
void readsPageWithGroupByClauseCorrectly() {
757757

758758
flushTestUsers();
759759

760+
repository.saveAndFlush(new User("Foo", "raymond", "[email protected]"));
761+
760762
Page<String> result = repository.findByLastnameGrouped(PageRequest.of(0, 10));
761763
assertThat(result.getTotalPages()).isOne();
764+
765+
assertThat(repository.findByLastnameGrouped(PageRequest.of(0, 3))).hasSize(3);
766+
assertThat(repository.findByLastnameGrouped(PageRequest.of(1, 2))).hasSize(2);
762767
}
763768

764769
@Test

0 commit comments

Comments
 (0)