diff --git a/README.md b/README.md
index 26101e39d..084fbb39d 100644
--- a/README.md
+++ b/README.md
@@ -102,6 +102,33 @@ data class Post(
```
+
Polymorphic serialization (sealed classes)
+
+This sdk will handle polymorphic serialization automatically if you have a sealed class and its children marked as `Serializable`. It will include a `type` property that will be used to discriminate which child class is the serialized.
+
+You can change this `type` property by using the `@FirebaseClassDiscrminator` annotation in the parent sealed class:
+
+```kotlin
+@Serializable
+@FirebaseClassDiscriminator("class")
+sealed class Parent {
+ @Serializable
+ @SerialName("child")
+ data class Child(
+ val property: Boolean
+ ) : Parent
+}
+```
+
+In combination with a `SerialName` specified for the child class, you have full control over the serialized data. In this case it will be:
+
+```json
+{
+ "class": "child",
+ "property": true
+}
+```
+
To reduce boilerplate, default arguments are used in the places where the Firebase Android SDK employs the builder pattern:
diff --git a/firebase-common/src/androidMain/kotlin/dev/gitlive/firebase/_decoders.kt b/firebase-common/src/androidMain/kotlin/dev/gitlive/firebase/_decoders.kt
index 2b31cece7..4516eabbe 100644
--- a/firebase-common/src/androidMain/kotlin/dev/gitlive/firebase/_decoders.kt
+++ b/firebase-common/src/androidMain/kotlin/dev/gitlive/firebase/_decoders.kt
@@ -5,13 +5,12 @@
package dev.gitlive.firebase
import kotlinx.serialization.encoding.CompositeDecoder
-import kotlinx.serialization.KSerializer
-import kotlinx.serialization.SerializationException
+import kotlinx.serialization.descriptors.PolymorphicKind
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.descriptors.StructureKind
-actual fun FirebaseDecoder.structureDecoder(descriptor: SerialDescriptor, decodeDouble: (value: Any?) -> Double?): CompositeDecoder = when(descriptor.kind as StructureKind) {
- StructureKind.CLASS, StructureKind.OBJECT -> (value as Map<*, *>).let { map ->
+actual fun FirebaseDecoder.structureDecoder(descriptor: SerialDescriptor, decodeDouble: (value: Any?) -> Double?): CompositeDecoder = when(descriptor.kind) {
+ StructureKind.CLASS, StructureKind.OBJECT, PolymorphicKind.SEALED -> (value as Map<*, *>).let { map ->
FirebaseClassDecoder(decodeDouble, map.size, { map.containsKey(it) }) { desc, index -> map[desc.getElementName(index)] }
}
StructureKind.LIST -> (value as List<*>).let {
@@ -20,4 +19,8 @@ actual fun FirebaseDecoder.structureDecoder(descriptor: SerialDescriptor, decode
StructureKind.MAP -> (value as Map<*, *>).entries.toList().let {
FirebaseCompositeDecoder(decodeDouble, it.size) { _, index -> it[index/2].run { if(index % 2 == 0) key else value } }
}
- }
\ No newline at end of file
+ else -> TODO("The firebase-kotlin-sdk does not support $descriptor for serialization yet")
+ }
+
+actual fun getPolymorphicType(value: Any?, discriminator: String): String =
+ (value as Map<*,*>)[discriminator] as String
\ No newline at end of file
diff --git a/firebase-common/src/androidMain/kotlin/dev/gitlive/firebase/_encoders.kt b/firebase-common/src/androidMain/kotlin/dev/gitlive/firebase/_encoders.kt
index 84576846e..928936d38 100644
--- a/firebase-common/src/androidMain/kotlin/dev/gitlive/firebase/_encoders.kt
+++ b/firebase-common/src/androidMain/kotlin/dev/gitlive/firebase/_encoders.kt
@@ -4,12 +4,11 @@
package dev.gitlive.firebase
-import kotlinx.serialization.encoding.CompositeEncoder
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.descriptors.StructureKind
import kotlin.collections.set
-actual fun FirebaseEncoder.structureEncoder(descriptor: SerialDescriptor): CompositeEncoder = when(descriptor.kind as StructureKind) {
+actual fun FirebaseEncoder.structureEncoder(descriptor: SerialDescriptor): FirebaseCompositeEncoder = when(descriptor.kind) {
StructureKind.LIST -> mutableListOf()
.also { value = it }
.let { FirebaseCompositeEncoder(shouldEncodeElementDefault, positiveInfinity) { _, index, value -> it.add(index, value) } }
@@ -17,5 +16,11 @@ actual fun FirebaseEncoder.structureEncoder(descriptor: SerialDescriptor): Compo
.let { FirebaseCompositeEncoder(shouldEncodeElementDefault, positiveInfinity, { value = it.chunked(2).associate { (k, v) -> k to v } }) { _, _, value -> it.add(value) } }
StructureKind.CLASS, StructureKind.OBJECT -> mutableMapOf()
.also { value = it }
- .let { FirebaseCompositeEncoder(shouldEncodeElementDefault, positiveInfinity) { _, index, value -> it[descriptor.getElementName(index)] = value } }
+ .let { FirebaseCompositeEncoder(shouldEncodeElementDefault, positiveInfinity,
+ setPolymorphicType = { discriminator, type ->
+ it[discriminator] = type
+ },
+ set = { _, index, value -> it[descriptor.getElementName(index)] = value }
+ ) }
+ else -> TODO("The firebase-kotlin-sdk does not support $descriptor for serialization yet")
}
\ No newline at end of file
diff --git a/firebase-common/src/commonMain/kotlin/dev/gitlive/firebase/FirebaseClassDiscriminator.kt b/firebase-common/src/commonMain/kotlin/dev/gitlive/firebase/FirebaseClassDiscriminator.kt
new file mode 100644
index 000000000..2ed4bafa1
--- /dev/null
+++ b/firebase-common/src/commonMain/kotlin/dev/gitlive/firebase/FirebaseClassDiscriminator.kt
@@ -0,0 +1,7 @@
+package dev.gitlive.firebase
+
+import kotlinx.serialization.InheritableSerialInfo
+
+@InheritableSerialInfo
+@Target(AnnotationTarget.CLASS)
+annotation class FirebaseClassDiscriminator(val discriminator: String)
\ No newline at end of file
diff --git a/firebase-common/src/commonMain/kotlin/dev/gitlive/firebase/Polymorphic.kt b/firebase-common/src/commonMain/kotlin/dev/gitlive/firebase/Polymorphic.kt
new file mode 100644
index 000000000..aceb6002f
--- /dev/null
+++ b/firebase-common/src/commonMain/kotlin/dev/gitlive/firebase/Polymorphic.kt
@@ -0,0 +1,59 @@
+package dev.gitlive.firebase
+
+import kotlinx.serialization.DeserializationStrategy
+import kotlinx.serialization.SerializationStrategy
+import kotlinx.serialization.descriptors.SerialDescriptor
+import kotlinx.serialization.findPolymorphicSerializer
+import kotlinx.serialization.internal.AbstractPolymorphicSerializer
+
+/*
+ * This code was inspired on polymorphic json serialization of kotlinx.serialization.
+ * See https://github.com/Kotlin/kotlinx.serialization/blob/master/formats/json/commonMain/src/kotlinx/serialization/json/internal/Polymorphic.kt
+ */
+@Suppress("UNCHECKED_CAST")
+internal fun FirebaseEncoder.encodePolymorphically(
+ serializer: SerializationStrategy,
+ value: T,
+ ifPolymorphic: (String) -> Unit
+) {
+ if (serializer !is AbstractPolymorphicSerializer<*>) {
+ serializer.serialize(this, value)
+ return
+ }
+ val casted = serializer as AbstractPolymorphicSerializer
+ val baseClassDiscriminator = serializer.descriptor.classDiscriminator()
+ val actualSerializer = casted.findPolymorphicSerializer(this, value as Any)
+ ifPolymorphic(baseClassDiscriminator)
+ actualSerializer.serialize(this, value)
+}
+
+@Suppress("UNCHECKED_CAST")
+internal fun FirebaseDecoder.decodeSerializableValuePolymorphic(
+ value: Any?,
+ decodeDouble: (value: Any?) -> Double?,
+ deserializer: DeserializationStrategy,
+): T {
+ if (deserializer !is AbstractPolymorphicSerializer<*>) {
+ return deserializer.deserialize(this)
+ }
+
+ val casted = deserializer as AbstractPolymorphicSerializer
+ val discriminator = deserializer.descriptor.classDiscriminator()
+ val type = getPolymorphicType(value, discriminator)
+ val actualDeserializer = casted.findPolymorphicSerializerOrNull(
+ structureDecoder(deserializer.descriptor, decodeDouble),
+ type
+ ) as DeserializationStrategy
+ return actualDeserializer.deserialize(this)
+}
+
+internal fun SerialDescriptor.classDiscriminator(): String {
+ // Plain loop is faster than allocation of Sequence or ArrayList
+ // We can rely on the fact that only one FirebaseClassDiscriminator is present —
+ // compiler plugin checked that.
+ for (annotation in annotations) {
+ if (annotation is FirebaseClassDiscriminator) return annotation.discriminator
+ }
+ return "type"
+}
+
diff --git a/firebase-common/src/commonMain/kotlin/dev/gitlive/firebase/decoders.kt b/firebase-common/src/commonMain/kotlin/dev/gitlive/firebase/decoders.kt
index c771d63e1..6be266b56 100644
--- a/firebase-common/src/commonMain/kotlin/dev/gitlive/firebase/decoders.kt
+++ b/firebase-common/src/commonMain/kotlin/dev/gitlive/firebase/decoders.kt
@@ -25,8 +25,8 @@ fun decode(strategy: DeserializationStrategy, value: Any?, decodeDouble:
require(value != null || strategy.descriptor.isNullable) { "Value was null for non-nullable type ${strategy.descriptor.serialName}" }
return FirebaseDecoder(value, decodeDouble).decodeSerializableValue(strategy)
}
-
expect fun FirebaseDecoder.structureDecoder(descriptor: SerialDescriptor, decodeDouble: (value: Any?) -> Double?): CompositeDecoder
+expect fun getPolymorphicType(value: Any?, discriminator: String): String
class FirebaseDecoder(internal val value: Any?, private val decodeDouble: (value: Any?) -> Double?) : Decoder {
@@ -59,8 +59,11 @@ class FirebaseDecoder(internal val value: Any?, private val decodeDouble: (value
override fun decodeNull() = decodeNull(value)
- @ExperimentalSerializationApi
override fun decodeInline(inlineDescriptor: SerialDescriptor) = FirebaseDecoder(value, decodeDouble)
+
+ override fun decodeSerializableValue(deserializer: DeserializationStrategy): T {
+ return decodeSerializableValuePolymorphic(value, decodeDouble, deserializer)
+ }
}
class FirebaseClassDecoder(
@@ -80,7 +83,7 @@ class FirebaseClassDecoder(
?: DECODE_DONE
}
-open class FirebaseCompositeDecoder constructor(
+open class FirebaseCompositeDecoder(
private val decodeDouble: (value: Any?) -> Double?,
private val size: Int,
private val get: (descriptor: SerialDescriptor, index: Int) -> Any?
@@ -134,6 +137,7 @@ open class FirebaseCompositeDecoder constructor(
@ExperimentalSerializationApi
override fun decodeInlineElement(descriptor: SerialDescriptor, index: Int): Decoder =
FirebaseDecoder(get(descriptor, index), decodeDouble)
+
}
private fun decodeString(value: Any?) = value.toString()
diff --git a/firebase-common/src/commonMain/kotlin/dev/gitlive/firebase/encoders.kt b/firebase-common/src/commonMain/kotlin/dev/gitlive/firebase/encoders.kt
index afb637492..7afe032bc 100644
--- a/firebase-common/src/commonMain/kotlin/dev/gitlive/firebase/encoders.kt
+++ b/firebase-common/src/commonMain/kotlin/dev/gitlive/firebase/encoders.kt
@@ -16,14 +16,23 @@ inline fun encode(value: T, shouldEncodeElementDefault: Boolean, pos
FirebaseEncoder(shouldEncodeElementDefault, positiveInfinity).apply { encodeSerializableValue(it.firebaseSerializer(), it) }.value
}
-expect fun FirebaseEncoder.structureEncoder(descriptor: SerialDescriptor): CompositeEncoder
+expect fun FirebaseEncoder.structureEncoder(descriptor: SerialDescriptor): FirebaseCompositeEncoder
class FirebaseEncoder(internal val shouldEncodeElementDefault: Boolean, positiveInfinity: Any) : TimestampEncoder(positiveInfinity), Encoder {
var value: Any? = null
override val serializersModule = EmptySerializersModule
- override fun beginStructure(descriptor: SerialDescriptor) = structureEncoder(descriptor)
+ private var polymorphicDiscriminator: String? = null
+
+ override fun beginStructure(descriptor: SerialDescriptor): CompositeEncoder {
+ val encoder = structureEncoder(descriptor)
+ if (polymorphicDiscriminator != null) {
+ encoder.encodePolymorphicClassDiscriminator(polymorphicDiscriminator!!, descriptor.serialName)
+ polymorphicDiscriminator = null
+ }
+ return encoder
+ }
override fun encodeBoolean(value: Boolean) {
this.value = value
@@ -73,9 +82,14 @@ class FirebaseEncoder(internal val shouldEncodeElementDefault: Boolean, positive
this.value = value
}
- @ExperimentalSerializationApi
override fun encodeInline(inlineDescriptor: SerialDescriptor): Encoder =
FirebaseEncoder(shouldEncodeElementDefault, positiveInfinity)
+
+ override fun encodeSerializableValue(serializer: SerializationStrategy, value: T) {
+ encodePolymorphically(serializer, value) {
+ polymorphicDiscriminator = it
+ }
+ }
}
abstract class TimestampEncoder(internal val positiveInfinity: Any) {
@@ -89,7 +103,8 @@ open class FirebaseCompositeEncoder constructor(
private val shouldEncodeElementDefault: Boolean,
positiveInfinity: Any,
private val end: () -> Unit = {},
- private val set: (descriptor: SerialDescriptor, index: Int, value: Any?) -> Unit
+ private val setPolymorphicType: (String, String) -> Unit = { _, _ -> },
+ private val set: (descriptor: SerialDescriptor, index: Int, value: Any?) -> Unit,
): TimestampEncoder(positiveInfinity), CompositeEncoder {
override val serializersModule = EmptySerializersModule
@@ -153,6 +168,9 @@ open class FirebaseCompositeEncoder constructor(
@ExperimentalSerializationApi
override fun encodeInlineElement(descriptor: SerialDescriptor, index: Int): Encoder =
FirebaseEncoder(shouldEncodeElementDefault, positiveInfinity)
-}
+ fun encodePolymorphicClassDiscriminator(discriminator: String, type: String) {
+ setPolymorphicType(discriminator, type)
+ }
+}
diff --git a/firebase-common/src/commonTest/kotlin/dev/gitlive/firebase/EncodersTest.kt b/firebase-common/src/commonTest/kotlin/dev/gitlive/firebase/EncodersTest.kt
index 2d5741835..d61c1e5d1 100644
--- a/firebase-common/src/commonTest/kotlin/dev/gitlive/firebase/EncodersTest.kt
+++ b/firebase-common/src/commonTest/kotlin/dev/gitlive/firebase/EncodersTest.kt
@@ -4,6 +4,7 @@
package dev.gitlive.firebase
+import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.builtins.ListSerializer
import kotlin.test.Test
@@ -17,6 +18,13 @@ expect fun nativeAssertEquals(expected: Any?, actual: Any?): Unit
@Serializable
data class TestData(val map: Map, val bool: Boolean = false, val nullableBool: Boolean? = null)
+@Serializable
+sealed class TestSealed {
+ @Serializable
+ @SerialName("child")
+ data class ChildClass(val map: Map, val bool: Boolean = false): TestSealed()
+}
+
class EncodersTest {
@Test
fun encodeMap() {
@@ -37,6 +45,12 @@ class EncodersTest {
nativeAssertEquals(nativeMapOf("map" to nativeMapOf("key" to "value"), "bool" to true, "nullableBool" to true), encoded)
}
+ @Test
+ fun encodeSealedClass() {
+ val encoded = encode(TestSealed.serializer(), TestSealed.ChildClass(mapOf("key" to "value"), true), shouldEncodeElementDefault = true)
+ nativeAssertEquals(nativeMapOf("type" to "child", "map" to nativeMapOf("key" to "value"), "bool" to true), encoded)
+ }
+
@Test
fun decodeObject() {
val decoded = decode(TestData.serializer(), nativeMapOf("map" to nativeMapOf("key" to "value")))
@@ -54,4 +68,10 @@ class EncodersTest {
val decoded = decode(TestData.serializer(), nativeMapOf("map" to mapOf("key" to "value"), "nullableBool" to null))
assertNull(decoded.nullableBool)
}
+
+ @Test
+ fun decodeSealedClass() {
+ val decoded = decode(TestSealed.serializer(), nativeMapOf("type" to "child", "map" to nativeMapOf("key" to "value"), "bool" to true))
+ assertEquals(TestSealed.ChildClass(mapOf("key" to "value"), true), decoded)
+ }
}
\ No newline at end of file
diff --git a/firebase-common/src/iosMain/kotlin/dev/gitlive/firebase/_decoders.kt b/firebase-common/src/iosMain/kotlin/dev/gitlive/firebase/_decoders.kt
index 05ffad2cd..5e87c2f9a 100644
--- a/firebase-common/src/iosMain/kotlin/dev/gitlive/firebase/_decoders.kt
+++ b/firebase-common/src/iosMain/kotlin/dev/gitlive/firebase/_decoders.kt
@@ -5,13 +5,12 @@
package dev.gitlive.firebase
import kotlinx.serialization.encoding.CompositeDecoder
-import kotlinx.serialization.KSerializer
-import kotlinx.serialization.SerializationException
+import kotlinx.serialization.descriptors.PolymorphicKind
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.descriptors.StructureKind
-actual fun FirebaseDecoder.structureDecoder(descriptor: SerialDescriptor, decodeDouble: (value: Any?) -> Double?): CompositeDecoder = when(descriptor.kind as StructureKind) {
- StructureKind.CLASS, StructureKind.OBJECT -> (value as Map<*, *>).let { map ->
+actual fun FirebaseDecoder.structureDecoder(descriptor: SerialDescriptor, decodeDouble: (value: Any?) -> Double?): CompositeDecoder = when(descriptor.kind) {
+ StructureKind.CLASS, StructureKind.OBJECT, PolymorphicKind.SEALED -> (value as Map<*, *>).let { map ->
FirebaseClassDecoder(decodeDouble, map.size, { map.containsKey(it) }) { desc, index -> map[desc.getElementName(index)] }
}
StructureKind.LIST -> (value as List<*>).let {
@@ -20,4 +19,8 @@ actual fun FirebaseDecoder.structureDecoder(descriptor: SerialDescriptor, decode
StructureKind.MAP -> (value as Map<*, *>).entries.toList().let {
FirebaseCompositeDecoder(decodeDouble, it.size) { _, index -> it[index/2].run { if(index % 2 == 0) key else value } }
}
-}
\ No newline at end of file
+ else -> TODO("The firebase-kotlin-sdk does not support $descriptor for serialization yet")
+}
+
+actual fun getPolymorphicType(value: Any?, discriminator: String): String =
+ (value as Map<*,*>)[discriminator] as String
\ No newline at end of file
diff --git a/firebase-common/src/iosMain/kotlin/dev/gitlive/firebase/_encoders.kt b/firebase-common/src/iosMain/kotlin/dev/gitlive/firebase/_encoders.kt
index 84576846e..e887f1957 100644
--- a/firebase-common/src/iosMain/kotlin/dev/gitlive/firebase/_encoders.kt
+++ b/firebase-common/src/iosMain/kotlin/dev/gitlive/firebase/_encoders.kt
@@ -4,18 +4,25 @@
package dev.gitlive.firebase
+import kotlinx.serialization.descriptors.PolymorphicKind
import kotlinx.serialization.encoding.CompositeEncoder
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.descriptors.StructureKind
import kotlin.collections.set
-actual fun FirebaseEncoder.structureEncoder(descriptor: SerialDescriptor): CompositeEncoder = when(descriptor.kind as StructureKind) {
+actual fun FirebaseEncoder.structureEncoder(descriptor: SerialDescriptor): FirebaseCompositeEncoder = when(descriptor.kind) {
StructureKind.LIST -> mutableListOf()
.also { value = it }
.let { FirebaseCompositeEncoder(shouldEncodeElementDefault, positiveInfinity) { _, index, value -> it.add(index, value) } }
StructureKind.MAP -> mutableListOf()
.let { FirebaseCompositeEncoder(shouldEncodeElementDefault, positiveInfinity, { value = it.chunked(2).associate { (k, v) -> k to v } }) { _, _, value -> it.add(value) } }
- StructureKind.CLASS, StructureKind.OBJECT -> mutableMapOf()
+ StructureKind.CLASS, StructureKind.OBJECT, PolymorphicKind.SEALED -> mutableMapOf()
.also { value = it }
- .let { FirebaseCompositeEncoder(shouldEncodeElementDefault, positiveInfinity) { _, index, value -> it[descriptor.getElementName(index)] = value } }
+ .let { FirebaseCompositeEncoder(shouldEncodeElementDefault, positiveInfinity,
+ setPolymorphicType = { discriminator, type ->
+ it[discriminator] = type
+ },
+ set = { _, index, value -> it[descriptor.getElementName(index)] = value }
+ ) }
+ else -> TODO("The firebase-kotlin-sdk does not support $descriptor for serialization yet")
}
\ No newline at end of file
diff --git a/firebase-common/src/jsMain/kotlin/dev/gitlive/firebase/_decoders.kt b/firebase-common/src/jsMain/kotlin/dev/gitlive/firebase/_decoders.kt
index 4e0d0b226..af200fc69 100644
--- a/firebase-common/src/jsMain/kotlin/dev/gitlive/firebase/_decoders.kt
+++ b/firebase-common/src/jsMain/kotlin/dev/gitlive/firebase/_decoders.kt
@@ -5,15 +5,14 @@
package dev.gitlive.firebase
import kotlinx.serialization.encoding.CompositeDecoder
-import kotlinx.serialization.KSerializer
-import kotlinx.serialization.SerializationException
+import kotlinx.serialization.descriptors.PolymorphicKind
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.descriptors.StructureKind
import kotlin.js.Json
@Suppress("UNCHECKED_CAST_TO_EXTERNAL_INTERFACE")
-actual fun FirebaseDecoder.structureDecoder(descriptor: SerialDescriptor, decodeDouble: (value: Any?) -> Double?): CompositeDecoder = when(descriptor.kind as StructureKind) {
- StructureKind.CLASS, StructureKind.OBJECT -> (value as Json).let { json ->
+actual fun FirebaseDecoder.structureDecoder(descriptor: SerialDescriptor, decodeDouble: (value: Any?) -> Double?): CompositeDecoder = when(descriptor.kind) {
+ StructureKind.CLASS, StructureKind.OBJECT, PolymorphicKind.SEALED -> (value as Json).let { json ->
FirebaseClassDecoder(decodeDouble, js("Object").keys(value).length as Int, { json[it] != undefined }) {
desc, index -> json[desc.getElementName(index)]
}
@@ -24,4 +23,9 @@ actual fun FirebaseDecoder.structureDecoder(descriptor: SerialDescriptor, decode
StructureKind.MAP -> (js("Object").entries(value) as Array>).let {
FirebaseCompositeDecoder(decodeDouble, it.size) { _, index -> it[index/2].run { if(index % 2 == 0) get(0) else get(1) } }
}
+ else -> TODO("The firebase-kotlin-sdk does not support $descriptor for serialization yet")
}
+
+@Suppress("UNCHECKED_CAST_TO_EXTERNAL_INTERFACE")
+actual fun getPolymorphicType(value: Any?, discriminator: String): String =
+ (value as Json)[discriminator] as String
diff --git a/firebase-common/src/jsMain/kotlin/dev/gitlive/firebase/_encoders.kt b/firebase-common/src/jsMain/kotlin/dev/gitlive/firebase/_encoders.kt
index 5a7ce7a0f..b5f5aeaef 100644
--- a/firebase-common/src/jsMain/kotlin/dev/gitlive/firebase/_encoders.kt
+++ b/firebase-common/src/jsMain/kotlin/dev/gitlive/firebase/_encoders.kt
@@ -4,12 +4,13 @@
package dev.gitlive.firebase
+import kotlinx.serialization.descriptors.PolymorphicKind
import kotlinx.serialization.encoding.CompositeEncoder
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.descriptors.StructureKind
import kotlin.js.json
-actual fun FirebaseEncoder.structureEncoder(descriptor: SerialDescriptor): CompositeEncoder = when(descriptor.kind as StructureKind) {
+actual fun FirebaseEncoder.structureEncoder(descriptor: SerialDescriptor): FirebaseCompositeEncoder = when(descriptor.kind) {
StructureKind.LIST -> Array(descriptor.elementsCount) { null }
.also { value = it }
.let { FirebaseCompositeEncoder(shouldEncodeElementDefault, positiveInfinity) { _, index, value -> it[index] = value } }
@@ -19,8 +20,16 @@ actual fun FirebaseEncoder.structureEncoder(descriptor: SerialDescriptor): Compo
value = map
FirebaseCompositeEncoder(shouldEncodeElementDefault, positiveInfinity) { _, index, value -> if(index % 2 == 0) lastKey = value as String else map[lastKey] = value }
}
- StructureKind.CLASS, StructureKind.OBJECT -> json()
+ StructureKind.CLASS, StructureKind.OBJECT, PolymorphicKind.SEALED -> json()
.also { value = it }
- .let { FirebaseCompositeEncoder(shouldEncodeElementDefault, positiveInfinity) { _, index, value -> it[descriptor.getElementName(index)] = value } }
+ .let { FirebaseCompositeEncoder(
+ shouldEncodeElementDefault,
+ positiveInfinity,
+ setPolymorphicType = { discriminator, type ->
+ it[discriminator] = type
+ },
+ set = { _, index, value -> it[descriptor.getElementName(index)] = value }
+ ) }
+ else -> TODO("The firebase-kotlin-sdk does not support $descriptor for serialization yet")
}