-
-
Notifications
You must be signed in to change notification settings - Fork 166
improve native serialization and timestamp fixes #371
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
improve native serialization and timestamp fixes #371
Conversation
vpodlesnyak
commented
Apr 11, 2023
- added GeoPoints
- added native serialization of DocumentReference
- fix for Timestamp extensions
- improve debugging
…extensions, improve debugging
@@ -453,6 +453,8 @@ external object firebase { | |||
fun update(field: FieldPath, value: Any?, vararg moreFieldsAndValues: Any?): Promise<Unit> | |||
fun delete(): Promise<Unit> | |||
fun onSnapshot(next: (snapshot: DocumentSnapshot) -> Unit, error: (error: Error) -> Unit): ()->Unit | |||
|
|||
fun isEqual(other: DocumentReference): Boolean |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
proper equality checks help a lot when writing tests in the applications using this SDK
@@ -88,6 +88,7 @@ db.collection("cities").document("LA").set(City.serializer(), city, encodeDefaul | |||
``` | |||
|
|||
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. | |||
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`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it helped me a lot so why not to mention it for other devs
actual typealias NativeGeoPoint = com.google.firebase.firestore.GeoPoint | ||
|
||
/** A class representing a Firebase GeoPoint. */ | ||
@Serializable(with = GeoPointSerializer::class) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this approach is similar to a PR #312
@@ -32,8 +32,8 @@ expect class Timestamp internal constructor(nativeValue: NativeTimestamp): BaseT | |||
} | |||
|
|||
fun Timestamp.Companion.fromMilliseconds(milliseconds: Double): Timestamp = | |||
Timestamp((milliseconds / 1000).toLong(), (milliseconds * 1000).toInt() % 1000000) | |||
fun Timestamp.toMilliseconds(): Double = seconds * 1000 + (nanoseconds / 1000.0) | |||
Timestamp((milliseconds / 1000).toLong(), ((milliseconds % 1000) * 1000000).toInt()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a bug fix here. nanoseconds weren't calculated properly. added a test
fun Query.where(field: String, inArray: List<Any>? = null, arrayContainsAny: List<Any>? = null) = _where(field, inArray, arrayContainsAny) | ||
fun Query.where(path: FieldPath, inArray: List<Any>? = null, arrayContainsAny: List<Any>? = null) = _where(path, inArray, arrayContainsAny) | ||
/** @return a native value of a wrapper or self. */ | ||
private val Any.value get() = when (this) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this unwrapping is needed to properly support querying by natively supported classes. added a test
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
am I right to assume that this change is required to perform a query that requires providing a timestamp field?
e.g. where("endAt", greaterThan = Timestamp.now())
I am unable to do so in 1.8.1
right now and am hoping this fixes it :)
This PR should close #324 right? |
/** @return a map extracted from the encoded data. */ | ||
expect fun encodedAsMap(encoded: Any?): Map<String, Any?> | ||
/** @return pairs as raw encoded data. */ | ||
expect fun Map<String, Any?>.asEncoded(): Any | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we have nativeMapOf and nativeAssertEquals that can be reused instead of adding additional calls
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nbransby thanks, I actually missed those. however in order for nativeMapOf
and nativeAssertEquals
to be available in firebase-firestore
tests, the methods shall be moved from the tests folder of the firebase-common
to a separate module (lets say firebase-common-test
). shall I make this change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good point - maybe would be easier to do it on a source set level instead of a separate module?
could add a commonTestUtil source set to firebase-common and include in the test source of firebase-firestore with:
val commonTest by getting {
kotlin.srcDir("../firebase-common/src/commonTestUtil/kotlin")
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good idea
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the suggested approach created a lot of noise - it required setting up not only common but platform tests. extracted a test-utils module instead
I've noticed a separate issue regarding the TimestampSerializer, compiling a project with the following class defined:
fails with
Any ideas on that? |
@nbransby the Timestamp gets encoded/decoded in TimestampTests so it looks suspicious. I'll investigate further by creating a sample app |
@nbransby the serializer not found issue was caused by the fact |
@@ -84,7 +95,7 @@ object DoubleAsTimestampSerializer : SpecialValueSerializer<Double>( | |||
toNativeValue = { value -> | |||
when(value) { | |||
serverTimestamp -> FieldValue.serverTimestamp.nativeValue | |||
else -> Timestamp.fromMilliseconds(value) | |||
else -> Timestamp.fromMilliseconds(value).nativeValue |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a bug fix - the native value shall be extracted as in the line above
can you use composition instead of inheritance for the logic shared in SpecialValueSerializer? As making the common module an api import will expose its public api to library consumers but it was designed to hold library internal shared code |
I might be wrong but I think the error is not related to composition/inheritance, but to whether the end user adds a Please also take a look at |
composition won't expose SpecialValueSerializer in the public API of DoubleAsTimestampSerializer therefore the firebase-common dependency is not required to be api (or manually included by client/end user). The readme doesn't actually mention the firebase-common module and adding FirebaseClassDiscriminator there was not ideal but since its there now its probably best to keep the dependency as api. Instead, for the firebase-common API not intended to be public we should create something like: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your hard work @vpodlesnyak
I've noticed |
my pleasure
I see that the failure is caused by unitTests and there are no unit test folders in the repo. I think the error was caused by a commit
|
good spot! |