Created
May 4, 2018 18:28
-
-
Save schmidt-sebastian/6dd9cb25015d14bc96d742c3d27d6fc6 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/packages/firestore/src/api/user_data_converter.ts b/packages/firestore/src/api/user_data_converter.ts | |
index a37f1be1..9544dbef 100644 | |
--- a/packages/firestore/src/api/user_data_converter.ts | |
+++ b/packages/firestore/src/api/user_data_converter.ts | |
@@ -173,6 +173,7 @@ class ParseContext { | |
constructor( | |
readonly dataSource: UserDataSource, | |
readonly methodName: string, | |
+ readonly localWriteTime: Timestamp, | |
readonly path: FieldPath | null, | |
readonly arrayElement?: boolean, | |
fieldTransforms?: FieldTransform[], | |
@@ -193,6 +194,7 @@ class ParseContext { | |
const context = new ParseContext( | |
this.dataSource, | |
this.methodName, | |
+ this.localWriteTime, | |
childPath, | |
/*arrayElement=*/ false, | |
this.fieldTransforms, | |
@@ -207,6 +209,7 @@ class ParseContext { | |
const context = new ParseContext( | |
this.dataSource, | |
this.methodName, | |
+ this.localWriteTime, | |
childPath, | |
/*arrayElement=*/ false, | |
this.fieldTransforms, | |
@@ -222,6 +225,7 @@ class ParseContext { | |
return new ParseContext( | |
this.dataSource, | |
this.methodName, | |
+ this.localWriteTime, | |
/*path=*/ null, | |
/*arrayElement=*/ true, | |
this.fieldTransforms, | |
@@ -295,6 +299,7 @@ export class UserDataConverter { | |
const context = new ParseContext( | |
UserDataSource.Set, | |
methodName, | |
+ Timestamp.now(), | |
FieldPath.EMPTY_PATH | |
); | |
validatePlainObject('Data must be an object, but it was:', context, input); | |
@@ -317,6 +322,7 @@ export class UserDataConverter { | |
const context = new ParseContext( | |
UserDataSource.MergeSet, | |
methodName, | |
+ Timestamp.now(), | |
FieldPath.EMPTY_PATH | |
); | |
validatePlainObject('Data must be an object, but it was:', context, input); | |
@@ -371,6 +377,7 @@ export class UserDataConverter { | |
const context = new ParseContext( | |
UserDataSource.Update, | |
methodName, | |
+ Timestamp.now(), | |
FieldPath.EMPTY_PATH | |
); | |
validatePlainObject('Data must be an object, but it was:', context, input); | |
@@ -408,6 +415,7 @@ export class UserDataConverter { | |
const context = new ParseContext( | |
UserDataSource.Update, | |
methodName, | |
+ Timestamp.now(), | |
FieldPath.EMPTY_PATH | |
); | |
const keys = [fieldPathFromArgument(methodName, field)]; | |
@@ -461,6 +469,7 @@ export class UserDataConverter { | |
const context = new ParseContext( | |
UserDataSource.Argument, | |
methodName, | |
+ Timestamp.now(), | |
FieldPath.EMPTY_PATH | |
); | |
const parsed = this.parseData(input, context); | |
@@ -601,12 +610,16 @@ export class UserDataConverter { | |
} | |
} else if (value instanceof ServerTimestampFieldValueImpl) { | |
context.fieldTransforms.push( | |
- new FieldTransform(context.path, ServerTimestampTransform.instance) | |
+ new FieldTransform( | |
+ context.path, | |
+ new ServerTimestampTransform(context.localWriteTime) | |
+ ) | |
); | |
} else if (value instanceof ArrayUnionFieldValueImpl) { | |
const parsedElements = this.parseArrayTransformElements( | |
value.methodName, | |
- value._elements | |
+ value._elements, | |
+ context | |
); | |
const arrayUnion = new ArrayUnionTransformOperation(parsedElements); | |
context.fieldTransforms.push( | |
@@ -615,7 +628,8 @@ export class UserDataConverter { | |
} else if (value instanceof ArrayRemoveFieldValueImpl) { | |
const parsedElements = this.parseArrayTransformElements( | |
value.methodName, | |
- value._elements | |
+ value._elements, | |
+ context | |
); | |
const arrayRemove = new ArrayRemoveTransformOperation(parsedElements); | |
context.fieldTransforms.push( | |
@@ -671,17 +685,22 @@ export class UserDataConverter { | |
private parseArrayTransformElements( | |
methodName: string, | |
- elements: AnyJs[] | |
+ elements: AnyJs[], | |
+ oldcontext: ParseContext | |
): FieldValue[] { | |
return elements.map((element, i) => { | |
// Although array transforms are used with writes, the actual elements | |
// being unioned or removed are not considered writes since they cannot | |
// contain any FieldValue sentinels, etc. | |
+ | |
+ // This should be .childContextForArgument or something along those lines | |
const context = new ParseContext( | |
UserDataSource.Argument, | |
methodName, | |
+ oldcontext.localWriteTime, | |
FieldPath.EMPTY_PATH | |
); | |
+ | |
return this.parseData(element, context.childContextForArray(i)); | |
}); | |
} | |
diff --git a/packages/firestore/src/local/local_serializer.ts b/packages/firestore/src/local/local_serializer.ts | |
index 5fa4d850..e1d8476e 100644 | |
--- a/packages/firestore/src/local/local_serializer.ts | |
+++ b/packages/firestore/src/local/local_serializer.ts | |
@@ -83,10 +83,10 @@ export class LocalSerializer { | |
/** Decodes a DbMutationBatch into a MutationBatch */ | |
fromDbMutationBatch(dbBatch: DbMutationBatch): MutationBatch { | |
+ const timestamp = Timestamp.fromMillis(dbBatch.localWriteTimeMs); | |
const mutations = dbBatch.mutations.map(m => | |
- this.remoteSerializer.fromMutation(m) | |
+ this.remoteSerializer.fromMutation(m, timestamp) | |
); | |
- const timestamp = Timestamp.fromMillis(dbBatch.localWriteTimeMs); | |
return new MutationBatch(dbBatch.batchId, timestamp, mutations); | |
} | |
diff --git a/packages/firestore/src/model/mutation.ts b/packages/firestore/src/model/mutation.ts | |
index 4d6e4d42..da2f41df 100644 | |
--- a/packages/firestore/src/model/mutation.ts | |
+++ b/packages/firestore/src/model/mutation.ts | |
@@ -243,8 +243,7 @@ export abstract class Mutation { | |
*/ | |
abstract applyToLocalView( | |
maybeDoc: MaybeDocument | null, | |
- baseDoc: MaybeDocument | null, | |
- localWriteTime: Timestamp | |
+ baseDoc: MaybeDocument | null | |
): MaybeDocument | null; | |
abstract isEqual(other: Mutation): boolean; | |
@@ -313,8 +312,7 @@ export class SetMutation extends Mutation { | |
applyToLocalView( | |
maybeDoc: MaybeDocument | null, | |
- baseDoc: MaybeDocument | null, | |
- localWriteTime: Timestamp | |
+ baseDoc: MaybeDocument | null | |
): MaybeDocument | null { | |
this.verifyKeyMatches(maybeDoc); | |
@@ -393,8 +391,7 @@ export class PatchMutation extends Mutation { | |
applyToLocalView( | |
maybeDoc: MaybeDocument | null, | |
- baseDoc: MaybeDocument | null, | |
- localWriteTime: Timestamp | |
+ baseDoc: MaybeDocument | null | |
): MaybeDocument | null { | |
this.verifyKeyMatches(maybeDoc); | |
@@ -504,8 +501,7 @@ export class TransformMutation extends Mutation { | |
applyToLocalView( | |
maybeDoc: MaybeDocument | null, | |
- baseDoc: MaybeDocument | null, | |
- localWriteTime: Timestamp | |
+ baseDoc: MaybeDocument | null | |
): MaybeDocument | null { | |
this.verifyKeyMatches(maybeDoc); | |
@@ -514,10 +510,7 @@ export class TransformMutation extends Mutation { | |
} | |
const doc = this.requireDocument(maybeDoc); | |
- const transformResults = this.localTransformResults( | |
- localWriteTime, | |
- baseDoc | |
- ); | |
+ const transformResults = this.localTransformResults(baseDoc); | |
const newData = this.transformObject(doc.data, transformResults); | |
return new Document(this.key, doc.version, newData, { | |
hasLocalMutations: true | |
@@ -606,10 +599,7 @@ export class TransformMutation extends Mutation { | |
* @param baseDoc The document prior to applying this mutation batch. | |
* @return The transform results list. | |
*/ | |
- private localTransformResults( | |
- localWriteTime: Timestamp, | |
- baseDoc: MaybeDocument | null | |
- ): FieldValue[] { | |
+ private localTransformResults(baseDoc: MaybeDocument | null): FieldValue[] { | |
const transformResults = [] as FieldValue[]; | |
for (const fieldTransform of this.fieldTransforms) { | |
const transform = fieldTransform.transform; | |
@@ -619,7 +609,7 @@ export class TransformMutation extends Mutation { | |
previousValue = baseDoc.field(fieldTransform.field) || null; | |
} | |
- transformResults.push(transform.transform(previousValue, localWriteTime)); | |
+ transformResults.push(transform.transform(previousValue)); | |
} | |
return transformResults; | |
} | |
@@ -670,8 +660,7 @@ export class DeleteMutation extends Mutation { | |
applyToLocalView( | |
maybeDoc: MaybeDocument | null, | |
- baseDoc: MaybeDocument | null, | |
- localWriteTime: Timestamp | |
+ baseDoc: MaybeDocument | null | |
): MaybeDocument | null { | |
this.verifyKeyMatches(maybeDoc); | |
diff --git a/packages/firestore/src/model/mutation_batch.ts b/packages/firestore/src/model/mutation_batch.ts | |
index c5fc7661..69bc449a 100644 | |
--- a/packages/firestore/src/model/mutation_batch.ts | |
+++ b/packages/firestore/src/model/mutation_batch.ts | |
@@ -104,11 +104,7 @@ export class MutationBatch { | |
for (let i = 0; i < this.mutations.length; i++) { | |
const mutation = this.mutations[i]; | |
if (mutation.key.isEqual(docKey)) { | |
- maybeDoc = mutation.applyToLocalView( | |
- maybeDoc, | |
- baseDoc, | |
- this.localWriteTime | |
- ); | |
+ maybeDoc = mutation.applyToLocalView(maybeDoc, baseDoc); | |
} | |
} | |
return maybeDoc; | |
diff --git a/packages/firestore/src/model/transform_operation.ts b/packages/firestore/src/model/transform_operation.ts | |
index 14f009ba..ab1e2034 100644 | |
--- a/packages/firestore/src/model/transform_operation.ts | |
+++ b/packages/firestore/src/model/transform_operation.ts | |
@@ -22,22 +22,17 @@ import { assert } from '../util/assert'; | |
/** Represents a transform within a TransformMutation. */ | |
export interface TransformOperation { | |
/** Transforms the provided `previousValue`. */ | |
- transform(previousValue: FieldValue, localWriteTime?: Timestamp): FieldValue; | |
+ transform(previousValue: FieldValue): FieldValue; | |
isEqual(other: TransformOperation): boolean; | |
} | |
/** Transforms a value into a server-generated timestamp. */ | |
export class ServerTimestampTransform implements TransformOperation { | |
- private constructor() {} | |
- static instance = new ServerTimestampTransform(); | |
+ constructor(private localWriteTime: Timestamp) {} | |
- transform(previousValue: FieldValue, localWriteTime?: Timestamp): FieldValue { | |
- assert( | |
- localWriteTime !== undefined, | |
- 'ServerTimestampTransform.transform() requires localWriteTime.' | |
- ); | |
- return new ServerTimestampValue(localWriteTime!, previousValue); | |
+ transform(previousValue: FieldValue): FieldValue { | |
+ return new ServerTimestampValue(this.localWriteTime, previousValue); | |
} | |
isEqual(other: TransformOperation): boolean { | |
@@ -49,7 +44,7 @@ export class ServerTimestampTransform implements TransformOperation { | |
export class ArrayUnionTransformOperation implements TransformOperation { | |
constructor(readonly elements: FieldValue[]) {} | |
- transform(previousValue: FieldValue, localWriteTime?: Timestamp): FieldValue { | |
+ transform(previousValue: FieldValue): FieldValue { | |
const result = coercedFieldValuesArray(previousValue); | |
for (const toUnion of this.elements) { | |
if (!result.find(element => element.isEqual(toUnion))) { | |
@@ -71,7 +66,7 @@ export class ArrayUnionTransformOperation implements TransformOperation { | |
export class ArrayRemoveTransformOperation implements TransformOperation { | |
constructor(readonly elements: FieldValue[]) {} | |
- transform(previousValue: FieldValue, localWriteTime?: Timestamp): FieldValue { | |
+ transform(previousValue: FieldValue): FieldValue { | |
let result = coercedFieldValuesArray(previousValue); | |
for (const toRemove of this.elements) { | |
result = result.filter(element => !element.isEqual(toRemove)); | |
diff --git a/packages/firestore/src/remote/serializer.ts b/packages/firestore/src/remote/serializer.ts | |
index 42915e45..eab52f38 100644 | |
--- a/packages/firestore/src/remote/serializer.ts | |
+++ b/packages/firestore/src/remote/serializer.ts | |
@@ -836,7 +836,7 @@ export class JsonProtoSerializer { | |
return result; | |
} | |
- fromMutation(proto: api.Write): Mutation { | |
+ fromMutation(proto: api.Write, writeTime: Timestamp): Mutation { | |
const precondition = proto.currentDocument | |
? this.fromPrecondition(proto.currentDocument) | |
: Precondition.NONE; | |
@@ -857,7 +857,7 @@ export class JsonProtoSerializer { | |
} else if (proto.transform) { | |
const key = this.fromName(proto.transform.document!); | |
const fieldTransforms = proto.transform.fieldTransforms!.map(transform => | |
- this.fromFieldTransform(transform) | |
+ this.fromFieldTransform(transform, writeTime) | |
); | |
assert( | |
precondition.exists === true, | |
@@ -936,7 +936,10 @@ export class JsonProtoSerializer { | |
} | |
} | |
- private fromFieldTransform(proto: api.FieldTransform): FieldTransform { | |
+ private fromFieldTransform( | |
+ proto: api.FieldTransform, | |
+ writeTime: Timestamp | |
+ ): FieldTransform { | |
// tslint:disable-next-line:no-any We need to match generated Proto types. | |
const type = (proto as any)['transform_type']; | |
let transform: TransformOperation | null = null; | |
@@ -945,7 +948,7 @@ export class JsonProtoSerializer { | |
proto.setToServerValue === 'REQUEST_TIME', | |
'Unknown server value transform proto: ' + JSON.stringify(proto) | |
); | |
- transform = ServerTimestampTransform.instance; | |
+ transform = new ServerTimestampTransform(writeTime); | |
} else if (hasTag(proto, type, 'appendMissingElements')) { | |
const values = proto.appendMissingElements!.values || []; | |
transform = new ArrayUnionTransformOperation( |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment