From 04157a952c63d82ceaad9d84be2a5664b96b52a2 Mon Sep 17 00:00:00 2001 From: Hyunsik Kang Date: Fri, 27 May 2022 07:05:20 +0900 Subject: [PATCH 1/5] feat: change eclipse test persistence.xml settings for support h2 2.1.212 --- eclipselink/src/test/resources/META-INF/persistence.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/eclipselink/src/test/resources/META-INF/persistence.xml b/eclipselink/src/test/resources/META-INF/persistence.xml index bdb3c469e..11f627f0c 100644 --- a/eclipselink/src/test/resources/META-INF/persistence.xml +++ b/eclipselink/src/test/resources/META-INF/persistence.xml @@ -26,11 +26,13 @@ - + + + From f6a131799bb1f1eafce1887ae6a61e1ee42c8a47 Mon Sep 17 00:00:00 2001 From: Hyunsik Kang Date: Fri, 27 May 2022 07:05:54 +0900 Subject: [PATCH 2/5] feat: change test persistence.xml settings for support h2 2.1.212 --- .../eclipselink/src/main/resources/META-INF/persistence.xml | 2 +- examples/hibernate/src/main/resources/META-INF/persistence.xml | 2 +- .../src/main/resources/META-INF/persistence.xml | 2 +- hibernate/src/test/resources/META-INF/persistence.xml | 2 +- .../src/main/resources/META-INF/persistence.xml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/eclipselink/src/main/resources/META-INF/persistence.xml b/examples/eclipselink/src/main/resources/META-INF/persistence.xml index 693462a43..441230ab5 100644 --- a/examples/eclipselink/src/main/resources/META-INF/persistence.xml +++ b/examples/eclipselink/src/main/resources/META-INF/persistence.xml @@ -8,7 +8,7 @@ com.linecorp.kotlinjdsl.eclipselink.example.entity.Book - + diff --git a/examples/hibernate/src/main/resources/META-INF/persistence.xml b/examples/hibernate/src/main/resources/META-INF/persistence.xml index cf4e26881..143f1c329 100644 --- a/examples/hibernate/src/main/resources/META-INF/persistence.xml +++ b/examples/hibernate/src/main/resources/META-INF/persistence.xml @@ -8,7 +8,7 @@ com.linecorp.kotlinjdsl.hibernate.example.entity.Book - + diff --git a/examples/spring-boot-hibernate-reactive-2.6/src/main/resources/META-INF/persistence.xml b/examples/spring-boot-hibernate-reactive-2.6/src/main/resources/META-INF/persistence.xml index e5ca65eba..9c618fe8c 100644 --- a/examples/spring-boot-hibernate-reactive-2.6/src/main/resources/META-INF/persistence.xml +++ b/examples/spring-boot-hibernate-reactive-2.6/src/main/resources/META-INF/persistence.xml @@ -12,7 +12,7 @@ - + diff --git a/hibernate/src/test/resources/META-INF/persistence.xml b/hibernate/src/test/resources/META-INF/persistence.xml index 11e6cc591..e0cdda06c 100644 --- a/hibernate/src/test/resources/META-INF/persistence.xml +++ b/hibernate/src/test/resources/META-INF/persistence.xml @@ -24,7 +24,7 @@ com.linecorp.kotlinjdsl.test.entity.test.TestTable - + diff --git a/test-fixture/hibernate-reactive/src/main/resources/META-INF/persistence.xml b/test-fixture/hibernate-reactive/src/main/resources/META-INF/persistence.xml index a391a9cf4..819ff49b0 100644 --- a/test-fixture/hibernate-reactive/src/main/resources/META-INF/persistence.xml +++ b/test-fixture/hibernate-reactive/src/main/resources/META-INF/persistence.xml @@ -31,7 +31,7 @@ - + From 22a1cda1735965229bd81f4106c46fea49d82ec6 Mon Sep 17 00:00:00 2001 From: Hyunsik Kang Date: Fri, 27 May 2022 07:06:29 +0900 Subject: [PATCH 3/5] feat: support spring boot 2.7.0 --- .../src/main/resources/application.yml | 2 +- .../src/main/resources/application.yml | 2 +- examples/spring-boot-2.5/build.gradle.kts | 4 +- .../src/main/resources/application.yml | 2 +- examples/spring-boot-2.6/build.gradle.kts | 10 +-- .../src/main/resources/application.yml | 2 +- examples/spring-boot-2.7/build.gradle.kts | 26 ++++++ .../kotlinjdsl/spring/data/example/Books.kt | 80 +++++++++++++++++++ .../kotlinjdsl/spring/data/example/Main.kt | 11 +++ .../spring/data/example/entity/Book.kt | 17 ++++ .../src/main/resources/application.yml | 20 +++++ .../example/BookControllerIntegrationTest.kt | 75 +++++++++++++++++ .../build.gradle.kts | 10 +-- .../build.gradle.kts | 33 ++++++++ .../kotlinjdsl/spring/data/example/Books.kt | 78 ++++++++++++++++++ .../kotlinjdsl/spring/data/example/Main.kt | 11 +++ .../data/example/QueryFactoryConfiguration.kt | 43 ++++++++++ .../spring/data/example/entity/Book.kt | 17 ++++ .../main/resources/META-INF/persistence.xml | 27 +++++++ .../example/BookControllerIntegrationTest.kt | 58 ++++++++++++++ settings.gradle.kts | 2 + 21 files changed, 514 insertions(+), 16 deletions(-) create mode 100644 examples/spring-boot-2.7/build.gradle.kts create mode 100644 examples/spring-boot-2.7/src/main/kotlin/com/linecorp/kotlinjdsl/spring/data/example/Books.kt create mode 100644 examples/spring-boot-2.7/src/main/kotlin/com/linecorp/kotlinjdsl/spring/data/example/Main.kt create mode 100644 examples/spring-boot-2.7/src/main/kotlin/com/linecorp/kotlinjdsl/spring/data/example/entity/Book.kt create mode 100644 examples/spring-boot-2.7/src/main/resources/application.yml create mode 100644 examples/spring-boot-2.7/src/test/kotlin/com/linecorp/kotlinjdsl/spring/data/example/BookControllerIntegrationTest.kt create mode 100644 examples/spring-boot-hibernate-reactive-2.7/build.gradle.kts create mode 100644 examples/spring-boot-hibernate-reactive-2.7/src/main/kotlin/com/linecorp/kotlinjdsl/spring/data/example/Books.kt create mode 100644 examples/spring-boot-hibernate-reactive-2.7/src/main/kotlin/com/linecorp/kotlinjdsl/spring/data/example/Main.kt create mode 100644 examples/spring-boot-hibernate-reactive-2.7/src/main/kotlin/com/linecorp/kotlinjdsl/spring/data/example/QueryFactoryConfiguration.kt create mode 100644 examples/spring-boot-hibernate-reactive-2.7/src/main/kotlin/com/linecorp/kotlinjdsl/spring/data/example/entity/Book.kt create mode 100644 examples/spring-boot-hibernate-reactive-2.7/src/main/resources/META-INF/persistence.xml create mode 100644 examples/spring-boot-hibernate-reactive-2.7/src/test/kotlin/com/linecorp/kotlinjdsl/spring/data/example/BookControllerIntegrationTest.kt diff --git a/examples/spring-boot-2.3/src/main/resources/application.yml b/examples/spring-boot-2.3/src/main/resources/application.yml index d405f290e..68c2c56fc 100644 --- a/examples/spring-boot-2.3/src/main/resources/application.yml +++ b/examples/spring-boot-2.3/src/main/resources/application.yml @@ -1,7 +1,7 @@ spring: datasource: driver-class-name: org.h2.Driver - url: jdbc:h2:mem:test;MODE=MYSQL + url: jdbc:h2:mem:test;MODE=MYSQL;DATABASE_TO_LOWER=TRUE username: sa password: password diff --git a/examples/spring-boot-2.4/src/main/resources/application.yml b/examples/spring-boot-2.4/src/main/resources/application.yml index d405f290e..68c2c56fc 100644 --- a/examples/spring-boot-2.4/src/main/resources/application.yml +++ b/examples/spring-boot-2.4/src/main/resources/application.yml @@ -1,7 +1,7 @@ spring: datasource: driver-class-name: org.h2.Driver - url: jdbc:h2:mem:test;MODE=MYSQL + url: jdbc:h2:mem:test;MODE=MYSQL;DATABASE_TO_LOWER=TRUE username: sa password: password diff --git a/examples/spring-boot-2.5/build.gradle.kts b/examples/spring-boot-2.5/build.gradle.kts index 445b362cc..d040c58ba 100644 --- a/examples/spring-boot-2.5/build.gradle.kts +++ b/examples/spring-boot-2.5/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - id("org.springframework.boot") version "2.5.8" + id("org.springframework.boot") version "2.5.14" kotlin("plugin.spring") kotlin("plugin.jpa") } @@ -24,7 +24,7 @@ dependencies { implementation("org.springframework.boot:spring-boot-starter-data-jpa") implementation(Dependencies.jacksonKotlinModule) implementation(Dependencies.h2) - implementation(platform("org.springframework.boot:spring-boot-dependencies:2.5.8")) + implementation(platform("org.springframework.boot:spring-boot-dependencies:2.5.14")) testImplementation("org.springframework.boot:spring-boot-starter-test") } diff --git a/examples/spring-boot-2.5/src/main/resources/application.yml b/examples/spring-boot-2.5/src/main/resources/application.yml index d405f290e..68c2c56fc 100644 --- a/examples/spring-boot-2.5/src/main/resources/application.yml +++ b/examples/spring-boot-2.5/src/main/resources/application.yml @@ -1,7 +1,7 @@ spring: datasource: driver-class-name: org.h2.Driver - url: jdbc:h2:mem:test;MODE=MYSQL + url: jdbc:h2:mem:test;MODE=MYSQL;DATABASE_TO_LOWER=TRUE username: sa password: password diff --git a/examples/spring-boot-2.6/build.gradle.kts b/examples/spring-boot-2.6/build.gradle.kts index 65e035eca..42b3d0860 100644 --- a/examples/spring-boot-2.6/build.gradle.kts +++ b/examples/spring-boot-2.6/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - id("org.springframework.boot") version Dependencies.springBootVersion + id("org.springframework.boot") version "2.6.8" kotlin("plugin.spring") kotlin("plugin.jpa") } @@ -16,11 +16,11 @@ dependencies { // implementation("com.linecorp.kotlin-jdsl:spring-data-kotlin-jdsl-starter:x.y.z") implementation(Modules.springDataStarter) - implementation(Dependencies.springBootWeb) - implementation(Dependencies.springBootJpa) + implementation("org.springframework.boot:spring-boot-starter-web") + implementation("org.springframework.boot:spring-boot-starter-data-jpa") implementation(Dependencies.jacksonKotlinModule) implementation(Dependencies.h2) - implementation(platform(Dependencies.springBootBom)) + implementation(platform("org.springframework.boot:spring-boot-dependencies:2.6.8")) - testImplementation(Dependencies.springBootTest) + testImplementation("org.springframework.boot:spring-boot-starter-test") } diff --git a/examples/spring-boot-2.6/src/main/resources/application.yml b/examples/spring-boot-2.6/src/main/resources/application.yml index d405f290e..68c2c56fc 100644 --- a/examples/spring-boot-2.6/src/main/resources/application.yml +++ b/examples/spring-boot-2.6/src/main/resources/application.yml @@ -1,7 +1,7 @@ spring: datasource: driver-class-name: org.h2.Driver - url: jdbc:h2:mem:test;MODE=MYSQL + url: jdbc:h2:mem:test;MODE=MYSQL;DATABASE_TO_LOWER=TRUE username: sa password: password diff --git a/examples/spring-boot-2.7/build.gradle.kts b/examples/spring-boot-2.7/build.gradle.kts new file mode 100644 index 000000000..65e035eca --- /dev/null +++ b/examples/spring-boot-2.7/build.gradle.kts @@ -0,0 +1,26 @@ +plugins { + id("org.springframework.boot") version Dependencies.springBootVersion + kotlin("plugin.spring") + kotlin("plugin.jpa") +} + +apply(plugin = "org.springframework.boot") +apply(plugin = "kotlin-spring") +apply(plugin = "kotlin-jpa") + +coverage { + exclude(project) +} + +dependencies { + // implementation("com.linecorp.kotlin-jdsl:spring-data-kotlin-jdsl-starter:x.y.z") + implementation(Modules.springDataStarter) + + implementation(Dependencies.springBootWeb) + implementation(Dependencies.springBootJpa) + implementation(Dependencies.jacksonKotlinModule) + implementation(Dependencies.h2) + implementation(platform(Dependencies.springBootBom)) + + testImplementation(Dependencies.springBootTest) +} diff --git a/examples/spring-boot-2.7/src/main/kotlin/com/linecorp/kotlinjdsl/spring/data/example/Books.kt b/examples/spring-boot-2.7/src/main/kotlin/com/linecorp/kotlinjdsl/spring/data/example/Books.kt new file mode 100644 index 000000000..848b7c815 --- /dev/null +++ b/examples/spring-boot-2.7/src/main/kotlin/com/linecorp/kotlinjdsl/spring/data/example/Books.kt @@ -0,0 +1,80 @@ +package com.linecorp.kotlinjdsl.spring.data.example + +import com.linecorp.kotlinjdsl.querydsl.expression.col +import com.linecorp.kotlinjdsl.spring.data.SpringDataQueryFactory +import com.linecorp.kotlinjdsl.spring.data.example.entity.Book +import com.linecorp.kotlinjdsl.spring.data.listQuery +import com.linecorp.kotlinjdsl.spring.data.singleQuery +import org.springframework.http.ResponseEntity +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional +import org.springframework.web.bind.annotation.* +import javax.persistence.EntityManager + +@RestController +@RequestMapping("/api/v1/books") +class BookController( + private val bookService: BookService, +) { + @PostMapping + fun createBook(@RequestBody spec: BookService.CreateBookSpec): ResponseEntity { + val book = bookService.create(spec) + + return ResponseEntity.ok(book.id) + } + + @GetMapping("/{bookId}") + fun findById(@PathVariable bookId: Long): ResponseEntity { + val book = bookService.findById(bookId) + + return ResponseEntity.ok(book) + } + + @GetMapping + fun findAll(@RequestParam("name") name: String): ResponseEntity> { + val books = bookService.findAll(BookService.FindBookSpec(name = name)) + + return ResponseEntity.ok(books) + } +} + +@Service +@Transactional +class BookService( + private val entityManager: EntityManager, + private val queryFactory: SpringDataQueryFactory, +) { + fun create(spec: CreateBookSpec): Book { + return Book(name = spec.name).also { + entityManager.persist(it) + } + } + + fun findById(id: Long): Book { + return queryFactory.singleQuery { + select(entity(Book::class)) + from(entity(Book::class)) + where(col(Book::id).equal(id)) + } + } + + fun findAll(spec: FindBookSpec): List { + return queryFactory.listQuery { + select(entity(Book::class)) + from(entity(Book::class)) + where(col(Book::name).like("%${spec.name}%")) + } + } + + data class CreateBookSpec( + val name: String + ) { + fun toJson() = """{"name":"$name"}""" + } + + data class FindBookSpec( + val name: String + ) { + fun toJson() = """{"name":"$name"}""" + } +} diff --git a/examples/spring-boot-2.7/src/main/kotlin/com/linecorp/kotlinjdsl/spring/data/example/Main.kt b/examples/spring-boot-2.7/src/main/kotlin/com/linecorp/kotlinjdsl/spring/data/example/Main.kt new file mode 100644 index 000000000..752348683 --- /dev/null +++ b/examples/spring-boot-2.7/src/main/kotlin/com/linecorp/kotlinjdsl/spring/data/example/Main.kt @@ -0,0 +1,11 @@ +package com.linecorp.kotlinjdsl.spring.data.example + +import org.springframework.boot.autoconfigure.SpringBootApplication +import org.springframework.boot.runApplication + +@SpringBootApplication +class ExampleApplication + +fun main(args: Array) { + runApplication(*args) +} diff --git a/examples/spring-boot-2.7/src/main/kotlin/com/linecorp/kotlinjdsl/spring/data/example/entity/Book.kt b/examples/spring-boot-2.7/src/main/kotlin/com/linecorp/kotlinjdsl/spring/data/example/entity/Book.kt new file mode 100644 index 000000000..e1137c86e --- /dev/null +++ b/examples/spring-boot-2.7/src/main/kotlin/com/linecorp/kotlinjdsl/spring/data/example/entity/Book.kt @@ -0,0 +1,17 @@ +package com.linecorp.kotlinjdsl.spring.data.example.entity + +import javax.persistence.* + +@Entity +@Table(name = "book") +data class Book( + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + val id: Long = 0, + + @Column + val name: String, +) { + fun toJson() = """{"id":$id,"name":"$name"}""" +} diff --git a/examples/spring-boot-2.7/src/main/resources/application.yml b/examples/spring-boot-2.7/src/main/resources/application.yml new file mode 100644 index 000000000..68c2c56fc --- /dev/null +++ b/examples/spring-boot-2.7/src/main/resources/application.yml @@ -0,0 +1,20 @@ +spring: + datasource: + driver-class-name: org.h2.Driver + url: jdbc:h2:mem:test;MODE=MYSQL;DATABASE_TO_LOWER=TRUE + username: sa + password: password + + jpa: + database-platform: org.hibernate.dialect.MySQL8Dialect + hibernate: + ddl-auto: update + use-new-id-generator-mappings: true + naming: + physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl + properties: + hibernate: + check_nullability: true + use_sql_comments: true + format_sql: true + show_sql: true \ No newline at end of file diff --git a/examples/spring-boot-2.7/src/test/kotlin/com/linecorp/kotlinjdsl/spring/data/example/BookControllerIntegrationTest.kt b/examples/spring-boot-2.7/src/test/kotlin/com/linecorp/kotlinjdsl/spring/data/example/BookControllerIntegrationTest.kt new file mode 100644 index 000000000..ba3a0b35c --- /dev/null +++ b/examples/spring-boot-2.7/src/test/kotlin/com/linecorp/kotlinjdsl/spring/data/example/BookControllerIntegrationTest.kt @@ -0,0 +1,75 @@ +package com.linecorp.kotlinjdsl.spring.data.example + +import com.linecorp.kotlinjdsl.spring.data.example.entity.Book +import org.assertj.core.api.WithAssertions +import org.junit.jupiter.api.Test +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.http.MediaType +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.MockMvcResultMatchersDsl +import org.springframework.test.web.servlet.get +import org.springframework.test.web.servlet.post + +@SpringBootTest +@AutoConfigureMockMvc +internal class BookControllerIntegrationTest : WithAssertions { + @Autowired + private lateinit var mockMvc: MockMvc + + private val context = "/api/v1/books" + + @Test + fun createBook() { + createBook(BookService.CreateBookSpec("name")) { + status { isOk() } + } + } + + @Test + fun findById() { + val spec = BookService.CreateBookSpec("name1") + val id = createBook(spec) + mockMvc.get("$context/$id") + .andExpect { + status { isOk() } + content { + json(Book(id = id, name = spec.name).toJson()) + } + } + } + + @Test + fun findByName() { + val spec1 = BookService.CreateBookSpec("name2") + val spec2 = BookService.CreateBookSpec("name2") + val id1 = createBook(spec1) + val id2 = createBook(spec2) + mockMvc.get(context) { + param("name", spec1.name) + } + .andExpect { + status { isOk() } + content { + json( + buildString { + append("[") + append(Book(id = id1, name = spec1.name).toJson()) + append(",") + append(Book(id = id2, name = spec2.name).toJson()) + append("]") + } + ) + } + } + } + + private fun createBook(spec: BookService.CreateBookSpec, dsl: MockMvcResultMatchersDsl.() -> Unit = {}) = mockMvc.post(context) { + contentType = MediaType.APPLICATION_JSON + content = spec.toJson() + }.andExpect(dsl) + .andReturn() + .response + .contentAsString.toLong() +} diff --git a/examples/spring-boot-hibernate-reactive-2.6/build.gradle.kts b/examples/spring-boot-hibernate-reactive-2.6/build.gradle.kts index 5ce24c781..0b5417dea 100644 --- a/examples/spring-boot-hibernate-reactive-2.6/build.gradle.kts +++ b/examples/spring-boot-hibernate-reactive-2.6/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - id("org.springframework.boot") version Dependencies.springBootVersion + id("org.springframework.boot") version "2.6.8" kotlin("plugin.spring") kotlin("plugin.jpa") } @@ -23,11 +23,11 @@ dependencies { implementation(Modules.testFixtureHibernateReactive) - implementation(Dependencies.springBootWebflux) - implementation(Dependencies.springBootJpa) + implementation("org.springframework.boot:spring-boot-starter-webflux") + implementation("org.springframework.boot:spring-boot-starter-data-jpa:") implementation(Dependencies.jacksonKotlinModule) implementation(Dependencies.h2) - implementation(platform(Dependencies.springBootBom)) + implementation(platform("org.springframework.boot:spring-boot-dependencies:2.6.8")) - testImplementation(Dependencies.springBootTest) + testImplementation("org.springframework.boot:spring-boot-starter-test") } diff --git a/examples/spring-boot-hibernate-reactive-2.7/build.gradle.kts b/examples/spring-boot-hibernate-reactive-2.7/build.gradle.kts new file mode 100644 index 000000000..5ce24c781 --- /dev/null +++ b/examples/spring-boot-hibernate-reactive-2.7/build.gradle.kts @@ -0,0 +1,33 @@ +plugins { + id("org.springframework.boot") version Dependencies.springBootVersion + kotlin("plugin.spring") + kotlin("plugin.jpa") +} + +apply(plugin = "org.springframework.boot") +apply(plugin = "kotlin-spring") +apply(plugin = "kotlin-jpa") + +coverage { + exclude(project) +} + +dependencies { + implementation(Modules.query) + // implementation("com.linecorp.kotlin-jdsl:spring-data-kotlin-jdsl-hibernate-reactive:x.y.z") + implementation(Modules.springDataHibernateReactive) + implementation(Dependencies.hibernateReactive) + implementation(Dependencies.coroutineJdk8) + implementation(Dependencies.coroutineReactor) + implementation(Dependencies.mutiny) + + implementation(Modules.testFixtureHibernateReactive) + + implementation(Dependencies.springBootWebflux) + implementation(Dependencies.springBootJpa) + implementation(Dependencies.jacksonKotlinModule) + implementation(Dependencies.h2) + implementation(platform(Dependencies.springBootBom)) + + testImplementation(Dependencies.springBootTest) +} diff --git a/examples/spring-boot-hibernate-reactive-2.7/src/main/kotlin/com/linecorp/kotlinjdsl/spring/data/example/Books.kt b/examples/spring-boot-hibernate-reactive-2.7/src/main/kotlin/com/linecorp/kotlinjdsl/spring/data/example/Books.kt new file mode 100644 index 000000000..5f7eaa70f --- /dev/null +++ b/examples/spring-boot-hibernate-reactive-2.7/src/main/kotlin/com/linecorp/kotlinjdsl/spring/data/example/Books.kt @@ -0,0 +1,78 @@ +package com.linecorp.kotlinjdsl.spring.data.example + +import com.linecorp.kotlinjdsl.querydsl.expression.col +import com.linecorp.kotlinjdsl.spring.data.example.entity.Book +import com.linecorp.kotlinjdsl.spring.data.reactive.query.SpringDataHibernateMutinyReactiveQueryFactory +import com.linecorp.kotlinjdsl.spring.data.reactive.query.listQuery +import com.linecorp.kotlinjdsl.spring.data.reactive.query.singleQuery +import org.hibernate.reactive.mutiny.Mutiny +import org.springframework.http.ResponseEntity +import org.springframework.stereotype.Service +import org.springframework.web.bind.annotation.* +import reactor.core.publisher.Mono +import java.util.concurrent.CompletionStage + +@RestController +@RequestMapping("/api/v1/books") +class BookController( + private val bookService: BookService, +) { + @PostMapping + fun createBook(@RequestBody spec: BookService.CreateBookSpec): Mono> = + Mono.fromCompletionStage { bookService.create(spec) }.map { ResponseEntity.ok().body(it.id) } + + @GetMapping("/{bookId}") + suspend fun findById(@PathVariable bookId: Long): ResponseEntity { + val book = bookService.findById(bookId) + + return ResponseEntity.ok(book) + } + + @GetMapping + suspend fun findAll(@RequestParam("name") name: String): ResponseEntity> { + val books = bookService.findAll(BookService.FindBookSpec(name = name)) + + return ResponseEntity.ok(books) + } +} + +@Service +class BookService( + private val mutinySessionFactory: Mutiny.SessionFactory, + private val queryFactory: SpringDataHibernateMutinyReactiveQueryFactory, +) { + fun create(spec: CreateBookSpec): CompletionStage { + val book = Book(name = spec.name) + return mutinySessionFactory.withSession { session -> session.persist(book).flatMap { session.flush() } } + .map { book } + .subscribeAsCompletionStage() + } + + suspend fun findById(id: Long): Book { + return queryFactory.singleQuery { + select(entity(Book::class)) + from(entity(Book::class)) + where(col(Book::id).equal(id)) + } + } + + suspend fun findAll(spec: FindBookSpec): List { + return queryFactory.listQuery { + select(entity(Book::class)) + from(entity(Book::class)) + where(col(Book::name).like("%${spec.name}%")) + } + } + + data class CreateBookSpec( + val name: String + ) { + fun toJson() = """{"name":"$name"}""" + } + + data class FindBookSpec( + val name: String + ) { + fun toJson() = """{"name":"$name"}""" + } +} diff --git a/examples/spring-boot-hibernate-reactive-2.7/src/main/kotlin/com/linecorp/kotlinjdsl/spring/data/example/Main.kt b/examples/spring-boot-hibernate-reactive-2.7/src/main/kotlin/com/linecorp/kotlinjdsl/spring/data/example/Main.kt new file mode 100644 index 000000000..752348683 --- /dev/null +++ b/examples/spring-boot-hibernate-reactive-2.7/src/main/kotlin/com/linecorp/kotlinjdsl/spring/data/example/Main.kt @@ -0,0 +1,11 @@ +package com.linecorp.kotlinjdsl.spring.data.example + +import org.springframework.boot.autoconfigure.SpringBootApplication +import org.springframework.boot.runApplication + +@SpringBootApplication +class ExampleApplication + +fun main(args: Array) { + runApplication(*args) +} diff --git a/examples/spring-boot-hibernate-reactive-2.7/src/main/kotlin/com/linecorp/kotlinjdsl/spring/data/example/QueryFactoryConfiguration.kt b/examples/spring-boot-hibernate-reactive-2.7/src/main/kotlin/com/linecorp/kotlinjdsl/spring/data/example/QueryFactoryConfiguration.kt new file mode 100644 index 000000000..5d1299e17 --- /dev/null +++ b/examples/spring-boot-hibernate-reactive-2.7/src/main/kotlin/com/linecorp/kotlinjdsl/spring/data/example/QueryFactoryConfiguration.kt @@ -0,0 +1,43 @@ +package com.linecorp.kotlinjdsl.spring.data.example + +import com.linecorp.kotlinjdsl.query.creator.SubqueryCreatorImpl +import com.linecorp.kotlinjdsl.spring.data.reactive.query.SpringDataHibernateMutinyReactiveQueryFactory +import org.hibernate.reactive.mutiny.Mutiny.SessionFactory +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import javax.persistence.EntityManagerFactory +import javax.persistence.Persistence + +@Configuration +class QueryFactoryConfiguration { + @Bean + fun entityManagerFactory() = Persistence.createEntityManagerFactory("book") + + @Bean + fun mutinySessionFactory(entityManagerFactory: EntityManagerFactory) = + entityManagerFactory.unwrap(SessionFactory::class.java) + .apply { + withSession { + // currently H2 db does not support officially + // and does not allow extract & create schema with h2 db in hibernate-reactive + // so DDL query execute directly + it.createNativeQuery( + """ + create table book ( + id bigint not null auto_increment, + name varchar(255), + primary key (id) + ) + """.trimIndent() + ).executeUpdate() + }.subscribeAsCompletionStage().get() + } + + @Bean + fun queryFactory(sessionFactory: SessionFactory): SpringDataHibernateMutinyReactiveQueryFactory { + return SpringDataHibernateMutinyReactiveQueryFactory( + sessionFactory = sessionFactory, + subqueryCreator = SubqueryCreatorImpl() + ) + } +} diff --git a/examples/spring-boot-hibernate-reactive-2.7/src/main/kotlin/com/linecorp/kotlinjdsl/spring/data/example/entity/Book.kt b/examples/spring-boot-hibernate-reactive-2.7/src/main/kotlin/com/linecorp/kotlinjdsl/spring/data/example/entity/Book.kt new file mode 100644 index 000000000..e1137c86e --- /dev/null +++ b/examples/spring-boot-hibernate-reactive-2.7/src/main/kotlin/com/linecorp/kotlinjdsl/spring/data/example/entity/Book.kt @@ -0,0 +1,17 @@ +package com.linecorp.kotlinjdsl.spring.data.example.entity + +import javax.persistence.* + +@Entity +@Table(name = "book") +data class Book( + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + val id: Long = 0, + + @Column + val name: String, +) { + fun toJson() = """{"id":$id,"name":"$name"}""" +} diff --git a/examples/spring-boot-hibernate-reactive-2.7/src/main/resources/META-INF/persistence.xml b/examples/spring-boot-hibernate-reactive-2.7/src/main/resources/META-INF/persistence.xml new file mode 100644 index 000000000..9c618fe8c --- /dev/null +++ b/examples/spring-boot-hibernate-reactive-2.7/src/main/resources/META-INF/persistence.xml @@ -0,0 +1,27 @@ + + + + + org.hibernate.reactive.provider.ReactivePersistenceProvider + com.linecorp.kotlinjdsl.spring.data.example.entity.Book + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/spring-boot-hibernate-reactive-2.7/src/test/kotlin/com/linecorp/kotlinjdsl/spring/data/example/BookControllerIntegrationTest.kt b/examples/spring-boot-hibernate-reactive-2.7/src/test/kotlin/com/linecorp/kotlinjdsl/spring/data/example/BookControllerIntegrationTest.kt new file mode 100644 index 000000000..ce12c959b --- /dev/null +++ b/examples/spring-boot-hibernate-reactive-2.7/src/test/kotlin/com/linecorp/kotlinjdsl/spring/data/example/BookControllerIntegrationTest.kt @@ -0,0 +1,58 @@ +package com.linecorp.kotlinjdsl.spring.data.example + +import com.linecorp.kotlinjdsl.spring.data.example.entity.Book +import org.assertj.core.api.WithAssertions +import org.junit.jupiter.api.Test +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.test.web.reactive.server.WebTestClient + +@SpringBootTest +@AutoConfigureWebTestClient(timeout = "100000") +internal class BookControllerIntegrationTest : WithAssertions { + @Autowired + private lateinit var client: WebTestClient + + private val context = "/api/v1/books" + + @Test + fun createBook() { + createBook(BookService.CreateBookSpec("name")) + } + + @Test + fun findById() { + val spec = BookService.CreateBookSpec("name1") + val id = createBook(spec) + client.get().uri("$context/$id") + .exchange() + .expectStatus().isOk + .expectBody(Book::class.java) + .value { + assertThat(Book(id = id, name = spec.name)).isEqualTo(it) + } + + } + + @Test + fun findByName() { + val spec1 = BookService.CreateBookSpec("name2") + val spec2 = BookService.CreateBookSpec("name2") + val id1 = createBook(spec1) + val id2 = createBook(spec2) + client.get().uri(context + "?name=${spec1.name}") + .exchange() + .expectStatus().isOk + .expectBodyList(Book::class.java) + .contains(Book(id = id1, name = spec1.name), Book(id = id2, name = spec2.name)) + } + + private fun createBook(spec: BookService.CreateBookSpec) = client.post().uri(context) + .bodyValue(spec) + .exchange() + .expectStatus().isOk + .returnResult(Long::class.java) + .responseBody + .blockFirst()!! +} diff --git a/settings.gradle.kts b/settings.gradle.kts index 25bc8d000..7f5f37dd5 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -39,7 +39,9 @@ module(name = ":test-fixture-hibernate-reactive", path = "test-fixture/hibernate module(name = ":hibernate-example", path = "examples/hibernate") module(name = ":eclipselink-example", path = "examples/eclipselink") module(name = ":spring-data-boot-2.6-example", path = "examples/spring-boot-2.6") +module(name = ":spring-data-boot-2.7-example", path = "examples/spring-boot-2.7") module(name = ":spring-data-boot-hibernate-reactive-2.6-example", path = "examples/spring-boot-hibernate-reactive-2.6") +module(name = ":spring-data-boot-hibernate-reactive-2.7-example", path = "examples/spring-boot-hibernate-reactive-2.7") module(name = ":spring-data-boot-2.5-example", path = "examples/spring-boot-2.5") module(name = ":spring-data-boot-2.4-example", path = "examples/spring-boot-2.4") module(name = ":spring-data-boot-2.3-example", path = "examples/spring-boot-2.3") From ad60c283ae61590363901f16272e8fce9443ed34 Mon Sep 17 00:00:00 2001 From: Hyunsik Kang Date: Fri, 27 May 2022 07:04:04 +0900 Subject: [PATCH 4/5] build: upgrade dependencies --- buildSrc/src/main/kotlin/Dependencies.kt | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/buildSrc/src/main/kotlin/Dependencies.kt b/buildSrc/src/main/kotlin/Dependencies.kt index e45a09897..f552eca4b 100644 --- a/buildSrc/src/main/kotlin/Dependencies.kt +++ b/buildSrc/src/main/kotlin/Dependencies.kt @@ -4,9 +4,9 @@ import org.gradle.api.artifacts.dsl.DependencyHandler object Dependencies { const val kotlinVersion = "1.6.21" - const val springCoreVersion = "5.3.19" - const val springBootVersion = "2.6.7" - const val springDataJpaVersion = "2.6.4" + const val springCoreVersion = "5.3.20" + const val springBootVersion = "2.7.0" + const val springDataJpaVersion = "2.7.0" const val coroutineVersion = "1.6.1" // kotlin @@ -17,12 +17,12 @@ object Dependencies { const val javaPersistenceApi = "javax.persistence:javax.persistence-api:2.2" const val slf4j = "org.slf4j:slf4j-api:1.7.36" const val logback = "ch.qos.logback:logback-classic:1.2.11" - const val hibernate = "org.hibernate:hibernate-core:5.6.8.Final" - const val hibernateReactive = "org.hibernate.reactive:hibernate-reactive-core:1.1.4.Final" + const val hibernate = "org.hibernate:hibernate-core:5.6.9.Final" + const val hibernateReactive = "org.hibernate.reactive:hibernate-reactive-core:1.1.6.Final" const val eclipselink = "org.eclipse.persistence:org.eclipse.persistence.jpa:2.7.10" const val jacksonKotlinModule = "com.fasterxml.jackson.module:jackson-module-kotlin" - const val agroalPool = "io.agroal:agroal-pool:1.14" - const val vertxJdbcClient = "io.vertx:vertx-jdbc-client:4.2.7" + const val agroalPool = "io.agroal:agroal-pool:2.0" + const val vertxJdbcClient = "io.vertx:vertx-jdbc-client:4.3.1" const val coroutineJdk8 = "org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:$coroutineVersion" const val coroutineReactor = "org.jetbrains.kotlinx:kotlinx-coroutines-reactor:$coroutineVersion" @@ -42,16 +42,16 @@ object Dependencies { const val springCore = "org.springframework:spring-core:${springCoreVersion}" const val springBeans = "org.springframework:spring-beans:${springCoreVersion}" const val springJpa = "org.springframework.data:spring-data-jpa:${springDataJpaVersion}" - const val springBatchInfrastructure = "org.springframework.batch:spring-batch-infrastructure:4.3.5" + const val springBatchInfrastructure = "org.springframework.batch:spring-batch-infrastructure:4.3.6" // Test const val junit = "org.junit.jupiter:junit-jupiter:5.8.2" const val assertJ = "org.assertj:assertj-core:3.22.0" - const val mockk = "io.mockk:mockk:1.12.3" + const val mockk = "io.mockk:mockk:1.12.4" - const val h2 = "com.h2database:h2:1.4.200" + const val h2 = "com.h2database:h2:2.1.212" - const val mutinyVersion = "1.4.0" + const val mutinyVersion = "1.5.0" const val mutinyCore = "io.smallrye.reactive:mutiny:$mutinyVersion" const val mutinyKotlin = "io.smallrye.reactive:mutiny-kotlin:$mutinyVersion" val mutiny = listOf(mutinyCore, mutinyKotlin) From 26bed473ee49c81d5b7f85e9f9eeee13b7a923cd Mon Sep 17 00:00:00 2001 From: Hyunsik Kang Date: Fri, 27 May 2022 14:40:32 +0900 Subject: [PATCH 5/5] chore: version 2.0.3.RELEASE --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 77b27e603..3114e4295 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -13,7 +13,7 @@ plugins { allprojects { group = "com.linecorp.kotlin-jdsl" - version = "2.0.2.RELEASE" + version = "2.0.3.RELEASE" repositories { mavenCentral()