Skip to content

Commit db7dae7

Browse files
author
Brian Chen
authored
Backport Android updateTransform changes (#4225)
1 parent 4512bc9 commit db7dae7

File tree

4 files changed

+30
-100
lines changed

4 files changed

+30
-100
lines changed

packages/firestore/src/model/mutation.ts

Lines changed: 27 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,11 @@ export class MutationResult {
8787
*/
8888
readonly version: SnapshotVersion,
8989
/**
90-
* The resulting fields returned from the backend after a
91-
* TransformMutation has been committed. Contains one FieldValue for each
92-
* FieldTransform that was in the mutation.
90+
* The resulting fields returned from the backend after a mutation
91+
* containing field transforms has been committed. Contains one FieldValue
92+
* for each FieldTransform that was in the mutation.
9393
*
94-
* Will be null if the mutation was not a TransformMutation.
94+
* Will be null if the mutation did not contain any field transforms.
9595
*/
9696
readonly transformResults: Array<ProtoValue | null> | null
9797
) {}
@@ -178,8 +178,8 @@ export function preconditionIsValidForDocument(
178178
* Mutations not only act on the value of the document but also its version.
179179
*
180180
* For local mutations (mutations that haven't been committed yet), we preserve
181-
* the existing version for Set, Patch, and Transform mutations. For Delete
182-
* mutations, we reset the version to 0.
181+
* the existing version for Set and Patch mutations. For Delete mutations, we
182+
* reset the version to 0.
183183
*
184184
* Here's the expected transition table.
185185
*
@@ -191,28 +191,22 @@ export function preconditionIsValidForDocument(
191191
* PatchMutation Document(v3) Document(v3)
192192
* PatchMutation NoDocument(v3) NoDocument(v3)
193193
* PatchMutation null null
194-
* TransformMutation Document(v3) Document(v3)
195-
* TransformMutation NoDocument(v3) NoDocument(v3)
196-
* TransformMutation null null
197194
* DeleteMutation Document(v3) NoDocument(v0)
198195
* DeleteMutation NoDocument(v3) NoDocument(v0)
199196
* DeleteMutation null NoDocument(v0)
200197
*
201198
* For acknowledged mutations, we use the updateTime of the WriteResponse as
202-
* the resulting version for Set, Patch, and Transform mutations. As deletes
203-
* have no explicit update time, we use the commitTime of the WriteResponse for
199+
* the resulting version for Set and Patch mutations. As deletes have no
200+
* explicit update time, we use the commitTime of the WriteResponse for
204201
* Delete mutations.
205202
*
206203
* If a mutation is acknowledged by the backend but fails the precondition check
207204
* locally, we return an `UnknownDocument` and rely on Watch to send us the
208205
* updated version.
209206
*
210-
* Note that TransformMutations don't create Documents (in the case of being
211-
* applied to a NoDocument), even though they would on the backend. This is
212-
* because the client always combines the TransformMutation with a SetMutation
213-
* or PatchMutation and we only want to apply the transform if the prior
214-
* mutation resulted in a Document (always true for a SetMutation, but not
215-
* necessarily for a PatchMutation).
207+
* Field transforms are used only with Patch and Set Mutations. We use the
208+
* `updateTransforms` message to store transforms, rather than the `transforms`s
209+
* messages.
216210
*
217211
* ## Subclassing Notes
218212
*
@@ -335,13 +329,7 @@ export function extractMutationBaseValue(
335329
mutation: Mutation,
336330
maybeDoc: MaybeDocument | null
337331
): ObjectValue | null {
338-
if (mutation.fieldTransforms !== undefined) {
339-
return extractTransformMutationBaseValue(
340-
mutation.fieldTransforms,
341-
maybeDoc
342-
);
343-
}
344-
return null;
332+
return extractTransformMutationBaseValue(mutation.fieldTransforms, maybeDoc);
345333
}
346334

347335
function extractTransformMutationBaseValue(
@@ -489,19 +477,17 @@ function applySetMutationToLocalView(
489477
}
490478

491479
let newData = mutation.value;
492-
if (mutation.fieldTransforms) {
493-
const transformResults = localTransformResults(
494-
mutation.fieldTransforms,
495-
localWriteTime,
496-
maybeDoc,
497-
baseDoc
498-
);
499-
newData = transformObject(
500-
mutation.fieldTransforms,
501-
newData,
502-
transformResults
503-
);
504-
}
480+
const transformResults = localTransformResults(
481+
mutation.fieldTransforms,
482+
localWriteTime,
483+
maybeDoc,
484+
baseDoc
485+
);
486+
newData = transformObject(
487+
mutation.fieldTransforms,
488+
newData,
489+
transformResults
490+
);
505491

506492
const version = getPostMutationVersion(maybeDoc);
507493
return new Document(mutation.key, version, newData, {
@@ -623,8 +609,8 @@ function patchObject(mutation: PatchMutation, data: ObjectValue): ObjectValue {
623609

624610
/**
625611
* Creates a list of "transform results" (a transform result is a field value
626-
* representing the result of applying a transform) for use after a
627-
* TransformMutation has been acknowledged by the server.
612+
* representing the result of applying a transform) for use after a mutation
613+
* containing transforms has been acknowledged by the server.
628614
*
629615
* @param fieldTransforms - The field transforms to apply the result to.
630616
* @param baseDoc - The document prior to applying this mutation batch.
@@ -664,10 +650,10 @@ function serverTransformResults(
664650
/**
665651
* Creates a list of "transform results" (a transform result is a field value
666652
* representing the result of applying a transform) for use when applying a
667-
* TransformMutation locally.
653+
* transform locally.
668654
*
669655
* @param fieldTransforms - The field transforms to apply the result to.
670-
* @param localWriteTime - The local time of the transform mutation (used to
656+
* @param localWriteTime - The local time of the mutation (used to
671657
* generate ServerTimestampValues).
672658
* @param maybeDoc - The current state of the document after applying all
673659
* previous mutations.
@@ -689,14 +675,6 @@ function localTransformResults(
689675
previousValue = maybeDoc.field(fieldTransform.field);
690676
}
691677

692-
if (previousValue === null && baseDoc instanceof Document) {
693-
// If the current document does not contain a value for the mutated
694-
// field, use the value that existed before applying this mutation
695-
// batch. This solves an edge case where a PatchMutation clears the
696-
// values in a nested map before the TransformMutation is applied.
697-
previousValue = baseDoc.field(fieldTransform.field);
698-
}
699-
700678
transformResults.push(
701679
applyTransformOperationToLocalView(
702680
transform,

packages/firestore/src/model/server_timestamps.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,8 @@ import { normalizeTimestamp } from './normalize';
3333
*
3434
* Notes:
3535
* - ServerTimestampValue instances are created as the result of applying a
36-
* TransformMutation (see TransformMutation.applyTo()). They can only exist in
37-
* the local view of a document. Therefore they do not need to be parsed or
38-
* serialized.
36+
* transform. They can only exist in the local view of a document. Therefore
37+
* they do not need to be parsed or serialized.
3938
* - When evaluated locally (e.g. for snapshot.data()), they by default
4039
* evaluate to `null`. This behavior can be configured by passing custom
4140
* FieldValueOptions to value().

packages/firestore/src/model/transform_operation.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import { normalizeNumber } from './normalize';
2525
import { serverTimestamp } from './server_timestamps';
2626
import { isArray, isInteger, isNumber, valueEquals } from './values';
2727

28-
/** Represents a transform within a TransformMutation. */
28+
/** Used to represent a field transform on a mutation. */
2929
export class TransformOperation {
3030
// Make sure that the structural type of `TransformOperation` is unique.
3131
// See https://github.com/microsoft/TypeScript/issues/5451

packages/firestore/test/integration/api/server_timestamp.test.ts

Lines changed: 0 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -104,25 +104,6 @@ apiDescribe('Server Timestamps', (persistence: boolean) => {
104104
);
105105
}
106106

107-
/**
108-
* Verifies a snapshot containing setData but using the previous field value
109-
* for the timestamps.
110-
*/
111-
function verifyTimestampsUsePreviousValue(
112-
current: firestore.DocumentSnapshot,
113-
prev: firestore.DocumentSnapshot | null
114-
): void {
115-
if (!prev) {
116-
verifyTimestampsAreNull(current);
117-
} else {
118-
expect(current.exists).to.equal(true);
119-
const when = prev.get('when');
120-
expect(current.data({ serverTimestamps: 'previous' })).to.deep.equal(
121-
expectedDataWithTimestamp(when)
122-
);
123-
}
124-
}
125-
126107
/**
127108
* Wraps a test, getting a docRef and event accumulator, and cleaning them
128109
* up when done.
@@ -207,34 +188,6 @@ apiDescribe('Server Timestamps', (persistence: boolean) => {
207188
});
208189
});
209190

210-
it('can return previous value', () => {
211-
// The following test includes an update of the nested map "deep", which
212-
// updates it to contain a single ServerTimestamp. This update is split
213-
// into two mutations: One that sets "deep" to an empty map and overwrites
214-
// the previous ServerTimestamp value and a second transform that writes
215-
// the new ServerTimestamp. This step in the test verifies that we can
216-
// still access the old ServerTimestamp value (from `previousSnapshot`) even
217-
// though it was removed in an intermediate step.
218-
219-
let previousSnapshot: firestore.DocumentSnapshot;
220-
221-
return withTestSetup(() => {
222-
return writeInitialData()
223-
.then(() => docRef.update(updateData))
224-
.then(() => accumulator.awaitLocalEvent())
225-
.then(snapshot => verifyTimestampsUsePreviousValue(snapshot, null))
226-
.then(() => accumulator.awaitRemoteEvent())
227-
.then(snapshot => {
228-
previousSnapshot = snapshot;
229-
})
230-
.then(() => docRef.update(updateData))
231-
.then(() => accumulator.awaitLocalEvent())
232-
.then(snapshot =>
233-
verifyTimestampsUsePreviousValue(snapshot, previousSnapshot)
234-
);
235-
});
236-
});
237-
238191
it('can return previous value of different type', () => {
239192
return withTestSetup(() => {
240193
return writeInitialData()

0 commit comments

Comments
 (0)