or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

column-adapters.mddatabase-driver.mdindex.mdlogging-utilities.mdquery-system.mdschema-management.mdtransaction-management.md
tile.json

tessl/maven-app-cash-sqldelight--runtime

SQLDelight multiplatform runtime library providing typesafe Kotlin APIs from SQL statements with compile-time schema verification

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
mavenpkg:maven/app.cash.sqldelight/runtime@2.1.x

To install, run

npx @tessl/cli install tessl/maven-app-cash-sqldelight--runtime@2.1.0

index.mddocs/

SQLDelight Runtime

SQLDelight Runtime is the multiplatform runtime library for SQLDelight, providing typesafe Kotlin APIs from SQL statements. It serves as the foundational layer that enables compile-time schema verification, reactive query results, and thread-safe database operations across JVM, Android, Native, and JavaScript platforms.

Package Information

  • Package Name: app.cash.sqldelight:runtime
  • Package Type: Maven/Gradle
  • Language: Kotlin (Multiplatform)
  • Installation: implementation "app.cash.sqldelight:runtime:2.1.0"

Core Imports

import app.cash.sqldelight.Query
import app.cash.sqldelight.Transacter
import app.cash.sqldelight.SuspendingTransacter
import app.cash.sqldelight.ColumnAdapter
import app.cash.sqldelight.EnumColumnAdapter
import app.cash.sqldelight.db.SqlDriver
import app.cash.sqldelight.db.SqlCursor
import app.cash.sqldelight.db.QueryResult
import app.cash.sqldelight.db.SqlSchema
import app.cash.sqldelight.db.AfterVersion
import app.cash.sqldelight.logs.LogSqliteDriver
import app.cash.sqldelight.logs.StatementParameterInterceptor

Basic Usage

import app.cash.sqldelight.Query
import app.cash.sqldelight.Transacter
import app.cash.sqldelight.db.SqlDriver

// Execute a query and get results
val users: List<User> = userQueries.selectAll().executeAsList()

// Execute a single result query
val user: User? = userQueries.selectById(123).executeAsOneOrNull()

// Listen to query result changes
userQueries.selectAll().addListener(object : Query.Listener {
    override fun queryResultsChanged() {
        // Handle query result updates
        updateUI()
    }
})

// Execute operations in a transaction
database.transaction {
    userQueries.insertUser("Alice", 25)
    userQueries.insertUser("Bob", 30)
    // Both inserts succeed or both are rolled back
}

Architecture

SQLDelight Runtime is built around several key components:

  • Query System: Type-safe query execution with reactive result updates via the observer pattern
  • Transaction Management: ACID transaction support with nested transaction capabilities and automatic resource cleanup
  • Driver Abstraction: Platform-agnostic database driver interface supporting both synchronous and asynchronous operations
  • Type Adaptation: Bidirectional type conversion system for mapping between Kotlin types and database column types
  • Multiplatform Design: Common API surface with platform-specific implementations using expect/actual declarations
  • Resource Management: Automatic cleanup and proper lifecycle management through Closeable pattern

Capabilities

Query Execution and Management

Core query functionality for executing SQL statements and managing result sets. Provides type-safe query execution with reactive updates and lifecycle management.

abstract class Query<out RowType : Any>(
    mapper: (SqlCursor) -> RowType
) : ExecutableQuery<RowType>(mapper) {
    abstract fun addListener(listener: Listener)
    abstract fun removeListener(listener: Listener)
    
    fun interface Listener {
        fun queryResultsChanged()
    }
}

abstract class ExecutableQuery<out RowType : Any>(
    val mapper: (SqlCursor) -> RowType
) {
    abstract fun <R> execute(mapper: (SqlCursor) -> QueryResult<R>): QueryResult<R>
    fun executeAsList(): List<RowType>
    fun executeAsOne(): RowType
    fun executeAsOneOrNull(): RowType?
}

// Factory functions for creating queries
fun <RowType : Any> Query(
    identifier: Int,
    queryKeys: Array<out String>,
    driver: SqlDriver,
    query: String,
    mapper: (SqlCursor) -> RowType
): Query<RowType>

Query System

Transaction Management

Comprehensive transaction support with ACID guarantees, nested transactions, and automatic resource management. Supports both synchronous and coroutine-based asynchronous operations.

interface Transacter : TransacterBase {
    fun <R> transactionWithResult(
        noEnclosing: Boolean = false,
        bodyWithReturn: TransactionWithReturn<R>.() -> R
    ): R
    
    fun transaction(
        noEnclosing: Boolean = false,
        body: TransactionWithoutReturn.() -> Unit
    )
}

interface SuspendingTransacter : TransacterBase {
    suspend fun <R> transactionWithResult(
        noEnclosing: Boolean = false,
        bodyWithReturn: suspend SuspendingTransactionWithReturn<R>.() -> R
    ): R
    
    suspend fun transaction(
        noEnclosing: Boolean = false,
        body: suspend SuspendingTransactionWithoutReturn.() -> Unit
    )
}

abstract class Transacter.Transaction : TransactionCallbacks {
    protected abstract val enclosingTransaction: Transaction?
    fun afterCommit(function: () -> Unit)
    fun afterRollback(function: () -> Unit)
    protected abstract fun endTransaction(successful: Boolean): QueryResult<Unit>
}

Transaction Management

Database Driver Interface

Platform-agnostic database driver abstraction that provides SQL execution, connection management, and query result handling. Supports both synchronous and asynchronous operation modes.

interface SqlDriver : Closeable {
    fun <R> executeQuery(
        identifier: Int?,
        sql: String,
        mapper: (SqlCursor) -> QueryResult<R>,
        parameters: Int,
        binders: (SqlPreparedStatement.() -> Unit)? = null
    ): QueryResult<R>
    
    fun execute(
        identifier: Int?,
        sql: String,
        parameters: Int,
        binders: (SqlPreparedStatement.() -> Unit)? = null
    ): QueryResult<Long>
    
    fun newTransaction(): QueryResult<Transacter.Transaction>
    fun currentTransaction(): Transacter.Transaction?
    fun addListener(vararg queryKeys: String, listener: Query.Listener)
    fun removeListener(vararg queryKeys: String, listener: Query.Listener)
    fun notifyListeners(vararg queryKeys: String)
}

interface SqlCursor {
    fun next(): QueryResult<Boolean>
    fun getString(index: Int): String?
    fun getLong(index: Int): Long?
    fun getBytes(index: Int): ByteArray?
    fun getDouble(index: Int): Double?
    fun getBoolean(index: Int): Boolean?
}

sealed interface QueryResult<T> {
    val value: T
    suspend fun await(): T
    
    value class Value<T>(override val value: T) : QueryResult<T>
    value class AsyncValue<T>(private val getter: suspend () -> T) : QueryResult<T>
}

Database Driver Interface

Column Type Adapters

Type conversion system for mapping between Kotlin types and database column types. Enables custom type serialization and provides built-in adapters for common use cases.

interface ColumnAdapter<T : Any, S> {
    fun decode(databaseValue: S): T
    fun encode(value: T): S
}

class EnumColumnAdapter<T : Enum<T>>(
    private val enumValues: Array<out T>
) : ColumnAdapter<T, String> {
    override fun decode(databaseValue: String): T
    override fun encode(value: T): String
}

// Factory function for enum adapters
inline fun <reified T : Enum<T>> EnumColumnAdapter(): EnumColumnAdapter<T>

Column Type Adapters

Logging and Debugging Utilities

Comprehensive logging and debugging tools for monitoring database operations, troubleshooting issues, and performance analysis.

class LogSqliteDriver(
    private val sqlDriver: SqlDriver,
    private val logger: (String) -> Unit
) : SqlDriver {
    // Logs all SQL operations including queries, executions, transactions
    override fun <R> executeQuery(
        identifier: Int?,
        sql: String,
        mapper: (SqlCursor) -> QueryResult<R>,
        parameters: Int,
        binders: (SqlPreparedStatement.() -> Unit)?
    ): QueryResult<R>
    
    override fun execute(
        identifier: Int?,
        sql: String,
        parameters: Int,
        binders: (SqlPreparedStatement.() -> Unit)?
    ): QueryResult<Long>
}

class StatementParameterInterceptor : SqlPreparedStatement {
    fun getAndClearParameters(): List<Any?>
    // Intercepts and stores parameter values for debugging
}

Logging and Utilities

Schema Management

Database schema creation, migration, and version management system. Provides APIs for initializing databases and handling schema changes across application versions.

interface SqlSchema<T : QueryResult<Unit>> {
    val version: Long
    fun create(driver: SqlDriver): T
    fun migrate(
        driver: SqlDriver,
        oldVersion: Long,
        newVersion: Long,
        vararg callbacks: AfterVersion
    ): T
}

class AfterVersion(
    val afterVersion: Long,
    val block: (SqlDriver) -> Unit
)

Schema Management

Types

// Core interfaces
sealed interface TransacterBase {
    // Base interface for all transaction-capable components
    // Implemented by Transacter and SuspendingTransacter
}
interface TransactionCallbacks {
    fun afterCommit(function: () -> Unit)
    fun afterRollback(function: () -> Unit)
}

// Transaction context interfaces
interface TransactionWithReturn<R> : TransactionCallbacks {
    fun rollback(returnValue: R): Nothing
    fun <R> transaction(body: TransactionWithReturn<R>.() -> R): R
}

interface TransactionWithoutReturn : TransactionCallbacks {
    fun rollback(): Nothing
    fun transaction(body: TransactionWithoutReturn.() -> Unit)
}

interface SuspendingTransactionWithReturn<R> : TransactionCallbacks {
    fun rollback(returnValue: R): Nothing
    suspend fun <R> transaction(body: suspend SuspendingTransactionWithReturn<R>.() -> R): R
}

interface SuspendingTransactionWithoutReturn : TransactionCallbacks {
    fun rollback(): Nothing
    suspend fun transactionWithResult(body: suspend SuspendingTransactionWithoutReturn.() -> Unit)
}

// Prepared statement interface
interface SqlPreparedStatement {
    fun bindBytes(index: Int, bytes: ByteArray?)
    fun bindLong(index: Int, long: Long?)
    fun bindDouble(index: Int, double: Double?)
    fun bindString(index: Int, string: String?)
    fun bindBoolean(index: Int, boolean: Boolean?)
}

// Platform abstraction
expect interface Closeable {
    fun close()
}

expect inline fun <T : Closeable?, R> T.use(body: (T) -> R): R

// Exception types  
class OptimisticLockException(
    message: String?, 
    cause: Throwable? = null
) : IllegalStateException(message, cause)

// Internal APIs
internal expect fun currentThreadId(): Long