@@ -28,15 +28,23 @@ import { FieldPath, ResourcePath } from '../model/path';
28
28
import { assert , fail } from '../util/assert' ;
29
29
import { Code , FirestoreError } from '../util/error' ;
30
30
import { isNullOrUndefined } from '../util/types' ;
31
+ import { Target } from './target' ;
31
32
33
+ /**
34
+ * Query encapsulates all the query attributes we support in the SDK. It can
35
+ * be run against the LocalStore, as well as be converted to a `Target` to
36
+ * query the RemoteStore results.
37
+ */
32
38
export class Query {
33
39
static atPath ( path : ResourcePath ) : Query {
34
40
return new Query ( path ) ;
35
41
}
36
42
37
- private memoizedCanonicalId : string | null = null ;
38
43
private memoizedOrderBy : OrderBy [ ] | null = null ;
39
44
45
+ // The corresponding `Target` of this `Query` instance.
46
+ private target : Target | null = null ;
47
+
40
48
/**
41
49
* Initializes a Query with a path and optional additional query constraints.
42
50
* Path must currently be empty if this is a collection group query.
@@ -219,107 +227,15 @@ export class Query {
219
227
// example, use as a dictionary key, but the implementation is subject to
220
228
// collisions. Make it collision-free.
221
229
canonicalId ( ) : string {
222
- if ( this . memoizedCanonicalId === null ) {
223
- let canonicalId = this . path . canonicalString ( ) ;
224
- if ( this . isCollectionGroupQuery ( ) ) {
225
- canonicalId += '|cg:' + this . collectionGroup ;
226
- }
227
- canonicalId += '|f:' ;
228
- for ( const filter of this . filters ) {
229
- canonicalId += filter . canonicalId ( ) ;
230
- canonicalId += ',' ;
231
- }
232
- canonicalId += '|ob:' ;
233
- // TODO(dimond): make this collision resistant
234
- for ( const orderBy of this . orderBy ) {
235
- canonicalId += orderBy . canonicalId ( ) ;
236
- canonicalId += ',' ;
237
- }
238
- if ( ! isNullOrUndefined ( this . limit ) ) {
239
- canonicalId += '|l:' ;
240
- canonicalId += this . limit ! ;
241
- }
242
- if ( this . startAt ) {
243
- canonicalId += '|lb:' ;
244
- canonicalId += this . startAt . canonicalId ( ) ;
245
- }
246
- if ( this . endAt ) {
247
- canonicalId += '|ub:' ;
248
- canonicalId += this . endAt . canonicalId ( ) ;
249
- }
250
- this . memoizedCanonicalId = canonicalId ;
251
- }
252
- return this . memoizedCanonicalId ;
230
+ return this . toTarget ( ) . canonicalId ( ) ;
253
231
}
254
232
255
233
toString ( ) : string {
256
- let str = 'Query(' + this . path . canonicalString ( ) ;
257
- if ( this . isCollectionGroupQuery ( ) ) {
258
- str += ' collectionGroup=' + this . collectionGroup ;
259
- }
260
- if ( this . filters . length > 0 ) {
261
- str += `, filters: [${ this . filters . join ( ', ' ) } ]` ;
262
- }
263
- if ( ! isNullOrUndefined ( this . limit ) ) {
264
- str += ', limit: ' + this . limit ;
265
- }
266
- if ( this . explicitOrderBy . length > 0 ) {
267
- str += `, orderBy: [${ this . explicitOrderBy . join ( ', ' ) } ]` ;
268
- }
269
- if ( this . startAt ) {
270
- str += ', startAt: ' + this . startAt . canonicalId ( ) ;
271
- }
272
- if ( this . endAt ) {
273
- str += ', endAt: ' + this . endAt . canonicalId ( ) ;
274
- }
275
-
276
- return str + ')' ;
234
+ return `Query(target=${ this . toTarget ( ) . toString ( ) } )` ;
277
235
}
278
236
279
237
isEqual ( other : Query ) : boolean {
280
- if ( this . limit !== other . limit ) {
281
- return false ;
282
- }
283
-
284
- if ( this . orderBy . length !== other . orderBy . length ) {
285
- return false ;
286
- }
287
-
288
- for ( let i = 0 ; i < this . orderBy . length ; i ++ ) {
289
- if ( ! this . orderBy [ i ] . isEqual ( other . orderBy [ i ] ) ) {
290
- return false ;
291
- }
292
- }
293
-
294
- if ( this . filters . length !== other . filters . length ) {
295
- return false ;
296
- }
297
-
298
- for ( let i = 0 ; i < this . filters . length ; i ++ ) {
299
- if ( ! this . filters [ i ] . isEqual ( other . filters [ i ] ) ) {
300
- return false ;
301
- }
302
- }
303
-
304
- if ( this . collectionGroup !== other . collectionGroup ) {
305
- return false ;
306
- }
307
-
308
- if ( ! this . path . isEqual ( other . path ) ) {
309
- return false ;
310
- }
311
-
312
- if (
313
- this . startAt !== null
314
- ? ! this . startAt . isEqual ( other . startAt )
315
- : other . startAt !== null
316
- ) {
317
- return false ;
318
- }
319
-
320
- return this . endAt !== null
321
- ? this . endAt . isEqual ( other . endAt )
322
- : other . endAt === null ;
238
+ return this . toTarget ( ) . isEqual ( other . toTarget ( ) ) ;
323
239
}
324
240
325
241
docComparator ( d1 : Document , d2 : Document ) : number {
@@ -381,17 +297,28 @@ export class Query {
381
297
}
382
298
383
299
isDocumentQuery ( ) : boolean {
384
- return (
385
- DocumentKey . isDocumentKey ( this . path ) &&
386
- this . collectionGroup === null &&
387
- this . filters . length === 0
388
- ) ;
300
+ return this . toTarget ( ) . isDocumentQuery ( ) ;
389
301
}
390
302
391
303
isCollectionGroupQuery ( ) : boolean {
392
304
return this . collectionGroup !== null ;
393
305
}
394
306
307
+ toTarget ( ) : Target {
308
+ if ( ! this . target ) {
309
+ this . target = new Target (
310
+ this . path ,
311
+ this . collectionGroup ,
312
+ this . orderBy ,
313
+ this . filters ,
314
+ this . limit ,
315
+ this . startAt ,
316
+ this . endAt
317
+ ) ;
318
+ }
319
+ return this . target ! ;
320
+ }
321
+
395
322
private matchesPathAndCollectionGroup ( doc : Document ) : boolean {
396
323
const docPath = doc . key . path ;
397
324
if ( this . collectionGroup !== null ) {
0 commit comments