SQLDelight multiplatform runtime library providing Kotlin APIs for type-safe database operations with compile-time SQL verification
—
Core query execution functionality providing type-safe database operations with result mapping and change notification capabilities.
Factory functions for creating Query and ExecutableQuery instances with various parameter combinations.
/**
* Creates a listenable query that can notify observers of result set changes
* @param identifier Unique identifier for prepared statement caching
* @param queryKeys Array of table/view names this query depends on
* @param driver SqlDriver instance for executing the query
* @param query SQL query string
* @param mapper Function to convert SqlCursor rows to RowType instances
*/
fun <RowType : Any> Query(
identifier: Int,
queryKeys: Array<out String>,
driver: SqlDriver,
query: String,
mapper: (SqlCursor) -> RowType
): Query<RowType>
/**
* Creates a listenable query with file and label information for debugging
*/
fun <RowType : Any> Query(
identifier: Int,
queryKeys: Array<out String>,
driver: SqlDriver,
fileName: String,
label: String,
query: String,
mapper: (SqlCursor) -> RowType
): Query<RowType>
/**
* Creates an executable query without change listening capability
* @param identifier Unique identifier for prepared statement caching
* @param driver SqlDriver instance for executing the query
* @param query SQL query string
* @param mapper Function to convert SqlCursor rows to RowType instances
*/
fun <RowType : Any> Query(
identifier: Int,
driver: SqlDriver,
query: String,
mapper: (SqlCursor) -> RowType
): ExecutableQuery<RowType>
/**
* Creates an executable query with file and label information for debugging
*/
fun <RowType : Any> Query(
identifier: Int,
driver: SqlDriver,
fileName: String,
label: String,
query: String,
mapper: (SqlCursor) -> RowType
): ExecutableQuery<RowType>Base class for executing SQL queries and mapping results to typed objects.
/**
* Base class for executable queries that can map SQL result cursors to typed objects
* @param RowType The type that query results will be mapped to
* @param mapper Function to convert SqlCursor rows to RowType instances
*/
abstract class ExecutableQuery<out RowType : Any>(
val mapper: (SqlCursor) -> RowType
) {
/**
* Execute the underlying statement with custom result mapping
* @param mapper Function to process the SqlCursor and return a QueryResult
* @return QueryResult containing the processed data
*/
abstract fun <R> execute(mapper: (SqlCursor) -> QueryResult<R>): QueryResult<R>
/**
* Execute the query and return all results as a list
* @return List of all rows mapped to RowType instances
*/
fun executeAsList(): List<RowType>
/**
* Execute the query and return exactly one result
* @return Single RowType instance
* @throws NullPointerException if the result set is empty
* @throws IllegalStateException if the result set has multiple rows
*/
fun executeAsOne(): RowType
/**
* Execute the query and return at most one result
* @return Single RowType instance or null if result set is empty
* @throws IllegalStateException if the result set has multiple rows
*/
fun executeAsOneOrNull(): RowType?
}Extended query class that supports change listening for reactive database operations.
/**
* A listenable, typed query that can notify observers when the underlying data changes
* @param RowType The type that query results will be mapped to
* @param mapper Function to convert SqlCursor rows to RowType instances
*/
abstract class Query<out RowType : Any>(
mapper: (SqlCursor) -> RowType
) : ExecutableQuery<RowType>(mapper) {
/**
* Register a listener to be notified of future changes in the result set
* @param listener Listener instance to register
*/
abstract fun addListener(listener: Listener)
/**
* Remove a listener to no longer be notified of future changes in the result set
* @param listener Listener instance to remove
*/
abstract fun removeListener(listener: Listener)
/**
* Functional interface for listening to query result changes
*/
fun interface Listener {
/**
* Called whenever the query this listener was attached to is dirtied.
* Calls are made synchronously on the thread where the update occurred,
* after the update applied successfully.
*/
fun queryResultsChanged()
}
}Usage Examples:
import app.cash.sqldelight.Query
import app.cash.sqldelight.db.SqlDriver
// Create a basic executable query
val userQuery = Query(
identifier = 1,
driver = sqlDriver,
query = "SELECT * FROM users WHERE active = 1",
mapper = { cursor ->
User(
id = cursor.getLong(0)!!,
name = cursor.getString(1)!!,
email = cursor.getString(2)!!
)
}
)
// Execute and get results
val allUsers: List<User> = userQuery.executeAsList()
val firstUser: User? = userQuery.executeAsOneOrNull()
// Create a listenable query
val activeUsersQuery = Query(
identifier = 2,
queryKeys = arrayOf("users"),
driver = sqlDriver,
query = "SELECT * FROM users WHERE active = 1",
mapper = { cursor ->
User(
id = cursor.getLong(0)!!,
name = cursor.getString(1)!!,
email = cursor.getString(2)!!
)
}
)
// Listen for changes
val listener = Query.Listener {
println("User data has changed!")
refreshUI()
}
activeUsersQuery.addListener(listener)
// Later, remove the listener
activeUsersQuery.removeListener(listener)
// Custom result processing
val userCount: Int = userQuery.execute { cursor ->
var count = 0
while (cursor.next().value) {
count++
}
QueryResult.Value(count)
}.valueInstall with Tessl CLI
npx tessl i tessl/maven-app-cash-sqldelight--runtime-iossimulatorarm64