Skip to content

Commit dd878df

Browse files
Merge 2a0ac56 into 74621b7
2 parents 74621b7 + 2a0ac56 commit dd878df

File tree

4 files changed

+53
-23
lines changed

4 files changed

+53
-23
lines changed

packages/firestore/CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
# Unreleased
2+
- [fixed] Fixed a regression introduced in v7.14.2 that incorrectly applied
3+
a `FieldValue.increment` in combination with `set({...}, {merge: true})`.
24
- [fixed] Firestore now rejects `onSnapshot()` listeners if they cannot be
35
registered in IndexedDB. Previously, these errors crashed the client.
46
- [fixed] Firestore now rejects write operations if they cannot be persisted

packages/firestore/src/api/field_value.ts

+29-12
Original file line numberDiff line numberDiff line change
@@ -102,12 +102,17 @@ export class ArrayUnionFieldValueImpl extends FieldValueImpl {
102102
// Although array transforms are used with writes, the actual elements
103103
// being uniomed or removed are not considered writes since they cannot
104104
// contain any FieldValue sentinels, etc.
105-
const parseContext = context.contextWith({
106-
dataSource: UserDataSource.Argument,
107-
methodName: this._methodName
108-
});
105+
const parseContext = new ParseContext(
106+
{
107+
dataSource: UserDataSource.Argument,
108+
methodName: this._methodName,
109+
arrayElement: true
110+
},
111+
context.databaseId,
112+
context.serializer
113+
);
109114
const parsedElements = this._elements.map(
110-
(element, i) => parseData(element, parseContext.childContextForArray(i))!
115+
element => parseData(element, parseContext)!
111116
);
112117
const arrayUnion = new ArrayUnionTransformOperation(parsedElements);
113118
return new FieldTransform(context.path!, arrayUnion);
@@ -128,12 +133,17 @@ export class ArrayRemoveFieldValueImpl extends FieldValueImpl {
128133
// Although array transforms are used with writes, the actual elements
129134
// being unioned or removed are not considered writes since they cannot
130135
// contain any FieldValue sentinels, etc.
131-
const parseContext = context.contextWith({
132-
dataSource: UserDataSource.Argument,
133-
methodName: this._methodName
134-
});
136+
const parseContext = new ParseContext(
137+
{
138+
dataSource: UserDataSource.Argument,
139+
methodName: this._methodName,
140+
arrayElement: true
141+
},
142+
context.databaseId,
143+
context.serializer
144+
);
135145
const parsedElements = this._elements.map(
136-
(element, i) => parseData(element, parseContext.childContextForArray(i))!
146+
element => parseData(element, parseContext)!
137147
);
138148
const arrayUnion = new ArrayRemoveTransformOperation(parsedElements);
139149
return new FieldTransform(context.path!, arrayUnion);
@@ -151,8 +161,15 @@ export class NumericIncrementFieldValueImpl extends FieldValueImpl {
151161
}
152162

153163
toFieldTransform(context: ParseContext): FieldTransform {
154-
context.contextWith({ methodName: this._methodName });
155-
const operand = parseData(this._operand, context)!;
164+
const parseContext = new ParseContext(
165+
{
166+
dataSource: UserDataSource.Argument,
167+
methodName: this._methodName
168+
},
169+
context.databaseId,
170+
context.serializer
171+
);
172+
const operand = parseData(this._operand, parseContext)!;
156173
const numericIncrement = new NumericIncrementTransformOperation(
157174
context.serializer,
158175
operand

packages/firestore/src/api/user_data_reader.ts

+13-10
Original file line numberDiff line numberDiff line change
@@ -140,9 +140,12 @@ interface ContextSettings {
140140
* nonempty path (indicating the context represents a nested location within
141141
* the data).
142142
*/
143-
readonly path: FieldPath | null;
144-
/** Whether or not this context corresponds to an element of an array. */
145-
readonly arrayElement: boolean;
143+
readonly path?: FieldPath;
144+
/**
145+
* Whether or not this context corresponds to an element of an array.
146+
* If not set, elements are treated as if they were outside of arrays.
147+
*/
148+
readonly arrayElement?: boolean;
146149
}
147150

148151
/** A "context" object passed around while parsing user data. */
@@ -181,7 +184,7 @@ export class ParseContext {
181184
this.fieldMask = fieldMask || [];
182185
}
183186

184-
get path(): FieldPath | null {
187+
get path(): FieldPath | undefined {
185188
return this.settings.path;
186189
}
187190

@@ -201,28 +204,28 @@ export class ParseContext {
201204
}
202205

203206
childContextForField(field: string): ParseContext {
204-
const childPath = this.path == null ? null : this.path.child(field);
207+
const childPath = this.path?.child(field);
205208
const context = this.contextWith({ path: childPath, arrayElement: false });
206209
context.validatePathSegment(field);
207210
return context;
208211
}
209212

210213
childContextForFieldPath(field: FieldPath): ParseContext {
211-
const childPath = this.path == null ? null : this.path.child(field);
214+
const childPath = this.path?.child(field);
212215
const context = this.contextWith({ path: childPath, arrayElement: false });
213216
context.validatePath();
214217
return context;
215218
}
216219

217220
childContextForArray(index: number): ParseContext {
218221
// TODO(b/34871131): We don't support array paths right now; so make path
219-
// null.
220-
return this.contextWith({ path: null, arrayElement: true });
222+
// undefined.
223+
return this.contextWith({ path: undefined, arrayElement: true });
221224
}
222225

223226
createError(reason: string): Error {
224227
const fieldDescription =
225-
this.path === null || this.path.isEmpty()
228+
!this.path || this.path.isEmpty()
226229
? ''
227230
: ` (found in field ${this.path.toString()})`;
228231
return new FirestoreError(
@@ -246,7 +249,7 @@ export class ParseContext {
246249
private validatePath(): void {
247250
// TODO(b/34871131): Remove null check once we have proper paths for fields
248251
// within arrays.
249-
if (this.path === null) {
252+
if (!this.path) {
250253
return;
251254
}
252255
for (let i = 0; i < this.path.length; i++) {

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

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/**
22
* @license
3-
* Copyright 2018 Google Inc.
3+
* Copyright 2018 Google LLC
44
*
55
* Licensed under the Apache License, Version 2.0 (the "License");
66
* you may not use this file except in compliance with the License.
@@ -140,6 +140,14 @@ apiDescribe('Numeric Transforms:', (persistence: boolean) => {
140140
});
141141
});
142142

143+
it('increments with set() and merge:true', async () => {
144+
await withTestSetup(async () => {
145+
await writeInitialData({ sum: 1 });
146+
await docRef.set({ sum: FieldValue.increment(1337) }, { merge: true });
147+
await expectLocalAndRemoteValue(1338);
148+
});
149+
});
150+
143151
it('multiple double increments', async () => {
144152
await withTestSetup(async () => {
145153
await writeInitialData({ sum: 0.0 });

0 commit comments

Comments
 (0)