Skip to content

Commit d3b1721

Browse files
committed
Merge branch 'master' into refactor-web-version-9
# Conflicts: # .github/workflows/pull_request.yml # firebase-common/src/jsMain/kotlin/dev/gitlive/firebase/externals.kt # firebase-database/src/commonTest/kotlin/dev/gitlive/firebase/database/database.kt # firebase-database/src/jsMain/kotlin/dev/gitlive/firebase/database/database.kt # firebase-firestore/src/jsMain/kotlin/dev/gitlive/firebase/firestore/firestore.kt
2 parents dd2e9d7 + c4451fe commit d3b1721

File tree

43 files changed

+723
-332
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+723
-332
lines changed

.github/workflows/pull_request.yml

+6-3
Original file line numberDiff line numberDiff line change
@@ -50,15 +50,18 @@ jobs:
5050
if: failure()
5151
with:
5252
name: "JS Test Report HTML"
53-
path: "firebase-firestore/build/reports/tests/jsLegacyTest/"
53+
path: |
54+
**/build/reports/tests/jsLegacyTest/
55+
**/build/reports/tests/jsLegacyBrowserTest/
56+
**/build/reports/tests/jsLegacyNodeTest/
5457
- name: Run iOS Tests
5558
run: ./gradlew cleanTest iosX64Test
5659
- name: Upload iOS test artifact
5760
uses: actions/upload-artifact@v2
5861
if: failure()
5962
with:
6063
name: "iOS Test Report HTML"
61-
path: "firebase-firestore/build/reports/tests/iosTest/"
64+
path: "**/build/reports/tests/iosX64Test/"
6265
- name: AVD cache
6366
uses: actions/cache@v3
6467
id: avd-cache
@@ -89,4 +92,4 @@ jobs:
8992
if: failure()
9093
with:
9194
name: "Android Test Report HTML"
92-
path: "firebase-firestore/build/reports/androidTests/"
95+
path: "**/build/reports/androidTests/"

README.md

+8-4
Original file line numberDiff line numberDiff line change
@@ -93,17 +93,21 @@ You can also omit the serializer but this is discouraged due to a [current limit
9393

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

96-
[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`:
96+
[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:
9797

9898
```kotlin
9999
@Serializable
100100
data class Post(
101101
// In case using Realtime Database.
102-
val timestamp: Double = ServerValue.TIMESTAMP,
102+
val timestamp = ServerValue.TIMESTAMP,
103103
// In case using Cloud Firestore.
104-
val timestamp: Double = FieldValue.serverTimestamp,
104+
val timestamp: Timestamp = Timestamp.ServerTimestamp,
105+
// or
106+
val alternativeTimestamp = FieldValue.serverTimestamp,
107+
// or
108+
@Serializable(with = DoubleAsTimestampSerializer::class),
109+
val doubleTimestamp: Double = DoubleAsTimestampSerializer.serverTimestamp
105110
)
106-
107111
```
108112

109113
<h4>Polymorphic serialization (sealed classes)</h4>

firebase-app/package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@gitlive/firebase-app",
3-
"version": "1.8.0",
3+
"version": "1.8.1",
44
"description": "Wrapper around firebase for usage in Kotlin Multiplatform projects",
55
"main": "firebase-app.js",
66
"scripts": {
@@ -23,7 +23,7 @@
2323
},
2424
"homepage": "https://github.com/GitLiveApp/firebase-kotlin-sdk",
2525
"dependencies": {
26-
"@gitlive/firebase-common": "1.8.0",
26+
"@gitlive/firebase-common": "1.8.1",
2727
"firebase": "9.19.1",
2828
"kotlin": "1.8.20",
2929
"kotlinx-coroutines-core": "1.6.4"

firebase-auth/package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@gitlive/firebase-auth",
3-
"version": "1.8.0",
3+
"version": "1.8.1",
44
"description": "Wrapper around firebase for usage in Kotlin Multiplatform projects",
55
"main": "firebase-auth.js",
66
"scripts": {
@@ -23,7 +23,7 @@
2323
},
2424
"homepage": "https://github.com/GitLiveApp/firebase-kotlin-sdk",
2525
"dependencies": {
26-
"@gitlive/firebase-app": "1.8.0",
26+
"@gitlive/firebase-app": "1.8.1",
2727
"firebase": "9.19.1",
2828
"kotlin": "1.8.20",
2929
"kotlinx-coroutines-core": "1.6.4"

firebase-common/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@gitlive/firebase-common",
3-
"version": "1.8.0",
3+
"version": "1.8.1",
44
"description": "Wrapper around firebase for usage in Kotlin Multiplatform projects",
55
"main": "firebase-common.js",
66
"scripts": {

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

+4-4
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@ import kotlinx.serialization.descriptors.PolymorphicKind
99
import kotlinx.serialization.descriptors.SerialDescriptor
1010
import kotlinx.serialization.descriptors.StructureKind
1111

12-
actual fun FirebaseDecoder.structureDecoder(descriptor: SerialDescriptor, decodeDouble: (value: Any?) -> Double?): CompositeDecoder = when(descriptor.kind) {
12+
actual fun FirebaseDecoder.structureDecoder(descriptor: SerialDescriptor): CompositeDecoder = when(descriptor.kind) {
1313
StructureKind.CLASS, StructureKind.OBJECT, PolymorphicKind.SEALED -> (value as Map<*, *>).let { map ->
14-
FirebaseClassDecoder(decodeDouble, map.size, { map.containsKey(it) }) { desc, index -> map[desc.getElementName(index)] }
14+
FirebaseClassDecoder(map.size, { map.containsKey(it) }) { desc, index -> map[desc.getElementName(index)] }
1515
}
1616
StructureKind.LIST -> (value as List<*>).let {
17-
FirebaseCompositeDecoder(decodeDouble, it.size) { _, index -> it[index] }
17+
FirebaseCompositeDecoder(it.size) { _, index -> it[index] }
1818
}
1919
StructureKind.MAP -> (value as Map<*, *>).entries.toList().let {
20-
FirebaseCompositeDecoder(decodeDouble, it.size) { _, index -> it[index/2].run { if(index % 2 == 0) key else value } }
20+
FirebaseCompositeDecoder(it.size) { _, index -> it[index/2].run { if(index % 2 == 0) key else value } }
2121
}
2222
else -> TODO("The firebase-kotlin-sdk does not support $descriptor for serialization yet")
2323
}

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@ import kotlin.collections.set
1111
actual fun FirebaseEncoder.structureEncoder(descriptor: SerialDescriptor): FirebaseCompositeEncoder = when(descriptor.kind) {
1212
StructureKind.LIST -> mutableListOf<Any?>()
1313
.also { value = it }
14-
.let { FirebaseCompositeEncoder(shouldEncodeElementDefault, positiveInfinity) { _, index, value -> it.add(index, value) } }
14+
.let { FirebaseCompositeEncoder(shouldEncodeElementDefault) { _, index, value -> it.add(index, value) } }
1515
StructureKind.MAP -> mutableListOf<Any?>()
16-
.let { FirebaseCompositeEncoder(shouldEncodeElementDefault, positiveInfinity, { value = it.chunked(2).associate { (k, v) -> k to v } }) { _, _, value -> it.add(value) } }
16+
.let { FirebaseCompositeEncoder(shouldEncodeElementDefault, { value = it.chunked(2).associate { (k, v) -> k to v } }) { _, _, value -> it.add(value) } }
1717
StructureKind.CLASS, StructureKind.OBJECT -> mutableMapOf<Any?, Any?>()
1818
.also { value = it }
19-
.let { FirebaseCompositeEncoder(shouldEncodeElementDefault, positiveInfinity,
19+
.let { FirebaseCompositeEncoder(shouldEncodeElementDefault,
2020
setPolymorphicType = { discriminator, type ->
2121
it[discriminator] = type
2222
},

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

+1-2
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ internal fun <T> FirebaseEncoder.encodePolymorphically(
3030
@Suppress("UNCHECKED_CAST")
3131
internal fun <T> FirebaseDecoder.decodeSerializableValuePolymorphic(
3232
value: Any?,
33-
decodeDouble: (value: Any?) -> Double?,
3433
deserializer: DeserializationStrategy<T>,
3534
): T {
3635
if (deserializer !is AbstractPolymorphicSerializer<*>) {
@@ -41,7 +40,7 @@ internal fun <T> FirebaseDecoder.decodeSerializableValuePolymorphic(
4140
val discriminator = deserializer.descriptor.classDiscriminator()
4241
val type = getPolymorphicType(value, discriminator)
4342
val actualDeserializer = casted.findPolymorphicSerializerOrNull(
44-
structureDecoder(deserializer.descriptor, decodeDouble),
43+
structureDecoder(deserializer.descriptor),
4544
type
4645
) as DeserializationStrategy<T>
4746
return actualDeserializer.deserialize(this)

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

+16-18
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?, noinline decodeDouble: (value: Any?) -> Double? = { null }): T {
19+
inline fun <reified T> decode(value: Any?): T {
2020
val strategy = serializer<T>()
21-
return decode(strategy as DeserializationStrategy<T>, value, decodeDouble)
21+
return decode(strategy as DeserializationStrategy<T>, value)
2222
}
2323

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

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

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

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

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

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

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

@@ -59,19 +59,18 @@ class FirebaseDecoder(internal val value: Any?, private val decodeDouble: (value
5959

6060
override fun decodeNull() = decodeNull(value)
6161

62-
override fun decodeInline(inlineDescriptor: SerialDescriptor) = FirebaseDecoder(value, decodeDouble)
62+
override fun decodeInline(inlineDescriptor: SerialDescriptor) = FirebaseDecoder(value)
6363

6464
override fun <T> decodeSerializableValue(deserializer: DeserializationStrategy<T>): T {
65-
return decodeSerializableValuePolymorphic(value, decodeDouble, deserializer)
65+
return decodeSerializableValuePolymorphic(value, deserializer)
6666
}
6767
}
6868

6969
class FirebaseClassDecoder(
70-
decodeDouble: (value: Any?) -> Double?,
7170
size: Int,
7271
private val containsKey: (name: String) -> Boolean,
7372
get: (descriptor: SerialDescriptor, index: Int) -> Any?
74-
) : FirebaseCompositeDecoder(decodeDouble, size, get) {
73+
) : FirebaseCompositeDecoder(size, get) {
7574
private var index: Int = 0
7675

7776
override fun decodeSequentially() = false
@@ -84,7 +83,6 @@ class FirebaseClassDecoder(
8483
}
8584

8685
open class FirebaseCompositeDecoder(
87-
private val decodeDouble: (value: Any?) -> Double?,
8886
private val size: Int,
8987
private val get: (descriptor: SerialDescriptor, index: Int) -> Any?
9088
): CompositeDecoder {
@@ -102,15 +100,15 @@ open class FirebaseCompositeDecoder(
102100
index: Int,
103101
deserializer: DeserializationStrategy<T>,
104102
previousValue: T?
105-
) = deserializer.deserialize(FirebaseDecoder(get(descriptor, index), decodeDouble))
103+
) = deserializer.deserialize(FirebaseDecoder(get(descriptor, index)))
106104

107105
override fun decodeBooleanElement(descriptor: SerialDescriptor, index: Int) = decodeBoolean(get(descriptor, index))
108106

109107
override fun decodeByteElement(descriptor: SerialDescriptor, index: Int) = decodeByte(get(descriptor, index))
110108

111109
override fun decodeCharElement(descriptor: SerialDescriptor, index: Int) = decodeChar(get(descriptor, index))
112110

113-
override fun decodeDoubleElement(descriptor: SerialDescriptor, index: Int) = decodeDouble(get(descriptor, index), decodeDouble)
111+
override fun decodeDoubleElement(descriptor: SerialDescriptor, index: Int) = decodeDouble(get(descriptor, index))
114112

115113
override fun decodeFloatElement(descriptor: SerialDescriptor, index: Int) = decodeFloat(get(descriptor, index))
116114

@@ -136,16 +134,16 @@ open class FirebaseCompositeDecoder(
136134

137135
@ExperimentalSerializationApi
138136
override fun decodeInlineElement(descriptor: SerialDescriptor, index: Int): Decoder =
139-
FirebaseDecoder(get(descriptor, index), decodeDouble)
137+
FirebaseDecoder(get(descriptor, index))
140138

141139
}
142140

143141
private fun decodeString(value: Any?) = value.toString()
144142

145-
private fun decodeDouble(value: Any?, decodeDouble: (value: Any?) -> Double?) = when(value) {
143+
private fun decodeDouble(value: Any?) = when(value) {
146144
is Number -> value.toDouble()
147145
is String -> value.toDouble()
148-
else -> decodeDouble(value) ?: throw SerializationException("Expected $value to be double")
146+
else -> throw SerializationException("Expected $value to be double")
149147
}
150148

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

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

+12-20
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,16 @@ import kotlinx.serialization.encoding.*
99
import kotlinx.serialization.descriptors.*
1010
import kotlinx.serialization.modules.EmptySerializersModule
1111

12-
fun <T> encode(strategy: SerializationStrategy<T>, value: T, shouldEncodeElementDefault: Boolean, positiveInfinity: Any = Double.POSITIVE_INFINITY): Any? =
13-
FirebaseEncoder(shouldEncodeElementDefault, positiveInfinity).apply { encodeSerializableValue(strategy, value) }.value//.also { println("encoded $it") }
12+
fun <T> encode(strategy: SerializationStrategy<T>, value: T, shouldEncodeElementDefault: Boolean): Any? =
13+
FirebaseEncoder(shouldEncodeElementDefault).apply { encodeSerializableValue(strategy, value) }.value//.also { println("encoded $it") }
1414

15-
inline fun <reified T> encode(value: T, shouldEncodeElementDefault: Boolean, positiveInfinity: Any = Double.POSITIVE_INFINITY): Any? = value?.let {
16-
FirebaseEncoder(shouldEncodeElementDefault, positiveInfinity).apply { encodeSerializableValue(it.firebaseSerializer(), it) }.value
15+
inline fun <reified T> encode(value: T, shouldEncodeElementDefault: Boolean): Any? = value?.let {
16+
FirebaseEncoder(shouldEncodeElementDefault).apply { encodeSerializableValue(it.firebaseSerializer(), it) }.value
1717
}
1818

1919
expect fun FirebaseEncoder.structureEncoder(descriptor: SerialDescriptor): FirebaseCompositeEncoder
2020

21-
class FirebaseEncoder(internal val shouldEncodeElementDefault: Boolean, positiveInfinity: Any) : TimestampEncoder(positiveInfinity), Encoder {
21+
class FirebaseEncoder(internal val shouldEncodeElementDefault: Boolean) : Encoder {
2222

2323
var value: Any? = null
2424

@@ -47,7 +47,7 @@ class FirebaseEncoder(internal val shouldEncodeElementDefault: Boolean, positive
4747
}
4848

4949
override fun encodeDouble(value: Double) {
50-
this.value = encodeTimestamp(value)
50+
this.value = value
5151
}
5252

5353
override fun encodeEnum(enumDescriptor: SerialDescriptor, index: Int) {
@@ -83,7 +83,7 @@ class FirebaseEncoder(internal val shouldEncodeElementDefault: Boolean, positive
8383
}
8484

8585
override fun encodeInline(inlineDescriptor: SerialDescriptor): Encoder =
86-
FirebaseEncoder(shouldEncodeElementDefault, positiveInfinity)
86+
FirebaseEncoder(shouldEncodeElementDefault)
8787

8888
override fun <T> encodeSerializableValue(serializer: SerializationStrategy<T>, value: T) {
8989
encodePolymorphically(serializer, value) {
@@ -92,20 +92,12 @@ class FirebaseEncoder(internal val shouldEncodeElementDefault: Boolean, positive
9292
}
9393
}
9494

95-
abstract class TimestampEncoder(internal val positiveInfinity: Any) {
96-
fun encodeTimestamp(value: Double) = when(value) {
97-
Double.POSITIVE_INFINITY -> positiveInfinity
98-
else -> value
99-
}
100-
}
101-
10295
open class FirebaseCompositeEncoder constructor(
10396
private val shouldEncodeElementDefault: Boolean,
104-
positiveInfinity: Any,
10597
private val end: () -> Unit = {},
10698
private val setPolymorphicType: (String, String) -> Unit = { _, _ -> },
10799
private val set: (descriptor: SerialDescriptor, index: Int, value: Any?) -> Unit,
108-
): TimestampEncoder(positiveInfinity), CompositeEncoder {
100+
): CompositeEncoder {
109101

110102
override val serializersModule = EmptySerializersModule
111103

@@ -128,7 +120,7 @@ open class FirebaseCompositeEncoder constructor(
128120
descriptor,
129121
index,
130122
value?.let {
131-
FirebaseEncoder(shouldEncodeElementDefault, positiveInfinity).apply {
123+
FirebaseEncoder(shouldEncodeElementDefault).apply {
132124
encodeSerializableValue(serializer, value)
133125
}.value
134126
}
@@ -142,7 +134,7 @@ open class FirebaseCompositeEncoder constructor(
142134
) = set(
143135
descriptor,
144136
index,
145-
FirebaseEncoder(shouldEncodeElementDefault, positiveInfinity).apply {
137+
FirebaseEncoder(shouldEncodeElementDefault).apply {
146138
encodeSerializableValue(serializer, value)
147139
}.value
148140
)
@@ -153,7 +145,7 @@ open class FirebaseCompositeEncoder constructor(
153145

154146
override fun encodeCharElement(descriptor: SerialDescriptor, index: Int, value: Char) = set(descriptor, index, value)
155147

156-
override fun encodeDoubleElement(descriptor: SerialDescriptor, index: Int, value: Double) = set(descriptor, index, encodeTimestamp(value))
148+
override fun encodeDoubleElement(descriptor: SerialDescriptor, index: Int, value: Double) = set(descriptor, index, value)
157149

158150
override fun encodeFloatElement(descriptor: SerialDescriptor, index: Int, value: Float) = set(descriptor, index, value)
159151

@@ -167,7 +159,7 @@ open class FirebaseCompositeEncoder constructor(
167159

168160
@ExperimentalSerializationApi
169161
override fun encodeInlineElement(descriptor: SerialDescriptor, index: Int): Encoder =
170-
FirebaseEncoder(shouldEncodeElementDefault, positiveInfinity)
162+
FirebaseEncoder(shouldEncodeElementDefault)
171163

172164
fun encodePolymorphicClassDiscriminator(discriminator: String, type: String) {
173165
setPolymorphicType(discriminator, type)

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

+27
Original file line numberDiff line numberDiff line change
@@ -104,3 +104,30 @@ class FirebaseListSerializer : KSerializer<Iterable<Any?>> {
104104
}
105105
}
106106

107+
/**
108+
* A special case of serializer for values natively supported by Firebase and
109+
* don't require an additional encoding/decoding.
110+
*/
111+
abstract class SpecialValueSerializer<T>(
112+
serialName: String,
113+
private val toNativeValue: (T) -> Any?,
114+
private val fromNativeValue: (Any?) -> T
115+
) : KSerializer<T> {
116+
override val descriptor = buildClassSerialDescriptor(serialName) { }
117+
118+
override fun serialize(encoder: Encoder, value: T) {
119+
if (encoder is FirebaseEncoder) {
120+
encoder.value = toNativeValue(value)
121+
} else {
122+
throw SerializationException("This serializer must be used with FirebaseEncoder")
123+
}
124+
}
125+
126+
override fun deserialize(decoder: Decoder): T {
127+
return if (decoder is FirebaseDecoder) {
128+
fromNativeValue(decoder.value)
129+
} else {
130+
throw SerializationException("This serializer must be used with FirebaseDecoder")
131+
}
132+
}
133+
}

0 commit comments

Comments
 (0)