Serialization

Strategies and helpers for converting between Kotlin types and the SQLite storage format.

Serialize collections with JSON

You are free to choose your own strategy for storing collections. A common pattern is to serialize the data as JSON. SQLiteNow ships utility helpers so you can keep the SQL clean and reuse adapters.

CREATE TABLE comment
(
    id   INTEGER PRIMARY KEY NOT NULL,

    -- @@{ field=tags, adapter=custom, propertyType=List<String> }
    tags TEXT
)

Then, configure your adapters with jsonDecodeFromSqlite and jsonEncodeToSqlite:

val db = SampleDatabase(
    dbName = resolveDatabasePath(dbName = "sample.db", appName = "SampleApp"),
    migration = VersionBasedDatabaseMigrations(),
    commentAdapters = SampleDatabase.CommentAdapters(
        sqlColumnToTags = { value -> value?.jsonDecodeFromSqlite() ?: emptyList() },
        tagsToSqlColumn = { tags -> tags?.jsonEncodeToSqlite() }
    )
)

Serialize timestamps

For absolute timestamps, prefer storing RFC3339 text and mapping it to kotlin.time.Instant.

CREATE TABLE comment
(
    id         INTEGER PRIMARY KEY NOT NULL,

    -- @@{ field=created_at, adapter=custom, propertyType=kotlin.time.Instant }
    created_at TEXT    NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now'))
)
val db = SampleDatabase(
    dbName = resolveDatabasePath(dbName = "sample.db", appName = "SampleApp"),
    migration = VersionBasedDatabaseMigrations(),
    commentAdapters = SampleDatabase.CommentAdapters(
        sqlColumnToCreatedAt = { value -> Instant.fromRfc3339String(value) },
        createdAtToSqlColumn = { instant -> instant.toRfc3339String() },
    )
)

Serialize enums with stable values

Prefer serializing enums using stable values instead of names or ordinals. The EnumByValueLookup helper simplifies mapping between enum constants and their persisted representation.

CREATE TABLE person_address
(
    id           INTEGER PRIMARY KEY NOT NULL,

    -- @@{ field=address_type, adapter=custom, propertyType=AddressType }
    address_type TEXT    NOT NULL
)
enum class AddressType(val value: String) {
    HOME("home"),
    WORK("work");

    companion object : EnumByValueLookup<String, AddressType>(entries.associateBy { it.value })
}
val db = SampleDatabase(
    dbName = resolveDatabasePath(dbName = "sample.db", appName = "SampleApp"),
    migration = VersionBasedDatabaseMigrations(),
    personAddressAdapters = SampleDatabase.PersonAddressAdapters(
        addressTypeToSqlColumn = { it.value },
        sqlColumnToAddressType = { value -> AddressType.from(value) },
    )
)