Skip to content

Commit c85cae2

Browse files
authored
add serverTimestamp() to FieldValue (#127)
* add serverTimestamp() to FieldValue support Timestamp to Double decoding * fix FirebaseFirestoreTest
1 parent dab6d45 commit c85cae2

File tree

24 files changed

+145
-55
lines changed

24 files changed

+145
-55
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ You can also omit the serializer but this is discouraged due to a [current limit
8686

8787
<h4><a href="https://firebase.google.com/docs/firestore/manage-data/add-data#server_timestamp">Server Timestamp</a></h3>
8888

89-
[Firestore](https://firebase.google.com/docs/reference/js/firebase.database.ServerValue#timestamp) and the [Realtime Database](https://firebase.google.com/docs/reference/android/com/google/firebase/database/ServerValue#TIMESTAMP) provide a sentinel value you can use to set a field in your document to a server timestamp. So you can use these values in custom classes they are of type `Double`:
89+
[Firestore](https://firebase.google.com/docs/reference/kotlin/com/google/firebase/firestore/FieldValue?hl=en#serverTimestamp()) and the [Realtime Database](https://firebase.google.com/docs/reference/android/com/google/firebase/database/ServerValue#TIMESTAMP) provide a sentinel value you can use to set a field in your document to a server timestamp. So you can use these values in custom classes they are of type `Double`:
9090

9191
```kotlin
9292
@Serializable

build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ buildscript {
1919
}
2020
}
2121
dependencies {
22-
classpath("com.android.tools.build:gradle:4.1.1")
22+
classpath("com.android.tools.build:gradle:4.0.2")
2323
classpath("de.undercouch:gradle-download-task:4.1.1")
2424
classpath("com.adarshr:gradle-test-logger-plugin:2.0.0")
2525
}

firebase-app/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
},
2424
"homepage": "https://github.com/GitLiveApp/firebase-kotlin-sdk",
2525
"dependencies": {
26-
"@gitlive/firebase-common": "1.0.0",
26+
"@gitlive/firebase-common": "1.1.0",
2727
"firebase": "8.2.0",
2828
"kotlin": "1.4.21",
2929
"kotlinx-coroutines-core": "1.4.2"

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

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

1010
actual val context: Any = Unit
1111

12-
actual fun runTest(test: suspend () -> Unit) = GlobalScope.promise { test() }.unsafeCast<Unit>()
12+
actual fun runTest(test: suspend () -> Unit) = GlobalScope.promise { test() }.asDynamic()

firebase-auth/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
},
2424
"homepage": "https://github.com/GitLiveApp/firebase-kotlin-sdk",
2525
"dependencies": {
26-
"@gitlive/firebase-app": "1.0.0",
26+
"@gitlive/firebase-app": "1.1.0",
2727
"firebase": "8.2.0",
2828
"kotlin": "1.4.21",
2929
"kotlinx-coroutines-core": "1.4.2"

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ actual open class FirebaseAuthWebException(code: String?, cause: Throwable): Fir
119119

120120
internal inline fun <T, R> T.rethrow(function: T.() -> R): R = dev.gitlive.firebase.auth.rethrow { function() }
121121

122-
internal inline fun <R> rethrow(function: () -> R): R {
122+
private inline fun <R> rethrow(function: () -> R): R {
123123
try {
124124
return function()
125125
} catch (e: Exception) {

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

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

1010
actual val context: Any = Unit
1111

12-
actual fun runTest(test: suspend () -> Unit) = GlobalScope.promise { test() }.unsafeCast<Unit>()
12+
actual fun runTest(test: suspend () -> Unit) = GlobalScope.promise { test() }.asDynamic()

firebase-common/src/androidMain/kotlin/dev/gitlive/firebase/_decoders.kt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,18 @@ package dev.gitlive.firebase
66

77
import kotlinx.serialization.encoding.CompositeDecoder
88
import kotlinx.serialization.KSerializer
9+
import kotlinx.serialization.SerializationException
910
import kotlinx.serialization.descriptors.SerialDescriptor
1011
import kotlinx.serialization.descriptors.StructureKind
1112

12-
actual fun FirebaseDecoder.structureDecoder(descriptor: SerialDescriptor): CompositeDecoder = when(descriptor.kind as StructureKind) {
13+
actual fun FirebaseDecoder.structureDecoder(descriptor: SerialDescriptor, decodeDouble: (value: Any?) -> Double?): CompositeDecoder = when(descriptor.kind as StructureKind) {
1314
StructureKind.CLASS, StructureKind.OBJECT -> (value as Map<*, *>).let { map ->
14-
FirebaseClassDecoder(map.size, { map.containsKey(it) }) { desc, index -> map[desc.getElementName(index)] }
15+
FirebaseClassDecoder(decodeDouble, map.size, { map.containsKey(it) }) { desc, index -> map[desc.getElementName(index)] }
1516
}
1617
StructureKind.LIST -> (value as List<*>).let {
17-
FirebaseCompositeDecoder(it.size) { _, index -> it[index] }
18+
FirebaseCompositeDecoder(decodeDouble, it.size) { _, index -> it[index] }
1819
}
1920
StructureKind.MAP -> (value as Map<*, *>).entries.toList().let {
20-
FirebaseCompositeDecoder(it.size) { _, index -> it[index/2].run { if(index % 2 == 0) key else value } }
21+
FirebaseCompositeDecoder(decodeDouble, it.size) { _, index -> it[index/2].run { if(index % 2 == 0) key else value } }
2122
}
2223
}

firebase-common/src/commonMain/kotlin/dev/gitlive/firebase/decoders.kt

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,28 +16,28 @@ import kotlinx.serialization.modules.SerializersModule
1616
import kotlinx.serialization.serializer
1717

1818
@Suppress("UNCHECKED_CAST")
19-
inline fun <reified T> decode(value: Any?): T {
19+
inline fun <reified T> decode(value: Any?, noinline decodeDouble: (value: Any?) -> Double? = { null }): T {
2020
val strategy = serializer<T>()
21-
return decode(strategy as DeserializationStrategy<T>, value)
21+
return decode(strategy as DeserializationStrategy<T>, value, decodeDouble)
2222
}
2323

24-
fun <T> decode(strategy: DeserializationStrategy<T>, value: Any?): T {
24+
fun <T> decode(strategy: DeserializationStrategy<T>, value: Any?, decodeDouble: (value: Any?) -> Double? = { null }): T {
2525
require(value != null || strategy.descriptor.isNullable) { "Value was null for non-nullable type ${strategy.descriptor.serialName}" }
26-
return FirebaseDecoder(value).decodeSerializableValue(strategy)
26+
return FirebaseDecoder(value, decodeDouble).decodeSerializableValue(strategy)
2727
}
2828

29-
expect fun FirebaseDecoder.structureDecoder(descriptor: SerialDescriptor): CompositeDecoder
29+
expect fun FirebaseDecoder.structureDecoder(descriptor: SerialDescriptor, decodeDouble: (value: Any?) -> Double?): CompositeDecoder
3030

31-
class FirebaseDecoder(internal val value: Any?) : Decoder {
31+
class FirebaseDecoder(internal val value: Any?, private val decodeDouble: (value: Any?) -> Double?) : Decoder {
3232

3333
override val serializersModule: SerializersModule
3434
get() = EmptySerializersModule
3535

36-
override fun beginStructure(descriptor: SerialDescriptor) = structureDecoder(descriptor)
36+
override fun beginStructure(descriptor: SerialDescriptor) = structureDecoder(descriptor, decodeDouble)
3737

3838
override fun decodeString() = decodeString(value)
3939

40-
override fun decodeDouble() = decodeDouble(value)
40+
override fun decodeDouble() = decodeDouble(value, decodeDouble)
4141

4242
override fun decodeLong() = decodeLong(value)
4343

@@ -61,10 +61,11 @@ class FirebaseDecoder(internal val value: Any?) : Decoder {
6161
}
6262

6363
class FirebaseClassDecoder(
64+
decodeDouble: (value: Any?) -> Double?,
6465
size: Int,
6566
private val containsKey: (name: String) -> Boolean,
6667
get: (descriptor: SerialDescriptor, index: Int) -> Any?
67-
) : FirebaseCompositeDecoder(size, get) {
68+
) : FirebaseCompositeDecoder(decodeDouble, size, get) {
6869
private var index: Int = 0
6970

7071
override fun decodeSequentially() = false
@@ -84,6 +85,7 @@ class FirebaseClassDecoder(
8485
}
8586

8687
open class FirebaseCompositeDecoder constructor(
88+
private val decodeDouble: (value: Any?) -> Double?,
8789
private val size: Int,
8890
private val get: (descriptor: SerialDescriptor, index: Int) -> Any?
8991
): CompositeDecoder {
@@ -98,7 +100,7 @@ open class FirebaseCompositeDecoder constructor(
98100

99101
override fun <T> decodeSerializableElement(descriptor: SerialDescriptor,
100102
index: Int, deserializer: DeserializationStrategy<T>, previousValue: T? ): T {
101-
return deserializer.deserialize(FirebaseDecoder(get(descriptor, index)))
103+
return deserializer.deserialize(FirebaseDecoder(get(descriptor, index), decodeDouble))
102104
}
103105

104106
override fun decodeBooleanElement(descriptor: SerialDescriptor, index: Int) = decodeBoolean(get(descriptor, index))
@@ -107,7 +109,7 @@ open class FirebaseCompositeDecoder constructor(
107109

108110
override fun decodeCharElement(descriptor: SerialDescriptor, index: Int) = decodeChar(get(descriptor, index))
109111

110-
override fun decodeDoubleElement(descriptor: SerialDescriptor, index: Int) = decodeDouble(get(descriptor, index))
112+
override fun decodeDoubleElement(descriptor: SerialDescriptor, index: Int) = decodeDouble(get(descriptor, index), decodeDouble)
111113

112114
override fun decodeFloatElement(descriptor: SerialDescriptor, index: Int) = decodeFloat(get(descriptor, index))
113115

@@ -133,10 +135,10 @@ open class FirebaseCompositeDecoder constructor(
133135

134136
private fun decodeString(value: Any?) = value.toString()
135137

136-
private fun decodeDouble(value: Any?) = when(value) {
138+
private fun decodeDouble(value: Any?, decodeDouble: (value: Any?) -> Double?) = when(value) {
137139
is Number -> value.toDouble()
138140
is String -> value.toDouble()
139-
else -> throw SerializationException("Expected $value to be double")
141+
else -> decodeDouble(value) ?: throw SerializationException("Expected $value to be double")
140142
}
141143

142144
private fun decodeLong(value: Any?) = when(value) {

firebase-common/src/iosMain/kotlin/dev/gitlive/firebase/_decoders.kt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,18 @@ package dev.gitlive.firebase
66

77
import kotlinx.serialization.encoding.CompositeDecoder
88
import kotlinx.serialization.KSerializer
9+
import kotlinx.serialization.SerializationException
910
import kotlinx.serialization.descriptors.SerialDescriptor
1011
import kotlinx.serialization.descriptors.StructureKind
1112

12-
actual fun FirebaseDecoder.structureDecoder(descriptor: SerialDescriptor): CompositeDecoder = when(descriptor.kind as StructureKind) {
13+
actual fun FirebaseDecoder.structureDecoder(descriptor: SerialDescriptor, decodeDouble: (value: Any?) -> Double?): CompositeDecoder = when(descriptor.kind as StructureKind) {
1314
StructureKind.CLASS, StructureKind.OBJECT -> (value as Map<*, *>).let { map ->
14-
FirebaseClassDecoder(map.size, { map.containsKey(it) }) { desc, index -> map[desc.getElementName(index)] }
15+
FirebaseClassDecoder(decodeDouble, map.size, { map.containsKey(it) }) { desc, index -> map[desc.getElementName(index)] }
1516
}
1617
StructureKind.LIST -> (value as List<*>).let {
17-
FirebaseCompositeDecoder(it.size) { _, index -> it[index] }
18+
FirebaseCompositeDecoder(decodeDouble, it.size) { _, index -> it[index] }
1819
}
1920
StructureKind.MAP -> (value as Map<*, *>).entries.toList().let {
20-
FirebaseCompositeDecoder(it.size) { _, index -> it[index/2].run { if(index % 2 == 0) key else value } }
21+
FirebaseCompositeDecoder(decodeDouble, it.size) { _, index -> it[index/2].run { if(index % 2 == 0) key else value } }
2122
}
2223
}

0 commit comments

Comments
 (0)