Skip to content

Commit 9792b74

Browse files
leoxs22nbransby
andauthored
Support for documentId in FieldPath (Firestore) (#125)
* Support for documentId in FieldPath * make FieldPath a wrapper class instead of typealias * fix ios compile error * print caused by in JS tests stacktraces Co-authored-by: nbransby <nbransby@gmail.com>
1 parent c85cae2 commit 9792b74

File tree

9 files changed

+162
-92
lines changed
  • firebase-app/src/jsTest/kotlin/dev/gitlive/firebase
  • firebase-auth/src/jsTest/kotlin/dev/gitlive/firebase/auth
  • firebase-common/src/jsMain/kotlin/dev/gitlive/firebase
  • firebase-firestore/src

9 files changed

+162
-92
lines changed

firebase-app/src/jsTest/kotlin/dev/gitlive/firebase/firebase.kt

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,20 @@ import kotlinx.coroutines.promise
99

1010
actual val context: Any = Unit
1111

12-
actual fun runTest(test: suspend () -> Unit) = GlobalScope.promise { test() }.asDynamic()
12+
actual fun runTest(test: suspend () -> Unit) = GlobalScope
13+
.promise {
14+
try {
15+
test()
16+
} catch (e: dynamic) {
17+
e.log()
18+
throw e
19+
}
20+
}.asDynamic()
21+
22+
internal fun Throwable.log() {
23+
console.error(this)
24+
cause?.let {
25+
console.error("Caused by:")
26+
it.log()
27+
}
28+
}

firebase-auth/src/jsTest/kotlin/dev/gitlive/firebase/auth/auth.kt

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,20 @@ import kotlinx.coroutines.promise
99

1010
actual val context: Any = Unit
1111

12-
actual fun runTest(test: suspend () -> Unit) = GlobalScope.promise { test() }.asDynamic()
12+
actual fun runTest(test: suspend () -> Unit) = GlobalScope
13+
.promise {
14+
try {
15+
test()
16+
} catch (e: dynamic) {
17+
e.log()
18+
throw e
19+
}
20+
}.asDynamic()
21+
22+
internal fun Throwable.log() {
23+
console.error(this)
24+
cause?.let {
25+
console.error("Caused by:")
26+
it.log()
27+
}
28+
}

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

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -337,8 +337,6 @@ external object firebase {
337337
fun clearPersistence(): Promise<Unit>
338338
}
339339

340-
open class FieldPath constructor(vararg fieldNames: String)
341-
342340
open class Timestamp {
343341
val seconds: Double
344342
val nanoseconds: Double
@@ -347,10 +345,12 @@ external object firebase {
347345

348346
open class Query {
349347
fun get(options: Any? = definedExternally): Promise<QuerySnapshot>
350-
fun where(field: Any, opStr: String, value: Any?): Query
348+
fun where(field: String, opStr: String, value: Any?): Query
349+
fun where(field: FieldPath, opStr: String, value: Any?): Query
351350
fun onSnapshot(next: (snapshot: QuerySnapshot) -> Unit, error: (error: Error) -> Unit): () -> Unit
352351
fun limit(limit: Double): Query
353-
fun orderBy(field: Any, direction: Any): Query
352+
fun orderBy(field: String, direction: Any): Query
353+
fun orderBy(field: FieldPath, direction: Any): Query
354354
}
355355

356356
open class CollectionReference : Query {
@@ -371,7 +371,8 @@ external object firebase {
371371
val exists: Boolean
372372
val metadata: SnapshotMetadata
373373
fun data(options: Any? = definedExternally): Any?
374-
fun get(fieldPath: Any, options: Any? = definedExternally): Any?
374+
fun get(fieldPath: String, options: Any? = definedExternally): Any?
375+
fun get(fieldPath: FieldPath, options: Any? = definedExternally): Any?
375376
}
376377

377378
open class SnapshotMetadata {
@@ -387,7 +388,8 @@ external object firebase {
387388
fun get(options: Any? = definedExternally): Promise<DocumentSnapshot>
388389
fun set(data: Any, options: Any? = definedExternally): Promise<Unit>
389390
fun update(data: Any): Promise<Unit>
390-
fun update(field: Any, value: Any?, vararg moreFieldsAndValues: Any?): Promise<Unit>
391+
fun update(field: String, value: Any?, vararg moreFieldsAndValues: Any?): Promise<Unit>
392+
fun update(field: FieldPath, value: Any?, vararg moreFieldsAndValues: Any?): Promise<Unit>
391393
fun delete(): Promise<Unit>
392394
fun onSnapshot(next: (snapshot: DocumentSnapshot) -> Unit, error: (error: Error) -> Unit): ()->Unit
393395
}
@@ -397,17 +399,25 @@ external object firebase {
397399
fun delete(documentReference: DocumentReference): WriteBatch
398400
fun set(documentReference: DocumentReference, data: Any, options: Any? = definedExternally): WriteBatch
399401
fun update(documentReference: DocumentReference, data: Any): WriteBatch
400-
fun update(documentReference: DocumentReference, field: Any, value: Any?, vararg moreFieldsAndValues: Any?): WriteBatch
402+
fun update(documentReference: DocumentReference, field: String, value: Any?, vararg moreFieldsAndValues: Any?): WriteBatch
403+
fun update(documentReference: DocumentReference, field: FieldPath, value: Any?, vararg moreFieldsAndValues: Any?): WriteBatch
401404
}
402405

403406
open class Transaction {
404407
fun get(documentReference: DocumentReference): Promise<DocumentSnapshot>
405408
fun set(documentReference: DocumentReference, data: Any, options: Any? = definedExternally): Transaction
406409
fun update(documentReference: DocumentReference, data: Any): Transaction
407-
fun update(documentReference: DocumentReference, field: Any, value: Any?, vararg moreFieldsAndValues: Any?): Transaction
410+
fun update(documentReference: DocumentReference, field: String, value: Any?, vararg moreFieldsAndValues: Any?): Transaction
411+
fun update(documentReference: DocumentReference, field: FieldPath, value: Any?, vararg moreFieldsAndValues: Any?): Transaction
408412
fun delete(documentReference: DocumentReference): Transaction
409413
}
410414

415+
open class FieldPath(vararg fieldNames: String) {
416+
companion object {
417+
val documentId: FieldPath
418+
}
419+
}
420+
411421
abstract class FieldValue {
412422
companion object {
413423
fun serverTimestamp(): FieldValue

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

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ actual class WriteBatch(val android: com.google.firebase.firestore.WriteBatch) {
7575
.let { this }
7676

7777
actual inline fun <reified T> set(documentRef: DocumentReference, data: T, encodeDefaults: Boolean, vararg mergeFieldPaths: FieldPath) =
78-
android.set(documentRef.android, encode(data, encodeDefaults)!!, SetOptions.mergeFieldPaths(mergeFieldPaths.toList()))
78+
android.set(documentRef.android, encode(data, encodeDefaults)!!, SetOptions.mergeFieldPaths(mergeFieldPaths.map { it.android }))
7979
.let { this }
8080

8181
actual fun <T> set(documentRef: DocumentReference, strategy: SerializationStrategy<T>, data: T, encodeDefaults: Boolean, merge: Boolean) = when(merge) {
@@ -88,7 +88,7 @@ actual class WriteBatch(val android: com.google.firebase.firestore.WriteBatch) {
8888
.let { this }
8989

9090
actual fun <T> set(documentRef: DocumentReference, strategy: SerializationStrategy<T>, data: T, encodeDefaults: Boolean, vararg mergeFieldPaths: FieldPath) =
91-
android.set(documentRef.android, encode(strategy, data, encodeDefaults)!!, SetOptions.mergeFieldPaths(mergeFieldPaths.toList()))
91+
android.set(documentRef.android, encode(strategy, data, encodeDefaults)!!, SetOptions.mergeFieldPaths(mergeFieldPaths.map { it.android }))
9292
.let { this }
9393

9494
@Suppress("UNCHECKED_CAST")
@@ -116,10 +116,10 @@ actual class WriteBatch(val android: com.google.firebase.firestore.WriteBatch) {
116116
android.takeUnless { fieldsAndValues.isEmpty() }
117117
?.update(
118118
documentRef.android,
119-
fieldsAndValues[0].first,
119+
fieldsAndValues[0].first.android,
120120
fieldsAndValues[0].second,
121121
*fieldsAndValues.drop(1).flatMap { (field, value) ->
122-
listOf(field, value?.let { encode(value, true) })
122+
listOf(field.android, value?.let { encode(value, true) })
123123
}.toTypedArray()
124124
).let { this }
125125

@@ -142,7 +142,7 @@ actual class Transaction(val android: com.google.firebase.firestore.Transaction)
142142
.let { this }
143143

144144
actual fun set(documentRef: DocumentReference, data: Any, encodeDefaults: Boolean, vararg mergeFieldPaths: FieldPath) =
145-
android.set(documentRef.android, encode(data, encodeDefaults)!!, SetOptions.mergeFieldPaths(mergeFieldPaths.toList()))
145+
android.set(documentRef.android, encode(data, encodeDefaults)!!, SetOptions.mergeFieldPaths(mergeFieldPaths.map { it.android }))
146146
.let { this }
147147

148148
actual fun <T> set(
@@ -161,7 +161,7 @@ actual class Transaction(val android: com.google.firebase.firestore.Transaction)
161161
.let { this }
162162

163163
actual fun <T> set(documentRef: DocumentReference, strategy: SerializationStrategy<T>, data: T, encodeDefaults: Boolean, vararg mergeFieldPaths: FieldPath) =
164-
android.set(documentRef.android, encode(strategy, data, encodeDefaults)!!, SetOptions.mergeFieldPaths(mergeFieldPaths.toList()))
164+
android.set(documentRef.android, encode(strategy, data, encodeDefaults)!!, SetOptions.mergeFieldPaths(mergeFieldPaths.map { it.android }))
165165
.let { this }
166166

167167
@Suppress("UNCHECKED_CAST")
@@ -189,10 +189,10 @@ actual class Transaction(val android: com.google.firebase.firestore.Transaction)
189189
android.takeUnless { fieldsAndValues.isEmpty() }
190190
?.update(
191191
documentRef.android,
192-
fieldsAndValues[0].first,
192+
fieldsAndValues[0].first.android,
193193
fieldsAndValues[0].second,
194194
*fieldsAndValues.drop(1).flatMap { (field, value) ->
195-
listOf(field, value?.let { encode(value, true) })
195+
listOf(field.android, value?.let { encode(value, true) })
196196
}.toTypedArray()
197197
).let { this }
198198

@@ -223,7 +223,7 @@ actual class DocumentReference(val android: com.google.firebase.firestore.Docume
223223
.await().run { Unit }
224224

225225
actual suspend inline fun <reified T> set(data: T, encodeDefaults: Boolean, vararg mergeFieldPaths: FieldPath) =
226-
android.set(encode(data, encodeDefaults)!!, SetOptions.mergeFieldPaths(mergeFieldPaths.toList()))
226+
android.set(encode(data, encodeDefaults)!!, SetOptions.mergeFieldPaths(mergeFieldPaths.map { it.android }))
227227
.await().run { Unit }
228228

229229
actual suspend fun <T> set(strategy: SerializationStrategy<T>, data: T, encodeDefaults: Boolean, merge: Boolean) = when(merge) {
@@ -236,7 +236,7 @@ actual class DocumentReference(val android: com.google.firebase.firestore.Docume
236236
.await().run { Unit }
237237

238238
actual suspend fun <T> set(strategy: SerializationStrategy<T>, data: T, encodeDefaults: Boolean, vararg mergeFieldPaths: FieldPath) =
239-
android.set(encode(strategy, data, encodeDefaults)!!, SetOptions.mergeFieldPaths(mergeFieldPaths.toList()))
239+
android.set(encode(strategy, data, encodeDefaults)!!, SetOptions.mergeFieldPaths(mergeFieldPaths.map { it.android }))
240240
.await().run { Unit }
241241

242242
@Suppress("UNCHECKED_CAST")
@@ -264,10 +264,10 @@ actual class DocumentReference(val android: com.google.firebase.firestore.Docume
264264
actual suspend fun update(vararg fieldsAndValues: Pair<FieldPath, Any?>) =
265265
android.takeUnless { fieldsAndValues.isEmpty() }
266266
?.update(
267-
fieldsAndValues[0].first,
267+
fieldsAndValues[0].first.android,
268268
fieldsAndValues[0].second,
269269
*fieldsAndValues.drop(1).flatMap { (field, value) ->
270-
listOf(field, value?.let { encode(value, true) })
270+
listOf(field.android, value?.let { encode(value, true) })
271271
}.toTypedArray()
272272
)
273273
?.await()
@@ -303,7 +303,7 @@ actual open class Query(open val android: com.google.firebase.firestore.Query) {
303303
}
304304

305305
internal actual fun _where(field: String, equalTo: Any?) = Query(android.whereEqualTo(field, equalTo))
306-
internal actual fun _where(path: FieldPath, equalTo: Any?) = Query(android.whereEqualTo(path, equalTo))
306+
internal actual fun _where(path: FieldPath, equalTo: Any?) = Query(android.whereEqualTo(path.android, equalTo))
307307

308308
internal actual fun _where(field: String, lessThan: Any?, greaterThan: Any?, arrayContains: Any?) = Query(
309309
(lessThan?.let { android.whereLessThan(field, it) } ?: android).let { android2 ->
@@ -314,9 +314,9 @@ actual open class Query(open val android: com.google.firebase.firestore.Query) {
314314
)
315315

316316
internal actual fun _where(path: FieldPath, lessThan: Any?, greaterThan: Any?, arrayContains: Any?) = Query(
317-
(lessThan?.let { android.whereLessThan(path, it) } ?: android).let { android2 ->
318-
(greaterThan?.let { android2.whereGreaterThan(path, it) } ?: android2).let { android3 ->
319-
arrayContains?.let { android3.whereArrayContains(path, it) } ?: android3
317+
(lessThan?.let { android.whereLessThan(path.android, it) } ?: android).let { android2 ->
318+
(greaterThan?.let { android2.whereGreaterThan(path.android, it) } ?: android2).let { android3 ->
319+
arrayContains?.let { android3.whereArrayContains(path.android, it) } ?: android3
320320
}
321321
}
322322
)
@@ -328,13 +328,13 @@ actual open class Query(open val android: com.google.firebase.firestore.Query) {
328328
)
329329

330330
internal actual fun _where(path: FieldPath, inArray: List<Any>?, arrayContainsAny: List<Any>?) = Query(
331-
(inArray?.let { android.whereIn(path, it) } ?: android).let { android2 ->
332-
arrayContainsAny?.let { android2.whereArrayContainsAny(path, it) } ?: android2
331+
(inArray?.let { android.whereIn(path.android, it) } ?: android).let { android2 ->
332+
arrayContainsAny?.let { android2.whereArrayContainsAny(path.android, it) } ?: android2
333333
}
334334
)
335335

336336
internal actual fun _orderBy(field: String, direction: Direction) = Query(android.orderBy(field, direction))
337-
internal actual fun _orderBy(field: FieldPath, direction: Direction) = Query(android.orderBy(field, direction))
337+
internal actual fun _orderBy(field: FieldPath, direction: Direction) = Query(android.orderBy(field.android, direction))
338338
}
339339

340340
actual typealias Direction = com.google.firebase.firestore.Query.Direction
@@ -394,14 +394,16 @@ actual class SnapshotMetadata(val android: com.google.firebase.firestore.Snapsho
394394
actual val isFromCache: Boolean get() = android.isFromCache()
395395
}
396396

397-
actual typealias FieldPath = com.google.firebase.firestore.FieldPath
398-
399-
actual fun FieldPath(vararg fieldNames: String) = FieldPath.of(*fieldNames)
397+
actual class FieldPath private constructor(val android: com.google.firebase.firestore.FieldPath) {
398+
actual constructor(vararg fieldNames: String) : this(com.google.firebase.firestore.FieldPath.of(*fieldNames))
399+
actual val documentId: FieldPath get() = FieldPath(com.google.firebase.firestore.FieldPath.documentId())
400+
}
400401

401402
actual object FieldValue {
402-
actual fun serverTimestamp() = Double.POSITIVE_INFINITY
403-
actual fun delete(): Any = com.google.firebase.firestore.FieldValue.delete()
404-
actual fun arrayUnion(vararg elements: Any): Any = com.google.firebase.firestore.FieldValue.arrayUnion(*elements)
405-
actual fun arrayRemove(vararg elements: Any): Any = com.google.firebase.firestore.FieldValue.arrayRemove(*elements)
403+
actual val serverTimestamp = Double.POSITIVE_INFINITY
404+
actual val delete: Any get() = FieldValue.delete()
405+
actual fun arrayUnion(vararg elements: Any): Any = FieldValue.arrayUnion(*elements)
406+
actual fun arrayRemove(vararg elements: Any): Any = FieldValue.arrayRemove(*elements)
407+
actual fun delete(): Any = delete
406408
}
407409

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

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import dev.gitlive.firebase.FirebaseException
1010
import kotlinx.coroutines.flow.Flow
1111
import kotlinx.serialization.DeserializationStrategy
1212
import kotlinx.serialization.SerializationStrategy
13+
import kotlin.js.JsName
1314

1415
/** Returns the [FirebaseFirestore] instance of the default [FirebaseApp]. */
1516
expect val Firebase.firestore: FirebaseFirestore
@@ -187,13 +188,16 @@ expect class SnapshotMetadata {
187188
val isFromCache: Boolean
188189
}
189190

190-
expect class FieldPath
191-
192-
expect fun FieldPath(vararg fieldNames: String): FieldPath
191+
expect class FieldPath(vararg fieldNames: String) {
192+
val documentId: FieldPath
193+
}
193194

194195
expect object FieldValue {
195-
fun serverTimestamp(): Double
196-
fun delete(): Any
196+
val serverTimestamp: Double
197+
val delete: Any
197198
fun arrayUnion(vararg elements: Any): Any
198199
fun arrayRemove(vararg elements: Any): Any
200+
@Deprecated("Replaced with FieldValue.delete")
201+
@JsName("deprecatedDelete")
202+
fun delete(): Any
199203
}

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,10 @@ class FirebaseFirestoreTest {
110110
.collection("testServerTimestampFieldValue")
111111
.document("test")
112112

113-
doc.set(FirestoreTest.serializer(), FirestoreTest("ServerTimestamp", FieldValue.serverTimestamp()))
113+
doc.set(FirestoreTest.serializer(), FirestoreTest("ServerTimestamp", FieldValue.serverTimestamp))
114114

115-
assertNotEquals(FieldValue.serverTimestamp(), doc.get().get("time"))
116-
assertNotEquals(FieldValue.serverTimestamp(), doc.get().data(FirestoreTest.serializer()).time)
115+
assertNotEquals(FieldValue.serverTimestamp, doc.get().get("time"))
116+
assertNotEquals(FieldValue.serverTimestamp, doc.get().data(FirestoreTest.serializer()).time)
117117

118118
}
119119

@@ -128,4 +128,4 @@ class FirebaseFirestoreTest {
128128
.document("three")
129129
.set(FirestoreTest.serializer(), FirestoreTest("ccc"))
130130
}
131-
}
131+
}

0 commit comments

Comments
 (0)