Skip to content

Commit 9b41a82

Browse files
committed
add childEvents
add orderByChild
1 parent d8ec120 commit 9b41a82

File tree

4 files changed

+114
-24
lines changed
  • firebase-common/src/jsMain/kotlin/dev/teamhub/firebase
  • firebase-database/src
    • androidMain/kotlin/dev/teamhub/firebase/database
    • commonMain/kotlin/dev/teamhub/firebase/database
    • jsMain/kotlin/dev/teamhub/firebase/database

4 files changed

+114
-24
lines changed

firebase-common/src/jsMain/kotlin/dev/teamhub/firebase/externals.kt

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ external object database
1515
@JsModule("firebase/firestore")
1616
external object firestore
1717

18+
typealias SnapshotCallback = (data: firebase.database.DataSnapshot, b: String?) -> Unit
19+
1820
@JsModule("firebase/app")
1921
external object firebase {
2022

@@ -99,15 +101,19 @@ external object firebase {
99101
}
100102
open class ThenableReference : Reference
101103

102-
open class Reference {
104+
105+
open class Query {
106+
fun on(eventType: String?, callback: SnapshotCallback, cancelCallbackOrContext: (error: Error) -> Unit? = definedExternally, context: Any? = definedExternally): SnapshotCallback
107+
fun off(eventType: String?, callback: SnapshotCallback?, context: Any? = definedExternally)
108+
fun once(eventType: String, callback: SnapshotCallback, failureCallbackOrContext: (error: Error) -> Unit? = definedExternally, context: Any? = definedExternally): SnapshotCallback
109+
fun orderByChild(path: String): Query
110+
}
111+
112+
open class Reference: Query {
103113
fun remove(): Promise<Unit>
104114
fun onDisconnect(): OnDisconnect
105-
106115
fun update(value: Any?): Promise<Unit>
107116
fun set(value: Any?): Promise<Unit>
108-
fun on(eventType: String?, callback: (data: DataSnapshot) -> Unit, cancelCallbackOrContext: (error: Error) -> Unit? = definedExternally, context: Any? = definedExternally): (DataSnapshot) -> Unit
109-
fun off(eventType: String?, callback: (data: DataSnapshot) -> Unit, context: Any? = definedExternally)
110-
fun once(eventType: String, callback: (data: DataSnapshot) -> Unit, failureCallbackOrContext: (error: Error) -> Unit? = definedExternally, context: Any? = definedExternally): (DataSnapshot)->Unit
111117
fun push(): ThenableReference
112118
}
113119
open class DataSnapshot {

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

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package dev.teamhub.firebase.database
22

33
import com.google.android.gms.tasks.Task
4+
import com.google.firebase.database.ChildEventListener
45
import com.google.firebase.database.Logger
56
import com.google.firebase.database.ServerValue
67
import com.google.firebase.database.ValueEventListener
78
import dev.teamhub.firebase.Firebase
89
import dev.teamhub.firebase.FirebaseApp
10+
import dev.teamhub.firebase.database.ChildEvent.Type
911
import dev.teamhub.firebase.decode
1012
import dev.teamhub.firebase.encode
1113
import kotlinx.coroutines.channels.awaitClose
@@ -23,7 +25,7 @@ suspend fun <T> Task<T>.awaitWhileOnline(): T = coroutineScope {
2325

2426
val notConnected = Firebase.database
2527
.reference(".info/connected")
26-
.snapshots
28+
.valueEvents
2729
.filter { !it.value<Boolean>() }
2830
.produceIn(this)
2931

@@ -59,15 +61,13 @@ actual class FirebaseDatabase internal constructor(val android: com.google.fireb
5961
android.setLogLevel(Logger.Level.DEBUG.takeIf { enabled } ?: Logger.Level.NONE)
6062
}
6163

62-
actual class DatabaseReference internal constructor(
63-
val android: com.google.firebase.database.DatabaseReference,
64+
actual open class Query internal constructor(
65+
open val android: com.google.firebase.database.Query,
6466
val persistenceEnabled: Boolean
6567
) {
68+
actual fun orderByChild(path: String) = android.orderByChild(path).let { this }
6669

67-
actual fun push() = DatabaseReference(android.push(), persistenceEnabled)
68-
actual fun onDisconnect() = OnDisconnect(android.onDisconnect(), persistenceEnabled)
69-
70-
actual val snapshots get() = callbackFlow {
70+
actual val valueEvents get() = callbackFlow {
7171
val listener = object : ValueEventListener {
7272
override fun onDataChange(snapshot: com.google.firebase.database.DataSnapshot) {
7373
offer(DataSnapshot(snapshot))
@@ -81,6 +81,46 @@ actual class DatabaseReference internal constructor(
8181
awaitClose { android.removeEventListener(listener) }
8282
}
8383

84+
actual fun childEvents(vararg types: Type) = callbackFlow {
85+
val listener = object : ChildEventListener {
86+
87+
val moved by lazy { types.contains(Type.MOVED) }
88+
override fun onChildMoved(snapshot: com.google.firebase.database.DataSnapshot, previousChildName: String?) {
89+
if(moved) offer(ChildEvent(Type.MOVED, DataSnapshot(snapshot), previousChildName))
90+
}
91+
92+
val changed by lazy { types.contains(Type.CHANGED) }
93+
override fun onChildChanged(snapshot: com.google.firebase.database.DataSnapshot, previousChildName: String?) {
94+
if(changed) offer(ChildEvent(Type.CHANGED, DataSnapshot(snapshot), previousChildName))
95+
}
96+
97+
val added by lazy { types.contains(Type.ADDED) }
98+
override fun onChildAdded(snapshot: com.google.firebase.database.DataSnapshot, previousChildName: String?) {
99+
if(added) offer(ChildEvent(Type.ADDED, DataSnapshot(snapshot), previousChildName))
100+
}
101+
102+
val removed by lazy { types.contains(Type.REMOVED) }
103+
override fun onChildRemoved(snapshot: com.google.firebase.database.DataSnapshot) {
104+
if(removed) offer(ChildEvent(Type.REMOVED, DataSnapshot(snapshot), null))
105+
}
106+
107+
override fun onCancelled(error: com.google.firebase.database.DatabaseError) {
108+
close(error.toException())
109+
}
110+
}
111+
android.addChildEventListener(listener)
112+
awaitClose { android.removeEventListener(listener) }
113+
}
114+
}
115+
116+
actual class DatabaseReference internal constructor(
117+
override val android: com.google.firebase.database.DatabaseReference,
118+
persistenceEnabled: Boolean
119+
): Query(android, persistenceEnabled) {
120+
121+
actual fun push() = DatabaseReference(android.push(), persistenceEnabled)
122+
actual fun onDisconnect() = OnDisconnect(android.onDisconnect(), persistenceEnabled)
123+
84124
actual suspend fun setValue(value: Any?) = android.setValue(encode(value))
85125
.run { if(persistenceEnabled) await() else awaitWhileOnline() }
86126
.run { Unit }

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

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package dev.teamhub.firebase.database
22

33
import dev.teamhub.firebase.Firebase
44
import dev.teamhub.firebase.FirebaseApp
5+
import dev.teamhub.firebase.database.ChildEvent.Type.*
56
import kotlinx.coroutines.flow.Flow
67
import kotlinx.serialization.DeserializationStrategy
78
import kotlinx.serialization.ImplicitReflectionSerializer
@@ -25,10 +26,24 @@ expect class FirebaseDatabase {
2526
fun setLoggingEnabled(enabled: Boolean)
2627
}
2728

28-
expect class DatabaseReference {
29+
data class ChildEvent internal constructor(val type: Type, val snapshot: DataSnapshot, val previousChildName: String?) {
30+
enum class Type {
31+
ADDED,
32+
CHANGED,
33+
MOVED,
34+
REMOVED
35+
}
36+
}
37+
38+
expect open class Query {
39+
val valueEvents: Flow<DataSnapshot>
40+
fun childEvents(vararg types: ChildEvent.Type = arrayOf(ADDED, CHANGED, MOVED, REMOVED)): Flow<ChildEvent>
41+
fun orderByChild(path: String): Query
42+
}
43+
44+
expect class DatabaseReference : Query {
2945
fun push(): DatabaseReference
3046
fun onDisconnect(): OnDisconnect
31-
val snapshots: Flow<DataSnapshot>
3247
@ImplicitReflectionSerializer
3348
suspend fun setValue(value: Any?)
3449
suspend inline fun <reified T> setValue(strategy: SerializationStrategy<T>, value: T)

firebase-database/src/jsMain/kotlin/dev/teamhub/firebase/database/database.kt

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,46 @@ actual class FirebaseDatabase internal constructor(val js: firebase.database.Dat
2525
actual fun setLoggingEnabled(enabled: Boolean) = rethrow { firebase.database.enableLogging(enabled) }
2626
}
2727

28+
actual open class Query internal constructor(open val js: firebase.database.Query) {
2829

29-
actual class DatabaseReference internal constructor(val js: firebase.database.Reference) {
30+
actual fun orderByChild(path: String) = js.orderByChild(path).let { this }
31+
32+
actual val valueEvents get() = callbackFlow {
33+
val listener = rethrow {
34+
js.on(
35+
"value",
36+
{ it, _ -> offer(DataSnapshot(it)) },
37+
{ close(DatabaseException(it)).run { Unit } }
38+
)
39+
}
40+
awaitClose { rethrow { js.off("value", listener) } }
41+
}
42+
43+
actual fun childEvents(vararg types: ChildEvent.Type) = callbackFlow {
44+
val listeners = rethrow {
45+
types.map { type ->
46+
"child_${type.name.toLowerCase()}".let { eventType ->
47+
eventType to js.on(
48+
eventType,
49+
{ snapshot, previousChildName ->
50+
offer(
51+
ChildEvent(
52+
type,
53+
DataSnapshot(snapshot),
54+
previousChildName
55+
)
56+
)
57+
},
58+
{ close(DatabaseException(it)).run { Unit } }
59+
)
60+
}
61+
}
62+
}
63+
awaitClose { rethrow { listeners.forEach { (eventType, listener) -> js.off(eventType, listener) } } }
64+
}
65+
}
66+
67+
actual class DatabaseReference internal constructor(override val js: firebase.database.Reference): Query(js) {
3068

3169
actual fun push() = rethrow { DatabaseReference(js.push()) }
3270
actual fun onDisconnect() = rethrow { OnDisconnect(js.onDisconnect()) }
@@ -42,15 +80,6 @@ actual class DatabaseReference internal constructor(val js: firebase.database.Re
4280

4381
actual suspend inline fun <reified T> setValue(strategy: SerializationStrategy<T>, value: T) =
4482
rethrow { js.set(encode(strategy, value)).await() }
45-
46-
actual val snapshots get() = callbackFlow {
47-
val listener = js.on(
48-
"value",
49-
{ offer(DataSnapshot(it)) },
50-
{ close(DatabaseException(it)).run { Unit } }
51-
)
52-
awaitClose { js.off("value", listener) }
53-
}
5483
}
5584

5685
actual class DataSnapshot internal constructor(val js: firebase.database.DataSnapshot) {

0 commit comments

Comments
 (0)