Skip to content

Getting Started

This guide adds Kuery Client to an existing Kotlin/Spring Boot project. If you would rather start from a complete application, clone the repository and follow the runnable Examples.

Requirements

  • Java 17 or later
  • Gradle 8.4 or later
  • An existing Kotlin/JVM Spring project
  • A Kotlin, Spring Boot, and Spring Data version compatible with the Kuery Client release; see Compatibility

Parameter binding relies on the Kuery Client Kotlin compiler plugin, which is applied through its Gradle plugin. Maven, Kotlin/JS, Kotlin/Native, and Kotlin/Wasm are not currently supported.

Choose R2DBC or JDBC

R2DBCJDBC
Client typeKueryClientKueryBlockingClient
Regular terminal operationssuspendingblocking
Streamingcold coroutine Floweager, resource-backed CloseableSequence
Statement optionsfetchSizefetchSize, maxRows, queryTimeoutSeconds

Apart from these execution and streaming differences, SQL construction and typed row mapping use the same API.

Install

The following examples use MySQL. Add the Kuery Client plugin, the matching Spring Boot starter, Kuery Client module, and database driver to the module that contains your repository code.

kotlin
plugins {
    id("dev.hsbrysk.kuery-client") version "1.1.0"
}

repositories {
    mavenCentral()
}

dependencies {
    implementation("org.springframework.boot:spring-boot-starter-data-r2dbc")
    implementation("dev.hsbrysk.kuery-client:kuery-client-spring-data-r2dbc:1.1.0")
    runtimeOnly("io.asyncer:r2dbc-mysql")
}
kotlin
plugins {
    id("dev.hsbrysk.kuery-client") version "1.1.0"
}

repositories {
    mavenCentral()
}

dependencies {
    implementation("org.springframework.boot:spring-boot-starter-data-jdbc")
    implementation("dev.hsbrysk.kuery-client:kuery-client-spring-data-jdbc:1.1.0")
    runtimeOnly("com.mysql:mysql-connector-j")
}

Kuery Client does not provide a Spring Boot starter and does not bring in a database driver. For PostgreSQL or H2 driver choices, see Supported Platforms.

Multi-module projects

Apply dev.hsbrysk.kuery-client to every module that contains sql { ... } calls. Applying it only to the application module does not transform repository code compiled in another module.

Runtime error: SqlBuilder.add / String.unaryPlus must be rewritten

This means the Gradle plugin was not applied to the module that compiled the call. +"..." / add(...) are intentionally broken without the compiler plugin; otherwise interpolation could be executed as raw SQL. Apply the plugin as shown above, then clean and rebuild the affected module.

For a new project, enable the settings below. They remain opt-in because they were introduced after Kuery Client's initial releases, but they are intended to become the defaults in a future release. This guide uses MySQL; replace mysql with the project's dialect when needed:

kotlin
kueryClient {
    autoTrimIndent = true
    sqlSyntaxCheck = "mysql"
    strict = true
}

Dialect validation can report false positives for uncommon vendor-specific SQL. See Configuration before enabling these options in an existing codebase.

Configure the database

Configure Spring Boot as usual. For a local MySQL instance listening on port 3306:

yaml
spring:
  r2dbc:
    url: r2dbc:mysql://localhost:3306/app
    username: app
    password: secret
yaml
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/app
    username: app
    password: secret

This guide assumes a table created by your preferred migration tool:

sql
CREATE TABLE users (
    user_id INT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(50) NOT NULL
);

Register the client

Kuery Client deliberately has no auto-configuration. Register one shared client using Spring Boot's auto-configured ConnectionFactory or DataSource:

kotlin
@Configuration(proxyBeanMethods = false)
class KueryClientConfiguration {
    @Bean
    fun kueryClient(connectionFactory: ConnectionFactory): KueryClient =
        SpringR2dbcKueryClient.builder()
            .connectionFactory(connectionFactory)
            .build()
}
kotlin
@Configuration(proxyBeanMethods = false)
class KueryClientConfiguration {
    @Bean
    fun kueryClient(dataSource: DataSource): KueryBlockingClient =
        SpringJdbcKueryClient.builder()
            .dataSource(dataSource)
            .build()
}

Run the first query

The compiler plugin converts $userId into a named bind parameter. The database receives SQL equivalent to WHERE user_id = :p0; the value is never concatenated into the SQL text.

kotlin
data class User(
    val userId: Int,
    val username: String,
)

@Repository
class UserRepository(private val kueryClient: KueryClient) {
    suspend fun findById(userId: Int): User? = kueryClient
        .sql { +"SELECT user_id, username FROM users WHERE user_id = $userId" }
        .singleOrNull()
}
kotlin
data class User(
    val userId: Int,
    val username: String,
)

@Repository
class UserRepository(private val kueryClient: KueryBlockingClient) {
    fun findById(userId: Int): User? = kueryClient
        .sql { +"SELECT user_id, username FROM users WHERE user_id = $userId" }
        .singleOrNull()
}

Next, read Building SQL, Fetching Results, and Row Mapping.