Skip to content
This repository was archived by the owner on Oct 27, 2019. It is now read-only.

Commit 95d2b72

Browse files
committed
Add functions to Query
* Add readValue to read single objects * Add readList to read complex types (e.g.: List)
1 parent 8e3aca5 commit 95d2b72

File tree

2 files changed

+52
-16
lines changed

2 files changed

+52
-16
lines changed

app/src/androidTest/java/kotlinx/coroutines/experimental/firebase/android/app/DatabaseReferenceIntegrationTest.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,19 @@ class DatabaseReferenceIntegrationTest : BaseIntegrationTest() {
2323

2424
val firstMessageNode = messagesNode.child("1")
2525
val secondMessageNode = messagesNode.child("2")
26+
val thirdMessageNode = messagesNode.child("3")
2627

2728
try {
2829
firstMessageNode.saveValue("Call Mary tomorrow morning")
2930
secondMessageNode.saveValue("See the new TV show season")
31+
thirdMessageNode.saveValue("Spread Kotlin word")
3032

3133
val first = firstMessageNode.readValue<String>()
3234
val second = secondMessageNode.readValue(String::class.java)
35+
val third = messagesNode.orderByValue().limitToFirst(1).readList<String>()
3336

37+
assertThat(third.size, `is`(equalTo(1)))
38+
assertThat(third[0], `is`(equalTo("Call Mary tomorrow morning")))
3439
assertThat(first, `is`(equalTo("Call Mary tomorrow morning")))
3540
assertThat(second, `is`(equalTo("See the new TV show season")))
3641
} catch (exception: FirebaseException) {

kotlinx-coroutines-firebase-android/src/main/java/kotlinx/coroutines/experimental/firebase/android/DatabaseReference.kt

Lines changed: 47 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import com.google.firebase.FirebaseException
44
import com.google.firebase.database.DataSnapshot
55
import com.google.firebase.database.DatabaseError
66
import com.google.firebase.database.DatabaseReference
7+
import com.google.firebase.database.GenericTypeIndicator
8+
import com.google.firebase.database.Query
79
import com.google.firebase.database.ValueEventListener
810
import kotlinx.coroutines.experimental.suspendCancellableCoroutine
911

@@ -106,21 +108,6 @@ suspend fun <T : Any> DatabaseReference.readValue(type: Class<T>): T = readRefer
106108
*/
107109
suspend inline fun <reified T : Any> DatabaseReference.readValue(): T = readValue(T::class.java)
108110

109-
/**
110-
* Coroutine to read a collection of values from Firebase Database
111-
*
112-
* This method is not intended to be used in the code. It's just a base function that contains the
113-
* main coroutine code that reads a collection of values from Firebase Database. To use it's
114-
* functionality call [kotlinx.coroutines.experimental.firebase.android.readValue] function.
115-
*
116-
* The implementation consists of a [suspendCancellableCoroutine] that encapsulates a
117-
* [ValueEventListener].
118-
*
119-
* @param reference The Firebase Database node to be read.
120-
* @param type Expected type wrapped in a Class instance.
121-
* @param T The type of the expected value from Firebase Database.
122-
* @return The persisted object of the type T informed.
123-
*/
124111
private suspend fun <T : Any> readReferences(
125112
reference: DatabaseReference,
126113
type: Class<T>
@@ -217,4 +204,48 @@ suspend inline fun <reified T : Any> DatabaseReference.readList(): List<T> = rea
217204
suspend fun <T : Any> DatabaseReference.saveValue(value: T): Unit =
218205
setValue(value).await().let { Unit }
219206

220-
suspend fun <T: Any> DatabaseReference.pushValue(value: T): Unit = push().saveValue(value)
207+
suspend fun <T : Any> DatabaseReference.pushValue(value: T): Unit = push().saveValue(value)
208+
209+
private suspend fun <T : Any> awaitQuerySingleValue(query: Query, type: Class<T>): T =
210+
suspendCancellableCoroutine { continuation ->
211+
val listener = object : ValueEventListener {
212+
override fun onDataChange(snapshot: DataSnapshot) = try {
213+
continuation.resume(snapshot.getValue(type)!!)
214+
} catch (exception: Exception) {
215+
continuation.resumeWithException(exception)
216+
}
217+
218+
override fun onCancelled(error: DatabaseError) =
219+
continuation.resumeWithException(error.toException())
220+
}
221+
222+
query.addListenerForSingleValueEvent(listener)
223+
continuation.invokeOnCompletion { query.removeEventListener(listener) }
224+
}
225+
226+
suspend fun <T : Any> Query.readValue(type: Class<T>): T = awaitQuerySingleValue(this, type)
227+
228+
suspend inline fun <reified T : Any> Query.readValue(): T = readValue(T::class.java)
229+
230+
private suspend fun <T : Any> awaitQueryListValue(query: Query, type: Class<T>): List<T> =
231+
suspendCancellableCoroutine { continuation ->
232+
val listener = object : ValueEventListener {
233+
override fun onDataChange(snapshot: DataSnapshot) = try {
234+
val data: List<T> = snapshot.children.toHashSet().map { it.getValue(type)!! }
235+
236+
continuation.resume(data)
237+
} catch (exception: Exception) {
238+
continuation.resumeWithException(exception)
239+
}
240+
241+
override fun onCancelled(error: DatabaseError) =
242+
continuation.resumeWithException(error.toException())
243+
}
244+
245+
query.addListenerForSingleValueEvent(listener)
246+
continuation.invokeOnCompletion { query.removeEventListener(listener) }
247+
}
248+
249+
suspend fun <T : Any> Query.readList(type: Class<T>): List<T> = awaitQueryListValue(this, type)
250+
251+
suspend inline fun <reified T : Any> Query.readList(): List<T> = readList(T::class.java)

0 commit comments

Comments
 (0)