KQLite Tables

Extend KQLiteTable to define a table within a KQLiteDatabase . Each table must declare at least one column. For best practice, define tables as singleton instances using Kotlin's object keyword.

Contacts Table

object TblContact : KQLiteTable("contacts") {
    val id = intColumn("id").notNull().primaryKey().autoIncrement()
    val firstName = textColumn("first_name").notNull()
    val lastName = textColumn("last_name")
    val phone = jsonArrayColumn("phone").notNull()
    val birthDate = dateColumn("birth_date")
    val email = textColumn("email").check { (it IS null) OR (it LIKE "%_@__%.__%") }
    val image = blobColumn("image")
    val type = enumColumn("type", ContactType.entries).notNull()
    val deleted = booleanColumn("deleted").notNull().default(false)
}

Mapping rows with KQLiteAdapter

KQLite provides an optional KQLiteAdapter to simplify mapping between database rows and Kotlin entities. To use this feature, your table must implement KQLiteAdapter . This requires you to define:

  • Binder - Responsible for binding entity values to SQL statements during insert or update operations.
  • Mapper - Responsible for converting query result rows into Kotlin objects.
By implementing `KQLiteAdapter`, you get a structured and type-safe way to handle object-relational mapping without relying on manual parsing.

data class Contact(
    val id: Int,
    val firstName: String,
    val lastName: String?,
    val phone: List,
    val birthDate: Instant?,
    val email: String?,
    val image: ByteArray?,
    val type: ContactType,
    val deleted: Boolean = false,
)
object TblContact : KQLiteTable("contacts"), KQLiteAdapter<Contact> {
    val id = intColumn("id").notNull().primaryKey().autoIncrement()
    val firstName = textColumn("first_name").notNull()
    val lastName = textColumn("last_name")
    val phone = jsonArrayColumn("phone").notNull()
    val birthDate = dateColumn("birth_date")
    val email = textColumn("email").check { (it IS null) OR (it LIKE "%_@__%.__%") }
    val image = blobColumn("image")
    val type = enumColumn("type", ContactType.entries).notNull()
    val deleted = booleanColumn("deleted").notNull().default(false)

    override fun binder(
        bind: Bind,
        item: Contact
    ) {
        bind.apply {
            firstName.bind(item.firstName)
            lastName.bind(item.lastName)
            phone.bind(JSON_ARRAY(*item.phone.toTypedArray()))
            if (item.birthDate != null) birthDate.bind(DATE(item.birthDate.toDateString()))
            else birthDate.bind(null)
            email.bind(item.email)
            image.bind(item.image)
            type.bind(item.type)
        }
    }

    override fun mapper(cursor: KQLiteCursor): Contact {
        return Contact(
            id = cursor[id],
            firstName = cursor[firstName],
            lastName = cursor[lastName],
            phone = Json.decodeFromString(cursor[phone].getText()),
            birthDate = cursor[birthDate]?.getText()?.toInstant(),
            email = cursor[email],
            image = cursor[image],
            type = cursor[type],
            deleted = cursor[deleted]
        )
    }
}

For more details and possibilities with KQLiteTable, please refer KQLiteTable Docs.

⬅ Overview Columns ⮕