Skip to content

Conversation

Daeda88
Copy link
Contributor

@Daeda88 Daeda88 commented Aug 30, 2024

Fixes #604 and trumps #605

This solution extends all update methods in Firestore to support more advanced update methods. String fields and FieldPaths can now be used interchangably and custom serializer can be passed.

documentRef.update("field" to "value, "otherField" to 1)

becomes

documentRef.update {
     // specifying build settings is optional
    buildSettings = {}

    "field" to "value"
    FieldPath("otherField") to 1
    "customField".to(CustomValueSerializer(), customValue)
}

Note that the existing vararg pairs can still be used.

Similar support has been added to where clauses as well as startAt/endAt/etc:

query.startAt {
    add(value)
    addWithStrategy(CustomValueSerializer(), customValue)
 }

There is a small regression on the existing update methods in that

public fun update(documentRef: DocumentReference, vararg fieldsAndValues: Pair<String, Any?>, buildSettings: EncodeSettings.Builder.() -> Unit)changed to public fun update(documentRef: DocumentReference, buildSettings: EncodeSettings.Builder.() -> Unit, vararg fieldsAndValues: Pair<String, Any?>) due to Kotlin not being able to figure out which update method to use.

Furthermore, I've split the Firestore tests into a few different files and extended them so they clean up all data after completion.

Lastly, I discovered bug #613 and fixed it

Daeda88 and others added 5 commits August 29, 2024 10:39
It had become part of commons-internal which kind of defeats the purpose.

Also made FirebaseEncoder/FirebaseDecoder an interface in the public API. Useful for writing custom Serializers that have custom behaviour on Firebase
@Daeda88
Copy link
Contributor Author

Daeda88 commented Aug 30, 2024

I still need to add Readme/some tests, but feedback would already be appreciated @nbransby as I wont be able to continue until next week

@Daeda88
Copy link
Contributor Author

Daeda88 commented Sep 2, 2024

Now fully ready for review @nbransby / @Reedyuk . See description above for details of changes.

@Daeda88
Copy link
Contributor Author

Daeda88 commented Sep 29, 2024

Will anyone ever review this @nbransby 😅

@nbransby
Copy link
Member

Sorry been a crazy month, will hopefully get to it soon

@nbransby
Copy link
Member

nbransby commented Oct 5, 2024

There is a small regression on the existing update methods in that

Does that make this a breaking change?

@nbransby
Copy link
Member

nbransby commented Oct 5, 2024

I still need to add Readme/some tests, but feedback would already be appreciated @nbransby as I wont be able to continue until next week

looks great to me, I would like to see more comprehensive documentation in the README that would also help me understand the intended usage.

@Daeda88
Copy link
Contributor Author

Daeda88 commented Oct 5, 2024

There is a small regression on the existing update methods in that

Does that make this a breaking change?

Yeah, its breaking. I went from:

update(docRef, "path" to value) { encodeDefaults = false }

to

update(docRef, { encodeDefaults = false }, "path" to value)

The reason I had to do something is because the new update method has the signature:

update(docRef) {
  "path" to value
}

and since the original method takes a vararg, it can be called as update(docRef) { encodeDefaults = false }, which means the compiler wont know wich method to call. I considered alternatives:

  1. Change the original code to always take at least one path (i.e. fun update(docRef, firstValue: Pair<String, Any>, vararg others: Pair<String, Any>) but that would mean you woundnt be able to call it with update(docRef, *listOfPairs.toTypedArray()) which I assume is a common usecase.
  2. Name the new update function something else, e.g. updateWith, but I though the downside of that was that it sort of breaks the agreement that we name stuff like it is named in the native libraries
  3. I do this approach, knowing that the encodeSettings closure is relatively new and will thus probably be not used that much yet.
  4. Keep the old signature and the new one as is now, but that means you have to use named arguments for the closure which sucks.

I think 1 is a definitive no-go. If you prefer we do 2, Im fine with that as well. Its always gonna be a tradeoff so its pick your poison basically.

As for documentation, Ill change that as soon as we agree on this point :)

@nbransby
Copy link
Member

nbransby commented Oct 5, 2024

I spent long enough trying to think of additional alternatives without joy so, I favour 2 and calling it updateFields

@Daeda88
Copy link
Contributor Author

Daeda88 commented Oct 7, 2024

Done @nbransby

Comment on lines +52 to +58
public final class dev/gitlive/firebase/FirebaseEncoder$DefaultImpls {
public static fun beginCollection (Ldev/gitlive/firebase/FirebaseEncoder;Lkotlinx/serialization/descriptors/SerialDescriptor;I)Lkotlinx/serialization/encoding/CompositeEncoder;
public static fun encodeNotNullMark (Ldev/gitlive/firebase/FirebaseEncoder;)V
public static fun encodeNullableSerializableValue (Ldev/gitlive/firebase/FirebaseEncoder;Lkotlinx/serialization/SerializationStrategy;Ljava/lang/Object;)V
public static fun encodeSerializableValue (Ldev/gitlive/firebase/FirebaseEncoder;Lkotlinx/serialization/SerializationStrategy;Ljava/lang/Object;)V
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does all the DefaultImpls need to be exposed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this is coming in from Kotlin. By extending the Encoder interface we inherit some default implementations. This is what that looks like from a JVM api perspective. There is no "DefaultImpls" class anywhere, the file is literally this:

public interface FirebaseEncoder : Encoder

Comment on lines 16 to 19
public final class dev/gitlive/firebase/EncodeDecodeSettingsKt {
public static final fun copyFrom (Ldev/gitlive/firebase/DecodeSettings$Builder;Ldev/gitlive/firebase/DecodeSettings$Builder;)V
public static final fun copyFrom (Ldev/gitlive/firebase/EncodeSettings$Builder;Ldev/gitlive/firebase/EncodeSettings$Builder;)V
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this need to be public?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, removed

@@ -576,117 +610,92 @@ public abstract interface class dev/gitlive/firebase/firestore/WhereConstraint {
}

public final class dev/gitlive/firebase/firestore/WhereConstraint$ArrayContains : dev/gitlive/firebase/firestore/WhereConstraint$ForObject {
public final fun component1 ()Ljava/lang/Object;
public fun <init> (Lkotlin/jvm/functions/Function0;)V
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

exposing constructor?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FilterBuilder uses it in its inline implementation. Marked as internal @PublishedAPI in code, so not actually visible for the kotlin side

@nbransby
Copy link
Member

does startAtFieldValues/startAfterFieldValues/endAtFieldValues/endBeforeFieldValues suffer the same signature clash issue as update or can they renamed to startAt/startAfter/endAt/endBefore` overrides?

@Daeda88
Copy link
Contributor Author

Daeda88 commented Jul 11, 2025

@nbransby @Reedyuk Sorry for the looooooong delay in picking this up. Priorities just got in the way so I never got around to addressing this.

I've tracked latest master, corrected the readme and where possible moved things out of the public API.

On startAtFieldValues etc, yes, unfortunately
public fun startAt(builder: FieldValuesDSL.() -> Unit)
would clash with the existing
public fun startAt(vararg fieldValues: Any?, buildSettings: EncodeSettings.Builder.() -> Unit)
as kotlin would not know which closure to use if you just call startAt {}, assuming fieldValues to be empty. The alternative is of course to replace the latter with public fun startAt(firstFieldValue: Any?, vararg fieldValues: Any?, buildSettings: EncodeSettings.Builder.() -> Unit), as calling startAt without any fieldValues in the first place is probably wrong, but since that would break the API Im guessing nobody is in favor of that.

On some of the things in the API: see individual comments.

@DatL4g
Copy link

DatL4g commented Aug 8, 2025

@Daeda88 is this still a thing?

If so, it would be really nice if you rebase and create a PR here: https://github.com/DatL4g/firebase-kotlin-sdk

@nbransby
Copy link
Member

@Daeda88 looks good, lets deprecate the old methods (update, startAt, endAt) with the plan to rename these new ones eventually in a future 3.x release then I will merge

@Daeda88
Copy link
Contributor Author

Daeda88 commented Aug 22, 2025

Ok, I'm on holiday the upcoming week, will do that when I'm back

@Daeda88
Copy link
Contributor Author

Daeda88 commented Aug 31, 2025

@nbransby added deprecation/updateWith annotation. Hope its finally good to go! (almost exactly a year further but worth it 😂 )

@Daeda88
Copy link
Contributor Author

Daeda88 commented Sep 1, 2025

Glad to see its approved. Im assuming you're holding of on merging due to the CI issue, but I have no idea what's causing it as API dump doesnt trigger any changes for me locally

@nbransby
Copy link
Member

nbransby commented Sep 2, 2025

@Reedyuk any ideas on that?

@Reedyuk
Copy link
Collaborator

Reedyuk commented Sep 2, 2025

Seems to be that there is changes it wants to push but doesn't have the permission to push.
The intention was to get it to autocommit the changes but i think we are going to have to just make it fail instead.
The issue is because of permissions and forks, i guess its because the action runs on gitlives workspace and so doesnt have write access to the forked branch.

@Reedyuk
Copy link
Collaborator

Reedyuk commented Sep 2, 2025

Im not sure if @Daeda88 is on a mac, but it could be that we generate the ios api too now, whereas previously it was only done on jvm and js

@Daeda88
Copy link
Contributor Author

Daeda88 commented Sep 2, 2025

@Reedyuk API is only for JVM targets (android/jvm) and I am running on Mac regardless. So that cant be it. Running it now with a git status command to see what its trying to commit. Also, what's the point of the auto commit task if it doesnt work?

@nbransby nbransby merged commit 213546b into GitLiveApp:master Sep 2, 2025
49 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Encoder is no longer accessible?
4 participants