Skip to content

Commit 844f0b4

Browse files
committed
Merge remote-tracking branch 'GitLiveApp/master' into feature/firestore-settings
2 parents a535e95 + ad577b3 commit 844f0b4

File tree

6 files changed

+177
-13
lines changed

6 files changed

+177
-13
lines changed

firebase-firestore/src/androidMain/kotlin/dev/gitlive/firebase/firestore/firestore.kt

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import com.google.firebase.firestore.PersistentCacheSettings
1414
import dev.gitlive.firebase.Firebase
1515
import dev.gitlive.firebase.FirebaseApp
1616
import kotlinx.coroutines.channels.ProducerScope
17+
import dev.gitlive.firebase.firestore.Source.*
1718
import kotlinx.coroutines.channels.awaitClose
1819
import kotlinx.coroutines.flow.Flow
1920
import kotlinx.coroutines.flow.callbackFlow
@@ -277,8 +278,8 @@ internal actual class NativeDocumentReference actual constructor(actual val nati
277278

278279
actual fun collection(collectionPath: String) = NativeCollectionReference(android.collection(collectionPath))
279280

280-
actual suspend fun get() =
281-
NativeDocumentSnapshot(android.get().await())
281+
actual suspend fun get(source: Source) =
282+
NativeDocumentSnapshot(android.get(source.toAndroidSource()).await())
282283

283284
actual suspend fun setEncoded(encodedData: Any, setOptions: SetOptions) {
284285
val task = (setOptions.android?.let {
@@ -344,7 +345,7 @@ actual open class Query internal actual constructor(nativeQuery: NativeQuery) {
344345

345346
open val android = nativeQuery.android
346347

347-
actual suspend fun get() = QuerySnapshot(android.get().await())
348+
actual suspend fun get(source: Source) = QuerySnapshot(android.get(source.toAndroidSource()).await())
348349

349350
actual fun limit(limit: Number) = Query(NativeQuery(android.limit(limit.toLong())))
350351

@@ -547,3 +548,11 @@ actual class FieldPath private constructor(val android: com.google.firebase.fire
547548
}
548549

549550
actual typealias EncodedFieldPath = com.google.firebase.firestore.FieldPath
551+
552+
internal typealias NativeSource = com.google.firebase.firestore.Source
553+
554+
private fun Source.toAndroidSource() = when(this) {
555+
CACHE -> NativeSource.CACHE
556+
SERVER -> NativeSource.SERVER
557+
DEFAULT -> NativeSource.DEFAULT
558+
}

firebase-firestore/src/commonMain/kotlin/dev/gitlive/firebase/firestore/firestore.kt

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ expect open class Query internal constructor(nativeQuery: NativeQuery) {
208208
fun limit(limit: Number): Query
209209
val snapshots: Flow<QuerySnapshot>
210210
fun snapshots(includeMetadataChanges: Boolean = false): Flow<QuerySnapshot>
211-
suspend fun get(): QuerySnapshot
211+
suspend fun get(source: Source = Source.DEFAULT): QuerySnapshot
212212

213213
internal fun where(filter: Filter): Query
214214

@@ -404,7 +404,7 @@ internal expect class NativeDocumentReference(nativeValue: NativeDocumentReferen
404404
fun snapshots(includeMetadataChanges: Boolean = false): Flow<NativeDocumentSnapshot>
405405

406406
fun collection(collectionPath: String): NativeCollectionReference
407-
suspend fun get(): NativeDocumentSnapshot
407+
suspend fun get(source: Source = Source.DEFAULT): NativeDocumentSnapshot
408408
suspend fun setEncoded(encodedData: Any, setOptions: SetOptions)
409409
suspend fun updateEncoded(encodedData: Any)
410410
suspend fun updateEncodedFieldsAndValues(encodedFieldsAndValues: List<Pair<String, Any?>>)
@@ -425,7 +425,7 @@ data class DocumentReference internal constructor(@PublishedApi internal val nat
425425
fun snapshots(includeMetadataChanges: Boolean = false): Flow<DocumentSnapshot> = native.snapshots(includeMetadataChanges).map(::DocumentSnapshot)
426426

427427
fun collection(collectionPath: String): CollectionReference = CollectionReference(native.collection(collectionPath))
428-
suspend fun get(): DocumentSnapshot = DocumentSnapshot(native.get())
428+
suspend fun get(source: Source = Source.DEFAULT): DocumentSnapshot = DocumentSnapshot(native.get(source))
429429

430430
@Deprecated("Deprecated. Use builder instead", replaceWith = ReplaceWith("set(data, merge) { this.encodeDefaults = encodeDefaults }"))
431431
suspend inline fun <reified T> set(data: T, encodeDefaults: Boolean, merge: Boolean = false) = set(data, merge) {
@@ -630,3 +630,9 @@ expect class FieldPath(vararg fieldNames: String) {
630630
}
631631

632632
expect class EncodedFieldPath
633+
634+
enum class Source {
635+
CACHE,
636+
SERVER,
637+
DEFAULT
638+
}
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
package dev.gitlive.firebase.firestore
2+
3+
import dev.gitlive.firebase.*
4+
import kotlin.test.*
5+
6+
/**
7+
* These tests are separated from other tests because
8+
* testing Firestore Source requires toggling persistence settings per test.
9+
*/
10+
class FirestoreSourceTest {
11+
lateinit var firestore: FirebaseFirestore
12+
13+
companion object {
14+
val testDoc = FirebaseFirestoreTest.FirestoreTest(
15+
"aaa",
16+
0.0,
17+
1,
18+
listOf("a", "aa", "aaa"),
19+
"notNull",
20+
)
21+
}
22+
23+
private suspend fun setDoc() {
24+
firestore.collection("testFirestoreQuerying").document("one").set(testDoc)
25+
}
26+
27+
private fun initializeFirebase(persistenceEnabled: Boolean = false) {
28+
val app = Firebase.apps(context).firstOrNull() ?: Firebase.initialize(
29+
context,
30+
FirebaseOptions(
31+
applicationId = "1:846484016111:ios:dd1f6688bad7af768c841a",
32+
apiKey = "AIzaSyCK87dcMFhzCz_kJVs2cT2AVlqOTLuyWV0",
33+
databaseUrl = "https://fir-kotlin-sdk.firebaseio.com",
34+
storageBucket = "fir-kotlin-sdk.appspot.com",
35+
projectId = "fir-kotlin-sdk",
36+
gcmSenderId = "846484016111"
37+
)
38+
)
39+
40+
firestore = Firebase.firestore(app).apply {
41+
useEmulator(emulatorHost, 8080)
42+
setSettings(persistenceEnabled = persistenceEnabled)
43+
}
44+
}
45+
46+
@AfterTest
47+
fun deinitializeFirebase() = runBlockingTest {
48+
Firebase.apps(context).forEach {
49+
it.delete()
50+
}
51+
}
52+
53+
@Test
54+
fun testGetFromServer_withPersistence() = runTest {
55+
initializeFirebase(persistenceEnabled = true)
56+
setDoc()
57+
val doc = firestore.collection("testFirestoreQuerying").document("one").get(Source.SERVER)
58+
assertTrue(doc.exists)
59+
assertFalse(doc.native.metadata.isFromCache)
60+
}
61+
62+
@Test
63+
fun testGetFromServer_withoutPersistence() = runTest {
64+
initializeFirebase(persistenceEnabled = false)
65+
setDoc()
66+
val doc = firestore.collection("testFirestoreQuerying").document("one").get(Source.SERVER)
67+
assertTrue(doc.exists)
68+
assertFalse(doc.native.metadata.isFromCache)
69+
}
70+
71+
@Test
72+
fun testGetFromCache() = runTest {
73+
initializeFirebase(persistenceEnabled = true)
74+
75+
// Warm up cache by setting a document
76+
setDoc()
77+
78+
val cachedDoc = firestore.collection("testFirestoreQuerying").document("one").get(Source.CACHE)
79+
assertTrue(cachedDoc.exists)
80+
assertTrue(cachedDoc.native.metadata.isFromCache)
81+
}
82+
83+
@Test
84+
fun testGetFromCache_withoutPersistence() = runTest {
85+
initializeFirebase(persistenceEnabled = false)
86+
setDoc()
87+
assertFailsWith(FirebaseFirestoreException::class) {
88+
firestore.collection("testFirestoreQuerying").document("one").get(Source.CACHE)
89+
}
90+
}
91+
92+
@Test
93+
fun testGetDefault_withPersistence() = runTest {
94+
initializeFirebase(persistenceEnabled = false)
95+
val doc = firestore.collection("testFirestoreQuerying").document("one").get(Source.DEFAULT)
96+
assertTrue(doc.exists)
97+
assertFalse(doc.native.metadata.isFromCache)
98+
}
99+
@Test
100+
fun testGet() = runTest {
101+
initializeFirebase(persistenceEnabled = false)
102+
val doc = firestore.collection("testFirestoreQuerying").document("one").get()
103+
assertTrue(doc.exists)
104+
assertFalse(doc.native.metadata.isFromCache)
105+
}
106+
107+
@Test
108+
fun testGetDefault_withoutPersistence() = runTest {
109+
initializeFirebase(persistenceEnabled = true)
110+
setDoc()
111+
val doc = firestore.collection("testFirestoreQuerying").document("one").get(Source.DEFAULT)
112+
assertTrue(doc.exists)
113+
// Firebase defaults to first fetching from server
114+
assertFalse(doc.native.metadata.isFromCache)
115+
}
116+
117+
}

firebase-firestore/src/iosMain/kotlin/dev/gitlive/firebase/firestore/firestore.kt

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -257,8 +257,8 @@ internal actual class NativeDocumentReference actual constructor(actual val nati
257257

258258
actual fun collection(collectionPath: String) = NativeCollectionReference(ios.collectionWithPath(collectionPath))
259259

260-
actual suspend fun get() =
261-
NativeDocumentSnapshot(awaitResult { ios.getDocumentWithCompletion(it) })
260+
actual suspend fun get(source: Source) =
261+
NativeDocumentSnapshot(awaitResult { ios.getDocumentWithSource(source.toIosSource(), it) })
262262

263263
actual suspend fun setEncoded(encodedData: Any, setOptions: SetOptions) = await {
264264
when (setOptions) {
@@ -307,7 +307,7 @@ actual open class Query internal actual constructor(nativeQuery: NativeQuery) {
307307

308308
open val ios: FIRQuery = nativeQuery.ios
309309

310-
actual suspend fun get() = QuerySnapshot(awaitResult { ios.getDocumentsWithCompletion(it) })
310+
actual suspend fun get(source: Source) = QuerySnapshot(awaitResult { ios.getDocumentsWithSource(source.toIosSource(),it) })
311311

312312
actual fun limit(limit: Number) = Query(ios.queryLimitedTo(limit.toLong()).native)
313313

@@ -557,3 +557,9 @@ suspend inline fun <T> await(function: (callback: (NSError?) -> Unit) -> T): T {
557557
job.await()
558558
return result
559559
}
560+
561+
private fun Source.toIosSource() = when (this) {
562+
Source.CACHE -> FIRFirestoreSource.FIRFirestoreSourceCache
563+
Source.SERVER -> FIRFirestoreSource.FIRFirestoreSourceServer
564+
Source.DEFAULT -> FIRFirestoreSource.FIRFirestoreSourceDefault
565+
}

firebase-firestore/src/jsMain/kotlin/dev/gitlive/firebase/firestore/externals/firestore.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,20 @@ external fun getDoc(
6868
options: Any? = definedExternally
6969
): Promise<DocumentSnapshot>
7070

71+
external fun getDocFromCache(
72+
reference: DocumentReference,
73+
): Promise<DocumentSnapshot>
74+
75+
external fun getDocFromServer(
76+
reference: DocumentReference,
77+
): Promise<DocumentSnapshot>
78+
7179
external fun getDocs(query: Query): Promise<QuerySnapshot>
7280

81+
external fun getDocsFromCache(query: Query): Promise<QuerySnapshot>
82+
83+
external fun getDocsFromServer(query: Query): Promise<QuerySnapshot>
84+
7385
external fun getFirestore(app: FirebaseApp? = definedExternally): Firestore
7486

7587
external fun increment(n: Int): FieldValue

firebase-firestore/src/jsMain/kotlin/dev/gitlive/firebase/firestore/firestore.kt

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import dev.gitlive.firebase.Firebase
88
import dev.gitlive.firebase.FirebaseApp
99
import dev.gitlive.firebase.FirebaseException
1010
import dev.gitlive.firebase.externals.getApp
11-
import dev.gitlive.firebase.firestore.externals.Firestore
1211
import dev.gitlive.firebase.firestore.externals.MemoryCacheSettings
1312
import dev.gitlive.firebase.firestore.externals.PersistentCacheSettings
1413
import dev.gitlive.firebase.firestore.externals.QueryConstraint
@@ -19,7 +18,11 @@ import dev.gitlive.firebase.firestore.externals.connectFirestoreEmulator
1918
import dev.gitlive.firebase.firestore.externals.deleteDoc
2019
import dev.gitlive.firebase.firestore.externals.doc
2120
import dev.gitlive.firebase.firestore.externals.getDoc
21+
import dev.gitlive.firebase.firestore.externals.getDocFromCache
22+
import dev.gitlive.firebase.firestore.externals.getDocFromServer
2223
import dev.gitlive.firebase.firestore.externals.getDocs
24+
import dev.gitlive.firebase.firestore.externals.getDocsFromCache
25+
import dev.gitlive.firebase.firestore.externals.getDocsFromServer
2326
import dev.gitlive.firebase.firestore.externals.initializeFirestore
2427
import dev.gitlive.firebase.firestore.externals.memoryEagerGarbageCollector
2528
import dev.gitlive.firebase.firestore.externals.memoryLocalCache
@@ -41,7 +44,6 @@ import kotlinx.coroutines.flow.callbackFlow
4144
import kotlinx.coroutines.promise
4245
import kotlin.js.Json
4346
import kotlin.js.json
44-
import kotlin.math.acos
4547
import dev.gitlive.firebase.externals.FirebaseApp as JsFirebaseApp
4648
import dev.gitlive.firebase.firestore.externals.Firestore as JsFirestore
4749
import dev.gitlive.firebase.firestore.externals.CollectionReference as JsCollectionReference
@@ -310,7 +312,7 @@ internal actual class NativeDocumentReference actual constructor(actual val nati
310312

311313
actual fun collection(collectionPath: String) = rethrow { NativeCollectionReference(jsCollection(js, collectionPath)) }
312314

313-
actual suspend fun get() = rethrow { NativeDocumentSnapshot( getDoc(js).await()) }
315+
actual suspend fun get(source: Source) = rethrow { NativeDocumentSnapshot( js.get(source).await()) }
314316

315317
actual val snapshots: Flow<NativeDocumentSnapshot> get() = snapshots()
316318

@@ -368,7 +370,7 @@ actual open class Query internal actual constructor(nativeQuery: NativeQuery) {
368370

369371
open val js: JsQuery = nativeQuery.js
370372

371-
actual suspend fun get() = rethrow { QuerySnapshot(getDocs(js).await()) }
373+
actual suspend fun get(source: Source) = rethrow { QuerySnapshot(js.get(source).await()) }
372374

373375
actual fun limit(limit: Number) = Query(query(js, jsLimit(limit)))
374376

@@ -635,3 +637,15 @@ fun entriesOf(jsObject: dynamic): List<Pair<String, Any?>> =
635637
// from: https://discuss.kotlinlang.org/t/how-to-access-native-js-object-as-a-map-string-any/509/8
636638
fun mapOf(jsObject: dynamic): Map<String, Any?> =
637639
entriesOf(jsObject).toMap()
640+
641+
private fun NativeDocumentReferenceType.get(source: Source) = when (source) {
642+
Source.DEFAULT -> getDoc(this)
643+
Source.CACHE -> getDocFromCache(this)
644+
Source.SERVER -> getDocFromServer(this)
645+
}
646+
647+
private fun JsQuery.get(source: Source) = when (source) {
648+
Source.DEFAULT -> getDocs(this)
649+
Source.CACHE -> getDocsFromCache(this)
650+
Source.SERVER -> getDocsFromServer(this)
651+
}

0 commit comments

Comments
 (0)