Skip to content

Commit d4602fd

Browse files
Simplify Document (#2685)
1 parent 5a603db commit d4602fd

File tree

8 files changed

+48
-170
lines changed

8 files changed

+48
-170
lines changed

packages/firestore/src/local/local_serializer.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,7 @@ export class LocalSerializer {
7979
const dbReadTime = this.toDbTimestampKey(readTime);
8080
const parentPath = maybeDoc.key.path.popLast().toArray();
8181
if (maybeDoc instanceof Document) {
82-
const doc = maybeDoc.proto
83-
? maybeDoc.proto
84-
: this.remoteSerializer.toDocument(maybeDoc);
82+
const doc = this.remoteSerializer.toDocument(maybeDoc);
8583
const hasCommittedMutations = maybeDoc.hasCommittedMutations;
8684
return new DbRemoteDocument(
8785
/* unknownDocument= */ null,

packages/firestore/src/model/document.ts

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

1818
import { SnapshotVersion } from '../core/snapshot_version';
19-
import { assert, fail } from '../util/assert';
19+
import { fail } from '../util/assert';
2020

2121
import { DocumentKey } from './document_key';
2222
import { FieldValue, JsonObject, ObjectValue } from './field_value';
2323
import { FieldPath } from './path';
2424

25-
import * as api from '../protos/firestore_proto_api';
26-
import * as obj from '../util/obj';
27-
2825
export interface DocumentOptions {
2926
hasLocalMutations?: boolean;
3027
hasCommittedMutations?: boolean;
@@ -60,76 +57,22 @@ export class Document extends MaybeDocument {
6057
readonly hasLocalMutations: boolean;
6158
readonly hasCommittedMutations: boolean;
6259

63-
/**
64-
* A cache of canonicalized FieldPaths to FieldValues that have already been
65-
* deserialized in `getField()`.
66-
*/
67-
private fieldValueCache?: Map<string, FieldValue | null>;
68-
6960
constructor(
7061
key: DocumentKey,
7162
version: SnapshotVersion,
72-
options: DocumentOptions,
73-
private objectValue?: ObjectValue,
74-
readonly proto?: api.Document,
75-
private readonly converter?: (value: api.Value) => FieldValue
63+
private readonly objectValue: ObjectValue,
64+
options: DocumentOptions
7665
) {
7766
super(key, version);
78-
assert(
79-
this.objectValue !== undefined ||
80-
(this.proto !== undefined && this.converter !== undefined),
81-
'If objectValue is not defined, proto and converter need to be set.'
82-
);
83-
8467
this.hasLocalMutations = !!options.hasLocalMutations;
8568
this.hasCommittedMutations = !!options.hasCommittedMutations;
8669
}
8770

8871
field(path: FieldPath): FieldValue | null {
89-
if (this.objectValue) {
90-
return this.objectValue.field(path);
91-
} else {
92-
if (!this.fieldValueCache) {
93-
// TODO(b/136090445): Remove the cache when `getField` is no longer
94-
// called during Query ordering.
95-
this.fieldValueCache = new Map<string, FieldValue>();
96-
}
97-
98-
const canonicalPath = path.canonicalString();
99-
100-
let fieldValue = this.fieldValueCache.get(canonicalPath);
101-
102-
if (fieldValue === undefined) {
103-
// Instead of deserializing the full Document proto, we only
104-
// deserialize the value at the requested field path. This speeds up
105-
// Query execution as query filters can discard documents based on a
106-
// single field.
107-
const protoValue = this.getProtoField(path);
108-
if (protoValue === undefined) {
109-
fieldValue = null;
110-
} else {
111-
fieldValue = this.converter!(protoValue);
112-
}
113-
this.fieldValueCache.set(canonicalPath, fieldValue);
114-
}
115-
116-
return fieldValue!;
117-
}
72+
return this.objectValue.field(path);
11873
}
11974

12075
data(): ObjectValue {
121-
if (!this.objectValue) {
122-
const result = ObjectValue.newBuilder();
123-
obj.forEach(this.proto!.fields || {}, (key: string, value: api.Value) => {
124-
result.set(new FieldPath([key]), this.converter!(value));
125-
});
126-
this.objectValue = result.build();
127-
128-
// Once objectValue is computed, values inside the fieldValueCache are no
129-
// longer accessed.
130-
this.fieldValueCache = undefined;
131-
}
132-
13376
return this.objectValue;
13477
}
13578

@@ -144,13 +87,13 @@ export class Document extends MaybeDocument {
14487
this.version.isEqual(other.version) &&
14588
this.hasLocalMutations === other.hasLocalMutations &&
14689
this.hasCommittedMutations === other.hasCommittedMutations &&
147-
this.data().isEqual(other.data())
90+
this.objectValue.isEqual(other.objectValue)
14891
);
14992
}
15093

15194
toString(): string {
15295
return (
153-
`Document(${this.key}, ${this.version}, ${this.data().toString()}, ` +
96+
`Document(${this.key}, ${this.version}, ${this.objectValue.toString()}, ` +
15497
`{hasLocalMutations: ${this.hasLocalMutations}}), ` +
15598
`{hasCommittedMutations: ${this.hasCommittedMutations}})`
15699
);
@@ -160,29 +103,6 @@ export class Document extends MaybeDocument {
160103
return this.hasLocalMutations || this.hasCommittedMutations;
161104
}
162105

163-
/**
164-
* Returns the nested Protobuf value for 'path`. Can only be called if
165-
* `proto` was provided at construction time.
166-
*/
167-
private getProtoField(path: FieldPath): api.Value | undefined {
168-
assert(
169-
this.proto !== undefined,
170-
'Can only call getProtoField() when proto is defined'
171-
);
172-
173-
let protoValue: api.Value | undefined = this.proto!.fields
174-
? this.proto!.fields[path.firstSegment()]
175-
: undefined;
176-
for (let i = 1; i < path.length; ++i) {
177-
if (!protoValue || !protoValue.mapValue || !protoValue.mapValue.fields) {
178-
return undefined;
179-
}
180-
protoValue = protoValue.mapValue.fields[path.get(i)];
181-
}
182-
183-
return protoValue;
184-
}
185-
186106
static compareByField(field: FieldPath, d1: Document, d2: Document): number {
187107
const v1 = d1.field(field);
188108
const v2 = d2.field(field);

packages/firestore/src/model/mutation.ts

Lines changed: 18 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -354,14 +354,9 @@ export class SetMutation extends Mutation {
354354
// have held.
355355

356356
const version = mutationResult.version;
357-
return new Document(
358-
this.key,
359-
version,
360-
{
361-
hasCommittedMutations: true
362-
},
363-
this.value
364-
);
357+
return new Document(this.key, version, this.value, {
358+
hasCommittedMutations: true
359+
});
365360
}
366361

367362
applyToLocalView(
@@ -376,14 +371,9 @@ export class SetMutation extends Mutation {
376371
}
377372

378373
const version = Mutation.getPostMutationVersion(maybeDoc);
379-
return new Document(
380-
this.key,
381-
version,
382-
{
383-
hasLocalMutations: true
384-
},
385-
this.value
386-
);
374+
return new Document(this.key, version, this.value, {
375+
hasLocalMutations: true
376+
});
387377
}
388378

389379
extractBaseValue(maybeDoc: MaybeDocument | null): null {
@@ -445,14 +435,9 @@ export class PatchMutation extends Mutation {
445435
}
446436

447437
const newData = this.patchDocument(maybeDoc);
448-
return new Document(
449-
this.key,
450-
mutationResult.version,
451-
{
452-
hasCommittedMutations: true
453-
},
454-
newData
455-
);
438+
return new Document(this.key, mutationResult.version, newData, {
439+
hasCommittedMutations: true
440+
});
456441
}
457442

458443
applyToLocalView(
@@ -468,14 +453,9 @@ export class PatchMutation extends Mutation {
468453

469454
const version = Mutation.getPostMutationVersion(maybeDoc);
470455
const newData = this.patchDocument(maybeDoc);
471-
return new Document(
472-
this.key,
473-
version,
474-
{
475-
hasLocalMutations: true
476-
},
477-
newData
478-
);
456+
return new Document(this.key, version, newData, {
457+
hasLocalMutations: true
458+
});
479459
}
480460

481461
extractBaseValue(maybeDoc: MaybeDocument | null): null {
@@ -573,14 +553,9 @@ export class TransformMutation extends Mutation {
573553

574554
const version = mutationResult.version;
575555
const newData = this.transformObject(doc.data(), transformResults);
576-
return new Document(
577-
this.key,
578-
version,
579-
{
580-
hasCommittedMutations: true
581-
},
582-
newData
583-
);
556+
return new Document(this.key, version, newData, {
557+
hasCommittedMutations: true
558+
});
584559
}
585560

586561
applyToLocalView(
@@ -601,14 +576,9 @@ export class TransformMutation extends Mutation {
601576
baseDoc
602577
);
603578
const newData = this.transformObject(doc.data(), transformResults);
604-
return new Document(
605-
this.key,
606-
doc.version,
607-
{
608-
hasLocalMutations: true
609-
},
610-
newData
611-
);
579+
return new Document(this.key, doc.version, newData, {
580+
hasLocalMutations: true
581+
});
612582
}
613583

614584
extractBaseValue(maybeDoc: MaybeDocument | null): ObjectValue | null {

packages/firestore/src/model/proto_values.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ function compareTimestamps(
242242
if (typeof left === 'string' && typeof right === 'string') {
243243
// Use string ordering for ISO 8601 timestamps, but strip the timezone
244244
// suffix to ensure proper ordering for timestamps of different precision.
245-
// The only supported timezone is UTC (i.e. 'Z') based on
245+
// The only supported timezone is UTC (i.e. 'Z') based on
246246
// ISO_TIMESTAMP_REG_EXP.
247247
return primitiveComparator(left.slice(0, -1), right.slice(0, -1));
248248
}

packages/firestore/src/remote/serializer.ts

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -483,14 +483,10 @@ export class JsonProtoSerializer {
483483
): Document {
484484
const key = this.fromName(document.name!);
485485
const version = this.fromVersion(document.updateTime!);
486-
return new Document(
487-
key,
488-
version,
489-
{ hasCommittedMutations: !!hasCommittedMutations },
490-
undefined,
491-
document,
492-
v => this.fromValue(v)
493-
);
486+
const data = this.fromFields(document.fields!);
487+
return new Document(key, version, data, {
488+
hasCommittedMutations: !!hasCommittedMutations
489+
});
494490
}
495491

496492
toFields(fields: fieldValue.ObjectValue): { [key: string]: api.Value } {
@@ -534,9 +530,8 @@ export class JsonProtoSerializer {
534530
assertPresent(doc.found.updateTime, 'doc.found.updateTime');
535531
const key = this.fromName(doc.found.name);
536532
const version = this.fromVersion(doc.found.updateTime);
537-
return new Document(key, version, {}, undefined, doc.found, v =>
538-
this.fromValue(v)
539-
);
533+
const data = this.fromFields(doc.found.fields!);
534+
return new Document(key, version, data, {});
540535
}
541536

542537
private fromMissing(result: api.BatchGetDocumentsResponse): NoDocument {
@@ -673,14 +668,8 @@ export class JsonProtoSerializer {
673668
);
674669
const key = this.fromName(entityChange.document.name);
675670
const version = this.fromVersion(entityChange.document.updateTime);
676-
const doc = new Document(
677-
key,
678-
version,
679-
{},
680-
undefined,
681-
entityChange.document!,
682-
v => this.fromValue(v)
683-
);
671+
const data = this.fromFields(entityChange.document.fields!);
672+
const doc = new Document(key, version, data, {});
684673
const updatedTargetIds = entityChange.targetIds || [];
685674
const removedTargetIds = entityChange.removedTargetIds || [];
686675
watchChange = new DocumentWatchChange(

packages/firestore/test/unit/local/lru_garbage_collector.test.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -247,8 +247,11 @@ function genericLruGarbageCollectorTests(
247247
return new Document(
248248
key,
249249
SnapshotVersion.fromMicroseconds(1000),
250-
{},
251-
wrapObject({ foo: 3, bar: false })
250+
wrapObject({
251+
foo: 3,
252+
bar: false
253+
}),
254+
{}
252255
);
253256
}
254257

@@ -782,8 +785,11 @@ function genericLruGarbageCollectorTests(
782785
const doc = new Document(
783786
middleDocToUpdate,
784787
SnapshotVersion.fromMicroseconds(2000),
785-
{},
786-
wrapObject({ foo: 4, bar: true })
788+
wrapObject({
789+
foo: 4,
790+
bar: true
791+
}),
792+
{}
787793
);
788794
return saveDocument(txn, doc).next(() => {
789795
return updateTargetInTransaction(txn, middleTarget);

packages/firestore/test/unit/model/mutation.test.ts

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -202,14 +202,9 @@ describe('Mutation', () => {
202202
.toBuilder()
203203
.set(field('foo.bar'), new ServerTimestampValue(timestamp, null))
204204
.build();
205-
const expectedDoc = new Document(
206-
key('collection/key'),
207-
version(0),
208-
{
209-
hasLocalMutations: true
210-
},
211-
data
212-
);
205+
const expectedDoc = new Document(key('collection/key'), version(0), data, {
206+
hasLocalMutations: true
207+
});
213208

214209
expect(transformedDoc).to.deep.equal(expectedDoc);
215210
});

packages/firestore/test/util/helpers.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ export function doc(
125125
json: JsonObject<unknown>,
126126
options: DocumentOptions = {}
127127
): Document {
128-
return new Document(key(keyStr), version(ver), options, wrapObject(json));
128+
return new Document(key(keyStr), version(ver), wrapObject(json), options);
129129
}
130130

131131
export function deletedDoc(

0 commit comments

Comments
 (0)