-
Notifications
You must be signed in to change notification settings - Fork 945
Make Documents mutable #4548
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
Make Documents mutable #4548
Conversation
|
3993f15
to
abda8e9
Compare
Binary Size ReportAffected SDKs
Test Logs
|
306e59a
to
e83e967
Compare
10587ca
to
ead9034
Compare
let newDoc = newMaybeDoc instanceof Document ? newMaybeDoc : null; | ||
if (newDoc) { | ||
debugAssert( | ||
key.isEqual(newDoc.key), | ||
'Mismatching keys found in document changes: ' + | ||
key + | ||
' != ' + | ||
newDoc.key | ||
); | ||
newDoc = queryMatches(this.query, newDoc) ? newDoc : null; | ||
} |
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 should be the only actual change here.
const builder = new ObjectValueBuilder(); | ||
const object = builder.build(); | ||
expect(object.isEqual(ObjectValue.empty())).to.be.true; | ||
describe('MutableObjectValue', () => { |
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.
I would like to rename this file to mutable_object_value.test.ts
but GitHub then sees it as a new file, so I will do this after the first review.
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.
FYI I will handle this when I port firebase/firebase-android-sdk#2494
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.
Mostly documentation nits with a few questions. Thanks for taking the time to go over this with me!
@@ -140,7 +139,7 @@ export function getDocFromCache<T>( | |||
reference._key, | |||
doc, | |||
new SnapshotMetadata( | |||
doc instanceof Document ? doc.hasLocalMutations : false, | |||
doc !== null && doc.hasLocalMutations, |
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.
Why don't we have to check the Document's state is FOUND_DOCUMENT
?
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 only use Document or null in our API layer. That's why I kept this pattern - anything that is not a Document is returned as null
once it leaves FirestoreClient
.
txn, | ||
changedDocs | ||
); | ||
return changedDocs; |
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.
Do you have to chain changedDocs off of applyLocalViewToDocuments
since it's a promise?
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.
Wow. Uhm. Yes. That's a pretty bad bug. Thanks for catching.
) | ||
); | ||
); | ||
return changedDocs; |
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.
Same here as above. Do we have to chain it?
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.
Fixed
@@ -48,7 +44,7 @@ export interface RemoteDocumentCache { | |||
getEntry( | |||
transaction: PersistenceTransaction, | |||
documentKey: DocumentKey | |||
): PersistencePromise<MaybeDocument | null>; | |||
): PersistencePromise<MutableDocument>; |
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.
Update jsdoc since we don't have MaybeDocument anymore. Also update the RemoteDocumentCache
interface description as well.
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.
Fixed here and on top.
@@ -441,13 +443,13 @@ function fromMissing( | |||
); | |||
const key = fromName(serializer, result.missing); | |||
const version = fromVersion(result.readTime); | |||
return new NoDocument(key, version); | |||
return MutableDocument.newNoDocument(key, version); | |||
} | |||
|
|||
export function fromMaybeDocument( |
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.
update function name since we don't use maybeDocument anymore.
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.
Updated to fromBatchGetDocumentsResponse
this.addDocumentToTarget(targetId, docChange.newDoc); | ||
} else if (docChange.newDoc instanceof NoDocument) { | ||
} else { |
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.
Question: How are we sure that this has type NO_DOCUMENT in order to remove the else if
?
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 is the Watch code. Watch can either send as a document or a delete. Unknown documents are only used with latency compensation, and invalid documents are only used for document lookups for keys that are not cached.
@@ -708,7 +713,7 @@ export function documentSet(...args: unknown[]): DocumentSet { | |||
} | |||
for (const doc of args) { | |||
debugAssert( | |||
doc instanceof Document, | |||
doc instanceof MutableDocument, |
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.
optional: It looks a bit weird that this checks for MutableDocument
, but the input parameter is Document[]
. docSet.add()
also takes in Document
as a parameter. Change parameter signature to MutableDocument
, or assertion to Document
?
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.
Interfaces can't be used in instanceof checks.
for (const docOrKey of docsOrKeys) { | ||
if (docOrKey instanceof Document) { | ||
if (docOrKey instanceof MutableDocument) { |
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.
optional: Same question as comment below, should this use Document
instead?
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.
Interfaces can't be used in instanceof checks.
return this.partialValue; | ||
} | ||
|
||
private extractNestedValue( |
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.
optional: this method can be static.
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.
Done (FWIW I just got the same comment on the iOS PR)
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 the thorough review! Someone deserves a vacation!
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.
lgtm!
@@ -134,7 +133,7 @@ export function getDoc<T>( | |||
reference.firestore, | |||
userDataWriter, | |||
reference._key, | |||
maybeDocument instanceof Document ? maybeDocument : null, | |||
maybeDocument.isFoundDocument() ? maybeDocument : null, |
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.
nit: rename maybeDocument variable since that concept no longer exists.
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.
Done
@@ -63,6 +58,7 @@ import { | |||
DbUnknownDocument | |||
} from './indexeddb_schema'; | |||
import { TargetData, TargetPurpose } from './target_data'; | |||
import { Timestamp } from '../exp/timestamp'; |
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.
Fix lint
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.
I think this was already fixed.
export interface DocumentOptions { | ||
hasLocalMutations?: boolean; | ||
hasCommittedMutations?: boolean; | ||
const enum DocumentType { |
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.
optional: add jsdoc description for `DocumentType
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.
Done
* returned. | ||
* Applies this mutation to the given document for the purposes of computing a | ||
* new remote document. If the input document doesn't match the expected state | ||
* (e.g. it is invalid or outdated), the document state may transition to |
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.
nit: s/state/type
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.
Done
This is a port of firebase/firebase-android-sdk#2383 and firebase/firebase-android-sdk#2468. The goal is to reduce the number of object creations, so that we can have clear object ownership in the C++ clients. With this change, the documents are owned either by the RemoteDocumentCache or by the View that contains them. Mutations mutate these existing documents and do not create copies.
The existing document hierarchy is removed and replaced by a single MutableDocument type that allows documents to transition between four states:
I kept Document, but it is now an interface that makes sure that we no longer modify the documents once we store them in View. MutableDocuments are produces by the RemoteDocumentCache and via RemoteEvents. We then apply all mutations and from then onwards treat them as Documents.
ObjectValue and ObjectValueBuilder are also merged to reduce immutable object creation.
There should be no functional changes. firebase/firebase-android-sdk#2383 contains a bunch of discussions that might help with this review.