Skip to content

Commit

Permalink
feat: support stream in spring data repository (#803)
Browse files Browse the repository at this point in the history
* feat: support stream in spring data repository

* docs: support stream in spring data repository
  • Loading branch information
shouwn authored Dec 17, 2024
1 parent 922eac6 commit 7556c84
Show file tree
Hide file tree
Showing 10 changed files with 849 additions and 36 deletions.
30 changes: 20 additions & 10 deletions docs/en/jpql-with-kotlin-jdsl/spring-supports.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,33 @@ If you declare your `JpqlSerializer` or `JpqlIntrospector` as a bean, it will be
If your `JpaRepository` extends `KotlinJdslJpqlExecutor`, you can use the extension provided by Kotlin JDSL.

```kotlin
interface AuthorRepository : JpaRepository<Author, Long>, KotlinJdslJpqlExecutor
interface BookRepository : JpaRepository<Book, Isbn>, KotlinJdslJpqlExecutor

authorRepository.findAll {
val result: List<Isbn?> = bookRepository.findAll {
select(
path(Author::authorId),
path(Book::isbn),
).from(
entity(Book::class),
)
}

val result: Page<Isbn?> = bookRepository.findPage(pageable) {
select(
path(Book::isbn),
).from(
entity(Author::class),
join(BookAuthor::class).on(path(Author::authorId).equal(path(BookAuthor::authorId))),
).groupBy(
path(Author::authorId),
).orderBy(
count(Author::authorId).desc(),
entity(Book::class),
)
}

val result: Slice<Isbn?> = bookRepository.findSlice(pageable) {
select(
path(Book::isbn),
).from(
entity(Book::class),
)
}

bookRepository.findPage(pageable) {
val result: Stream<Isbn?> = bookRepository.findStream {
select(
path(Book::isbn),
).from(
Expand Down
30 changes: 20 additions & 10 deletions docs/ko/jpql-with-kotlin-jdsl/spring-supports.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,33 @@ Kotlin JDSL은 Spring Boot AutoConfigure를 지원합니다.
만약 사용하고 있는 `JpaRepository``KotlinJdslJpqlExecutor`를 상속하면, Kotlin JDSL이 제공하는 확장 기능을 사용할 수 있습니다.

```kotlin
interface AuthorRepository : JpaRepository<Author, Long>, KotlinJdslJpqlExecutor
interface BookRepository : JpaRepository<Book, Isbn>, KotlinJdslJpqlExecutor

authorRepository.findAll {
val result: List<Isbn?> = bookRepository.findAll {
select(
path(Author::authorId),
path(Book::isbn),
).from(
entity(Book::class),
)
}

val result: Page<Isbn?> = bookRepository.findPage(pageable) {
select(
path(Book::isbn),
).from(
entity(Author::class),
join(BookAuthor::class).on(path(Author::authorId).equal(path(BookAuthor::authorId))),
).groupBy(
path(Author::authorId),
).orderBy(
count(Author::authorId).desc(),
entity(Book::class),
)
}

val result: Slice<Isbn?> = bookRepository.findSlice(pageable) {
select(
path(Book::isbn),
).from(
entity(Book::class),
)
}

bookRepository.findPage(pageable) {
val result: Stream<Isbn?> = bookRepository.findStream {
select(
path(Book::isbn),
).from(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import org.springframework.data.domain.PageRequest
import org.springframework.data.domain.Sort
import org.springframework.transaction.annotation.Transactional
import java.time.OffsetDateTime
import java.util.stream.Collectors

@Transactional
@SpringBootTest
Expand Down Expand Up @@ -89,6 +90,30 @@ class SelectExample : WithAssertions {
assertThat(actual).isEqualTo(listOf(Isbn("04"), Isbn("05"), Isbn("06")))
}

@Test
fun `the stream of books`() {
// given
val pageable = PageRequest.of(1, 3, Sort.by(Sort.Direction.ASC, "isbn"))

// when
val actual = bookRepository.findStream(pageable) {
select(
path(Book::isbn),
).from(
entity(Book::class),
)
}

// then
assertThat(actual.collect(Collectors.toList())).isEqualTo(
listOf(
Isbn("04"),
Isbn("05"),
Isbn("06"),
),
)
}

@Test
fun `the page of books`() {
// given
Expand Down Expand Up @@ -302,6 +327,39 @@ class SelectExample : WithAssertions {
)
}

@Test
fun the_number_of_employees_per_department_stream() {
// given
data class Row(
val departmentId: Long,
val count: Long,
)

// when
val actual = employeeRepository.findStream {
selectNew<Row>(
path(EmployeeDepartment::departmentId),
count(Employee::employeeId),
).from(
entity(Employee::class),
join(Employee::departments),
).groupBy(
path(EmployeeDepartment::departmentId),
).orderBy(
path(EmployeeDepartment::departmentId).asc(),
)
}

// then
assertThat(actual.collect(Collectors.toList())).isEqualTo(
listOf(
Row(1, 6),
Row(2, 15),
Row(3, 18),
),
)
}

@Test
fun `the number of employees who belong to more than one department`() {
// when
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,24 @@ class SelectExample : WithAssertions {
assertThat(actual.hasNext()).isTrue
}

@Test
fun `the stream of books`() {
// given
val pageable = PageRequest.of(1, 3, Sort.by(Sort.Direction.ASC, "isbn"))

// when
val actual = bookRepository.findStream(pageable) {
select(
path(Book::isbn),
).from(
entity(Book::class),
)
}

// then
assertThat(actual.toList()).isEqualTo(listOf(Isbn("04"), Isbn("05"), Isbn("06")))
}

@Test
fun `the book with the most authors`() {
// when
Expand Down Expand Up @@ -321,6 +339,39 @@ class SelectExample : WithAssertions {
)
}

@Test
fun the_number_of_employees_per_department_stream() {
// given
data class Row(
val departmentId: Long,
val count: Long,
)

// when
val actual = employeeRepository.findStream {
selectNew<Row>(
path(EmployeeDepartment::departmentId),
count(Employee::employeeId),
).from(
entity(Employee::class),
join(Employee::departments),
).groupBy(
path(EmployeeDepartment::departmentId),
).orderBy(
path(EmployeeDepartment::departmentId).asc(),
)
}

// then
assertThat(actual.toList()).isEqualTo(
listOf(
Row(1, 6),
Row(2, 15),
Row(3, 18),
),
)
}

@Test
fun `the number of employees who belong to more than one department`() {
// given
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import org.springframework.data.domain.Page
import org.springframework.data.domain.Pageable
import org.springframework.data.domain.Slice
import org.springframework.data.repository.NoRepositoryBean
import java.util.stream.Stream

@NoRepositoryBean
@SinceJdsl("3.0.0")
Expand Down Expand Up @@ -134,6 +135,67 @@ interface KotlinJdslJpqlExecutor {
init: DSL.() -> JpqlQueryable<SelectQuery<T>>,
): Slice<T?>

/**
* Returns all results of the select query.
*/
@SinceJdsl("3.5.4")
fun <T : Any> findStream(
offset: Int? = null,
limit: Int? = null,
init: Jpql.() -> JpqlQueryable<SelectQuery<T>>,
): Stream<T?>

/**
* Returns all results of the select query.
*/
@SinceJdsl("3.5.4")
fun <T : Any, DSL : JpqlDsl> findStream(
dsl: JpqlDsl.Constructor<DSL>,
offset: Int? = null,
limit: Int? = null,
init: DSL.() -> JpqlQueryable<SelectQuery<T>>,
): Stream<T?>

/**
* Returns all results of the select query.
*/
@SinceJdsl("3.5.4")
fun <T : Any, DSL : JpqlDsl> findStream(
dsl: DSL,
offset: Int? = null,
limit: Int? = null,
init: DSL.() -> JpqlQueryable<SelectQuery<T>>,
): Stream<T?>

/**
* Returns all results of the select query.
*/
@SinceJdsl("3.5.4")
fun <T : Any> findStream(
pageable: Pageable,
init: Jpql.() -> JpqlQueryable<SelectQuery<T>>,
): Stream<T?>

/**
* Returns all results of the select query.
*/
@SinceJdsl("3.5.4")
fun <T : Any, DSL : JpqlDsl> findStream(
dsl: JpqlDsl.Constructor<DSL>,
pageable: Pageable,
init: DSL.() -> JpqlQueryable<SelectQuery<T>>,
): Stream<T?>

/**
* Returns all results of the select query.
*/
@SinceJdsl("3.5.4")
fun <T : Any, DSL : JpqlDsl> findStream(
dsl: DSL,
pageable: Pageable,
init: DSL.() -> JpqlQueryable<SelectQuery<T>>,
): Stream<T?>

/**
* Execute the update query.
*
Expand Down
Loading

0 comments on commit 7556c84

Please sign in to comment.