Skip to content

Commit

Permalink
SpringR2dbcKueryClient
Browse files Browse the repository at this point in the history
  • Loading branch information
be-hase committed May 27, 2024
1 parent 5c6d192 commit a4db1ab
Show file tree
Hide file tree
Showing 12 changed files with 169 additions and 39 deletions.
5 changes: 5 additions & 0 deletions build-logic/settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,8 @@ dependencyResolutionManagement {
}

rootProject.name = "build-logic"

plugins {
// Apply the foojay-resolver plugin to allow automatic download of JDKs
id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0"
}
21 changes: 7 additions & 14 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,26 +1,19 @@
[versions]
grpc-java = "1.64.0"
grpc-kotlin = "1.4.1"
kotlin-core = "2.0.0"
kotlin-core = "1.9.24"
kotlin-coroutines = "1.8.1"
ktlint = "1.2.1"
protobuf = "3.25.3"
spring-data = "3.3.0"

[libraries]
assertk = { module = "com.willowtreeapps.assertk:assertk-jvm", version = "0.28.1" }
grpc-java-protobuf = { module = "io.grpc:grpc-protobuf", version.ref = "grpc-java" }
grpc-java-stub = { module = "io.grpc:grpc-stub", version.ref = "grpc-java" }
grpc-kotlin-stub = { module = "io.grpc:grpc-kotlin-stub", version.ref = "grpc-kotlin" }
junit-bom = { module = "org.junit:junit-bom", version = "5.10.2" }
kotlinpoet = { module = "com.squareup:kotlinpoet", version = "1.17.0" }
kotlin-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlin-coroutines" }
kotlin-coroutines-reactor = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-reactor", version.ref = "kotlin-coroutines" }
mockk-core = { module = "io.mockk:mockk", version = "1.13.11" }
protobuf-java = { module = "com.google.protobuf:protobuf-java", version.ref = "protobuf" }
protobuf-kotlin = { module = "com.google.protobuf:protobuf-kotlin", version.ref = "protobuf" }
spring-data-jdbc = { module = "org.springframework.data:spring-data-jdbc", version.ref = "spring-data" }
spring-data-r2dbc = { module = "org.springframework.data:spring-data-r2dbc", version.ref = "spring-data" }

# gradle plugins for build-logic
gradle-plugin-detekt = { module = "io.gitlab.arturbosch.detekt:detekt-gradle-plugin", version = "1.23.6" }
gradle-plugin-kotlin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin-core" }
gradle-plugin-ktlint = { module = "org.jlleitschuh.gradle:ktlint-gradle", version = "12.1.1" }

[plugins]
protobuf = { id = "com.google.protobuf", version = "0.9.4" }
sonatype-central-upload = { id = "cl.franciscosolis.sonatype-central-upload", version = "1.0.3" }
4 changes: 4 additions & 0 deletions kuery-client-core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,7 @@ plugins {
id("conventions.ktlint")
id("conventions.detekt")
}

dependencies {
compileOnly(libs.kotlin.coroutines.core)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package dev.hsbrysk.kuery.core

import kotlinx.coroutines.flow.Flow
import kotlin.reflect.KClass

interface KueryClient {
fun sql(block: SqlDsl.() -> Unit): KueryFetchSpec
}

interface KueryFetchSpec {
suspend fun <T : Any> single(returnType: KClass<T>): T

suspend fun <T : Any> singleOrNull(returnType: KClass<T>): T?

suspend fun <T : Any> list(returnType: KClass<T>): List<T>

fun <T : Any> flow(returnType: KClass<T>): Flow<T>

suspend fun rowsUpdated(): Long

suspend fun generatedValues(vararg columns: String): Map<String, Any>
}
11 changes: 11 additions & 0 deletions kuery-client-core/src/main/kotlin/dev/hsbrysk/kuery/core/SqlDsl.kt
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,14 @@ interface SqlDsl {
inline fun <reified T : Any> SqlDsl.bind(value: T?): String {
return bind(value, T::class)
}

private val NUMBER_REGEX = "^[0-9]+$".toRegex()

fun (SqlDsl.() -> Unit).id(): String {
val parts = this.javaClass.name.split("$").filterNot { it.matches(NUMBER_REGEX) }
return if (parts.isEmpty()) {
"UNKNOWN"
} else {
parts.joinToString(".")
}
}
9 changes: 9 additions & 0 deletions kuery-client-spring-data-jdbc/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
plugins {
id("conventions.kotlin")
id("conventions.ktlint")
id("conventions.detekt")
}

dependencies {
implementation(libs.spring.data.jdbc)
}
12 changes: 12 additions & 0 deletions kuery-client-spring-data-r2dbc/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
plugins {
id("conventions.kotlin")
id("conventions.ktlint")
id("conventions.detekt")
}

dependencies {
implementation(projects.kueryClientCore)
implementation(libs.spring.data.r2dbc)
implementation(libs.kotlin.coroutines.core)
implementation(libs.kotlin.coroutines.reactor)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package dev.hsbrysk.kuery.spring.r2dbc

import dev.hsbrysk.kuery.core.Sql
import dev.hsbrysk.kuery.core.SqlDsl
import org.springframework.r2dbc.core.DatabaseClient

fun DatabaseClient.sql(block: SqlDsl.() -> Unit): DatabaseClient.GenericExecuteSpec {
val sql = Sql.create(block)
@Suppress("SqlSourceToSinkFlow")
return sql.parameters.fold(this.sql(sql.body)) { acc, parameter ->
if (parameter.value != null) {
acc.bindNull(parameter.name, parameter.kClass.java)
} else {
acc.bind(parameter.name, checkNotNull(parameter.value))
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package dev.hsbrysk.kuery.spring.r2dbc

import dev.hsbrysk.kuery.core.KueryClient
import dev.hsbrysk.kuery.core.KueryFetchSpec
import dev.hsbrysk.kuery.core.SqlDsl
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.reactor.awaitSingle
import org.springframework.data.r2dbc.convert.EntityRowMapper
import org.springframework.data.r2dbc.core.R2dbcEntityOperations
import org.springframework.r2dbc.core.DatabaseClient.GenericExecuteSpec
import org.springframework.r2dbc.core.RowsFetchSpec
import org.springframework.r2dbc.core.awaitOne
import org.springframework.r2dbc.core.awaitOneOrNull
import org.springframework.r2dbc.core.awaitRowsUpdated
import org.springframework.r2dbc.core.flow
import java.util.function.Function
import kotlin.reflect.KClass

class SpringR2dbcKueryClient(
private val operations: R2dbcEntityOperations,
) : KueryClient {
override fun sql(block: SqlDsl.() -> Unit): KueryFetchSpec {
return SpringR2dbcKueryFetchSpec(operations, block)
}
}

class SpringR2dbcKueryFetchSpec(
private val operations: R2dbcEntityOperations,
private val block: SqlDsl.() -> Unit,
) : KueryFetchSpec {
override suspend fun <T : Any> single(returnType: KClass<T>): T {
return operations.databaseClient.sql(block)
.map(returnType)
.awaitOne()
}

override suspend fun <T : Any> singleOrNull(returnType: KClass<T>): T? {
return operations.databaseClient.sql(block)
.map(returnType)
.awaitOneOrNull()
}

override suspend fun <T : Any> list(returnType: KClass<T>): List<T> {
return operations.databaseClient.sql(block)
.map(returnType)
.all()
.collectList()
.awaitSingle()
}

override fun <T : Any> flow(returnType: KClass<T>): Flow<T> {
return operations.databaseClient.sql(block)
.map(returnType)
.flow()
}

override suspend fun rowsUpdated(): Long {
return operations.databaseClient.sql(block)
.fetch()
.awaitRowsUpdated()
}

override suspend fun generatedValues(vararg columns: String): Map<String, Any> {
return operations.databaseClient.sql(block)
.filter(Function { it.returnGeneratedValues(*columns) })
.fetch()
.awaitOne()
}

private fun <T : Any> GenericExecuteSpec.map(returnType: KClass<T>): RowsFetchSpec<T> {
return this.map(EntityRowMapper(returnType.java, operations.converter))
}
}
11 changes: 9 additions & 2 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ dependencyResolutionManagement {

rootProject.name = "kuery-client"

include("kuery-client-core")
enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")

plugins {
// Apply the foojay-resolver plugin to allow automatic download of JDKs
id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0"
}

include("tmp")
include("kuery-client-core")
include("kuery-client-spring-data-jdbc")
include("kuery-client-spring-data-r2dbc")
10 changes: 0 additions & 10 deletions tmp/build.gradle.kts

This file was deleted.

13 changes: 0 additions & 13 deletions tmp/src/main/kotlin/Tmp.kt

This file was deleted.

0 comments on commit a4db1ab

Please sign in to comment.