couchbase-lite-ktx

Couchbase Lite Community Edition – Kotlin Extensions

The KTX extensions include the excellent Kotlin extensions by MOLO17, as well as other convenience functions for composing queries, observing change Flows, and creating indexes.

Installation

kotlin {
sourceSets {
commonMain {
dependencies {
implementation("dev.kotbase:couchbase-lite-ktx:3.0.15-1.0.1")
}
}
}
}

Usage

QueryBuilder extensions

The syntax for building a query is more straight-forward thanks to Kotlin's infix function support.

select(all()) from database where { "type" equalTo "user" }

Or just a bunch of fields:

select("name", "surname") from database where { "type" equalTo "user" }

Or if you also want the document ID:

select(Meta.id, all()) from database where { "type" equalTo "user" }
select(Meta.id, "name", "surname") from database where { "type" equalTo "user" }

You can even do more powerful querying:

select("name", "type")
.from(database)
.where {
("type" equalTo "user" and "name" equalTo "Damian") or
("type" equalTo "pet" and "name" like "Kitt")
}
.orderBy { "name".ascending() }
.limit(10)

There are also convenience extensions for performing SELECT COUNT(*) queries:

val query = selectCount() from database where { "type" equalTo "user" }
val count = query.execute().countResult()

Document builder DSL

For creating a MutableDocument ready to be saved, you can use a Kotlin builder DSL:

val document = MutableDocument {
"name" to "Damian"
"surname" to "Giusti"
"age" to 24
"pets" to listOf("Kitty", "Kitten", "Kitto")
"type" to "user"
}

database.save(document)

Flow support

Supplementing the Flow APIs from Couchbase Lite Android KTX present in the base couchbase-lite modules, Kotbase KTX adds some additional useful Flow APIs.

Query Flow

Query.asFlow() builds on top of Query.queryChangeFlow() to emit non-null ResultSets and throw any QueryChange errors.

select(all())
.from(database)
.where { "type" equalTo "user" }
.asFlow()
.collect { value: ResultSet ->
// consume ResultSet
}
Document Flow

Unlike Database.documentChangeFlow(), which only emits DocumentChanges, Database.documentFlow() handles the common use case of getting the initial document state and observing changes from the database, enabling reactive UI patterns.

database.documentFlow("userProfile")
.collect { doc: Document? ->
// consume Document
}

ResultSet model mapping

Map delegation

Thanks to Map delegation, mapping a ResultSet to a Kotlin class has never been so easy.

The library provides the ResultSet.toObjects() and Query.asObjectsFlow() extensions for helping to map results given a factory lambda.

Such factory lambdas accept a Map<String, Any?> and return an instance of a certain type. Those requirements fit perfectly with a Map-delegated class.

class User(map: Map<String, Any?>) {
val name: String by map
val surname: String by map
val age: Int by map
}

val users: List<User> = query.execute().toObjects(::User)

val usersFlow: Flow<List<User>> = query.asObjectsFlow(::User)
JSON deserialization

Kotbase KTX also provides extensions for mapping documents from a JSON string to Kotlin class. This works well together with a serialization library, like kotlinx-serialization, to decode the JSON string to a Kotlin object.

@Serializable
class User(
val name: String,
val surname: String,
val age: Int
)

val users: List<User> = query.execute().toObjects { json: String ->
Json.decodeFromString<User>(json)
}

val usersFlow: Flow<List<User>> = query.asObjectsFlow { json: String ->
Json.decodeFromString<User>(json)
}
Index creation

Kotbase KTX provides concise top-level functions for index creation:

database.createIndex("typeNameIndex", valueIndex("type", "name"))
database.createIndex("overviewFTSIndex", fullTextIndex("overview"))
Replicator extensions

For the Android platform, you can bind the Replicator start() and stop() methods to be performed automatically when your Lifecycle-enabled component gets resumed or paused.

// Binds the Replicator to the Application lifecycle.
replicator.bindToLifecycle(ProcessLifecycleOwner.get().lifecycle)
// Binds the Replicator to the Activity/Fragment lifecycle.
// inside an Activity or Fragment...
override fun onCreate(savedInstanceState: Bundle?) {
replicator.bindToLifecycle(lifecycle)
}

That's it! The Replicator will be automatically started when your component passes the ON_RESUME state, and it will be stopped when the component passes the ON_PAUSED state. As you may imagine, no further action will be made after the ON_DESTROY state.

Couchbase Lite Community Edition – Kotlin Extensions

The KTX extensions include the excellent Kotlin extensions by MOLO17, as well as other convenience functions for composing queries, observing change Flows, and creating indexes.

Installation

kotlin {
sourceSets {
commonMain {
dependencies {
implementation("dev.kotbase:couchbase-lite-ktx:3.0.15-1.0.1")
}
}
}
}

Usage

QueryBuilder extensions

The syntax for building a query is more straight-forward thanks to Kotlin's infix function support.

select(all()) from database where { "type" equalTo "user" }

Or just a bunch of fields:

select("name", "surname") from database where { "type" equalTo "user" }

Or if you also want the document ID:

select(Meta.id, all()) from database where { "type" equalTo "user" }
select(Meta.id, "name", "surname") from database where { "type" equalTo "user" }

You can even do more powerful querying:

select("name", "type")
.from(database)
.where {
("type" equalTo "user" and "name" equalTo "Damian") or
("type" equalTo "pet" and "name" like "Kitt")
}
.orderBy { "name".ascending() }
.limit(10)

There are also convenience extensions for performing SELECT COUNT(*) queries:

val query = selectCount() from database where { "type" equalTo "user" }
val count = query.execute().countResult()

Document builder DSL

For creating a MutableDocument ready to be saved, you can use a Kotlin builder DSL:

val document = MutableDocument {
"name" to "Damian"
"surname" to "Giusti"
"age" to 24
"pets" to listOf("Kitty", "Kitten", "Kitto")
"type" to "user"
}

database.save(document)

Flow support

Supplementing the Flow APIs from Couchbase Lite Android KTX present in the base couchbase-lite modules, Kotbase KTX adds some additional useful Flow APIs.

Query Flow

Query.asFlow() builds on top of Query.queryChangeFlow() to emit non-null ResultSets and throw any QueryChange errors.

select(all())
.from(database)
.where { "type" equalTo "user" }
.asFlow()
.collect { value: ResultSet ->
// consume ResultSet
}
Document Flow

Unlike Database.documentChangeFlow(), which only emits DocumentChanges, Database.documentFlow() handles the common use case of getting the initial document state and observing changes from the database, enabling reactive UI patterns.

database.documentFlow("userProfile")
.collect { doc: Document? ->
// consume Document
}

ResultSet model mapping

Map delegation

Thanks to Map delegation, mapping a ResultSet to a Kotlin class has never been so easy.

The library provides the ResultSet.toObjects() and Query.asObjectsFlow() extensions for helping to map results given a factory lambda.

Such factory lambdas accept a Map<String, Any?> and return an instance of a certain type. Those requirements fit perfectly with a Map-delegated class.

class User(map: Map<String, Any?>) {
val name: String by map
val surname: String by map
val age: Int by map
}

val users: List<User> = query.execute().toObjects(::User)

val usersFlow: Flow<List<User>> = query.asObjectsFlow(::User)
JSON deserialization

Kotbase KTX also provides extensions for mapping documents from a JSON string to Kotlin class. This works well together with a serialization library, like kotlinx-serialization, to decode the JSON string to a Kotlin object.

@Serializable
class User(
val name: String,
val surname: String,
val age: Int
)

val users: List<User> = query.execute().toObjects { json: String ->
Json.decodeFromString<User>(json)
}

val usersFlow: Flow<List<User>> = query.asObjectsFlow { json: String ->
Json.decodeFromString<User>(json)
}
Index creation

Kotbase KTX provides concise top-level functions for index creation:

database.createIndex("typeNameIndex", valueIndex("type", "name"))
database.createIndex("overviewFTSIndex", fullTextIndex("overview"))
Replicator extensions

For the Android platform, you can bind the Replicator start() and stop() methods to be performed automatically when your Lifecycle-enabled component gets resumed or paused.

// Binds the Replicator to the Application lifecycle.
replicator.bindToLifecycle(ProcessLifecycleOwner.get().lifecycle)
// Binds the Replicator to the Activity/Fragment lifecycle.
// inside an Activity or Fragment...
override fun onCreate(savedInstanceState: Bundle?) {
replicator.bindToLifecycle(lifecycle)
}

That's it! The Replicator will be automatically started when your component passes the ON_RESUME state, and it will be stopped when the component passes the ON_PAUSED state. As you may imagine, no further action will be made after the ON_DESTROY state.

Packages

Link copied to clipboard
common