Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compat class for DocumentSnapshot #4051

Merged
merged 6 commits into from
Nov 11, 2020

Conversation

schmidt-sebastian
Copy link
Contributor

@schmidt-sebastian schmidt-sebastian commented Nov 9, 2020

This is the Compat class for DocumentSnapshot. The only real challenge here is that it we now either generate firestore-exp or Classic DocumentReferences or Bytes/Blob types. To facilitate this, I pass the UserDataWriter as an argument to the DocumentSnapshot.

@changeset-bot
Copy link

changeset-bot bot commented Nov 9, 2020

🦋 Changeset detected

Latest commit: 6f8e9a3

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 8 packages
Name Type
@firebase/firestore Patch
firebase Patch
@firebase/rules-unit-testing Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@@ -233,14 +237,15 @@ export function getDocsFromCache<T>(
): Promise<QuerySnapshot<T>> {
const firestore = cast(query.firestore, FirebaseFirestore);
const client = ensureFirestoreConfigured(firestore);
const userDataWriter = newExpUserDataWriter(firestore, query._converter);
Copy link
Contributor

Choose a reason for hiding this comment

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

Optional: you could save a little bit of memory by deferring the creation of the userDataWriter until you need it just as you're creating the QuerySnapshot.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I slightly prefer the current arrangement as I can use the same pattern across all functions. It also keeps the assignment in the Lambda shorter, which makes it fit one in line.

@@ -1233,3 +1247,14 @@ export function newUserDataReader(
serializer
);
}

export function newExpUserDataWriter<T>(
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm surprised this doesn't live closer to the UserDataWriter. It doesn't seem like it belongs in reference.ts.

Also, it's confusing that this is named newExpUserDataWriter but it lives in the lite SDK?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Huh, you do catch all the weirdness here :) I was hoping I could get away with this weird name. I ended up fixing this by applying your suggestion below. There is now a LiteUserDataWriter, an ExpUserDataWriter and an UserDataWriter (which we could name ClassicUserDataWriter, but I don't yet use this term in our class names). Note that LiteUserDataWriter and ExpUserDataWriter are essentially the same, but I kept them separate for clarity. I also re-exported the DocumentReference types from /exp/src/api/reference for additional clarity.

firestore: FirebaseFirestore,
converter: UntypedFirestoreDataConverter<T> | null
): UserDataWriter {
return new UserDataWriter(
Copy link
Contributor

Choose a reason for hiding this comment

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

A more traditional arrangement would be to have UserDataWriter be an abstract class and have different subclasses supply the conversion routines by implementing methods that are missing. Then you wouldn't need a newExpUserDataWriter function, you'd just invoke the constructor of the subtype instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I updated the PR as suggested (which would match what we discussed last week). I was a bit lazy in the first iteration, as the factory functions were already implemented.

convertValue(value: ProtoValue): unknown {
convertValue(
value: ProtoValue,
serverTimestampBehavior: ServerTimestampBehavior = 'none'
Copy link
Contributor

Choose a reason for hiding this comment

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

Why can't this remain a constructor parameter? That seemed like a cleaner arrangement.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Since I am now "injecting" the UserDataWriter when the DocumentSnapshot is constructed, I don't yet know what the setting for serverTimestampBehavior will be.

@wilhuff wilhuff assigned schmidt-sebastian and unassigned wilhuff Nov 10, 2020

protected convertReference(name: string): DocumentReference {
const key = this.convertDocumentKey(name, this.firestore._databaseId);
return DocumentReference.forKey(key, this.firestore, /* converter= */ null);
Copy link
Contributor

Choose a reason for hiding this comment

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

This seems like it now unconditionally creates a reference without a converter, where previously the converter was propagated in from the API construct that was used to create the reference/snapshot. Why is this OK?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I thought about this problem, but I think this new behavior actually makes sense. We don't know anything about the document that is referenced here, so it seems like we shouldn't assume that the original converter applies here. I think this is an edge case that probably no one noticed, but it would be pretty challenging to continue exposing the old behavior if we deemed this a breaking change.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think it's reasonable to call the old behavior a bug and call this a fix :-).

We should probably call this out in the release notes.

Copy link
Contributor

@wilhuff wilhuff left a comment

Choose a reason for hiding this comment

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

LGTM


protected convertReference(name: string): DocumentReference {
const key = this.convertDocumentKey(name, this.firestore._databaseId);
return DocumentReference.forKey(key, this.firestore, /* converter= */ null);
Copy link
Contributor

Choose a reason for hiding this comment

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

I think it's reasonable to call the old behavior a bug and call this a fix :-).

We should probably call this out in the release notes.

@wilhuff wilhuff assigned schmidt-sebastian and unassigned wilhuff Nov 11, 2020
@firebase firebase deleted a comment from google-oss-bot Nov 11, 2020
@google-oss-bot
Copy link
Contributor

google-oss-bot commented Nov 11, 2020

Size Analysis Report

Affected Products

No changes between base commit (8602cda) and head commit (a039cf1).

Test Logs

@schmidt-sebastian schmidt-sebastian merged commit d2adf4e into master Nov 11, 2020
@google-oss-bot google-oss-bot mentioned this pull request Nov 12, 2020
@firebase firebase locked and limited conversation to collaborators Dec 12, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants