|
1 | | -# couchbase-lite-kotlin |
| 1 | +# Couchbase Lite Kotlin |
| 2 | + |
2 | 3 | Kotlin-friendly extensions for Couchbase Lite Android and Java SDKs. |
| 4 | + |
| 5 | +Proudly made by [MOLO17 Srl](https://molo17.com/) 🚀 |
| 6 | + |
| 7 | +## Kotlin extensions for Couchbase Lite |
| 8 | + |
| 9 | +Couchbase Lite Kotlin is a lightweight library that adds convenient |
| 10 | +extension functions to [Couchbase Lite](https://docs.couchbase.com/couchbase-lite/current/java-android.html) |
| 11 | +Android and Java SDKs. |
| 12 | + |
| 13 | +This library introduces a lightweight wrapper on top of N1QL query language, |
| 14 | +Document creation and much more. Also, it provides support for a more |
| 15 | +fluent listener API, introducing first-class support for |
| 16 | +[Kotlin Coroutines](https://kotlinlang.org/docs/reference/coroutines-overview.html) and the |
| 17 | +[Flow API](https://kotlinlang.org/docs/reference/coroutines/flow.html). |
| 18 | + |
| 19 | +## Installing |
| 20 | + |
| 21 | +Add JitPack as repository for your project: |
| 22 | + |
| 23 | +```groovy |
| 24 | +allprojects { |
| 25 | + repositories { |
| 26 | + ... |
| 27 | + maven { url "https://jitpack.io" } |
| 28 | + } |
| 29 | +} |
| 30 | +``` |
| 31 | + |
| 32 | +And then to your module `build.gradle` file: |
| 33 | + |
| 34 | +```groovy |
| 35 | +implementation "com.github.MOLO17:couchbase-lite-kotlin:1.0.0" |
| 36 | +``` |
| 37 | + |
| 38 | +## Contents |
| 39 | + |
| 40 | +Here are the main features that Couchbase Lite Kotlin provides for |
| 41 | +boosting the integration of the Couchbase Lite SDK with Kotlin. |
| 42 | + |
| 43 | +- [QueryBuilder extensions](#querybuilder-extensions) |
| 44 | +- [Document builder DSL](#document-builder-dsl) |
| 45 | +- [Query Flow support](#query-flow-support) |
| 46 | +- [ResultSet model mapping](#resultset-model-mapping) |
| 47 | +- [Database extensions](#database-extensions) |
| 48 | +- [Replicator extensions](#replicator-extensions) |
| 49 | + |
| 50 | +### QueryBuilder extensions |
| 51 | + |
| 52 | +Syntax for building a query has gone more straight-forward thanks to the |
| 53 | +`infix` function support. |
| 54 | + |
| 55 | +```kotlin |
| 56 | +select(all()) from database where { "type" equalTo "user" } |
| 57 | +``` |
| 58 | + |
| 59 | +Or just a bunch of fields: |
| 60 | + |
| 61 | +```kotlin |
| 62 | +select("name", "surname") from database where { "type" equalTo "user" } |
| 63 | +``` |
| 64 | + |
| 65 | +You can even do more powerful querying: |
| 66 | + |
| 67 | +```kotlin |
| 68 | +select("name", "type") |
| 69 | + .from(database) |
| 70 | + .where { |
| 71 | + ("type" equalTo "user" and "name" equalTo "Damian") or |
| 72 | + ("type" equalTo "pet" and "name" like "Kitt") |
| 73 | + } |
| 74 | + .orderBy { "name".ascending() } |
| 75 | + .limit(10) |
| 76 | +``` |
| 77 | + |
| 78 | +### Document builder DSL |
| 79 | + |
| 80 | +For creating a new `MutableDocument` ready to be saved, you can now use |
| 81 | +a new Kotlin DSL: |
| 82 | + |
| 83 | +```kotlin |
| 84 | +val document = MutableDocument { |
| 85 | + "name" to "Damian" |
| 86 | + "surname" to "Giusti" |
| 87 | + "age" to 24 |
| 88 | + "pets" to listOf("Kitty", "Kitten", "Kitto") |
| 89 | + "type" to "user" |
| 90 | +} |
| 91 | + |
| 92 | +database.save(document) |
| 93 | +``` |
| 94 | + |
| 95 | +### Query Flow support |
| 96 | + |
| 97 | +Now Couchbase Lite queries become Flows. Couchbase Lite Kotlin ports |
| 98 | +the coroutines Flow stream API for observing Live Queries results. |
| 99 | + |
| 100 | +```kotlin |
| 101 | +select(all()) |
| 102 | + .from(database) |
| 103 | + .where { "type" equalTo "user" } |
| 104 | + .asFlow() |
| 105 | + .collect { value: ResultSet -> |
| 106 | + // consume ResultSet |
| 107 | + } |
| 108 | +``` |
| 109 | + |
| 110 | +As plus, you receive automatic LiveQuery cancellation when the Flow tears down. |
| 111 | + |
| 112 | +### ResultSet model mapping |
| 113 | + |
| 114 | +Thanks to [Map delegation](https://kotlinlang.org/docs/reference/delegated-properties.html#storing-properties-in-a-map), |
| 115 | +mapping a ResultSet to a Kotlin class has never been so easy. |
| 116 | + |
| 117 | +The library provides the `ResultSet.toObjects()` and `Query.asObjectsFlow()` |
| 118 | +extensions for helping to map results given a factory lambda. |
| 119 | + |
| 120 | +Such factory lambda accepts a `Map<String, Any?>` and returns an instance |
| 121 | +of a certain type. Those requirements fits perfectly with a Map-delegated |
| 122 | +class. |
| 123 | + |
| 124 | +```kotlin |
| 125 | +class User(map: Map<String, Any?>) { |
| 126 | + val name: String by map |
| 127 | + val surname: String by map |
| 128 | + val age: Int by map |
| 129 | +} |
| 130 | + |
| 131 | +val users: List<User> = query.execute().toObjects(::User) |
| 132 | +``` |
| 133 | + |
| 134 | +```kotlin |
| 135 | +class User(map: Map<String, Any?>) { |
| 136 | + val name: String by map |
| 137 | + val surname: String by map |
| 138 | + val age: Int by map |
| 139 | +} |
| 140 | + |
| 141 | +val users: Flow<List<User>> = query.asObjectsFlow(::User) |
| 142 | +``` |
| 143 | + |
| 144 | +### Database extensions |
| 145 | + |
| 146 | +As seen with the Query extensions, the Database has also been powered up. |
| 147 | + |
| 148 | +You can now observe the `DatabaseChange` and `DocumentChangeEvents` using |
| 149 | +the Kotlin Flow API. |
| 150 | + |
| 151 | +```kotlin |
| 152 | +val changes: Flow<DatabaseChange> = database.changesFlow() |
| 153 | +val documentChanges: Flow<DocumentChange> = database.documentChangesFlow(docId) |
| 154 | +``` |
| 155 | + |
| 156 | +Also, a new useful syntax has been introduced when performing batch operations: |
| 157 | + |
| 158 | +```kotlin |
| 159 | +database.doInBatch { |
| 160 | + save(document) |
| 161 | + delete(otherDocument) |
| 162 | +} |
| 163 | +``` |
| 164 | + |
| 165 | +The `Database` is used as receiver in the specified lambda. |
| 166 | + |
| 167 | +### Replicator extensions |
| 168 | + |
| 169 | +Replicator syntax has been boosted with the Kotlin Flow API. You can |
| 170 | +observe events using the following Flows: |
| 171 | + |
| 172 | +```kotlin |
| 173 | +val changesFlow: Flow<ReplicatorChange> = replicator.changesFlow() |
| 174 | +val replicationFlow: Flow<DocumentReplication> = replicator.documentReplicationFlow() |
| 175 | +``` |
| 176 | + |
| 177 | +In addition, for Android users, you can now bind the Replicator |
| 178 | +`start()` and `stop()` methods to be performed automatically when your |
| 179 | +[Lifecycle](https://developer.android.com/jetpack/androidx/releases/lifecycle)-enabled |
| 180 | +component gets resumed or paused. |
| 181 | + |
| 182 | +```kotlin |
| 183 | +// Binds the Replicator to the Application lifecycle. |
| 184 | + |
| 185 | +replicator.bindToLifecycle(ProcessLifecycleOwner.get().lifecycle) |
| 186 | +``` |
| 187 | + |
| 188 | +```kotlin |
| 189 | +// Binds the Replicator to the Activity/Fragment lifecycle. |
| 190 | +{ |
| 191 | + // inside an Activity or a Fragment ... |
| 192 | + |
| 193 | + replicator.bindToLifecycle(lifecycle) |
| 194 | +} |
| 195 | +``` |
| 196 | + |
| 197 | +That's it! Replicator will be automatically started when your component |
| 198 | +passes the `ON_RESUME` state, and it will be stopped when the component |
| 199 | +passes the `ON_PAUSED` state. As you may imagine, no further action will |
| 200 | +be made after the `ON_DESTROY` state. |
| 201 | + |
| 202 | +## Authors |
| 203 | + |
| 204 | +- [Damiano Giusti](https://github.com/damianogiusti/) |
| 205 | +- [MOLO17 Srl](https://molo17.com/) |
0 commit comments