Skip to content

Commit 8305507

Browse files
committed
Use builders instead
Uses builders instead of named arguments to improve maintainability
1 parent 0c6e22c commit 8305507

File tree

21 files changed

+353
-206
lines changed

21 files changed

+353
-206
lines changed

README.md

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -210,14 +210,6 @@ citiesRef.where {
210210
}
211211
```
212212

213-
<h3><a href="https://kotlinlang.org/docs/reference/functions.html#named-arguments">Named arguments</a></h3>
214-
215-
To improve readability functions such as the Cloud Firestore data encoding/decoding use named arguments:
216-
217-
```kotlin
218-
documentRef.set(data, encodeDefaults = false, serializersModule = customSerializerModule)
219-
```
220-
221213
<h3><a href="https://kotlinlang.org/docs/reference/operator-overloading.html">Operator overloading</a></h3>
222214

223215
In cases where it makes sense, such as Firebase Functions HTTPS Callable, operator overloading is used:

firebase-common/src/commonMain/kotlin/dev/gitlive/firebase/EncodeDecodeSettings.kt

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,30 @@ sealed class EncodeDecodeSettings {
1919
* @property shouldEncodeElementDefault if `true` this will explicitly encode elements even if they are their default value
2020
* @param serializersModule the [SerializersModule] to use for serialization. This allows for polymorphic serialization on runtime
2121
*/
22-
data class EncodeSettings(
23-
val shouldEncodeElementDefault: Boolean = true,
24-
override val serializersModule: SerializersModule = EmptySerializersModule(),
25-
) : EncodeDecodeSettings()
22+
data class EncodeSettings internal constructor(
23+
val shouldEncodeElementDefault: Boolean,
24+
override val serializersModule: SerializersModule,
25+
) : EncodeDecodeSettings() {
26+
class Builder {
27+
var shouldEncodeElementDefault: Boolean = true
28+
var serializersModule: SerializersModule = EmptySerializersModule()
29+
30+
@PublishedApi
31+
internal fun build() = EncodeSettings(shouldEncodeElementDefault, serializersModule)
32+
}
33+
}
2634

2735
/**
2836
* [EncodeDecodeSettings] used when decoding an object
2937
* @param serializersModule the [SerializersModule] to use for deserialization. This allows for polymorphic serialization on runtime
3038
*/
31-
data class DecodeSettings(
39+
data class DecodeSettings internal constructor(
3240
override val serializersModule: SerializersModule = EmptySerializersModule(),
33-
) : EncodeDecodeSettings()
41+
) : EncodeDecodeSettings() {
42+
43+
class Builder {
44+
var serializersModule: SerializersModule = EmptySerializersModule()
45+
46+
internal fun build() = DecodeSettings(serializersModule)
47+
}
48+
}

firebase-common/src/commonMain/kotlin/dev/gitlive/firebase/decoders.kt

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,15 @@ import kotlinx.serialization.modules.EmptySerializersModule
1515
import kotlinx.serialization.modules.SerializersModule
1616
import kotlinx.serialization.serializer
1717

18-
inline fun <reified T> decode(value: Any?, serializersModule: SerializersModule = EmptySerializersModule()): T {
18+
inline fun <reified T> decode(value: Any?): T = decode(value) {}
19+
inline fun <reified T> decode(value: Any?, noinline buildSettings: DecodeSettings.Builder.() -> Unit): T {
1920
val strategy = serializer<T>()
20-
return decode(strategy as DeserializationStrategy<T>, value, serializersModule)
21+
return decode(strategy as DeserializationStrategy<T>, value, buildSettings)
2122
}
22-
fun <T> decode(strategy: DeserializationStrategy<T>, value: Any?, serializersModule: SerializersModule = EmptySerializersModule()): T {
23+
fun <T> decode(strategy: DeserializationStrategy<T>, value: Any?): T = decode(strategy, value) {}
24+
fun <T> decode(strategy: DeserializationStrategy<T>, value: Any?, buildSettings: DecodeSettings.Builder.() -> Unit): T {
2325
require(value != null || strategy.descriptor.isNullable) { "Value was null for non-nullable type ${strategy.descriptor.serialName}" }
24-
return FirebaseDecoder(value, DecodeSettings(serializersModule)).decodeSerializableValue(strategy)
26+
return FirebaseDecoder(value, DecodeSettings.Builder().apply(buildSettings).build()).decodeSerializableValue(strategy)
2527
}
2628
expect fun FirebaseDecoder.structureDecoder(descriptor: SerialDescriptor, polymorphicIsNested: Boolean): CompositeDecoder
2729
expect fun getPolymorphicType(value: Any?, discriminator: String): String

firebase-common/src/commonMain/kotlin/dev/gitlive/firebase/encoders.kt

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,22 @@ package dev.gitlive.firebase
77
import kotlinx.serialization.*
88
import kotlinx.serialization.descriptors.*
99
import kotlinx.serialization.encoding.*
10-
import kotlinx.serialization.modules.EmptySerializersModule
1110
import kotlinx.serialization.modules.SerializersModule
1211

13-
fun <T> encode(strategy: SerializationStrategy<T>, value: T, shouldEncodeElementDefault: Boolean, serializersModule: SerializersModule = EmptySerializersModule()): Any? = encode(strategy, value, EncodeSettings(shouldEncodeElementDefault, serializersModule))
12+
@Deprecated("Deprecated. Use builder instead", replaceWith = ReplaceWith("encode(strategy, value) { this.shouldEncodeElementDefault = shouldEncodeElementDefault }"))
13+
fun <T> encode(strategy: SerializationStrategy<T>, value: T, shouldEncodeElementDefault: Boolean): Any? = encode(strategy, value) {
14+
this.shouldEncodeElementDefault = shouldEncodeElementDefault
15+
}
1416

15-
fun <T> encode(strategy: SerializationStrategy<T>, value: T, settings: EncodeSettings): Any? =
16-
FirebaseEncoder(settings).apply { encodeSerializableValue(strategy, value) }.value
17+
fun <T> encode(strategy: SerializationStrategy<T>, value: T, buildSettings: EncodeSettings.Builder.() -> Unit): Any? =
18+
FirebaseEncoder(EncodeSettings.Builder().apply(buildSettings).build()).apply { encodeSerializableValue(strategy, value) }.value
1719

18-
inline fun <reified T> encode(value: T, shouldEncodeElementDefault: Boolean, serializersModule: SerializersModule = EmptySerializersModule()): Any? = encode(value, EncodeSettings(shouldEncodeElementDefault, serializersModule))
19-
inline fun <reified T> encode(value: T, settings: EncodeSettings): Any? = value?.let {
20-
FirebaseEncoder(settings).apply {
20+
@Deprecated("Deprecated. Use builder instead", replaceWith = ReplaceWith("encode(value) { this.shouldEncodeElementDefault = shouldEncodeElementDefault }"))
21+
inline fun <reified T> encode(value: T, shouldEncodeElementDefault: Boolean): Any? = encode(value) {
22+
this.shouldEncodeElementDefault = shouldEncodeElementDefault
23+
}
24+
inline fun <reified T> encode(value: T, buildSettings: EncodeSettings.Builder.() -> Unit): Any? = value?.let {
25+
FirebaseEncoder(EncodeSettings.Builder().apply(buildSettings).build()).apply {
2126
if (it is ValueWithSerializer<*> && it.value is T) {
2227
@Suppress("UNCHECKED_CAST")
2328
(it as ValueWithSerializer<T>).let {
@@ -43,7 +48,9 @@ class FirebaseEncoder(
4348
internal val settings: EncodeSettings
4449
) : Encoder {
4550

46-
constructor(shouldEncodeElementDefault: Boolean, serializersModule: SerializersModule = EmptySerializersModule()) : this(EncodeSettings(shouldEncodeElementDefault, serializersModule))
51+
constructor(shouldEncodeElementDefault: Boolean) : this(
52+
EncodeSettings.Builder().apply { this.shouldEncodeElementDefault = shouldEncodeElementDefault }.build()
53+
)
4754

4855
var value: Any? = null
4956

firebase-common/src/commonTest/kotlin/dev/gitlive/firebase/EncodersTest.kt

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -141,11 +141,17 @@ class EncodersTest {
141141
polymorphic(AbstractClass::class, ImplementedClass::class, ImplementedClass.serializer())
142142
}
143143
val abstractClass: AbstractClass = ImplementedClass("value", true)
144-
val encoded = encode(AbstractClass.serializer(), abstractClass, EncodeSettings(true, module))
144+
val encoded =
145+
encode(AbstractClass.serializer(), abstractClass) {
146+
shouldEncodeElementDefault = true
147+
serializersModule = module
148+
}
145149

146150
nativeAssertEquals(nativeMapOf("type" to "implemented", "value" to "value", "otherValue" to true), encoded)
147151

148-
val decoded = decode(AbstractClass.serializer(), encoded, module)
152+
val decoded = decode(AbstractClass.serializer(), encoded) {
153+
serializersModule = module
154+
}
149155
assertEquals(abstractClass, decoded)
150156
}
151157

@@ -158,7 +164,10 @@ class EncodersTest {
158164
val sealedClass: SealedClass = SealedClass.Test("value")
159165
val abstractClass: AbstractClass = ImplementedClass("value", true)
160166
val nestedClass = NestedClass(sealedClass, abstractClass, listOf(sealedClass), listOf(abstractClass), mapOf(sealedClass to sealedClass), mapOf(abstractClass to abstractClass))
161-
val encoded = encode(NestedClass.serializer(), nestedClass, EncodeSettings(true, module))
167+
val encoded = encode(NestedClass.serializer(), nestedClass) {
168+
shouldEncodeElementDefault = true
169+
serializersModule = module
170+
}
162171

163172
val sealedEncoded = nativeMapOf("type" to "test", "value" to "value")
164173
val abstractEncoded = nativeMapOf("type" to "implemented", "value" to "value", "otherValue" to true)
@@ -174,7 +183,9 @@ class EncodersTest {
174183
encoded
175184
)
176185

177-
val decoded = decode(NestedClass.serializer(), encoded, module)
186+
val decoded = decode(NestedClass.serializer(), encoded) {
187+
serializersModule = module
188+
}
178189
assertEquals(nestedClass, decoded)
179190
}
180191
}

firebase-crashlytics/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@gitlive/firebase-crashlytics",
3-
"version": "1.11.0",
3+
"version": "1.11.4",
44
"description": "Wrapper around firebase for usage in Kotlin Multiplatform projects",
55
"main": "firebase-crashlytics.js",
66
"scripts": {

firebase-database/src/androidMain/kotlin/dev/gitlive/firebase/database/database.kt

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import kotlinx.coroutines.flow.*
1616
import kotlinx.coroutines.tasks.await
1717
import kotlinx.serialization.DeserializationStrategy
1818
import kotlinx.serialization.KSerializer
19-
import kotlinx.serialization.modules.SerializersModule
2019
import java.util.*
2120
import kotlin.time.Duration.Companion.seconds
2221

@@ -184,22 +183,22 @@ actual class DatabaseReference internal constructor(
184183
.run { Unit }
185184

186185
@Suppress("UNCHECKED_CAST")
187-
override suspend fun updateChildren(update: Map<String, Any?>, encodeDefaults: Boolean, serializersModule: SerializersModule) =
188-
android.updateChildren(encode(update, encodeDefaults, serializersModule) as Map<String, Any?>)
186+
override suspend fun updateChildren(update: Map<String, Any?>, buildSettings: EncodeSettings.Builder.() -> Unit) =
187+
android.updateChildren(encode(update, buildSettings) as Map<String, Any?>)
189188
.run { if(persistenceEnabled) await() else awaitWhileOnline(database) }
190189
.run { Unit }
191190

192191
actual suspend fun removeValue() = android.removeValue()
193192
.run { if(persistenceEnabled) await() else awaitWhileOnline(database) }
194193
.run { Unit }
195194

196-
actual suspend fun <T> runTransaction(strategy: KSerializer<T>, serializersModule: SerializersModule, transactionUpdate: (currentData: T) -> T): DataSnapshot {
195+
actual suspend fun <T> runTransaction(strategy: KSerializer<T>, buildSettings: DecodeSettings.Builder.() -> Unit, transactionUpdate: (currentData: T) -> T): DataSnapshot {
197196
val deferred = CompletableDeferred<DataSnapshot>()
198197
android.runTransaction(object : Transaction.Handler {
199198

200199
override fun doTransaction(currentData: MutableData): Transaction.Result {
201200
currentData.value = currentData.value?.let {
202-
transactionUpdate(decode(strategy, it, serializersModule))
201+
transactionUpdate(decode(strategy, it, buildSettings))
203202
}
204203
return Transaction.success(currentData)
205204
}
@@ -237,8 +236,8 @@ actual class DataSnapshot internal constructor(
237236
actual inline fun <reified T> value() =
238237
decode<T>(value = android.value)
239238

240-
actual fun <T> value(strategy: DeserializationStrategy<T>, serializersModule: SerializersModule) =
241-
decode(strategy, android.value, serializersModule)
239+
actual fun <T> value(strategy: DeserializationStrategy<T>, buildSettings: DecodeSettings.Builder.() -> Unit) =
240+
decode(strategy, android.value, buildSettings)
242241

243242
actual fun child(path: String) = DataSnapshot(android.child(path), persistenceEnabled)
244243
actual val hasChildren get() = android.hasChildren()
@@ -263,8 +262,8 @@ actual class OnDisconnect internal constructor(
263262
.run { if(persistenceEnabled) await() else awaitWhileOnline(database) }
264263
.run { Unit }
265264

266-
override suspend fun updateChildren(update: Map<String, Any?>, encodeDefaults: Boolean, serializersModule: SerializersModule) =
267-
android.updateChildren(update.mapValues { (_, it) -> encode(it, encodeDefaults, serializersModule) })
265+
override suspend fun updateChildren(update: Map<String, Any?>, buildSettings: EncodeSettings.Builder.() -> Unit) =
266+
android.updateChildren(update.mapValues { (_, it) -> encode(it, buildSettings) })
268267
.run { if(persistenceEnabled) await() else awaitWhileOnline(database) }
269268
.run { Unit }
270269
}

firebase-database/src/commonMain/kotlin/dev/gitlive/firebase/database/database.kt

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,16 @@
44

55
package dev.gitlive.firebase.database
66

7+
import dev.gitlive.firebase.DecodeSettings
8+
import dev.gitlive.firebase.EncodeSettings
79
import dev.gitlive.firebase.Firebase
810
import dev.gitlive.firebase.FirebaseApp
9-
import dev.gitlive.firebase.database.ChildEvent.Type.ADDED
10-
import dev.gitlive.firebase.database.ChildEvent.Type.CHANGED
11-
import dev.gitlive.firebase.database.ChildEvent.Type.MOVED
12-
import dev.gitlive.firebase.database.ChildEvent.Type.REMOVED
11+
import dev.gitlive.firebase.database.ChildEvent.Type.*
1312
import dev.gitlive.firebase.encode
1413
import kotlinx.coroutines.flow.Flow
1514
import kotlinx.serialization.DeserializationStrategy
1615
import kotlinx.serialization.KSerializer
1716
import kotlinx.serialization.SerializationStrategy
18-
import kotlinx.serialization.modules.EmptySerializersModule
19-
import kotlinx.serialization.modules.SerializersModule
2017

2118
/** Returns the [FirebaseDatabase] instance of the default [FirebaseApp]. */
2219
expect val Firebase.database: FirebaseDatabase
@@ -73,13 +70,29 @@ expect open class Query internal constructor(nativeQuery: NativeQuery) {
7370
}
7471

7572
abstract class BaseDatabaseReference internal constructor(nativeQuery: NativeQuery) : Query(nativeQuery) {
76-
suspend inline fun <reified T> setValue(value: T?, encodeDefaults: Boolean = true, serializersModule: SerializersModule = EmptySerializersModule()) =
77-
setValueEncoded(encode(value, encodeDefaults, serializersModule))
78-
suspend fun <T> setValue(strategy: SerializationStrategy<T>, value: T, encodeDefaults: Boolean = true, serializersModule: SerializersModule = EmptySerializersModule()) =
79-
setValueEncoded(encode(strategy, value, encodeDefaults, serializersModule))
73+
74+
@Deprecated("Deprecated. Use builder instead", replaceWith = ReplaceWith("setValue(value) { shouldEncodeElementDefault = encodeDefaults }"))
75+
suspend inline fun <reified T> setValue(value: T?, encodeDefaults: Boolean) =
76+
setValue(value) {
77+
shouldEncodeElementDefault = encodeDefaults
78+
}
79+
suspend inline fun <reified T> setValue(value: T?, buildSettings: EncodeSettings.Builder.() -> Unit = {}) =
80+
setValueEncoded(encode(value, buildSettings))
81+
82+
@Deprecated("Deprecated. Use builder instead", replaceWith = ReplaceWith("setValue(strategy, value) { shouldEncodeElementDefault = encodeDefaults }"))
83+
suspend fun <T> setValue(strategy: SerializationStrategy<T>, value: T, encodeDefaults: Boolean) =
84+
setValue(strategy, value) {
85+
shouldEncodeElementDefault = encodeDefaults
86+
}
87+
suspend fun <T> setValue(strategy: SerializationStrategy<T>, value: T, buildSettings: EncodeSettings.Builder.() -> Unit = {}) = setValueEncoded(encode(strategy, value, buildSettings))
8088

8189
abstract suspend fun setValueEncoded(encodedValue: Any?)
82-
abstract suspend fun updateChildren(update: Map<String, Any?>, encodeDefaults: Boolean = true, serializersModule: SerializersModule = EmptySerializersModule())
90+
91+
@Deprecated("Deprecated. Use builder instead", replaceWith = ReplaceWith("updateChildren(update) { shouldEncodeElementDefault = encodeDefaults }"))
92+
suspend fun updateChildren(update: Map<String, Any?>, encodeDefaults: Boolean) = updateChildren(update) {
93+
shouldEncodeElementDefault = encodeDefaults
94+
}
95+
abstract suspend fun updateChildren(update: Map<String, Any?>, buildSettings: EncodeSettings.Builder.() -> Unit = {})
8396
}
8497

8598
expect class DatabaseReference : BaseDatabaseReference {
@@ -90,7 +103,7 @@ expect class DatabaseReference : BaseDatabaseReference {
90103

91104
suspend fun removeValue()
92105

93-
suspend fun <T> runTransaction(strategy: KSerializer<T>, serializersModule: SerializersModule = EmptySerializersModule(), transactionUpdate: (currentData: T) -> T): DataSnapshot
106+
suspend fun <T> runTransaction(strategy: KSerializer<T>, buildSettings: DecodeSettings.Builder.() -> Unit = {}, transactionUpdate: (currentData: T) -> T): DataSnapshot
94107
}
95108

96109
expect class DataSnapshot {
@@ -99,7 +112,7 @@ expect class DataSnapshot {
99112
val ref: DatabaseReference
100113
val value: Any?
101114
inline fun <reified T> value(): T
102-
fun <T> value(strategy: DeserializationStrategy<T>, serializersModule: SerializersModule = EmptySerializersModule()): T
115+
fun <T> value(strategy: DeserializationStrategy<T>, buildSettings: DecodeSettings.Builder.() -> Unit = {}): T
103116
fun child(path: String): DataSnapshot
104117
val hasChildren: Boolean
105118
val children: Iterable<DataSnapshot>
@@ -108,13 +121,22 @@ expect class DataSnapshot {
108121
expect class DatabaseException(message: String?, cause: Throwable?) : RuntimeException
109122

110123
abstract class BaseOnDisconnect internal constructor() {
111-
suspend inline fun <reified T> setValue(value: T?, encodeDefaults: Boolean = true, serializersModule: SerializersModule = EmptySerializersModule()) =
112-
setValue(encode(value, encodeDefaults, serializersModule))
113-
suspend fun <T> setValue(strategy: SerializationStrategy<T>, value: T, encodeDefaults: Boolean = true, serializersModule: SerializersModule = EmptySerializersModule()) =
114-
setValue(encode(strategy, value, encodeDefaults, serializersModule))
124+
@Deprecated("Deprecated. Use builder instead", replaceWith = ReplaceWith("setValue(value) { shouldEncodeElementDefault = encodeDefaults }"))
125+
suspend inline fun <reified T> setValue(value: T?, encodeDefaults: Boolean) =
126+
setValue(value) { shouldEncodeElementDefault = encodeDefaults }
127+
suspend inline fun <reified T> setValue(value: T?, buildSettings: EncodeSettings.Builder.() -> Unit = {}) =
128+
setValue(encode(value, buildSettings))
129+
@Deprecated("Deprecated. Use builder instead", replaceWith = ReplaceWith("setValue(strategy, value) { shouldEncodeElementDefault = encodeDefaults }"))
130+
suspend fun <T> setValue(strategy: SerializationStrategy<T>, value: T, encodeDefaults: Boolean) =
131+
setValue(strategy, value) { shouldEncodeElementDefault = encodeDefaults }
132+
suspend fun <T> setValue(strategy: SerializationStrategy<T>, value: T, buildSettings: EncodeSettings.Builder.() -> Unit = {}) = setValue(encode(strategy, value, buildSettings))
115133
abstract suspend fun setValue(encodedValue: Any?)
116134

117-
abstract suspend fun updateChildren(update: Map<String, Any?>, encodeDefaults: Boolean = true, serializersModule: SerializersModule = EmptySerializersModule())
135+
abstract suspend fun updateChildren(update: Map<String, Any?>, buildSettings: EncodeSettings.Builder.() -> Unit = {})
136+
@Deprecated("Deprecated. Use builder instead", replaceWith = ReplaceWith("updateChildren(update) { shouldEncodeElementDefault = encodeDefaults }"))
137+
suspend fun updateChildren(update: Map<String, Any?>, encodeDefaults: Boolean) = updateChildren(update) {
138+
shouldEncodeElementDefault = encodeDefaults
139+
}
118140
}
119141

120142
expect class OnDisconnect : BaseOnDisconnect {

0 commit comments

Comments
 (0)