diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/aot/JdbcCodeBlocks.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/aot/JdbcCodeBlocks.java index 4eec7f069..8e4f59a3e 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/aot/JdbcCodeBlocks.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/aot/JdbcCodeBlocks.java @@ -49,6 +49,7 @@ import org.springframework.data.repository.aot.generate.MethodReturn; import org.springframework.data.repository.query.parser.Part; import org.springframework.data.support.PageableExecutionUtils; import org.springframework.data.util.Pair; +import org.springframework.data.util.Streamable; import org.springframework.javapoet.CodeBlock; import org.springframework.javapoet.CodeBlock.Builder; import org.springframework.javapoet.TypeName; @@ -811,8 +812,14 @@ class JdbcCodeBlocks { return builder.build(); } - builder.addStatement("return ($T) convertMany($L, %s)".formatted(dynamicProjection ? "$L" : "$T.class"), - methodReturn.getTypeName(), result, queryResultTypeRef); + if (methodReturn.toClass().equals(Streamable.class)) { + builder.addStatement( + "return ($1T) $1T.of(($2T) convertMany($3L, %s))".formatted(dynamicProjection ? "$4L" : "$4T.class"), + Streamable.class, Iterable.class, result, queryResultTypeRef); + } else { + builder.addStatement("return ($T) convertMany($L, %s)".formatted(dynamicProjection ? "$L" : "$T.class"), + methodReturn.getTypeName(), result, queryResultTypeRef); + } } else if (queryMethod.isStreamQuery()) { builder.addStatement("$1T $2L = " + decorator.decorate("getJdbcOperations().queryForStream($3L, $4L, $5L)"), diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/aot/JdbcRepositoryContributorIntegrationTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/aot/JdbcRepositoryContributorIntegrationTests.java index b05dab742..2a77935d3 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/aot/JdbcRepositoryContributorIntegrationTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/aot/JdbcRepositoryContributorIntegrationTests.java @@ -47,6 +47,7 @@ import org.springframework.data.jdbc.testing.EnabledOnDatabase; import org.springframework.data.jdbc.testing.IntegrationTest; import org.springframework.data.jdbc.testing.TestClass; import org.springframework.data.jdbc.testing.TestConfiguration; +import org.springframework.data.util.Streamable; import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; /** @@ -188,6 +189,14 @@ class JdbcRepositoryContributorIntegrationTests { assertThat(users).hasSize(2); } + @Test // GH-2175 + void shouldReturnStreamable() { + + Streamable users = fragment.findStreamableByAgeBetween(40, 51); + + assertThat(users).hasSize(2); + } + @Test // GH-2121 void streamByAgeGreaterThan() { assertThat(fragment.streamByAgeGreaterThan(20)).hasSize(5); @@ -221,6 +230,14 @@ class JdbcRepositoryContributorIntegrationTests { assertThat(page.hasNext()).isFalse(); } + @Test // GH-2175 + void shouldReturnPagedStreamable() { + + Streamable result = fragment.findStreamableByAgeGreaterThan(PageRequest.of(0, 4, Sort.by("age")), 10); + + assertThat(result).hasSize(4); + } + @Test // GH-2121 void countByAgeLessThan() { @@ -313,6 +330,14 @@ class JdbcRepositoryContributorIntegrationTests { assertThat(users).hasSize(6); } + @Test // GH-2175 + void shouldReturnStreamableFromDeclaredQuery() { + + Streamable users = fragment.findStreamableCreatedBefore(Instant.now().plusSeconds(180)); + + assertThat(users).hasSize(6); + } + @Test // GH-2174 void shouldSupportDeclaredQueryWithAggregateReference() { diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/aot/UserRepository.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/aot/UserRepository.java index 5d1ace2b1..22b3950ec 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/aot/UserRepository.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/aot/UserRepository.java @@ -28,6 +28,7 @@ import org.springframework.data.jdbc.repository.query.Modifying; import org.springframework.data.jdbc.repository.query.Query; import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.query.Param; +import org.springframework.data.util.Streamable; public interface UserRepository extends CrudRepository { @@ -51,6 +52,8 @@ public interface UserRepository extends CrudRepository { List findAllByAgeBetween(int start, int end); + Streamable findStreamableByAgeBetween(int start, int end); + Optional findOptionalByFirstname(String name); Stream streamByAgeGreaterThan(int age); @@ -67,6 +70,8 @@ public interface UserRepository extends CrudRepository { Page findPageByAgeGreaterThan(Pageable pageable, int age); + Streamable findStreamableByAgeGreaterThan(Pageable pageable, int age); + // ------------------------------------------------------------------------- // Declared Queries // ------------------------------------------------------------------------- @@ -97,6 +102,9 @@ public interface UserRepository extends CrudRepository { @Query(value = "SELECT * FROM MY_USER WHERE created < :instant") List findCreatedBefore(Instant instant); + @Query(value = "SELECT * FROM MY_USER WHERE created < :instant") + Streamable findStreamableCreatedBefore(Instant instant); + // ------------------------------------------------------------------------- // Parameter naming // -------------------------------------------------------------------------