@@ -43,7 +43,7 @@ export const enum LimitType {
43
43
/**
44
44
* The Query interface defines all external properties of a query.
45
45
*
46
- * QueryImpl implements this interface to provide memoization for `queryOrderBy `
46
+ * QueryImpl implements this interface to provide memoization for `queryNormalizedOrderBy `
47
47
* and `queryToTarget`.
48
48
*/
49
49
export interface Query {
@@ -65,7 +65,7 @@ export interface Query {
65
65
* Visible for testing.
66
66
*/
67
67
export class QueryImpl implements Query {
68
- memoizedOrderBy : OrderBy [ ] | null = null ;
68
+ memoizedNormalizedOrderBy : OrderBy [ ] | null = null ;
69
69
70
70
// The corresponding `Target` of this `Query` instance.
71
71
memoizedTarget : Target | null = null ;
@@ -86,13 +86,13 @@ export class QueryImpl implements Query {
86
86
) {
87
87
if ( this . startAt ) {
88
88
debugAssert (
89
- this . startAt . position . length <= queryOrderBy ( this ) . length ,
89
+ this . startAt . position . length <= queryNormalizedOrderBy ( this ) . length ,
90
90
'Bound is longer than orderBy'
91
91
) ;
92
92
}
93
93
if ( this . endAt ) {
94
94
debugAssert (
95
- this . endAt . position . length <= queryOrderBy ( this ) . length ,
95
+ this . endAt . position . length <= queryNormalizedOrderBy ( this ) . length ,
96
96
'Bound is longer than orderBy'
97
97
) ;
98
98
}
@@ -211,32 +211,16 @@ export function isCollectionGroupQuery(query: Query): boolean {
211
211
}
212
212
213
213
/**
214
- * Returns the implicit order by constraint that is used to execute the Query,
214
+ * Returns the normalized order by constraint that is used to execute the Query,
215
215
* which can be different from the order by constraints the user provided (e.g.
216
- * the SDK and backend always orders by `__name__`).
216
+ * the SDK and backend always orders by `__name__`). The normalized order-by
217
+ * includes implicit order-bys in addition to the explicit user provided
218
+ * order-bys.
217
219
*/
218
- export function queryOrderBy (
219
- query : Query ,
220
- settings ?: { includeImplicitOrderBy : boolean }
221
- ) : OrderBy [ ] {
222
- if ( ! settings ) {
223
- settings = {
224
- includeImplicitOrderBy : true
225
- } ;
226
- }
227
-
220
+ export function queryNormalizedOrderBy ( query : Query ) : OrderBy [ ] {
228
221
const queryImpl = debugCast ( query , QueryImpl ) ;
229
- if ( queryImpl . memoizedOrderBy === null ) {
230
- queryImpl . memoizedOrderBy = [ ] ;
231
-
232
- // If there are no explicit order-by operators, and we are not including
233
- // implicit order-bys, then return the empty memoizedOrderBy result
234
- if (
235
- queryImpl . explicitOrderBy . length === 0 &&
236
- ! settings . includeImplicitOrderBy
237
- ) {
238
- return queryImpl . memoizedOrderBy ;
239
- }
222
+ if ( queryImpl . memoizedNormalizedOrderBy === null ) {
223
+ queryImpl . memoizedNormalizedOrderBy = [ ] ;
240
224
241
225
const inequalityField = getInequalityFilterField ( queryImpl ) ;
242
226
const firstOrderByField = getFirstOrderByField ( queryImpl ) ;
@@ -245,9 +229,9 @@ export function queryOrderBy(
245
229
// inequality filter field for it to be a valid query.
246
230
// Note that the default inequality field and key ordering is ascending.
247
231
if ( ! inequalityField . isKeyField ( ) ) {
248
- queryImpl . memoizedOrderBy . push ( new OrderBy ( inequalityField ) ) ;
232
+ queryImpl . memoizedNormalizedOrderBy . push ( new OrderBy ( inequalityField ) ) ;
249
233
}
250
- queryImpl . memoizedOrderBy . push (
234
+ queryImpl . memoizedNormalizedOrderBy . push (
251
235
new OrderBy ( FieldPath . keyField ( ) , Direction . ASCENDING )
252
236
) ;
253
237
} else {
@@ -259,7 +243,7 @@ export function queryOrderBy(
259
243
) ;
260
244
let foundKeyOrdering = false ;
261
245
for ( const orderBy of queryImpl . explicitOrderBy ) {
262
- queryImpl . memoizedOrderBy . push ( orderBy ) ;
246
+ queryImpl . memoizedNormalizedOrderBy . push ( orderBy ) ;
263
247
if ( orderBy . field . isKeyField ( ) ) {
264
248
foundKeyOrdering = true ;
265
249
}
@@ -272,52 +256,53 @@ export function queryOrderBy(
272
256
? queryImpl . explicitOrderBy [ queryImpl . explicitOrderBy . length - 1 ]
273
257
. dir
274
258
: Direction . ASCENDING ;
275
- queryImpl . memoizedOrderBy . push (
259
+ queryImpl . memoizedNormalizedOrderBy . push (
276
260
new OrderBy ( FieldPath . keyField ( ) , lastDirection )
277
261
) ;
278
262
}
279
263
}
280
264
}
281
- return queryImpl . memoizedOrderBy ;
265
+ return queryImpl . memoizedNormalizedOrderBy ;
282
266
}
283
267
284
268
/**
285
269
* Converts this `Query` instance to it's corresponding `Target` representation.
286
270
*/
287
271
export function queryToTarget ( query : Query ) : Target {
288
- return _queryToTarget ( query ) ;
272
+ return _queryToTarget ( query , queryNormalizedOrderBy ( query ) ) ;
289
273
}
290
274
275
+ /**
276
+ * Converts this `Query` instance to it's corresponding `Target` representation,
277
+ * for use within an aggregate query.
278
+ */
291
279
export function aggregateQueryToTarget ( query : Query ) : Target {
292
- return _queryToTarget ( query , { includeImplicitOrderBy : false } ) ;
280
+ // Do not include implicit order-bys for aggregate queries.
281
+ return _queryToTarget ( query , query . explicitOrderBy ) ;
293
282
}
294
283
295
- export function _queryToTarget (
296
- query : Query ,
297
- settings ?: { includeImplicitOrderBy : boolean }
298
- ) : Target {
284
+ export function _queryToTarget ( query : Query , orderBys : OrderBy [ ] ) : Target {
299
285
const queryImpl = debugCast ( query , QueryImpl ) ;
300
286
if ( ! queryImpl . memoizedTarget ) {
301
287
if ( queryImpl . limitType === LimitType . First ) {
302
288
queryImpl . memoizedTarget = newTarget (
303
289
queryImpl . path ,
304
290
queryImpl . collectionGroup ,
305
- queryOrderBy ( queryImpl , settings ) ,
291
+ orderBys ,
306
292
queryImpl . filters ,
307
293
queryImpl . limit ,
308
294
queryImpl . startAt ,
309
295
queryImpl . endAt
310
296
) ;
311
297
} else {
312
298
// Flip the orderBy directions since we want the last results
313
- const orderBys = [ ] as OrderBy [ ] ;
314
- for ( const orderBy of queryOrderBy ( queryImpl ) ) {
299
+ orderBys = orderBys . map ( orderBy => {
315
300
const dir =
316
301
orderBy . dir === Direction . DESCENDING
317
302
? Direction . ASCENDING
318
303
: Direction . DESCENDING ;
319
- orderBys . push ( new OrderBy ( orderBy . field , dir ) ) ;
320
- }
304
+ return new OrderBy ( orderBy . field , dir ) ;
305
+ } ) ;
321
306
322
307
// We need to swap the cursors to match the now-flipped query ordering.
323
308
const startAt = queryImpl . endAt
@@ -490,13 +475,13 @@ function queryMatchesPathAndCollectionGroup(
490
475
* in the results.
491
476
*/
492
477
function queryMatchesOrderBy ( query : Query , doc : Document ) : boolean {
493
- // We must use `queryOrderBy ()` to get the list of all orderBys (both implicit and explicit).
478
+ // We must use `queryNormalizedOrderBy ()` to get the list of all orderBys (both implicit and explicit).
494
479
// Note that for OR queries, orderBy applies to all disjunction terms and implicit orderBys must
495
480
// be taken into account. For example, the query "a > 1 || b==1" has an implicit "orderBy a" due
496
481
// to the inequality, and is evaluated as "a > 1 orderBy a || b==1 orderBy a".
497
482
// A document with content of {b:1} matches the filters, but does not match the orderBy because
498
483
// it's missing the field 'a'.
499
- for ( const orderBy of queryOrderBy ( query ) ) {
484
+ for ( const orderBy of queryNormalizedOrderBy ( query ) ) {
500
485
// order by key always matches
501
486
if ( ! orderBy . field . isKeyField ( ) && doc . data . field ( orderBy . field ) === null ) {
502
487
return false ;
@@ -518,13 +503,13 @@ function queryMatchesFilters(query: Query, doc: Document): boolean {
518
503
function queryMatchesBounds ( query : Query , doc : Document ) : boolean {
519
504
if (
520
505
query . startAt &&
521
- ! boundSortsBeforeDocument ( query . startAt , queryOrderBy ( query ) , doc )
506
+ ! boundSortsBeforeDocument ( query . startAt , queryNormalizedOrderBy ( query ) , doc )
522
507
) {
523
508
return false ;
524
509
}
525
510
if (
526
511
query . endAt &&
527
- ! boundSortsAfterDocument ( query . endAt , queryOrderBy ( query ) , doc )
512
+ ! boundSortsAfterDocument ( query . endAt , queryNormalizedOrderBy ( query ) , doc )
528
513
) {
529
514
return false ;
530
515
}
@@ -555,7 +540,7 @@ export function newQueryComparator(
555
540
) : ( d1 : Document , d2 : Document ) => number {
556
541
return ( d1 : Document , d2 : Document ) : number => {
557
542
let comparedOnKeyField = false ;
558
- for ( const orderBy of queryOrderBy ( query ) ) {
543
+ for ( const orderBy of queryNormalizedOrderBy ( query ) ) {
559
544
const comp = compareDocs ( orderBy , d1 , d2 ) ;
560
545
if ( comp !== 0 ) {
561
546
return comp ;
0 commit comments