From 0aa54f2b9bcb339d23f037cc892c4d154df46b97 Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Fri, 17 Jan 2025 11:36:08 +0100 Subject: [PATCH] regorganize stuff --- .../mongodb/aot/generated/MongoBlocks.java | 30 ++------ .../test/java/example/aot/UserRepository.java | 37 +++++++--- .../MongoRepositoryContributorTests.java | 73 ++++++++++++++++++- 3 files changed, 105 insertions(+), 35 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/aot/generated/MongoBlocks.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/aot/generated/MongoBlocks.java index c4c405080..653ec17b4 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/aot/generated/MongoBlocks.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/aot/generated/MongoBlocks.java @@ -75,14 +75,9 @@ public class MongoBlocks { builder.add("\n"); if (isProjecting) { - // builder.addStatement("$T<$T> finder = $L.query($T.class).as($T.class).matching($L)", TerminatingFind.class, - // actualReturnType, mongoOpsRef, repositoryInformation.getDomainType(), actualReturnType, queryVariableName); builder.addStatement("$T<$T> finder = $L.query($T.class).as($T.class)", FindWithQuery.class, actualReturnType, mongoOpsRef, context.getRepositoryInformation().getDomainType(), actualReturnType); } else { - // builder.addStatement("$T<$T> finder = $L.query($T.class).matching($L)", TerminatingFind.class, - // actualReturnType, - // mongoOpsRef, repositoryInformation.getDomainType(), queryVariableName); builder.addStatement("$T<$T> finder = $L.query($T.class)", FindWithQuery.class, actualReturnType, mongoOpsRef, context.getRepositoryInformation().getDomainType()); } @@ -92,9 +87,9 @@ public class MongoBlocks { if (context.returnsOptionalValue()) { terminatingMethod = "one()"; - } else if(context.isCountMethod()){ + } else if (context.isCountMethod()) { terminatingMethod = "count()"; - } else if(context.isExistsMethod()){ + } else if (context.isExistsMethod()) { terminatingMethod = "exists()"; } else { terminatingMethod = "oneValue()"; @@ -110,13 +105,8 @@ public class MongoBlocks { context.getPageableParameterName(), queryVariableName); } else { builder.addStatement("return finder.matching($L).$L", queryVariableName, terminatingMethod); - // builder.addStatement("return $T.getPage(finder.$L, $L, () -> finder.count())", PageableExecutionUtils.class, - // terminatingMethod, - // metadata.getPageableParameterName()); } - // new MongoQueryExecution.PagedExecution(finder, page).execute(query); - return builder.build(); } @@ -128,9 +118,7 @@ public class MongoBlocks { AotRepositoryMethodGenerationContext context; StringQuery source; List arguments; - - // MongoParameters argumentSource; - + public QueryBlockBuilder(AotRepositoryMethodGenerationContext context) { this.context = context; this.arguments = Arrays.stream(context.getMethod().getParameters()).map(Parameter::getName) @@ -151,8 +139,6 @@ public class MongoBlocks { CodeBlock.Builder builder = CodeBlock.builder(); builder.add("\n"); - // String queryStringName = "%sString".formatted(queryVariableName); - // builder.addStatement("String $L = $S", queryStringName, queryString); String queryDocumentVariableName = "%sDocument".formatted(queryVariableName); builder.add(renderExpressionToDocument(source.getQueryString(), queryVariableName)); builder.addStatement("$T $L = new $T($L)", BasicQuery.class, queryVariableName, BasicQuery.class, @@ -181,7 +167,7 @@ public class MongoBlocks { } String pageableParameter = context.getPageableParameterName(); - if (StringUtils.hasText(pageableParameter) && (!context.returnsPage() || !context.returnsSlice())) { + if (StringUtils.hasText(pageableParameter) && !context.returnsPage() && !context.returnsSlice()) { builder.addStatement("$L.with($L)", queryVariableName, pageableParameter); } @@ -205,11 +191,9 @@ public class MongoBlocks { private CodeBlock renderExpressionToDocument(@Nullable String source, String variableName) { Builder builder = CodeBlock.builder(); - if(!StringUtils.hasText(source)) { - builder.addStatement("$T $L = new $T()", Document.class, "%sDocument".formatted(variableName), - Document.class); - } - else if (!containsPlaceholder(source)) { + if (!StringUtils.hasText(source)) { + builder.addStatement("$T $L = new $T()", Document.class, "%sDocument".formatted(variableName), Document.class); + } else if (!containsPlaceholder(source)) { builder.addStatement("$T $L = $T.parse($S)", Document.class, "%sDocument".formatted(variableName), Document.class, source); } else { diff --git a/spring-data-mongodb/src/test/java/example/aot/UserRepository.java b/spring-data-mongodb/src/test/java/example/aot/UserRepository.java index cddfbe1e8..8a796e52f 100644 --- a/spring-data-mongodb/src/test/java/example/aot/UserRepository.java +++ b/spring-data-mongodb/src/test/java/example/aot/UserRepository.java @@ -33,6 +33,8 @@ import org.springframework.data.repository.CrudRepository; */ public interface UserRepository extends CrudRepository { + /* Derived Queries */ + List findUserNoArgumentsBy(); User findOneByUsername(String username); @@ -61,6 +63,18 @@ public interface UserRepository extends CrudRepository { Slice findSliceOfUserByLastnameStartingWith(String lastname, Pageable page); + // TODO: Streaming + // TODO: Scrolling + // TODO: GeoQueries + + /* Annotated Queries */ + + @Query("{ 'username' : ?0 }") + User findAnnotatedQueryByUsername(String username); + + @Query(value = "{ 'lastname' : { '$regex' : '^?0' } }", count = true) + Long countAnnotatedQueryByLastname(String lastname); + @Query("{ 'lastname' : { '$regex' : '^?0' } }") List findAnnotatedQueryByLastname(String lastname); @@ -90,22 +104,27 @@ public interface UserRepository extends CrudRepository { @Query("{ 'lastname' : { '$regex' : '^?0' } }") Slice findAnnotatedQuerySliceOfUsersByLastname(String lastname, Pageable pageable); + // TODO: deletes + // TODO: updates + // TODO: Aggregations + + /* Derived With Annotated Options */ + @Query(sort = "{ 'username' : 1 }") List findWithAnnotatedSortByLastnameStartingWith(String lastname); - @ReadPreference("secondary") - User findWithReadPreferenceByUsername(String username); + @Query(fields = "{ 'username' : 1 }") + List findWithAnnotatedFieldsProjectionByLastnameStartingWith(String lastname); - Page findUserProjectionBy(Pageable pageable); + @ReadPreference("no-such-read-preference") + User findWithReadPreferenceByUsername(String username); - @Query(sort = "{ 'last_name' : -1}") - List findByLastnameAfter(String lastname); + // TODO: hints - @Query(fields = "{ '_id' : -1}") - List findByLastnameBefore(String lastname); + /* Projecting Queries */ - List findByLastnameOrderByFirstnameDesc(String lastname); + List findUserProjectionByLastnameStartingWith(String lastname); - List findUserByLastnameLike(String lastname); + Page findUserProjectionByLastnameStartingWith(String lastname, Pageable page); } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/aot/generated/MongoRepositoryContributorTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/aot/generated/MongoRepositoryContributorTests.java index fb7611e15..4e0d8bb7c 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/aot/generated/MongoRepositoryContributorTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/aot/generated/MongoRepositoryContributorTests.java @@ -32,8 +32,10 @@ package org.springframework.data.mongodb.aot.generated; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import example.aot.User; +import example.aot.UserProjection; import example.aot.UserRepository; import java.util.LinkedHashMap; @@ -66,6 +68,7 @@ import org.springframework.data.mongodb.test.util.MongoTestTemplate; import org.springframework.data.mongodb.test.util.MongoTestUtils; import org.springframework.data.util.Lazy; import org.springframework.test.util.ReflectionTestUtils; +import org.springframework.util.StringUtils; import com.mongodb.client.MongoClient; @@ -273,7 +276,27 @@ public class MongoRepositoryContributorTests { } @Test - void testAnnotatedFinderWithQuery() { + void testAnnotatedFinderReturningSingleValueWithQuery() { + + generated.verify(methodInvoker -> { + + User user = methodInvoker.invoke("findAnnotatedQueryByUsername", "yoda").onBean("aotUserRepository"); + assertThat(user).isNotNull().extracting(User::getUsername).isEqualTo("yoda"); + }); + } + + @Test + void testAnnotatedCount() { + + generated.verify(methodInvoker -> { + + Long value = methodInvoker.invoke("countAnnotatedQueryByLastname", "Skywalker").onBean("aotUserRepository"); + assertThat(value).isEqualTo(2L); + }); + } + + @Test + void testAnnotatedFinderReturningListWithQuery() { generated.verify(methodInvoker -> { @@ -376,9 +399,53 @@ public class MongoRepositoryContributorTests { }); } - // findAnnotatedQueryPageOfUsersByLastname + @Test + void testDerivedFinderWithAnnotatedFieldsProjection() { + + generated.verify(methodInvoker -> { + + List users = methodInvoker.invoke("findWithAnnotatedFieldsProjectionByLastnameStartingWith", "S") + .onBean("aotUserRepository"); + assertThat(users).allMatch( + user -> StringUtils.hasText(user.getUsername()) && user.getLastname() == null && user.getFirstname() == null); + }); + } - // countUsersByLastname + @Test + void testReadPreferenceAppliedToQuery() { + + generated.verify(methodInvoker -> { + + // check if it fails when trying to parse the read preference to indicate it would get applied + assertThatExceptionOfType(IllegalArgumentException.class) + .isThrownBy(() -> methodInvoker.invoke("findWithReadPreferenceByUsername", "S").onBean("aotUserRepository")) + .withMessageContaining("No match for read preference"); + }); + } + + @Test + void testDerivedFinderReturningListOfProjections() { + + generated.verify(methodInvoker -> { + + List users = methodInvoker.invoke("findUserProjectionByLastnameStartingWith", "S") + .onBean("aotUserRepository"); + assertThat(users).extracting(UserProjection::getUsername).containsExactlyInAnyOrder("han", "kylo", "luke", + "vader"); + }); + } + + @Test + void testDerivedFinderReturningPageOfProjections() { + + generated.verify(methodInvoker -> { + + Page users = methodInvoker + .invoke("findUserProjectionByLastnameStartingWith", "S", PageRequest.of(0, 2, Sort.by("username"))) + .onBean("aotUserRepository"); + assertThat(users).extracting(UserProjection::getUsername).containsExactly("han", "kylo"); + }); + } private static void initUsers() {