Queries

August 23, 2026 ยท View on GitHub

Prefer adapter.select() on the generated database. Terminal calls are suspend and need a transaction scope.

db.readableTransaction {
    val all = userAdapter.select().list()
    val ada = (userAdapter.select() where (User.name eq "Ada")).single()
    val maybe = (userAdapter.select() where (User.id eq 1)).singleOrNull()
}

single() applies a one-row read and throws SQLiteException if missing. list() never throws on empty.

Columns

userAdapter.select(User.id, User.name)

Count / exists

db.readableTransaction {
    val count = userAdapter.selectCountOf().execute()
    val anyAda = (userAdapter.selectCountOf() where (User.name eq "Ada")).hasData()
}

Map onto another type

Use a @Query model and pass its adapter:

db.readableTransaction {
    userAdapter.select().list(userNameQueryAdapter)
}

See query models.

select from

(select from userAdapter where (User.name eq "Ada")).list()
(select from User where (User.name eq "Ada")).list()

// after createDB, KClass lookup also works
(select from User::class where (User.name eq "Ada")).list()

createDB registers adapters so KClass lookups work after open.

Raw cursor

db.readableTransaction {
    userAdapter.select().cursor().use { cursor ->
        // close it
    }
}

@DelicateDBFlowApi.

Observe

userAdapter.select().toFlow(db) { list() }

See observability.