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 Flow
s, and creating indexes.
Installation
kotlin {
sourceSets {
commonMain.dependencies {
implementation("dev.kotbase:couchbase-lite-ktx:3.1.9-1.1.1")
}
}
}
Usage
QueryBuilder extensions
The syntax for building a query is more straight-forward thanks to Kotlin's infix
function support.
select(all()) from collection where { "type" equalTo "user" }
Or just a bunch of fields:
select("name", "surname") from collection where { "type" equalTo "user" }
Or if you also want the document ID:
select(Meta.id, all()) from collection where { "type" equalTo "user" }
select(Meta.id, "name", "surname") from collection where { "type" equalTo "user" }
You can even do more powerful querying:
select("name", "type")
.from(collection)
.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 collection 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"
}
collection.save(document)
Collection creation functions
You can create a MutableArray
or MutableDictionary
using idiomatic vararg
functions:
mutableArrayOf("hello", 42, true)
mutableDictOf("key1" to "value1", "key2" to 2, "key3" to null)
The similar mutableDocOf
function allows nesting dictionary types, unlike the MutableDocument
DSL:
mutableDocOf(
"string" to "hello",
"number" to 42,
"array" to mutableArrayOf(1, 2, 3),
"dict" to mutableDictOf("key" to "value")
)
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 ResultSet
s and throw any QueryChange
errors.
select(all())
.from(collection)
.where { "type" equalTo "user" }
.asFlow()
.collect { value: ResultSet ->
// consume ResultSet
}
Document Flow
Unlike Collection.documentChangeFlow()
, which only emits DocumentChange
s, Collection.documentFlow()
handles the common use case of getting the initial document state and observing changes from the collection, enabling reactive UI patterns.
collection.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:
collection.createIndex("typeNameIndex", valueIndex("type", "name"))
collection.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 Flow
s, and creating indexes.
Installation
kotlin {
sourceSets {
commonMain.dependencies {
implementation("dev.kotbase:couchbase-lite-ktx:3.1.9-1.1.1")
}
}
}
Usage
QueryBuilder extensions
The syntax for building a query is more straight-forward thanks to Kotlin's infix
function support.
select(all()) from collection where { "type" equalTo "user" }
Or just a bunch of fields:
select("name", "surname") from collection where { "type" equalTo "user" }
Or if you also want the document ID:
select(Meta.id, all()) from collection where { "type" equalTo "user" }
select(Meta.id, "name", "surname") from collection where { "type" equalTo "user" }
You can even do more powerful querying:
select("name", "type")
.from(collection)
.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 collection 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"
}
collection.save(document)
Collection creation functions
You can create a MutableArray
or MutableDictionary
using idiomatic vararg
functions:
mutableArrayOf("hello", 42, true)
mutableDictOf("key1" to "value1", "key2" to 2, "key3" to null)
The similar mutableDocOf
function allows nesting dictionary types, unlike the MutableDocument
DSL:
mutableDocOf(
"string" to "hello",
"number" to 42,
"array" to mutableArrayOf(1, 2, 3),
"dict" to mutableDictOf("key" to "value")
)
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 ResultSet
s and throw any QueryChange
errors.
select(all())
.from(collection)
.where { "type" equalTo "user" }
.asFlow()
.collect { value: ResultSet ->
// consume ResultSet
}
Document Flow
Unlike Collection.documentChangeFlow()
, which only emits DocumentChange
s, Collection.documentFlow()
handles the common use case of getting the initial document state and observing changes from the collection, enabling reactive UI patterns.
collection.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:
collection.createIndex("typeNameIndex", valueIndex("type", "name"))
collection.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.