Skip to content

Commit 2e49efd

Browse files
Add some more tests
1 parent 70a560d commit 2e49efd

File tree

3 files changed

+147
-16
lines changed

3 files changed

+147
-16
lines changed

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

+96-16
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,24 @@
1515
*/
1616
package org.springframework.data.jpa.repository;
1717

18-
import static org.assertj.core.api.Assertions.*;
19-
import static org.springframework.data.domain.Sort.Direction.*;
18+
import static org.assertj.core.api.Assertions.assertThat;
19+
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
20+
import static org.springframework.data.domain.Sort.Direction.ASC;
21+
import static org.springframework.data.domain.Sort.Direction.DESC;
2022

2123
import jakarta.persistence.EntityManager;
2224

2325
import java.util.Arrays;
2426
import java.util.List;
27+
import java.util.Map;
2528

29+
import org.assertj.core.data.Offset;
2630
import org.junit.jupiter.api.AfterEach;
2731
import org.junit.jupiter.api.BeforeEach;
2832
import org.junit.jupiter.api.Test;
2933
import org.junit.jupiter.api.extension.ExtendWith;
34+
import org.junit.jupiter.params.ParameterizedTest;
35+
import org.junit.jupiter.params.provider.ValueSource;
3036
import org.springframework.beans.factory.annotation.Autowired;
3137
import org.springframework.dao.InvalidDataAccessApiUsageException;
3238
import org.springframework.data.domain.Limit;
@@ -45,6 +51,9 @@
4551
import org.springframework.data.jpa.repository.sample.UserRepository.IdOnly;
4652
import org.springframework.data.jpa.repository.sample.UserRepository.NameOnly;
4753
import org.springframework.data.jpa.repository.sample.UserRepository.RolesAndFirstname;
54+
import org.springframework.data.jpa.repository.sample.UserRepository.UserExcerpt;
55+
import org.springframework.data.jpa.repository.sample.UserRepository.UserRoleCountDtoProjection;
56+
import org.springframework.data.jpa.repository.sample.UserRepository.UserRoleCountInterfaceProjection;
4857
import org.springframework.data.repository.query.QueryLookupStrategy;
4958
import org.springframework.test.context.ContextConfiguration;
5059
import org.springframework.test.context.junit.jupiter.SpringExtension;
@@ -247,9 +256,9 @@ void executesQueryWithLimitAndScrollPosition() {
247256
@Test // GH-3409
248257
void executesWindowQueryWithPageable() {
249258

250-
Window<User> first = userRepository.findByLastnameOrderByFirstname("Matthews", PageRequest.of(0,1));
259+
Window<User> first = userRepository.findByLastnameOrderByFirstname("Matthews", PageRequest.of(0, 1));
251260

252-
Window<User> next = userRepository.findByLastnameOrderByFirstname("Matthews", PageRequest.of(1,1));
261+
Window<User> next = userRepository.findByLastnameOrderByFirstname("Matthews", PageRequest.of(1, 1));
253262

254263
assertThat(first).containsExactly(dave);
255264
assertThat(next).containsExactly(oliver);
@@ -406,21 +415,92 @@ void findByNegatingSimplePropertyUsingMixedNullNonNullArgument() {
406415
assertThat(result).containsExactly(carter);
407416
}
408417

409-
@Test // GH-3076
410-
void dtoProjectionShouldApplyConstructorExpressionRewriting() {
418+
@Test // GH-3076
419+
void dtoProjectionShouldApplyConstructorExpressionRewriting() {
411420

412-
List<UserRepository.UserExcerpt> dtos = userRepository.findRecordProjection();
421+
List<UserExcerpt> dtos = userRepository.findRecordProjection();
413422

414-
assertThat(dtos).flatExtracting(UserRepository.UserExcerpt::firstname) //
415-
.contains("Dave", "Carter", "Oliver August");
416-
}
423+
assertThat(dtos).flatExtracting(UserRepository.UserExcerpt::firstname) //
424+
.contains("Dave", "Carter", "Oliver August");
425+
}
426+
427+
@Test // GH-3076
428+
void dtoMultiselectProjectionShouldApplyConstructorExpressionRewriting() {
429+
430+
List<UserExcerpt> dtos = userRepository.findMultiselectRecordProjection();
431+
432+
assertThat(dtos).flatExtracting(UserRepository.UserExcerpt::firstname) //
433+
.contains("Dave", "Carter", "Oliver August");
434+
}
435+
436+
@Test // GH-3076
437+
void dynamicDtoProjection() {
438+
439+
List<UserExcerpt> dtos = userRepository.findRecordProjection(UserExcerpt.class);
440+
441+
assertThat(dtos).flatExtracting(UserRepository.UserExcerpt::firstname) //
442+
.contains("Dave", "Carter", "Oliver August");
443+
}
444+
445+
@Test // GH-3076
446+
void dtoProjectionWithEntityAndAggregatedValue() {
447+
448+
Map<String, User> musicians = Map.of(carter.getFirstname(), carter, dave.getFirstname(), dave,
449+
oliver.getFirstname(), oliver);
450+
451+
assertThat(userRepository.dtoProjectionEntityAndAggregatedValue()).allSatisfy(projection -> {
452+
assertThat(projection.user()).isIn(musicians.values());
453+
assertThat(projection.roleCount()).isCloseTo(musicians.get(projection.user().getFirstname()).getRoles().size(),
454+
Offset.offset(0L));
455+
});
456+
}
417457

418-
@Test // GH-3076
419-
void dtoMultiselectProjectionShouldApplyConstructorExpressionRewriting() {
458+
@Test // GH-3076
459+
void interfaceProjectionWithEntityAndAggregatedValue() {
420460

421-
List<UserRepository.UserExcerpt> dtos = userRepository.findMultiselectRecordProjection();
461+
Map<String, User> musicians = Map.of(carter.getFirstname(), carter, dave.getFirstname(), dave,
462+
oliver.getFirstname(), oliver);
463+
464+
assertThat(userRepository.interfaceProjectionEntityAndAggregatedValue()).allSatisfy(projection -> {
465+
assertThat(projection.getUser()).isIn(musicians.values());
466+
assertThat(projection.getRoleCount())
467+
.isCloseTo(musicians.get(projection.getUser().getFirstname()).getRoles().size(), Offset.offset(0L));
468+
});
469+
}
470+
471+
@Test // GH-3076
472+
void rawMapProjectionWithEntityAndAggregatedValue() {
473+
474+
Map<String, User> musicians = Map.of(carter.getFirstname(), carter, dave.getFirstname(), dave,
475+
oliver.getFirstname(), oliver);
476+
477+
assertThat(userRepository.rawMapProjectionEntityAndAggregatedValue()).allSatisfy(projection -> {
478+
assertThat(projection.get("user")).isIn(musicians.values());
479+
assertThat(projection).containsKey("roleCount");
480+
});
481+
}
482+
483+
@Test // GH-3076
484+
void dtoProjectionWithEntityAndAggregatedValueWithPageable() {
485+
486+
Map<String, User> musicians = Map.of(carter.getFirstname(), carter, dave.getFirstname(), dave,
487+
oliver.getFirstname(), oliver);
488+
489+
assertThat(
490+
userRepository.dtoProjectionEntityAndAggregatedValue(PageRequest.of(0, 10).withSort(Sort.by("firstname"))))
491+
.allSatisfy(projection -> {
492+
assertThat(projection.user()).isIn(musicians.values());
493+
assertThat(projection.roleCount())
494+
.isCloseTo(musicians.get(projection.user().getFirstname()).getRoles().size(), Offset.offset(0L));
495+
});
496+
}
497+
498+
@ParameterizedTest // GH-3076
499+
@ValueSource(classes = { UserRoleCountDtoProjection.class, UserRoleCountInterfaceProjection.class })
500+
<T> void dynamicProjectionWithEntityAndAggregated(Class<T> resultType) {
501+
502+
assertThat(userRepository.findMultiselectRecordDynamicProjection(resultType)).hasSize(3)
503+
.hasOnlyElementsOfType(resultType);
504+
}
422505

423-
assertThat(dtos).flatExtracting(UserRepository.UserExcerpt::firstname) //
424-
.contains("Dave", "Carter", "Oliver August");
425-
}
426506
}

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

+20
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,21 @@ void shouldTranslateSingleProjectionToDto() {
4949
"SELECT new org.springframework.data.jpa.repository.query.JpqlDtoQueryTransformerUnitTests$MyRecord(p.foo, p.bar) from Person p");
5050
}
5151

52+
// @Test // GH-3076
53+
// void xxx() {
54+
//
55+
// JpaQueryMethod method = getMethod("dtoProjection2");
56+
// JpqlSortedQueryTransformer transformer = new JpqlSortedQueryTransformer(Sort.unsorted(), null,
57+
// method.getResultProcessor().getReturnedType());
58+
//
59+
// JpaQueryEnhancer.JpqlQueryParser parser = JpaQueryEnhancer.JpqlQueryParser.parseQuery("select u.foo, u.bar, count(r) from User u left outer join u.role r group by u");
60+
//
61+
// QueryTokenStream visit = transformer.visit(parser.getContext());
62+
//
63+
// assertThat(QueryRenderer.TokenRenderer.render(visit)).isEqualTo(
64+
// "select new org.springframework.data.jpa.repository.query.JpqlDtoQueryTransformerUnitTests$MyRecord2(u.foo, u.bar, count(r)) from User u left outer join u.role r group by u");
65+
// }
66+
5267
@Test // GH-3076
5368
void shouldRewriteQueriesWithSubselect() {
5469

@@ -100,6 +115,7 @@ private JpaQueryMethod getMethod(String name, Class<?>... parameterTypes) {
100115
interface MyRepo extends Repository<Person, String> {
101116

102117
MyRecord dtoProjection();
118+
MyRecord2 dtoProjection2();
103119
}
104120

105121
record Person(String id) {
@@ -109,4 +125,8 @@ record Person(String id) {
109125
record MyRecord(String foo, String bar) {
110126

111127
}
128+
129+
record MyRecord2(String foo, String bar, Integer count) {
130+
131+
}
112132
}

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

+31
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
import jakarta.persistence.EntityManager;
1919
import jakarta.persistence.QueryHint;
2020

21+
import java.lang.annotation.Retention;
22+
import java.lang.annotation.RetentionPolicy;
2123
import java.util.Collection;
2224
import java.util.Date;
2325
import java.util.List;
@@ -721,11 +723,33 @@ List<String> findAllAndSortByFunctionResultNamedParameter(@Param("namedParameter
721723
@Query("select u from User u")
722724
List<UserExcerpt> findRecordProjection();
723725

726+
@Query("select u from User u")
727+
<T> List<T> findRecordProjection(Class<T> projectionType);
728+
724729
@Query("select u.firstname, u.lastname from User u")
725730
List<UserExcerpt> findMultiselectRecordProjection();
726731

732+
@UserRoleCountProjectingQuery
733+
List<UserRoleCountDtoProjection> dtoProjectionEntityAndAggregatedValue();
734+
735+
@UserRoleCountProjectingQuery
736+
Page<UserRoleCountDtoProjection> dtoProjectionEntityAndAggregatedValue(PageRequest page);
737+
738+
@UserRoleCountProjectingQuery
739+
List<UserRoleCountInterfaceProjection> interfaceProjectionEntityAndAggregatedValue();
740+
741+
@UserRoleCountProjectingQuery
742+
List<Map<String, Object>> rawMapProjectionEntityAndAggregatedValue();
743+
744+
@UserRoleCountProjectingQuery
745+
<T> List<T> findMultiselectRecordDynamicProjection(Class<T> projectionType);
746+
727747
Window<User> findBy(OffsetScrollPosition position);
728748

749+
@Retention(RetentionPolicy.RUNTIME)
750+
@Query("select u AS user, count(r) AS roleCount from User u left outer join u.roles r group by u")
751+
@interface UserRoleCountProjectingQuery {}
752+
729753
interface RolesAndFirstname {
730754

731755
String getFirstname();
@@ -754,4 +778,11 @@ record UserExcerpt(String firstname, String lastname) {
754778

755779
}
756780

781+
record UserRoleCountDtoProjection(User user, Long roleCount) {}
782+
783+
interface UserRoleCountInterfaceProjection {
784+
User getUser();
785+
Long getRoleCount();
786+
}
787+
757788
}

0 commit comments

Comments
 (0)