From bf709a3c507361b64cb0d00720c3220ee8368496 Mon Sep 17 00:00:00 2001 From: Gijs van Veen Date: Tue, 23 Jan 2024 10:58:50 +0100 Subject: [PATCH] Fixed Android crash, updated tests + cleanup --- .../kotlin/dev/gitlive/firebase/decoders.kt | 1 - .../kotlin/dev/gitlive/firebase/encoders.kt | 8 +- .../firebase/reencodeTransformation.kt | 15 +- .../dev/gitlive/firebase/EncodersTest.kt | 157 ++++++++++++++++-- .../dev/gitlive/firebase/database/database.kt | 60 +++++-- .../dev/gitlive/firebase/database/database.kt | 5 +- .../dev/gitlive/firebase/database/database.kt | 17 +- .../dev/gitlive/firebase/database/database.kt | 27 ++- .../dev/gitlive/firebase/database/database.kt | 31 +++- .../gitlive/firebase/firestore/firestore.kt | 28 ++-- .../gitlive/firebase/firestore/firestore.kt | 1 - .../gitlive/firebase/firestore/firestore.kt | 34 +++- 12 files changed, 309 insertions(+), 75 deletions(-) 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 8b650422c..08129e9af 100644 --- a/firebase-common/src/commonMain/kotlin/dev/gitlive/firebase/decoders.kt +++ b/firebase-common/src/commonMain/kotlin/dev/gitlive/firebase/decoders.kt @@ -11,7 +11,6 @@ import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.encoding.CompositeDecoder import kotlinx.serialization.encoding.CompositeDecoder.Companion.DECODE_DONE import kotlinx.serialization.encoding.Decoder -import kotlinx.serialization.modules.EmptySerializersModule import kotlinx.serialization.modules.SerializersModule import kotlinx.serialization.serializer 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 5d2389522..33178187c 100644 --- a/firebase-common/src/commonMain/kotlin/dev/gitlive/firebase/encoders.kt +++ b/firebase-common/src/commonMain/kotlin/dev/gitlive/firebase/encoders.kt @@ -4,9 +4,11 @@ package dev.gitlive.firebase -import kotlinx.serialization.* -import kotlinx.serialization.descriptors.* -import kotlinx.serialization.encoding.* +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.SerializationStrategy +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.CompositeEncoder +import kotlinx.serialization.encoding.Encoder import kotlinx.serialization.modules.SerializersModule @Deprecated("Deprecated. Use builder instead", replaceWith = ReplaceWith("encode(strategy, value) { this.shouldEncodeElementDefault = shouldEncodeElementDefault }")) diff --git a/firebase-common/src/commonMain/kotlin/dev/gitlive/firebase/reencodeTransformation.kt b/firebase-common/src/commonMain/kotlin/dev/gitlive/firebase/reencodeTransformation.kt index 6812732c0..7c9704157 100644 --- a/firebase-common/src/commonMain/kotlin/dev/gitlive/firebase/reencodeTransformation.kt +++ b/firebase-common/src/commonMain/kotlin/dev/gitlive/firebase/reencodeTransformation.kt @@ -2,14 +2,21 @@ package dev.gitlive.firebase import kotlinx.serialization.KSerializer -inline fun reencodeTransformation(value: Any?, builder: EncodeDecodeSettingsBuilder.() -> Unit, transform: (T) -> T): Any? { +inline fun reencodeTransformation(value: Any?, builder: EncodeDecodeSettingsBuilder.() -> Unit = {}, transform: (T) -> T): Any? { val encodeDecodeSettingsBuilder = EncodeDecodeSettingsBuilderImpl().apply(builder) val oldValue: T = decode(value, encodeDecodeSettingsBuilder.buildDecodeSettings()) - return encode(transform(oldValue), encodeDecodeSettingsBuilder.buildEncodeSettings()) + return encode( + transform(oldValue), + encodeDecodeSettingsBuilder.buildEncodeSettings() + ) } -inline fun reencodeTransformation(strategy: KSerializer, value: Any?, builder: EncodeDecodeSettingsBuilder.() -> Unit, transform: (T) -> T): Any? { +inline fun reencodeTransformation(strategy: KSerializer, value: Any?, builder: EncodeDecodeSettingsBuilder.() -> Unit = {}, transform: (T) -> T): Any? { val encodeDecodeSettingsBuilder = EncodeDecodeSettingsBuilderImpl().apply(builder) val oldValue: T = decode(strategy, value, encodeDecodeSettingsBuilder.buildDecodeSettings()) - return encode(strategy, transform(oldValue), encodeDecodeSettingsBuilder.buildEncodeSettings()) + return encode( + strategy, + transform(oldValue), + encodeDecodeSettingsBuilder.buildEncodeSettings() + ) } \ No newline at end of file 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 f1feedf5b..99026654e 100644 --- a/firebase-common/src/commonTest/kotlin/dev/gitlive/firebase/EncodersTest.kt +++ b/firebase-common/src/commonTest/kotlin/dev/gitlive/firebase/EncodersTest.kt @@ -7,14 +7,11 @@ package dev.gitlive.firebase import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlinx.serialization.builtins.ListSerializer -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertNull -import dev.gitlive.firebase.nativeAssertEquals -import dev.gitlive.firebase.nativeMapOf import kotlinx.serialization.builtins.MapSerializer import kotlinx.serialization.builtins.serializer import kotlinx.serialization.modules.SerializersModule +import kotlin.test.Test +import kotlin.test.assertEquals @Serializable object TestObject { @@ -62,7 +59,7 @@ class EncodersTest { @Test fun encodeDecodeList() { val list = listOf("One", "Two", "Three") - val encoded = encode(list, shouldEncodeElementDefault = true) + val encoded = encode>(list) { shouldEncodeElementDefault = true } nativeAssertEquals(nativeListOf("One", "Two", "Three"), encoded) @@ -73,7 +70,7 @@ class EncodersTest { @Test fun encodeDecodeMap() { val map = mapOf("key" to "value", "key2" to "value2", "key3" to "value3") - val encoded = encode(map, shouldEncodeElementDefault = true) + val encoded = encode>(map) { shouldEncodeElementDefault = true } nativeAssertEquals(nativeMapOf("key" to "value", "key2" to "value2", "key3" to "value3"), encoded) @@ -83,7 +80,7 @@ class EncodersTest { @Test fun encodeDecodeObject() { - val encoded = encode(TestObject.serializer(), TestObject, shouldEncodeElementDefault = false) + val encoded = encode(TestObject.serializer(), TestObject) { shouldEncodeElementDefault = false } nativeAssertEquals(nativeMapOf(), encoded) val decoded = decode(TestObject.serializer(), encoded) @@ -93,7 +90,7 @@ class EncodersTest { @Test fun encodeDecodeClass() { val testDataClass = TestData(mapOf("key" to "value"), mapOf(1 to 1), true) - val encoded = encode(TestData.serializer(), testDataClass, shouldEncodeElementDefault = false) + val encoded = encode(TestData.serializer(), testDataClass) { shouldEncodeElementDefault = false } nativeAssertEquals(nativeMapOf("map" to nativeMapOf("key" to "value"), "otherMap" to nativeMapOf(1 to 1), "bool" to true), encoded) @@ -104,7 +101,7 @@ class EncodersTest { @Test fun encodeDecodeClassNullableValue() { val testDataClass = TestData(mapOf("key" to "value"), mapOf(1 to 1), true, nullableBool = true) - val encoded = encode(TestData.serializer(), testDataClass, shouldEncodeElementDefault = true) + val encoded = encode(TestData.serializer(), testDataClass) { shouldEncodeElementDefault = true } nativeAssertEquals(nativeMapOf("map" to nativeMapOf("key" to "value"), "otherMap" to nativeMapOf(1 to 1), "bool" to true, "nullableBool" to true), encoded) @@ -116,7 +113,7 @@ class EncodersTest { fun encodeDecodeGenericClass() { val innerClass = TestData(mapOf("key" to "value"), mapOf(1 to 1), true) val genericClass = GenericClass(innerClass) - val encoded = encode(GenericClass.serializer(TestData.serializer()), genericClass, shouldEncodeElementDefault = true) + val encoded = encode(GenericClass.serializer(TestData.serializer()), genericClass) { shouldEncodeElementDefault = true } nativeAssertEquals(nativeMapOf("inner" to nativeMapOf("map" to nativeMapOf("key" to "value"), "otherMap" to nativeMapOf(1 to 1), "bool" to true, "nullableBool" to null)), encoded) @@ -188,4 +185,142 @@ class EncodersTest { } assertEquals(nestedClass, decoded) } + + @Test + fun reencodeTransformationList() { + val reencoded = reencodeTransformation>(nativeListOf("One", "Two", "Three")) { + assertEquals(listOf("One", "Two", "Three"), it) + it.map { value -> "new$value" } + } + nativeAssertEquals(nativeListOf("newOne", "newTwo", "newThree"), reencoded) + } + + @Test + fun reencodeTransformationMap() { + val reencoded = reencodeTransformation>(nativeMapOf("key" to "value", "key2" to "value2", "key3" to "value3")) { + assertEquals(mapOf("key" to "value", "key2" to "value2", "key3" to "value3"), it) + it.mapValues { (_, value) -> "new-$value" } + } + + nativeAssertEquals(nativeMapOf("key" to "new-value", "key2" to "new-value2", "key3" to "new-value3"), reencoded) + } + + @Test + fun reencodeTransformationObject() { + val reencoded = reencodeTransformation(nativeMapOf(), { shouldEncodeElementDefault = false }) { + assertEquals(TestObject, it) + it + } + nativeAssertEquals(nativeMapOf(), reencoded) + } + + @Test + fun reencodeTransformationClass() { + val reencoded = reencodeTransformation( + nativeMapOf("map" to nativeMapOf("key" to "value"), "otherMap" to nativeMapOf(1 to 1), "bool" to true, "nullableBool" to true), + { shouldEncodeElementDefault = false } + ) { + assertEquals(TestData(mapOf("key" to "value"), mapOf(1 to 1), bool = true, nullableBool = true), it) + it.copy(map = mapOf("newKey" to "newValue"), nullableBool = null) + } + + nativeAssertEquals(nativeMapOf("map" to nativeMapOf("newKey" to "newValue"), "otherMap" to nativeMapOf(1 to 1), "bool" to true), reencoded) + } + + @Test + fun reencodeTransformationNullableValue() { + val reencoded = reencodeTransformation( + nativeMapOf("map" to nativeMapOf("key" to "value"), "otherMap" to nativeMapOf(1 to 1), "bool" to true, "nullableBool" to true), + { shouldEncodeElementDefault = false } + ) { + assertEquals(TestData(mapOf("key" to "value"), mapOf(1 to 1), bool = true, nullableBool = true), it) + null + } + + nativeAssertEquals(null, reencoded) + } + + @Test + fun reencodeTransformationGenericClass() { + val reencoded = reencodeTransformation( + GenericClass.serializer(TestData.serializer()), + nativeMapOf("inner" to nativeMapOf("map" to nativeMapOf("key" to "value"), "otherMap" to nativeMapOf(1 to 1), "bool" to true, "nullableBool" to false)), + { shouldEncodeElementDefault = false } + ) { + assertEquals( + GenericClass(TestData(mapOf("key" to "value"), mapOf(1 to 1), bool = true, nullableBool = false)), + it + ) + GenericClass(it.inner.copy(map = mapOf("newKey" to "newValue"), nullableBool = null)) + } + + nativeAssertEquals(nativeMapOf("inner" to nativeMapOf("map" to nativeMapOf("newKey" to "newValue"), "otherMap" to nativeMapOf(1 to 1), "bool" to true)), reencoded) + } + + @Test + fun reencodeTransformationSealedClass() { + val reencoded = reencodeTransformation(SealedClass.serializer(), nativeMapOf("type" to "test", "value" to "value")) { + assertEquals(SealedClass.Test("value"), it) + SealedClass.Test("newTest") + } + + nativeAssertEquals(nativeMapOf("type" to "test", "value" to "newTest"), reencoded) + } + + @Test + fun reencodeTransformationPolymorphicClass() { + val module = SerializersModule { + polymorphic(AbstractClass::class, ImplementedClass::class, ImplementedClass.serializer()) + } + + val reencoded = reencodeTransformation( + AbstractClass.serializer(), + nativeMapOf("type" to "implemented", "value" to "value", "otherValue" to true), + builder = { + serializersModule = module + } + ) { + assertEquals(ImplementedClass("value", true), it) + ImplementedClass("new-${it.value}", false) + } + + nativeAssertEquals(nativeMapOf("type" to "implemented", "value" to "new-value", "otherValue" to false), reencoded) + } + + @Test + fun reencodeTransformationNestedClass() { + val module = SerializersModule { + polymorphic(AbstractClass::class, ImplementedClass::class, ImplementedClass.serializer()) + } + + val sealedClass: SealedClass = SealedClass.Test("value") + val abstractClass: AbstractClass = ImplementedClass("value", true) + val nestedClass = NestedClass(sealedClass, abstractClass, listOf(sealedClass), listOf(abstractClass), mapOf(sealedClass to sealedClass), mapOf(abstractClass to abstractClass)) + val encoded = encode(NestedClass.serializer(), nestedClass) { + shouldEncodeElementDefault = true + serializersModule = module + } + + val reencoded = reencodeTransformation(NestedClass.serializer(), encoded, builder = { + shouldEncodeElementDefault = true + serializersModule = module + }) { + assertEquals(nestedClass, it) + it.copy(sealed = SealedClass.Test("newValue")) + } + + val sealedEncoded = nativeMapOf("type" to "test", "value" to "value") + val abstractEncoded = nativeMapOf("type" to "implemented", "value" to "value", "otherValue" to true) + nativeAssertEquals( + nativeMapOf( + "sealed" to nativeMapOf("type" to "test", "value" to "newValue"), + "abstract" to abstractEncoded, + "sealedList" to nativeListOf(sealedEncoded), + "abstractList" to nativeListOf(abstractEncoded), + "sealedMap" to nativeMapOf(sealedEncoded to sealedEncoded), + "abstractMap" to nativeMapOf(abstractEncoded to abstractEncoded) + ), + reencoded + ) + } } diff --git a/firebase-database/src/androidMain/kotlin/dev/gitlive/firebase/database/database.kt b/firebase-database/src/androidMain/kotlin/dev/gitlive/firebase/database/database.kt index f6e13b372..55f440699 100644 --- a/firebase-database/src/androidMain/kotlin/dev/gitlive/firebase/database/database.kt +++ b/firebase-database/src/androidMain/kotlin/dev/gitlive/firebase/database/database.kt @@ -5,18 +5,36 @@ package dev.gitlive.firebase.database import com.google.android.gms.tasks.Task -import com.google.firebase.database.* -import dev.gitlive.firebase.* +import com.google.firebase.database.ChildEventListener +import com.google.firebase.database.DatabaseError +import com.google.firebase.database.Logger +import com.google.firebase.database.MutableData +import com.google.firebase.database.Transaction +import com.google.firebase.database.ValueEventListener +import dev.gitlive.firebase.DecodeSettings +import dev.gitlive.firebase.EncodeDecodeSettingsBuilder +import dev.gitlive.firebase.Firebase +import dev.gitlive.firebase.FirebaseApp import dev.gitlive.firebase.database.ChildEvent.Type import dev.gitlive.firebase.database.FirebaseDatabase.Companion.FirebaseDatabase +import dev.gitlive.firebase.decode +import dev.gitlive.firebase.reencodeTransformation import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.channels.trySendBlocking -import kotlinx.coroutines.flow.* +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.callbackFlow +import kotlinx.coroutines.flow.debounce +import kotlinx.coroutines.flow.filterNot +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.merge import kotlinx.coroutines.tasks.await import kotlinx.serialization.DeserializationStrategy +import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.KSerializer -import java.util.* +import java.util.WeakHashMap import kotlin.time.Duration.Companion.seconds suspend fun Task.awaitWhileOnline(database: FirebaseDatabase): T = @@ -118,18 +136,18 @@ actual open class Query internal actual constructor( actual val valueEvents: Flow get() = callbackFlow { - val listener = object : ValueEventListener { - override fun onDataChange(snapshot: com.google.firebase.database.DataSnapshot) { - trySendBlocking(DataSnapshot(snapshot, persistenceEnabled)) - } + val listener = object : ValueEventListener { + override fun onDataChange(snapshot: com.google.firebase.database.DataSnapshot) { + trySendBlocking(DataSnapshot(snapshot, persistenceEnabled)) + } - override fun onCancelled(error: com.google.firebase.database.DatabaseError) { - close(error.toException()) + override fun onCancelled(error: com.google.firebase.database.DatabaseError) { + close(error.toException()) + } } + android.addValueEventListener(listener) + awaitClose { android.removeEventListener(listener) } } - android.addValueEventListener(listener) - awaitClose { android.removeEventListener(listener) } - } actual fun childEvents(vararg types: Type): Flow = callbackFlow { val listener = object : ChildEventListener { @@ -192,12 +210,22 @@ actual class DatabaseReference internal constructor( .run { if(persistenceEnabled) await() else awaitWhileOnline(database) } .run { Unit } + @OptIn(ExperimentalSerializationApi::class) actual suspend fun runTransaction(strategy: KSerializer, buildSettings: EncodeDecodeSettingsBuilder.() -> Unit, transactionUpdate: (currentData: T) -> T): DataSnapshot { val deferred = CompletableDeferred() android.runTransaction(object : Transaction.Handler { override fun doTransaction(currentData: MutableData): Transaction.Result { - currentData.value = reencodeTransformation(strategy, currentData.value, buildSettings, transactionUpdate) + val valueToReencode = currentData.value + // Value may be null initially, so only reencode if this is allowed + if (strategy.descriptor.isNullable || valueToReencode != null) { + currentData.value = reencodeTransformation( + strategy, + valueToReencode, + buildSettings, + transactionUpdate + ) + } return Transaction.success(currentData) } @@ -257,8 +285,8 @@ actual class OnDisconnect internal constructor( .run { Unit } override suspend fun setValue(encodedValue: Any?) = android.setValue(encodedValue) - .run { if(persistenceEnabled) await() else awaitWhileOnline(database) } - .run { Unit } + .run { if(persistenceEnabled) await() else awaitWhileOnline(database) } + .run { Unit } override suspend fun updateEncodedChildren(encodedUpdate: Map) = android.updateChildren(encodedUpdate) diff --git a/firebase-database/src/commonMain/kotlin/dev/gitlive/firebase/database/database.kt b/firebase-database/src/commonMain/kotlin/dev/gitlive/firebase/database/database.kt index 75b8ada24..27fa9feba 100644 --- a/firebase-database/src/commonMain/kotlin/dev/gitlive/firebase/database/database.kt +++ b/firebase-database/src/commonMain/kotlin/dev/gitlive/firebase/database/database.kt @@ -9,7 +9,10 @@ import dev.gitlive.firebase.EncodeDecodeSettingsBuilder import dev.gitlive.firebase.EncodeSettings import dev.gitlive.firebase.Firebase import dev.gitlive.firebase.FirebaseApp -import dev.gitlive.firebase.database.ChildEvent.Type.* +import dev.gitlive.firebase.database.ChildEvent.Type.ADDED +import dev.gitlive.firebase.database.ChildEvent.Type.CHANGED +import dev.gitlive.firebase.database.ChildEvent.Type.MOVED +import dev.gitlive.firebase.database.ChildEvent.Type.REMOVED import dev.gitlive.firebase.encode import kotlinx.coroutines.flow.Flow import kotlinx.serialization.DeserializationStrategy diff --git a/firebase-database/src/commonTest/kotlin/dev/gitlive/firebase/database/database.kt b/firebase-database/src/commonTest/kotlin/dev/gitlive/firebase/database/database.kt index 29ee7e35b..ba3f7be59 100644 --- a/firebase-database/src/commonTest/kotlin/dev/gitlive/firebase/database/database.kt +++ b/firebase-database/src/commonTest/kotlin/dev/gitlive/firebase/database/database.kt @@ -1,13 +1,22 @@ package dev.gitlive.firebase.database -import dev.gitlive.firebase.* +import dev.gitlive.firebase.Firebase +import dev.gitlive.firebase.FirebaseOptions +import dev.gitlive.firebase.apps +import dev.gitlive.firebase.initialize +import dev.gitlive.firebase.runBlockingTest +import dev.gitlive.firebase.runTest import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.first import kotlinx.coroutines.withContext import kotlinx.coroutines.withTimeout import kotlinx.serialization.Serializable import kotlinx.serialization.SerializationStrategy -import kotlin.test.* +import kotlin.test.AfterTest +import kotlin.test.BeforeTest +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertTrue import kotlin.time.Duration.Companion.minutes expect val emulatorHost: String @@ -92,7 +101,7 @@ class FirebaseDatabaseTest { assertEquals(data.likes, userDocBefore.likes) // Run transaction - val transactionSnapshot = userRef.runTransaction(DatabaseTest.serializer()) { DatabaseTest(data.title, it.likes + 1) } + val transactionSnapshot = userRef.runTransaction(DatabaseTest.serializer()) { it.copy(likes = it.likes + 1) } val userDocAfter = transactionSnapshot.value(DatabaseTest.serializer()) // Check the database after transaction @@ -113,7 +122,7 @@ class FirebaseDatabaseTest { assertEquals(data.likes, userDocBefore.likes) // Run transaction - val transactionSnapshot = userRef.runTransaction(DatabaseTest.serializer()) { DatabaseTest(data.title, it.likes - 1) } + val transactionSnapshot = userRef.runTransaction(DatabaseTest.serializer()) { it.copy(likes = it.likes - 1) } val userDocAfter = transactionSnapshot.value(DatabaseTest.serializer()) // Check the database after transaction diff --git a/firebase-database/src/iosMain/kotlin/dev/gitlive/firebase/database/database.kt b/firebase-database/src/iosMain/kotlin/dev/gitlive/firebase/database/database.kt index a264705f8..b6451234e 100644 --- a/firebase-database/src/iosMain/kotlin/dev/gitlive/firebase/database/database.kt +++ b/firebase-database/src/iosMain/kotlin/dev/gitlive/firebase/database/database.kt @@ -4,11 +4,27 @@ package dev.gitlive.firebase.database -import cocoapods.FirebaseDatabase.* -import cocoapods.FirebaseDatabase.FIRDataEventType.* -import dev.gitlive.firebase.* +import cocoapods.FirebaseDatabase.FIRDataEventType.FIRDataEventTypeChildAdded +import cocoapods.FirebaseDatabase.FIRDataEventType.FIRDataEventTypeChildChanged +import cocoapods.FirebaseDatabase.FIRDataEventType.FIRDataEventTypeChildMoved +import cocoapods.FirebaseDatabase.FIRDataEventType.FIRDataEventTypeChildRemoved +import cocoapods.FirebaseDatabase.FIRDataEventType.FIRDataEventTypeValue +import cocoapods.FirebaseDatabase.FIRDataSnapshot +import cocoapods.FirebaseDatabase.FIRDatabase +import cocoapods.FirebaseDatabase.FIRDatabaseQuery +import cocoapods.FirebaseDatabase.FIRDatabaseReference +import cocoapods.FirebaseDatabase.FIRTransactionResult +import dev.gitlive.firebase.DecodeSettings +import dev.gitlive.firebase.EncodeDecodeSettingsBuilder +import dev.gitlive.firebase.Firebase +import dev.gitlive.firebase.FirebaseApp import dev.gitlive.firebase.database.ChildEvent.Type -import dev.gitlive.firebase.database.ChildEvent.Type.* +import dev.gitlive.firebase.database.ChildEvent.Type.ADDED +import dev.gitlive.firebase.database.ChildEvent.Type.CHANGED +import dev.gitlive.firebase.database.ChildEvent.Type.MOVED +import dev.gitlive.firebase.database.ChildEvent.Type.REMOVED +import dev.gitlive.firebase.decode +import dev.gitlive.firebase.reencodeTransformation import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.channels.awaitClose @@ -19,11 +35,8 @@ import kotlinx.coroutines.flow.produceIn import kotlinx.coroutines.selects.select import kotlinx.serialization.DeserializationStrategy import kotlinx.serialization.KSerializer -import kotlinx.serialization.SerializationStrategy import platform.Foundation.NSError import platform.Foundation.allObjects -import kotlin.collections.component1 -import kotlin.collections.component2 actual val Firebase.database by lazy { FirebaseDatabase(FIRDatabase.database()) } diff --git a/firebase-database/src/jsMain/kotlin/dev/gitlive/firebase/database/database.kt b/firebase-database/src/jsMain/kotlin/dev/gitlive/firebase/database/database.kt index fbc6c078c..218dd2958 100644 --- a/firebase-database/src/jsMain/kotlin/dev/gitlive/firebase/database/database.kt +++ b/firebase-database/src/jsMain/kotlin/dev/gitlive/firebase/database/database.kt @@ -4,11 +4,34 @@ package dev.gitlive.firebase.database -import dev.gitlive.firebase.* +import dev.gitlive.firebase.DecodeSettings +import dev.gitlive.firebase.EncodeDecodeSettingsBuilder +import dev.gitlive.firebase.Firebase import dev.gitlive.firebase.FirebaseApp -import dev.gitlive.firebase.database.externals.* -import kotlinx.coroutines.* +import dev.gitlive.firebase.database.externals.CancelCallback +import dev.gitlive.firebase.database.externals.ChangeSnapshotCallback +import dev.gitlive.firebase.database.externals.Database +import dev.gitlive.firebase.database.externals.child +import dev.gitlive.firebase.database.externals.connectDatabaseEmulator +import dev.gitlive.firebase.database.externals.enableLogging +import dev.gitlive.firebase.database.externals.getDatabase +import dev.gitlive.firebase.database.externals.onChildAdded +import dev.gitlive.firebase.database.externals.onChildChanged +import dev.gitlive.firebase.database.externals.onChildMoved +import dev.gitlive.firebase.database.externals.onChildRemoved +import dev.gitlive.firebase.database.externals.onDisconnect +import dev.gitlive.firebase.database.externals.onValue +import dev.gitlive.firebase.database.externals.push +import dev.gitlive.firebase.database.externals.query +import dev.gitlive.firebase.database.externals.ref +import dev.gitlive.firebase.database.externals.remove +import dev.gitlive.firebase.database.externals.set +import dev.gitlive.firebase.database.externals.update +import dev.gitlive.firebase.decode +import dev.gitlive.firebase.reencodeTransformation +import kotlinx.coroutines.asDeferred import kotlinx.coroutines.channels.awaitClose +import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.produceIn @@ -87,7 +110,7 @@ actual open class Query internal actual constructor( val callback: ChangeSnapshotCallback = { snapshot, previousChildName -> trySend( ChildEvent( - DataSnapshot(snapshot, database), + DataSnapshot(snapshot, database), type, previousChildName ) diff --git a/firebase-firestore/src/androidMain/kotlin/dev/gitlive/firebase/firestore/firestore.kt b/firebase-firestore/src/androidMain/kotlin/dev/gitlive/firebase/firestore/firestore.kt index 060f81f42..3a1a57119 100644 --- a/firebase-firestore/src/androidMain/kotlin/dev/gitlive/firebase/firestore/firestore.kt +++ b/firebase-firestore/src/androidMain/kotlin/dev/gitlive/firebase/firestore/firestore.kt @@ -5,24 +5,18 @@ @file:JvmName("android") package dev.gitlive.firebase.firestore -import com.google.android.gms.tasks.Task -import com.google.firebase.firestore.* -import dev.gitlive.firebase.* -import kotlinx.coroutines.runBlocking -import kotlinx.coroutines.CompletableDeferred -import kotlinx.coroutines.Deferred +import com.google.firebase.firestore.MetadataChanges +import dev.gitlive.firebase.Firebase +import dev.gitlive.firebase.FirebaseApp import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.callbackFlow -import kotlinx.coroutines.tasks.asDeferred +import kotlinx.coroutines.runBlocking import kotlinx.coroutines.tasks.await -import kotlinx.serialization.DeserializationStrategy import kotlinx.serialization.Serializable -import kotlinx.serialization.SerializationStrategy - -import com.google.firebase.firestore.Query as AndroidQuery import com.google.firebase.firestore.FieldPath as AndroidFieldPath import com.google.firebase.firestore.Filter as AndroidFilter +import com.google.firebase.firestore.Query as AndroidQuery actual val Firebase.firestore get() = FirebaseFirestore(com.google.firebase.firestore.FirebaseFirestore.getInstance()) @@ -58,12 +52,12 @@ actual class FirebaseFirestore(val android: com.google.firebase.firestore.Fireba actual fun setSettings(persistenceEnabled: Boolean?, sslEnabled: Boolean?, host: String?, cacheSizeBytes: Long?) { android.firestoreSettings = com.google.firebase.firestore.FirebaseFirestoreSettings.Builder().also { builder -> - persistenceEnabled?.let { builder.setPersistenceEnabled(it) } - sslEnabled?.let { builder.isSslEnabled = it } - host?.let { builder.host = it } - cacheSizeBytes?.let { builder.cacheSizeBytes = it } - }.build() - } + persistenceEnabled?.let { builder.setPersistenceEnabled(it) } + sslEnabled?.let { builder.isSslEnabled = it } + host?.let { builder.host = it } + cacheSizeBytes?.let { builder.cacheSizeBytes = it } + }.build() + } actual suspend fun disableNetwork() = android.disableNetwork().await().run { } diff --git a/firebase-firestore/src/commonMain/kotlin/dev/gitlive/firebase/firestore/firestore.kt b/firebase-firestore/src/commonMain/kotlin/dev/gitlive/firebase/firestore/firestore.kt index 21cd30506..8b774c02e 100644 --- a/firebase-firestore/src/commonMain/kotlin/dev/gitlive/firebase/firestore/firestore.kt +++ b/firebase-firestore/src/commonMain/kotlin/dev/gitlive/firebase/firestore/firestore.kt @@ -5,7 +5,6 @@ package dev.gitlive.firebase.firestore import dev.gitlive.firebase.* -import kotlinx.coroutines.Deferred import kotlinx.coroutines.flow.Flow import kotlinx.serialization.DeserializationStrategy import kotlinx.serialization.Serializable diff --git a/firebase-firestore/src/jsMain/kotlin/dev/gitlive/firebase/firestore/firestore.kt b/firebase-firestore/src/jsMain/kotlin/dev/gitlive/firebase/firestore/firestore.kt index 5f87ced08..439ea9ae1 100644 --- a/firebase-firestore/src/jsMain/kotlin/dev/gitlive/firebase/firestore/firestore.kt +++ b/firebase-firestore/src/jsMain/kotlin/dev/gitlive/firebase/firestore/firestore.kt @@ -4,15 +4,37 @@ package dev.gitlive.firebase.firestore -import dev.gitlive.firebase.* -import dev.gitlive.firebase.firestore.externals.* -import kotlinx.coroutines.* +import dev.gitlive.firebase.Firebase +import dev.gitlive.firebase.FirebaseApp +import dev.gitlive.firebase.FirebaseException +import dev.gitlive.firebase.firestore.externals.Firestore +import dev.gitlive.firebase.firestore.externals.QueryConstraint +import dev.gitlive.firebase.firestore.externals.addDoc +import dev.gitlive.firebase.firestore.externals.and +import dev.gitlive.firebase.firestore.externals.clearIndexedDbPersistence +import dev.gitlive.firebase.firestore.externals.connectFirestoreEmulator +import dev.gitlive.firebase.firestore.externals.deleteDoc +import dev.gitlive.firebase.firestore.externals.doc +import dev.gitlive.firebase.firestore.externals.enableIndexedDbPersistence +import dev.gitlive.firebase.firestore.externals.getDoc +import dev.gitlive.firebase.firestore.externals.getDocs +import dev.gitlive.firebase.firestore.externals.getFirestore +import dev.gitlive.firebase.firestore.externals.initializeFirestore +import dev.gitlive.firebase.firestore.externals.onSnapshot +import dev.gitlive.firebase.firestore.externals.or +import dev.gitlive.firebase.firestore.externals.orderBy +import dev.gitlive.firebase.firestore.externals.query +import dev.gitlive.firebase.firestore.externals.refEqual +import dev.gitlive.firebase.firestore.externals.setDoc +import dev.gitlive.firebase.firestore.externals.setLogLevel +import dev.gitlive.firebase.firestore.externals.writeBatch +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.await import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.callbackFlow -import kotlinx.serialization.DeserializationStrategy +import kotlinx.coroutines.promise import kotlinx.serialization.Serializable -import kotlinx.serialization.SerializationStrategy import kotlin.js.Json import kotlin.js.json import dev.gitlive.firebase.firestore.externals.CollectionReference as JsCollectionReference @@ -490,7 +512,7 @@ fun errorToException(e: dynamic) = (e?.code ?: e?.message ?: "") FirebaseFirestoreException(e, FirestoreExceptionCode.UNKNOWN) } } -} + } // from: https://discuss.kotlinlang.org/t/how-to-access-native-js-object-as-a-map-string-any/509/8 fun entriesOf(jsObject: dynamic): List> =