1
1
package dev.teamhub.firebase.database
2
2
3
+ import com.google.android.gms.tasks.Task
3
4
import com.google.firebase.database.Logger
4
5
import com.google.firebase.database.ServerValue
5
6
import com.google.firebase.database.ValueEventListener
@@ -8,11 +9,31 @@ import dev.teamhub.firebase.FirebaseApp
8
9
import dev.teamhub.firebase.decode
9
10
import dev.teamhub.firebase.encode
10
11
import kotlinx.coroutines.channels.awaitClose
12
+ import kotlinx.coroutines.coroutineScope
11
13
import kotlinx.coroutines.flow.callbackFlow
14
+ import kotlinx.coroutines.flow.conflate
15
+ import kotlinx.coroutines.flow.filter
16
+ import kotlinx.coroutines.flow.produceIn
17
+ import kotlinx.coroutines.selects.select
18
+ import kotlinx.coroutines.tasks.asDeferred
12
19
import kotlinx.coroutines.tasks.await
13
20
import kotlinx.serialization.DeserializationStrategy
14
21
import kotlinx.serialization.SerializationStrategy
15
22
23
+ suspend fun <T > Task<T>.awaitWhileOnline (): T = coroutineScope {
24
+ val notConnected = Firebase .database
25
+ .reference(" .info/connected" )
26
+ .snapshots
27
+ .filter { ! it.value<Boolean >() }
28
+ .conflate()
29
+ .produceIn(this )
30
+
31
+ select<T > {
32
+ asDeferred().onAwait { it }
33
+ notConnected.onReceive { throw DatabaseException (" Database not connected" ) }
34
+ }
35
+ }
36
+
16
37
actual val Firebase .database
17
38
get() = FirebaseDatabase (com.google.firebase.database.FirebaseDatabase .getInstance())
18
39
@@ -26,18 +47,26 @@ actual fun Firebase.database(app: FirebaseApp, url: String) =
26
47
FirebaseDatabase (com.google.firebase.database.FirebaseDatabase .getInstance(app.android, url))
27
48
28
49
actual class FirebaseDatabase internal constructor(val android : com.google.firebase.database.FirebaseDatabase ) {
29
- actual fun reference (path : String ) = DatabaseReference (android.getReference(path))
30
50
31
- actual fun setPersistenceEnabled (enabled : Boolean ) = android.setPersistenceEnabled(enabled)
51
+ private var persistenceEnabled = true
52
+
53
+ actual fun reference (path : String ) =
54
+ DatabaseReference (android.getReference(path), persistenceEnabled)
55
+
56
+ actual fun setPersistenceEnabled (enabled : Boolean ) =
57
+ android.setPersistenceEnabled(enabled).also { persistenceEnabled = enabled }
32
58
33
59
actual fun setLoggingEnabled (enabled : Boolean ) =
34
60
android.setLogLevel(Logger .Level .DEBUG .takeIf { enabled } ? : Logger .Level .NONE )
35
61
}
36
62
37
- actual class DatabaseReference internal constructor(val android : com.google.firebase.database.DatabaseReference ) {
63
+ actual class DatabaseReference internal constructor(
64
+ val android : com.google.firebase.database.DatabaseReference ,
65
+ val persistenceEnabled : Boolean
66
+ ) {
38
67
39
- actual fun push () = DatabaseReference (android.push())
40
- actual fun onDisconnect () = OnDisconnect (android.onDisconnect())
68
+ actual fun push () = DatabaseReference (android.push(), persistenceEnabled )
69
+ actual fun onDisconnect () = OnDisconnect (android.onDisconnect(), persistenceEnabled )
41
70
42
71
actual val snapshots get() = callbackFlow {
43
72
val listener = object : ValueEventListener {
@@ -53,16 +82,23 @@ actual class DatabaseReference internal constructor(val android: com.google.fire
53
82
awaitClose { android.removeEventListener(listener) }
54
83
}
55
84
56
- actual suspend fun setValue (value : Any? ) =
57
- android.setValue(encode(value)).await().run { Unit }
85
+ actual suspend fun setValue (value : Any? ) = android.setValue(encode(value))
86
+ .run { if (persistenceEnabled) await() else awaitWhileOnline() }
87
+ .run { Unit }
58
88
59
89
actual suspend inline fun <reified T > setValue (strategy : SerializationStrategy <T >, value : T ) =
60
- android.setValue(encode(strategy, value)).await().run { Unit }
90
+ android.setValue(encode(strategy, value))
91
+ .run { if (persistenceEnabled) await() else awaitWhileOnline() }
92
+ .run { Unit }
61
93
62
94
actual suspend fun updateChildren (update : Map <String , Any ?>) =
63
- android.updateChildren(update.mapValues { (_, it) -> encode(value = it) }).await().run { Unit }
95
+ android.updateChildren(update.mapValues { (_, it) -> encode(value = it) })
96
+ .run { if (persistenceEnabled) await() else awaitWhileOnline() }
97
+ .run { Unit }
64
98
65
- actual suspend fun removeValue () = android.removeValue().await().run { Unit }
99
+ actual suspend fun removeValue () = android.removeValue()
100
+ .run { if (persistenceEnabled) await() else awaitWhileOnline() }
101
+ .run { Unit }
66
102
}
67
103
68
104
@Suppress(" UNCHECKED_CAST" )
@@ -80,19 +116,33 @@ actual class DataSnapshot internal constructor(val android: com.google.firebase.
80
116
actual val children: Iterable <DataSnapshot > get() = android.children.map { DataSnapshot (it) }
81
117
}
82
118
83
- actual class OnDisconnect internal constructor(val android : com.google.firebase.database.OnDisconnect ) {
119
+ actual class OnDisconnect internal constructor(
120
+ val android : com.google.firebase.database.OnDisconnect ,
121
+ val persistenceEnabled : Boolean
122
+ ) {
123
+
124
+ actual suspend fun removeValue () = android.removeValue()
125
+ .run { if (persistenceEnabled) await() else awaitWhileOnline() }
126
+ .run { Unit }
84
127
85
- actual suspend fun removeValue () = android.removeValue().await().run { Unit }
86
- actual suspend fun cancel () = android.cancel().await().run { Unit }
128
+ actual suspend fun cancel () = android.cancel()
129
+ .run { if (persistenceEnabled) await() else awaitWhileOnline() }
130
+ .run { Unit }
87
131
88
132
actual suspend inline fun <reified T : Any > setValue (value : T ) =
89
- android.setValue(encode(value = value)).await().run { Unit }
133
+ android.setValue(encode(value = value))
134
+ .run { if (persistenceEnabled) await() else awaitWhileOnline() }
135
+ .run { Unit }
90
136
91
137
actual suspend inline fun <reified T > setValue (strategy : SerializationStrategy <T >, value : T ) =
92
- android.setValue(encode(strategy, value)).await().run { Unit }
138
+ android.setValue(encode(strategy, value))
139
+ .run { if (persistenceEnabled) await() else awaitWhileOnline() }
140
+ .run { Unit }
93
141
94
142
actual suspend fun updateChildren (update : Map <String , Any ?>) =
95
- android.updateChildren(update.mapValues { (_, it) -> encode(value = it) }).await().run { Unit }
143
+ android.updateChildren(update.mapValues { (_, it) -> encode(value = it) })
144
+ .run { if (persistenceEnabled) await() else awaitWhileOnline() }
145
+ .run { Unit }
96
146
}
97
147
98
148
actual typealias DatabaseException = com.google.firebase.database.DatabaseException
0 commit comments