CtrlK
BlogDocsLog inGet started
Tessl Logo

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

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

Pending
Overview
Eval results
Files

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

Install with Tessl CLI

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