Skip to content

Add Kotlin serialization-based APIs#475

Open
snej wants to merge 2 commits intomasterfrom
feature/kotlin-serialization
Open

Add Kotlin serialization-based APIs#475
snej wants to merge 2 commits intomasterfrom
feature/kotlin-serialization

Conversation

@snej
Copy link
Copy Markdown
Contributor

@snej snej commented May 8, 2026

Implements Kotlin extension methods that use serialization to allow developers to work with documents and query rows as native Kotlin classes. (Equivalent to the Swift API extensions implemented last year.)

Query Results & ResultSets

/** Uses Kotlin Serialization to create an object of type [T] from the query row.
 *  If the [key] parameter is non-null, it uses the row's value for that key as the source,
 *  instead of the entire row.
 *
 *  For example, if your query is `SELECT name, age, shoeSize FROM people` and you have a
 *  serializable Person class with properties name, age and shoeSize, you can call:
 *  `val person = result.data<Person>()`
 *
 *  Or you could use the query `SELECT * as person FROM people` and create the Person with
 *  `val person = result.data<Person>("person")`.
 */
@ExperimentalSerializationApi
inline fun <reified T> Result.data(key: String? = null): T

/** Returns the query rows transformed by Kotlin Serialization into instances of [T]. */
@ExperimentalSerializationApi
inline fun <reified T> ResultSet.data(key: String? = null): Sequence<T>

Documents

Document model classes must implement a new interface DocumentModel that defines a documentMeta property that stores the document id and revID, which is needed in order to save the document.

/** Document model classes must implement this interface.
 *  It adds a [documentMeta] property that's used by Couchbase Lite. */
interface DocumentModel {
    /** This tags the model instance with the document ID and revision it was read from,
     *  which enables conflict detection when it's later saved.
     *  You may read this property, but DO NOT alter it.
     *  It should be implemented as a stored property defaulting to `null`, for example:
     *  `@Transient override var documentMeta: DocumentMeta? = null` */
    @Transient var documentMeta: DocumentMeta?
}

/** Stores the Couchbase Lite metadata of a document. Used by the [DocumentModel] interface. */
class DocumentMeta internal constructor(val collection: Collection?,
                                        val id: String,
                                        val revisionID: String)

Documents can be loaded and saved as model instances:

/** Gets an existing document with the given ID, and uses Kotlin Serialization to create an
 *  instance of class [T] from it. [T] must implement [DocumentModel].
 *  If a document with the given ID doesn't exist in the collection, returns null. */
@ExperimentalSerializationApi
inline fun <reified T: DocumentModel> Collection.getDocumentAs(id: String): T? =
    getDocumentAs(id, serializer())

/** Saves a [DocumentModel] instance as a document in the collection, with a specified conflict handler.
 *  If the model's [DocumentModel.documentMeta] property is null, it will be saved as a new document with the
 *  given [docID], which must not be null.
 *  Otherwise the [DocumentModel.documentMeta] property determines the document ID and prior revision ID, and the
 *  [docID] parameter should be null.
 *  After a successful save, the [DocumentModel.documentMeta] property is updated to the current state. */
@ExperimentalSerializationApi
inline fun <reified T: DocumentModel> Collection.save(model: T,
                                                      docID: String? = null,
                                                      noinline conflictHandler: ModelConflictHandler<T>? = null) =

Lower-Level

Both of these use some new internal functions that serialize Kotlin classes to and from Fleece.

/** Uses Kotlin Serialization to encode an arbitrary object or collection to Fleece.
 *  @param value  The object to encode.
 *  @param encoder  A Fleece [FLEncoder] to use; defaults to a fresh instance.
 *  @return  The encoded Fleece data. */
@ExperimentalSerializationApi
inline fun <reified T> serializeToFleece(value: T, encoder: FLEncoder? = null): ByteArray

/** Decodes an object from a Fleece [FLValue] using Kotlin Serialization. */
@ExperimentalSerializationApi
inline fun <reified T> deserializeFromFleece(root: FLValue): T

snej added 2 commits May 7, 2026 12:16
- Collection.getDocumentAs(), save()
- Result.data()
- ResultSet.data()
@snej
Copy link
Copy Markdown
Contributor Author

snej commented May 8, 2026

I just noticed that Swift has model-based Collection.delete and Collection.purge methods; I'll add those.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant