@@ -33,41 +33,45 @@ import { ParseContext, parseData, UserDataSource } from './user_data_reader';
33
33
import { debugAssert } from '../util/assert' ;
34
34
35
35
/**
36
- * An opaque base class for FieldValue sentinel objects in our public API,
37
- * with public static methods for creating said sentinel objects .
36
+ * An opaque base class for FieldValue sentinel objects in our public API that
37
+ * is shared between the full, lite and legacy SDK .
38
38
*/
39
- export abstract class FieldValueImpl {
40
- protected constructor ( readonly _methodName : string ) { }
39
+ export abstract class SerializableFieldValue {
40
+ /** The public API endpoint that returns this class. */
41
+ abstract readonly _methodName : string ;
41
42
42
- abstract toFieldTransform ( context : ParseContext ) : FieldTransform | null ;
43
+ /** A pointer to the implementing class. */
44
+ readonly _delegate : SerializableFieldValue = this ;
43
45
44
- abstract isEqual ( other : FieldValue ) : boolean ;
46
+ abstract _toFieldTransform ( context : ParseContext ) : FieldTransform | null ;
47
+
48
+ abstract isEqual ( other : SerializableFieldValue ) : boolean ;
45
49
}
46
50
47
- export class DeleteFieldValueImpl extends FieldValueImpl {
48
- constructor ( ) {
49
- super ( 'FieldValue.delete' ) ;
51
+ export class DeleteFieldValueImpl extends SerializableFieldValue {
52
+ constructor ( readonly _methodName : string ) {
53
+ super ( ) ;
50
54
}
51
55
52
- toFieldTransform ( context : ParseContext ) : null {
56
+ _toFieldTransform ( context : ParseContext ) : null {
53
57
if ( context . dataSource === UserDataSource . MergeSet ) {
54
58
// No transform to add for a delete, but we need to add it to our
55
59
// fieldMask so it gets deleted.
56
60
context . fieldMask . push ( context . path ! ) ;
57
61
} else if ( context . dataSource === UserDataSource . Update ) {
58
62
debugAssert (
59
63
context . path ! . length > 0 ,
60
- 'FieldValue.delete () at the top level should have already' +
61
- ' been handled.'
64
+ ` ${ this . _methodName } () at the top level should have already ` +
65
+ 'been handled.'
62
66
) ;
63
67
throw context . createError (
64
- 'FieldValue.delete () can only appear at the top level ' +
68
+ ` ${ this . _methodName } () can only appear at the top level ` +
65
69
'of your update data'
66
70
) ;
67
71
} else {
68
72
// We shouldn't encounter delete sentinels for queries or non-merge set() calls.
69
73
throw context . createError (
70
- 'FieldValue.delete () cannot be used with set() unless you pass ' +
74
+ ` ${ this . _methodName } () cannot be used with set() unless you pass ` +
71
75
'{merge:true}'
72
76
) ;
73
77
}
@@ -79,12 +83,12 @@ export class DeleteFieldValueImpl extends FieldValueImpl {
79
83
}
80
84
}
81
85
82
- export class ServerTimestampFieldValueImpl extends FieldValueImpl {
83
- constructor ( ) {
84
- super ( 'FieldValue.serverTimestamp' ) ;
86
+ export class ServerTimestampFieldValueImpl extends SerializableFieldValue {
87
+ constructor ( readonly _methodName : string ) {
88
+ super ( ) ;
85
89
}
86
90
87
- toFieldTransform ( context : ParseContext ) : FieldTransform {
91
+ _toFieldTransform ( context : ParseContext ) : FieldTransform {
88
92
return new FieldTransform ( context . path ! , ServerTimestampTransform . instance ) ;
89
93
}
90
94
@@ -93,12 +97,15 @@ export class ServerTimestampFieldValueImpl extends FieldValueImpl {
93
97
}
94
98
}
95
99
96
- export class ArrayUnionFieldValueImpl extends FieldValueImpl {
97
- constructor ( private readonly _elements : unknown [ ] ) {
98
- super ( 'FieldValue.arrayUnion' ) ;
100
+ export class ArrayUnionFieldValueImpl extends SerializableFieldValue {
101
+ constructor (
102
+ readonly _methodName : string ,
103
+ private readonly _elements : unknown [ ]
104
+ ) {
105
+ super ( ) ;
99
106
}
100
107
101
- toFieldTransform ( context : ParseContext ) : FieldTransform {
108
+ _toFieldTransform ( context : ParseContext ) : FieldTransform {
102
109
// Although array transforms are used with writes, the actual elements
103
110
// being uniomed or removed are not considered writes since they cannot
104
111
// contain any FieldValue sentinels, etc.
@@ -125,12 +132,12 @@ export class ArrayUnionFieldValueImpl extends FieldValueImpl {
125
132
}
126
133
}
127
134
128
- export class ArrayRemoveFieldValueImpl extends FieldValueImpl {
129
- constructor ( readonly _elements : unknown [ ] ) {
130
- super ( 'FieldValue.arrayRemove' ) ;
135
+ export class ArrayRemoveFieldValueImpl extends SerializableFieldValue {
136
+ constructor ( readonly _methodName : string , readonly _elements : unknown [ ] ) {
137
+ super ( ) ;
131
138
}
132
139
133
- toFieldTransform ( context : ParseContext ) : FieldTransform {
140
+ _toFieldTransform ( context : ParseContext ) : FieldTransform {
134
141
// Although array transforms are used with writes, the actual elements
135
142
// being unioned or removed are not considered writes since they cannot
136
143
// contain any FieldValue sentinels, etc.
@@ -157,12 +164,12 @@ export class ArrayRemoveFieldValueImpl extends FieldValueImpl {
157
164
}
158
165
}
159
166
160
- export class NumericIncrementFieldValueImpl extends FieldValueImpl {
161
- constructor ( private readonly _operand : number ) {
162
- super ( 'FieldValue.increment' ) ;
167
+ export class NumericIncrementFieldValueImpl extends SerializableFieldValue {
168
+ constructor ( readonly _methodName : string , private readonly _operand : number ) {
169
+ super ( ) ;
163
170
}
164
171
165
- toFieldTransform ( context : ParseContext ) : FieldTransform {
172
+ _toFieldTransform ( context : ParseContext ) : FieldTransform {
166
173
const parseContext = new ParseContext (
167
174
{
168
175
dataSource : UserDataSource . Argument ,
@@ -186,38 +193,75 @@ export class NumericIncrementFieldValueImpl extends FieldValueImpl {
186
193
}
187
194
}
188
195
189
- export class FieldValue implements firestore . FieldValue {
190
- static delete ( ) : FieldValueImpl {
196
+ /** The public FieldValue class of the lite API. */
197
+ export abstract class FieldValue extends SerializableFieldValue
198
+ implements firestore . FieldValue {
199
+ static delete ( ) : firestore . FieldValue {
191
200
validateNoArgs ( 'FieldValue.delete' , arguments ) ;
192
- return new DeleteFieldValueImpl ( ) ;
201
+ return new FieldValueDelegate (
202
+ new DeleteFieldValueImpl ( 'FieldValue.delete' )
203
+ ) ;
193
204
}
194
205
195
- static serverTimestamp ( ) : FieldValueImpl {
206
+ static serverTimestamp ( ) : firestore . FieldValue {
196
207
validateNoArgs ( 'FieldValue.serverTimestamp' , arguments ) ;
197
- return new ServerTimestampFieldValueImpl ( ) ;
208
+ return new FieldValueDelegate (
209
+ new ServerTimestampFieldValueImpl ( 'FieldValue.serverTimestamp' )
210
+ ) ;
198
211
}
199
212
200
- static arrayUnion ( ...elements : unknown [ ] ) : FieldValueImpl {
213
+ static arrayUnion ( ...elements : unknown [ ] ) : firestore . FieldValue {
201
214
validateAtLeastNumberOfArgs ( 'FieldValue.arrayUnion' , arguments , 1 ) ;
202
215
// NOTE: We don't actually parse the data until it's used in set() or
203
- // update() since we need access to the Firestore instance.
204
- return new ArrayUnionFieldValueImpl ( elements ) ;
216
+ // update() since we'd need the Firestore instance to do this.
217
+ return new FieldValueDelegate (
218
+ new ArrayUnionFieldValueImpl ( 'FieldValue.arrayUnion' , elements )
219
+ ) ;
205
220
}
206
221
207
- static arrayRemove ( ...elements : unknown [ ] ) : FieldValueImpl {
222
+ static arrayRemove ( ...elements : unknown [ ] ) : firestore . FieldValue {
208
223
validateAtLeastNumberOfArgs ( 'FieldValue.arrayRemove' , arguments , 1 ) ;
209
224
// NOTE: We don't actually parse the data until it's used in set() or
210
- // update() since we need access to the Firestore instance.
211
- return new ArrayRemoveFieldValueImpl ( elements ) ;
225
+ // update() since we'd need the Firestore instance to do this.
226
+ return new FieldValueDelegate (
227
+ new ArrayRemoveFieldValueImpl ( 'FieldValue.arrayRemove' , elements )
228
+ ) ;
212
229
}
213
230
214
- static increment ( n : number ) : FieldValueImpl {
231
+ static increment ( n : number ) : firestore . FieldValue {
215
232
validateArgType ( 'FieldValue.increment' , 'number' , 1 , n ) ;
216
233
validateExactNumberOfArgs ( 'FieldValue.increment' , arguments , 1 ) ;
217
- return new NumericIncrementFieldValueImpl ( n ) ;
234
+ return new FieldValueDelegate (
235
+ new NumericIncrementFieldValueImpl ( 'FieldValue.increment' , n )
236
+ ) ;
218
237
}
238
+ }
219
239
220
- isEqual ( other : FieldValue ) : boolean {
221
- return this === other ;
240
+ /**
241
+ * A delegate class that allows the FieldValue implementations returned by
242
+ * deleteField(), serverTimestamp(), arrayUnion(), arrayRemove() and
243
+ * increment() to be an instance of the legacy FieldValue class declared above.
244
+ *
245
+ * We don't directly subclass `FieldValue` in the various field value
246
+ * implementations as the base FieldValue class differs between the lite, full
247
+ * and legacy SDK.
248
+ */
249
+ class FieldValueDelegate extends FieldValue implements firestore . FieldValue {
250
+ readonly _methodName : string ;
251
+
252
+ constructor ( readonly _delegate : SerializableFieldValue ) {
253
+ super ( ) ;
254
+ this . _methodName = _delegate . _methodName ;
255
+ }
256
+
257
+ _toFieldTransform ( context : ParseContext ) : FieldTransform | null {
258
+ return this . _delegate . _toFieldTransform ( context ) ;
259
+ }
260
+
261
+ isEqual ( other : firestore . FieldValue ) : boolean {
262
+ if ( ! ( other instanceof FieldValueDelegate ) ) {
263
+ return false ;
264
+ }
265
+ return this . _delegate . isEqual ( other . _delegate ) ;
222
266
}
223
267
}
0 commit comments