Skip to content

Commit abda8e9

Browse files
Mutable Documents
1 parent e558d3e commit abda8e9

File tree

71 files changed

+2320
-2175
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+2320
-2175
lines changed

packages/firestore/src/api/user_data_reader.ts

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ import {
3636
Precondition,
3737
SetMutation
3838
} from '../model/mutation';
39-
import { ObjectValue, ObjectValueBuilder } from '../model/object_value';
39+
import { ObjectValue } from '../model/object_value';
4040
import { FieldPath as InternalFieldPath } from '../model/path';
4141
import {
4242
ArrayRemoveTransformOperation,
@@ -578,7 +578,7 @@ export function parseUpdateData(
578578
validatePlainObject('Data must be an object, but it was:', context, input);
579579

580580
const fieldMaskPaths: InternalFieldPath[] = [];
581-
const updateData = new ObjectValueBuilder();
581+
const updateData = ObjectValue.empty();
582582
forEach(input as Dict<unknown>, (key, value) => {
583583
const path = fieldPathFromDotSeparatedString(methodName, key, targetDoc);
584584

@@ -602,11 +602,7 @@ export function parseUpdateData(
602602
});
603603

604604
const mask = new FieldMask(fieldMaskPaths);
605-
return new ParsedUpdateData(
606-
updateData.build(),
607-
mask,
608-
context.fieldTransforms
609-
);
605+
return new ParsedUpdateData(updateData, mask, context.fieldTransforms);
610606
}
611607

612608
/** Parse update data from a list of field/value arguments. */
@@ -645,7 +641,7 @@ export function parseUpdateVarargs(
645641
}
646642

647643
const fieldMaskPaths: InternalFieldPath[] = [];
648-
const updateData = new ObjectValueBuilder();
644+
const updateData = ObjectValue.empty();
649645

650646
// We iterate in reverse order to pick the last value for a field if the
651647
// user specified the field multiple times.
@@ -675,11 +671,7 @@ export function parseUpdateVarargs(
675671
}
676672

677673
const mask = new FieldMask(fieldMaskPaths);
678-
return new ParsedUpdateData(
679-
updateData.build(),
680-
mask,
681-
context.fieldTransforms
682-
);
674+
return new ParsedUpdateData(updateData, mask, context.fieldTransforms);
683675
}
684676

685677
/**

packages/firestore/src/core/bundle.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717

1818
import { LoadBundleTaskProgress } from '@firebase/firestore-types';
1919

20-
import { MaybeDocumentMap } from '../model/collections';
21-
import { MaybeDocument } from '../model/document';
20+
import { MutableDocumentMap } from '../model/collections';
21+
import { Document } from '../model/document';
2222
import { DocumentKey } from '../model/document_key';
2323
import { BundledDocumentMetadata as ProtoBundledDocumentMetadata } from '../protos/firestore_bundle_proto';
2424
import {
@@ -28,6 +28,7 @@ import {
2828

2929
import { Query } from './query';
3030
import { SnapshotVersion } from './snapshot_version';
31+
import { MutableDocument } from '../model/mutable_document';
3132

3233
/**
3334
* Represents a bundled document, including the metadata and the document
@@ -46,7 +47,7 @@ export type BundledDocuments = BundledDocument[];
4647
export class BundleLoadResult {
4748
constructor(
4849
readonly progress: LoadBundleTaskProgress,
49-
readonly changedDocs: MaybeDocumentMap
50+
readonly changedDocs: MutableDocumentMap
5051
) {}
5152
}
5253

@@ -89,9 +90,9 @@ export interface BundleConverter {
8990
toDocumentKey(name: string): DocumentKey;
9091

9192
/**
92-
* Converts a BundleDocument to a MaybeDocument.
93+
* Converts a BundleDocument to a MutableDocument.
9394
*/
94-
toMaybeDocument(bundledDoc: BundledDocument): MaybeDocument;
95+
toMaybeDocument(bundledDoc: BundledDocument): MutableDocument;
9596

9697
toSnapshotVersion(time: ApiTimestamp): SnapshotVersion;
9798
}

packages/firestore/src/core/bundle_impl.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import {
2323
localStoreSaveNamedQuery
2424
} from '../local/local_store_impl';
2525
import { documentKeySet, DocumentKeySet } from '../model/collections';
26-
import { MaybeDocument, NoDocument } from '../model/document';
26+
import { Document } from '../model/document';
2727
import { DocumentKey } from '../model/document_key';
2828
import {
2929
BundleMetadata as ProtoBundleMetadata,
@@ -46,6 +46,7 @@ import {
4646
BundleLoadResult
4747
} from './bundle';
4848
import { SnapshotVersion } from './snapshot_version';
49+
import { MutableDocument } from '../model/mutable_document';
4950

5051
/**
5152
* Helper to convert objects from bundles to model objects in the SDK.
@@ -60,15 +61,15 @@ export class BundleConverterImpl implements BundleConverter {
6061
/**
6162
* Converts a BundleDocument to a MaybeDocument.
6263
*/
63-
toMaybeDocument(bundledDoc: BundledDocument): MaybeDocument {
64+
toMaybeDocument(bundledDoc: BundledDocument): MutableDocument {
6465
if (bundledDoc.metadata.exists) {
6566
debugAssert(
6667
!!bundledDoc.document,
6768
'Document is undefined when metadata.exist is true.'
6869
);
6970
return fromDocument(this.serializer, bundledDoc.document!, false);
7071
} else {
71-
return new NoDocument(
72+
return MutableDocument.newNoDocument(
7273
this.toDocumentKey(bundledDoc.metadata.name!),
7374
this.toSnapshotVersion(bundledDoc.metadata.readTime!)
7475
);

packages/firestore/src/core/firestore_client.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import {
3131
localStoreReadDocument
3232
} from '../local/local_store_impl';
3333
import { Persistence } from '../local/persistence';
34-
import { Document, NoDocument } from '../model/document';
34+
import { Document } from '../model/document';
3535
import { DocumentKey } from '../model/document_key';
3636
import { Mutation } from '../model/mutation';
3737
import { toByteStreamReader } from '../platform/byte_stream_reader';
@@ -85,6 +85,7 @@ import { Transaction } from './transaction';
8585
import { TransactionRunner } from './transaction_runner';
8686
import { View } from './view';
8787
import { ViewSnapshot } from './view_snapshot';
88+
import { MutableDocument } from '../model/mutable_document';
8889

8990
const LOG_TAG = 'FirestoreClient';
9091
export const MAX_CONCURRENT_LIMBO_RESOLUTIONS = 100;
@@ -498,10 +499,10 @@ async function readDocumentFromCache(
498499
result: Deferred<Document | null>
499500
): Promise<void> {
500501
try {
501-
const maybeDoc = await localStoreReadDocument(localStore, docKey);
502-
if (maybeDoc instanceof Document) {
503-
result.resolve(maybeDoc);
504-
} else if (maybeDoc instanceof NoDocument) {
502+
const document = await localStoreReadDocument(localStore, docKey);
503+
if (document.isFoundDocument()) {
504+
result.resolve(document);
505+
} else if (document.isNoDocument()) {
505506
result.resolve(null);
506507
} else {
507508
result.reject(

packages/firestore/src/core/query.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,7 @@ export function stringifyQuery(query: Query): string {
456456
/** Returns whether `doc` matches the constraints of `query`. */
457457
export function queryMatches(query: Query, doc: Document): boolean {
458458
return (
459+
doc.isFoundDocument() &&
459460
queryMatchesPathAndCollectionGroup(query, doc) &&
460461
queryMatchesOrderBy(query, doc) &&
461462
queryMatchesFilters(query, doc) &&
@@ -491,7 +492,7 @@ function queryMatchesPathAndCollectionGroup(
491492
function queryMatchesOrderBy(query: Query, doc: Document): boolean {
492493
for (const orderBy of query.explicitOrderBy) {
493494
// order by key always matches
494-
if (!orderBy.field.isKeyField() && doc.field(orderBy.field) === null) {
495+
if (!orderBy.field.isKeyField() && doc.data.field(orderBy.field) === null) {
495496
return false;
496497
}
497498
}

packages/firestore/src/core/sync_engine_impl.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,9 @@ import { TargetData, TargetPurpose } from '../local/target_data';
4545
import {
4646
DocumentKeySet,
4747
documentKeySet,
48-
MaybeDocumentMap
48+
DocumentMap,
49+
MutableDocumentMap
4950
} from '../model/collections';
50-
import { MaybeDocument, NoDocument } from '../model/document';
5151
import { DocumentKey } from '../model/document_key';
5252
import { Mutation } from '../model/mutation';
5353
import { MutationBatchResult } from '../model/mutation_batch';
@@ -114,6 +114,7 @@ import {
114114
ViewChange
115115
} from './view';
116116
import { ViewSnapshot } from './view_snapshot';
117+
import { MutableDocument } from '../model/mutable_document';
117118

118119
const LOG_TAG = 'SyncEngine';
119120

@@ -161,7 +162,7 @@ class LimboResolution {
161162
*/
162163
type ApplyDocChangesHandler = (
163164
queryView: QueryView,
164-
changes: MaybeDocumentMap,
165+
changes: DocumentMap,
165166
remoteEvent?: RemoteEvent
166167
) => Promise<ViewSnapshot | undefined>;
167168

@@ -618,12 +619,12 @@ export async function syncEngineRejectListen(
618619
// This is kind of a hack. Ideally, we would have a method in the local
619620
// store to purge a document. However, it would be tricky to keep all of
620621
// the local store's invariants with another method.
621-
let documentUpdates = new SortedMap<DocumentKey, MaybeDocument>(
622+
let documentUpdates = new SortedMap<DocumentKey, MutableDocument>(
622623
DocumentKey.comparator
623624
);
624625
documentUpdates = documentUpdates.insert(
625626
limboKey,
626-
new NoDocument(limboKey, SnapshotVersion.min())
627+
MutableDocument.newNoDocument(limboKey, SnapshotVersion.min())
627628
);
628629
const resolvedLimboDocuments = documentKeySet().add(limboKey);
629630
const event = new RemoteEvent(
@@ -1001,7 +1002,7 @@ export function syncEngineGetEnqueuedLimboDocumentResolutions(
10011002

10021003
export async function syncEngineEmitNewSnapsAndNotifyLocalStore(
10031004
syncEngine: SyncEngine,
1004-
changes: MaybeDocumentMap,
1005+
changes: DocumentMap,
10051006
remoteEvent?: RemoteEvent
10061007
): Promise<void> {
10071008
const syncEngineImpl = debugCast(syncEngine, SyncEngineImpl);
@@ -1052,7 +1053,7 @@ export async function syncEngineEmitNewSnapsAndNotifyLocalStore(
10521053
async function applyDocChanges(
10531054
syncEngineImpl: SyncEngineImpl,
10541055
queryView: QueryView,
1055-
changes: MaybeDocumentMap,
1056+
changes: DocumentMap,
10561057
remoteEvent?: RemoteEvent
10571058
): Promise<ViewSnapshot | undefined> {
10581059
let viewDocChanges = queryView.view.computeDocChanges(changes);

packages/firestore/src/core/target.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
* limitations under the License.
1616
*/
1717

18-
import { Document } from '../model/document';
1918
import { DocumentKey } from '../model/document_key';
2019
import { FieldPath, ResourcePath } from '../model/path';
2120
import {
@@ -30,6 +29,7 @@ import {
3029
import { Value as ProtoValue } from '../protos/firestore_proto_api';
3130
import { debugAssert, debugCast, fail } from '../util/assert';
3231
import { isNullOrUndefined } from '../util/types';
32+
import { Document } from '../model/document';
3333

3434
/**
3535
* A Target represents the WatchTarget representation of a Query, which is used
@@ -298,7 +298,7 @@ export class FieldFilter extends Filter {
298298
}
299299

300300
matches(doc: Document): boolean {
301-
const other = doc.field(this.field);
301+
const other = doc.data.field(this.field);
302302
// Types do not have to match in NOT_EQUAL filters.
303303
if (this.op === Operator.NOT_EQUAL) {
304304
return (
@@ -459,7 +459,7 @@ export class ArrayContainsFilter extends FieldFilter {
459459
}
460460

461461
matches(doc: Document): boolean {
462-
const other = doc.field(this.field);
462+
const other = doc.data.field(this.field);
463463
return isArray(other) && arrayValueContains(other.arrayValue, this.value);
464464
}
465465
}
@@ -472,7 +472,7 @@ export class InFilter extends FieldFilter {
472472
}
473473

474474
matches(doc: Document): boolean {
475-
const other = doc.field(this.field);
475+
const other = doc.data.field(this.field);
476476
return other !== null && arrayValueContains(this.value.arrayValue!, other);
477477
}
478478
}
@@ -490,7 +490,7 @@ export class NotInFilter extends FieldFilter {
490490
) {
491491
return false;
492492
}
493-
const other = doc.field(this.field);
493+
const other = doc.data.field(this.field);
494494
return other !== null && !arrayValueContains(this.value.arrayValue!, other);
495495
}
496496
}
@@ -503,7 +503,7 @@ export class ArrayContainsAnyFilter extends FieldFilter {
503503
}
504504

505505
matches(doc: Document): boolean {
506-
const other = doc.field(this.field);
506+
const other = doc.data.field(this.field);
507507
if (!isArray(other) || !other.arrayValue.values) {
508508
return false;
509509
}
@@ -588,7 +588,7 @@ export function sortsBeforeDocument(
588588
doc.key
589589
);
590590
} else {
591-
const docValue = doc.field(orderByComponent.field);
591+
const docValue = doc.data.field(orderByComponent.field);
592592
debugAssert(
593593
docValue !== null,
594594
'Field should exist since document matched the orderBy already.'

packages/firestore/src/core/transaction.ts

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
*/
1717

1818
import { ParsedSetData, ParsedUpdateData } from '../api/user_data_reader';
19-
import { Document, MaybeDocument, NoDocument } from '../model/document';
19+
import { Document } from '../model/document';
2020
import { DocumentKey } from '../model/document_key';
2121
import {
2222
DeleteMutation,
@@ -33,6 +33,7 @@ import { fail, debugAssert } from '../util/assert';
3333
import { Code, FirestoreError } from '../util/error';
3434

3535
import { SnapshotVersion } from './snapshot_version';
36+
import { MutableDocument } from '../model/mutable_document';
3637

3738
/**
3839
* Internal transaction object responsible for accumulating the mutations to
@@ -60,7 +61,7 @@ export class Transaction {
6061

6162
constructor(private datastore: Datastore) {}
6263

63-
async lookup(keys: DocumentKey[]): Promise<MaybeDocument[]> {
64+
async lookup(keys: DocumentKey[]): Promise<Document[]> {
6465
this.ensureCommitNotCalled();
6566

6667
if (this.mutations.length > 0) {
@@ -70,13 +71,7 @@ export class Transaction {
7071
);
7172
}
7273
const docs = await invokeBatchGetDocumentsRpc(this.datastore, keys);
73-
docs.forEach(doc => {
74-
if (doc instanceof NoDocument || doc instanceof Document) {
75-
this.recordVersion(doc);
76-
} else {
77-
fail('Document in a transaction was a ' + doc.constructor.name);
78-
}
79-
});
74+
docs.forEach(doc => this.recordVersion(doc));
8075
return docs;
8176
}
8277

@@ -120,12 +115,12 @@ export class Transaction {
120115
this.committed = true;
121116
}
122117

123-
private recordVersion(doc: MaybeDocument): void {
118+
private recordVersion(doc: Document): void {
124119
let docVersion: SnapshotVersion;
125120

126-
if (doc instanceof Document) {
121+
if (doc.isFoundDocument()) {
127122
docVersion = doc.version;
128-
} else if (doc instanceof NoDocument) {
123+
} else if (doc.isNoDocument()) {
129124
// For deleted docs, we must use baseVersion 0 when we overwrite them.
130125
docVersion = SnapshotVersion.min();
131126
} else {

0 commit comments

Comments
 (0)