Skip to content

Commit 13b0d2b

Browse files
authored
Merge branch 'master' into gitlive/kotlin-1.8.21-gradle-8
2 parents 6536957 + a3c295f commit 13b0d2b

File tree

38 files changed

+713
-93
lines changed

38 files changed

+713
-93
lines changed

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ db.collection("cities").document("LA").set(City.serializer(), city, encodeDefaul
8888
```
8989

9090
The `encodeDefaults` parameter is optional and defaults to `true`, set this to false to omit writing optional properties if they are equal to theirs default values.
91+
Using [@EncodeDefault](https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization/-encode-default/) on properties is a recommended way to locally override the behavior set with `encodeDefaults`.
9192

9293
You can also omit the serializer but this is discouraged due to a [current limitation on Kotlin/JS and Kotlin/Native](https://github.com/Kotlin/kotlinx.serialization/issues/1116#issuecomment-704342452)
9394

@@ -110,6 +111,21 @@ data class Post(
110111
)
111112
```
112113

114+
In addition `firebase-firestore` provides [GeoPoint] and [DocumentReference] classes which allow persisting
115+
geo points and document references in a native way:
116+
117+
```kotlin
118+
@Serializable
119+
data class PointOfInterest(
120+
val reference: DocumentReference,
121+
val location: GeoPoint
122+
)
123+
val document = PointOfInterest(
124+
reference = Firebase.firestore.collection("foo").document("bar"),
125+
location = GeoPoint(51.939, 4.506)
126+
)
127+
```
128+
113129
<h4>Polymorphic serialization (sealed classes)</h4>
114130

115131
This sdk will handle polymorphic serialization automatically if you have a sealed class and its children marked as `Serializable`. It will include a `type` property that will be used to discriminate which child class is the serialized.

build.gradle.kts

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,28 @@ subprojects {
6565
onlyIf { project.gradle.startParameter.taskNames.contains("MavenRepository") }
6666
}
6767

68+
val skipPublishing = project.name == "test-utils" // skip publishing for test utils
69+
6870
tasks {
71+
withType<Test> {
72+
testLogging {
73+
showExceptions = true
74+
exceptionFormat = TestExceptionFormat.FULL
75+
showStandardStreams = true
76+
showCauses = true
77+
showStackTraces = true
78+
events = setOf(
79+
TestLogEvent.STARTED,
80+
TestLogEvent.FAILED,
81+
TestLogEvent.PASSED,
82+
TestLogEvent.SKIPPED,
83+
TestLogEvent.STANDARD_OUT,
84+
TestLogEvent.STANDARD_ERROR
85+
)
86+
}
87+
}
88+
89+
if (skipPublishing) return@tasks
6990

7091
register<Exec>("updateVersion") {
7192
commandLine("npm", "--allow-same-version", "--prefix", projectDir, "version", "${project.property("${project.name}.version")}")
@@ -136,24 +157,6 @@ subprojects {
136157
commandLine("npm", "publish")
137158
}
138159
}
139-
140-
withType<Test> {
141-
testLogging {
142-
showExceptions = true
143-
exceptionFormat = TestExceptionFormat.FULL
144-
showStandardStreams = true
145-
showCauses = true
146-
showStackTraces = true
147-
events = setOf(
148-
TestLogEvent.STARTED,
149-
TestLogEvent.FAILED,
150-
TestLogEvent.PASSED,
151-
TestLogEvent.SKIPPED,
152-
TestLogEvent.STANDARD_OUT,
153-
TestLogEvent.STANDARD_ERROR
154-
)
155-
}
156-
}
157160
}
158161

159162
afterEvaluate {
@@ -184,8 +187,10 @@ subprojects {
184187
}
185188
}
186189

187-
apply(plugin="maven-publish")
188-
apply(plugin="signing")
190+
if (skipPublishing) return@subprojects
191+
192+
apply(plugin = "maven-publish")
193+
apply(plugin = "signing")
189194

190195

191196
configure<PublishingExtension> {
@@ -238,6 +243,7 @@ subprojects {
238243
}
239244
}
240245
}
246+
241247
}
242248

243249
// Workaround for setting kotlinOptions.jvmTarget

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,9 @@ import platform.Foundation.*
1919
actual val Firebase.auth
2020
get() = FirebaseAuth(FIRAuth.auth())
2121

22-
actual fun Firebase.auth(app: FirebaseApp): FirebaseAuth = TODO("Come back to issue")
23-
// FirebaseAuth(FIRAuth.authWithApp(app.ios))
22+
actual fun Firebase.auth(app: FirebaseApp): FirebaseAuth = FirebaseAuth(
23+
FIRAuth.authWithApp(app.ios as objcnames.classes.FIRApp)
24+
)
2425

2526
actual class FirebaseAuth internal constructor(val ios: FIRAuth) {
2627

firebase-common/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ kotlin {
9999
implementation(kotlin("test"))
100100
implementation(kotlin("test-common"))
101101
implementation(kotlin("test-annotations-common"))
102+
implementation(project(":test-utils"))
102103
}
103104
}
104105

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,14 @@ import kotlinx.serialization.descriptors.StructureKind
1111

1212
actual fun FirebaseDecoder.structureDecoder(descriptor: SerialDescriptor): CompositeDecoder = when(descriptor.kind) {
1313
StructureKind.CLASS, StructureKind.OBJECT, PolymorphicKind.SEALED -> (value as Map<*, *>).let { map ->
14-
FirebaseClassDecoder(map.size, { map.containsKey(it) }) { desc, index -> map[desc.getElementName(index)] }
14+
FirebaseClassDecoder(map.size, { map.containsKey(it) }) { desc, index ->
15+
val elementName = desc.getElementName(index)
16+
if (desc.kind is PolymorphicKind && elementName == "value") {
17+
map
18+
} else {
19+
map[desc.getElementName(index)]
20+
}
21+
}
1522
}
1623
StructureKind.LIST -> (value as List<*>).let {
1724
FirebaseCompositeDecoder(it.size) { _, index -> it[index] }

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ class FirebaseListSerializer : KSerializer<Iterable<Any?>> {
108108
* A special case of serializer for values natively supported by Firebase and
109109
* don't require an additional encoding/decoding.
110110
*/
111-
abstract class SpecialValueSerializer<T>(
111+
class SpecialValueSerializer<T>(
112112
serialName: String,
113113
private val toNativeValue: (T) -> Any?,
114114
private val fromNativeValue: (Any?) -> T

firebase-common/src/commonTest/kotlin/dev/gitlive/firebase/EncodersTest.kt

Lines changed: 61 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,6 @@ import kotlin.test.Test
1111
import kotlin.test.assertEquals
1212
import kotlin.test.assertNull
1313

14-
expect fun nativeMapOf(vararg pairs: Pair<String, Any?>): Any
15-
expect fun nativeListOf(vararg elements: Any): Any
16-
expect fun nativeAssertEquals(expected: Any?, actual: Any?): Unit
17-
1814
@Serializable
1915
data class TestData(val map: Map<String, String>, val bool: Boolean = false, val nullableBool: Boolean? = null)
2016

@@ -25,6 +21,9 @@ sealed class TestSealed {
2521
data class ChildClass(val map: Map<String, String>, val bool: Boolean = false): TestSealed()
2622
}
2723

24+
@Serializable
25+
data class TestSealedList(val list: List<TestSealed>)
26+
2827
class EncodersTest {
2928
@Test
3029
fun encodeMap() {
@@ -74,4 +73,62 @@ class EncodersTest {
7473
val decoded = decode(TestSealed.serializer(), nativeMapOf("type" to "child", "map" to nativeMapOf("key" to "value"), "bool" to true))
7574
assertEquals(TestSealed.ChildClass(mapOf("key" to "value"), true), decoded)
7675
}
76+
77+
@Test
78+
fun encodeSealedClassList() {
79+
val toEncode = TestSealedList(
80+
list = listOf(
81+
TestSealed.ChildClass(
82+
map = mapOf("key" to "value"),
83+
bool = false
84+
)
85+
)
86+
)
87+
val encoded = encode<TestSealedList>(
88+
TestSealedList.serializer(),
89+
toEncode,
90+
shouldEncodeElementDefault = true
91+
)
92+
val expected = nativeMapOf(
93+
"list" to nativeListOf(
94+
nativeMapOf(
95+
"type" to "child",
96+
"map" to nativeMapOf(
97+
"key" to "value"
98+
),
99+
"bool" to false
100+
)
101+
)
102+
)
103+
nativeAssertEquals(expected, encoded)
104+
}
105+
106+
@Test
107+
fun decodeSealedClassList() {
108+
val toDecode = nativeMapOf(
109+
"list" to nativeListOf(
110+
nativeMapOf(
111+
"type" to "child",
112+
"map" to nativeMapOf(
113+
"key" to "value"
114+
),
115+
"bool" to false
116+
)
117+
)
118+
)
119+
val decoded = decode(
120+
TestSealedList.serializer(),
121+
toDecode
122+
)
123+
val expected = TestSealedList(
124+
list = listOf(
125+
TestSealed.ChildClass(
126+
map = mapOf("key" to "value"),
127+
bool = false
128+
)
129+
)
130+
)
131+
132+
assertEquals(expected, decoded)
133+
}
77134
}

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,14 @@ import kotlinx.serialization.descriptors.StructureKind
1111

1212
actual fun FirebaseDecoder.structureDecoder(descriptor: SerialDescriptor): CompositeDecoder = when(descriptor.kind) {
1313
StructureKind.CLASS, StructureKind.OBJECT, PolymorphicKind.SEALED -> (value as Map<*, *>).let { map ->
14-
FirebaseClassDecoder(map.size, { map.containsKey(it) }) { desc, index -> map[desc.getElementName(index)] }
14+
FirebaseClassDecoder(map.size, { map.containsKey(it) }) { desc, index ->
15+
val elementName = desc.getElementName(index)
16+
if (desc.kind is PolymorphicKind && elementName == "value") {
17+
map
18+
} else {
19+
map[desc.getElementName(index)]
20+
}
21+
}
1522
}
1623
StructureKind.LIST -> (value as List<*>).let {
1724
FirebaseCompositeDecoder(it.size) { _, index -> it[index] }

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,13 @@ import kotlin.js.Json
1313
@Suppress("UNCHECKED_CAST_TO_EXTERNAL_INTERFACE")
1414
actual fun FirebaseDecoder.structureDecoder(descriptor: SerialDescriptor): CompositeDecoder = when(descriptor.kind) {
1515
StructureKind.CLASS, StructureKind.OBJECT, PolymorphicKind.SEALED -> (value as Json).let { json ->
16-
FirebaseClassDecoder(js("Object").keys(value).length as Int, { json[it] != undefined }) {
17-
desc, index -> json[desc.getElementName(index)]
16+
FirebaseClassDecoder(js("Object").keys(value).length as Int, { json[it] != undefined }) { desc, index ->
17+
val elementName = desc.getElementName(index)
18+
if (desc.kind is PolymorphicKind && elementName == "value") {
19+
json
20+
} else {
21+
json[desc.getElementName(index)]
22+
}
1823
}
1924
}
2025
StructureKind.LIST -> (value as Array<*>).let {

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,6 @@ external object firebase {
276276
object functions {
277277
class Functions {
278278
fun httpsCallable(name: String, options: Json?): HttpsCallable
279-
fun useFunctionsEmulator(origin: String)
280279
fun useEmulator(host: String, port: Int)
281280
}
282281
interface HttpsCallableResult {
@@ -453,6 +452,8 @@ external object firebase {
453452
fun update(field: FieldPath, value: Any?, vararg moreFieldsAndValues: Any?): Promise<Unit>
454453
fun delete(): Promise<Unit>
455454
fun onSnapshot(next: (snapshot: DocumentSnapshot) -> Unit, error: (error: Error) -> Unit): ()->Unit
455+
456+
fun isEqual(other: DocumentReference): Boolean
456457
}
457458

458459
open class WriteBatch {
@@ -477,6 +478,8 @@ external object firebase {
477478
companion object {
478479
val documentId: FieldPath
479480
}
481+
482+
fun isEqual(other: FieldPath): Boolean
480483
}
481484

482485
abstract class FieldValue {
@@ -490,6 +493,13 @@ external object firebase {
490493

491494
fun isEqual(other: FieldValue): Boolean
492495
}
496+
497+
open class GeoPoint(latitude: Double, longitude: Double) {
498+
val latitude: Double
499+
val longitude: Double
500+
501+
fun isEqual(other: GeoPoint): Boolean
502+
}
493503
}
494504

495505
fun remoteConfig(app: App? = definedExternally): remoteConfig.RemoteConfig

0 commit comments

Comments
 (0)