@@ -105,28 +105,30 @@ export function canonifyTarget(target: Target): string {
105
105
const targetImpl = debugCast ( target , TargetImpl ) ;
106
106
107
107
if ( targetImpl . memoizedCanonicalId === null ) {
108
- let canonicalId = targetImpl . path . canonicalString ( ) ;
108
+ let str = targetImpl . path . canonicalString ( ) ;
109
109
if ( targetImpl . collectionGroup !== null ) {
110
- canonicalId += '|cg:' + targetImpl . collectionGroup ;
110
+ str += '|cg:' + targetImpl . collectionGroup ;
111
111
}
112
- canonicalId += '|f:' ;
113
- canonicalId += targetImpl . filters . map ( f => canonifyFilter ( f ) ) . join ( ',' ) ;
114
- canonicalId += '|ob:' ;
115
- canonicalId += targetImpl . orderBy . map ( o => canonifyOrderBy ( o ) ) . join ( ',' ) ;
112
+ str += '|f:' ;
113
+ str += targetImpl . filters . map ( f => canonifyFilter ( f ) ) . join ( ',' ) ;
114
+ str += '|ob:' ;
115
+ str += targetImpl . orderBy . map ( o => canonifyOrderBy ( o ) ) . join ( ',' ) ;
116
116
117
117
if ( ! isNullOrUndefined ( targetImpl . limit ) ) {
118
- canonicalId += '|l:' ;
119
- canonicalId += targetImpl . limit ! ;
118
+ str += '|l:' ;
119
+ str += targetImpl . limit ! ;
120
120
}
121
121
if ( targetImpl . startAt ) {
122
- canonicalId += '|lb:' ;
123
- canonicalId += canonifyBound ( targetImpl . startAt ) ;
122
+ str += '|lb:' ;
123
+ str += targetImpl . startAt . inclusive ? 'b:' : 'a:' ;
124
+ str += targetImpl . startAt . position . map ( p => canonicalId ( p ) ) . join ( ',' ) ;
124
125
}
125
126
if ( targetImpl . endAt ) {
126
- canonicalId += '|ub:' ;
127
- canonicalId += canonifyBound ( targetImpl . endAt ) ;
127
+ str += '|ub:' ;
128
+ str += targetImpl . endAt . inclusive ? 'a:' : 'b:' ;
129
+ str += targetImpl . endAt . position . map ( p => canonicalId ( p ) ) . join ( ',' ) ;
128
130
}
129
- targetImpl . memoizedCanonicalId = canonicalId ;
131
+ targetImpl . memoizedCanonicalId = str ;
130
132
}
131
133
return targetImpl . memoizedCanonicalId ;
132
134
}
@@ -150,10 +152,14 @@ export function stringifyTarget(target: Target): string {
150
152
. join ( ', ' ) } ]`;
151
153
}
152
154
if ( target . startAt ) {
153
- str += ', startAt: ' + canonifyBound ( target . startAt ) ;
155
+ str += ', startAt: ' ;
156
+ str += target . startAt . inclusive ? 'b:' : 'a:' ;
157
+ str += target . startAt . position . map ( p => canonicalId ( p ) ) . join ( ',' ) ;
154
158
}
155
159
if ( target . endAt ) {
156
- str += ', endAt: ' + canonifyBound ( target . endAt ) ;
160
+ str += ', endAt: ' ;
161
+ str += target . endAt . inclusive ? 'a:' : 'b:' ;
162
+ str += target . endAt . position . map ( p => canonicalId ( p ) ) . join ( ',' ) ;
157
163
}
158
164
return `Target(${ str } )` ;
159
165
}
@@ -351,7 +357,7 @@ export function targetGetLowerBound(
351
357
const cursorValue = target . startAt . position [ i ] ;
352
358
if ( valuesMax ( segmentValue , cursorValue ) === cursorValue ) {
353
359
segmentValue = cursorValue ;
354
- segmentInclusive = ! target . startAt . before ;
360
+ segmentInclusive = target . startAt . inclusive ;
355
361
}
356
362
break ;
357
363
}
@@ -365,7 +371,7 @@ export function targetGetLowerBound(
365
371
values . push ( segmentValue ) ;
366
372
inclusive &&= segmentInclusive ;
367
373
}
368
- return new Bound ( values , ! inclusive ) ;
374
+ return new Bound ( values , inclusive ) ;
369
375
}
370
376
/**
371
377
* Returns an upper bound of field values that can be used as an ending point
@@ -436,7 +442,7 @@ export function targetGetUpperBound(
436
442
const cursorValue = target . endAt . position [ i ] ;
437
443
if ( valuesMin ( segmentValue , cursorValue ) === cursorValue ) {
438
444
segmentValue = cursorValue ;
439
- segmentInclusive = ! target . endAt . before ;
445
+ segmentInclusive = target . endAt . inclusive ;
440
446
}
441
447
break ;
442
448
}
@@ -451,7 +457,7 @@ export function targetGetUpperBound(
451
457
inclusive &&= segmentInclusive ;
452
458
}
453
459
454
- return new Bound ( values , ! inclusive ) ;
460
+ return new Bound ( values , inclusive ) ;
455
461
}
456
462
457
463
export abstract class Filter {
@@ -772,7 +778,6 @@ export class ArrayContainsAnyFilter extends FieldFilter {
772
778
}
773
779
}
774
780
775
- // TODO(indexing): Change Bound.before to "inclusive"
776
781
/**
777
782
* Represents a bound of a query.
778
783
*
@@ -788,14 +793,7 @@ export class ArrayContainsAnyFilter extends FieldFilter {
788
793
* just after the provided values.
789
794
*/
790
795
export class Bound {
791
- constructor ( readonly position : ProtoValue [ ] , readonly before : boolean ) { }
792
- }
793
-
794
- export function canonifyBound ( bound : Bound ) : string {
795
- // TODO(b/29183165): Make this collision robust.
796
- return `${ bound . before ? 'b' : 'a' } :${ bound . position
797
- . map ( p => canonicalId ( p ) )
798
- . join ( ',' ) } `;
796
+ constructor ( readonly position : ProtoValue [ ] , readonly inclusive : boolean ) { }
799
797
}
800
798
801
799
/**
@@ -821,15 +819,11 @@ export function orderByEquals(left: OrderBy, right: OrderBy): boolean {
821
819
return left . dir === right . dir && left . field . isEqual ( right . field ) ;
822
820
}
823
821
824
- /**
825
- * Returns true if a document sorts before a bound using the provided sort
826
- * order.
827
- */
828
- export function sortsBeforeDocument (
822
+ function boundCompareToDocument (
829
823
bound : Bound ,
830
824
orderBy : OrderBy [ ] ,
831
825
doc : Document
832
- ) : boolean {
826
+ ) : number {
833
827
debugAssert (
834
828
bound . position . length <= orderBy . length ,
835
829
"Bound has more components than query's orderBy"
@@ -862,7 +856,33 @@ export function sortsBeforeDocument(
862
856
break ;
863
857
}
864
858
}
865
- return bound . before ? comparison <= 0 : comparison < 0 ;
859
+ return comparison ;
860
+ }
861
+
862
+ /**
863
+ * Returns true if a document sorts after a bound using the provided sort
864
+ * order.
865
+ */
866
+ export function boundSortsAfterDocument (
867
+ bound : Bound ,
868
+ orderBy : OrderBy [ ] ,
869
+ doc : Document
870
+ ) : boolean {
871
+ const comparison = boundCompareToDocument ( bound , orderBy , doc ) ;
872
+ return bound . inclusive ? comparison >= 0 : comparison > 0 ;
873
+ }
874
+
875
+ /**
876
+ * Returns true if a document sorts before a bound using the provided sort
877
+ * order.
878
+ */
879
+ export function boundSortsBeforeDocument (
880
+ bound : Bound ,
881
+ orderBy : OrderBy [ ] ,
882
+ doc : Document
883
+ ) : boolean {
884
+ const comparison = boundCompareToDocument ( bound , orderBy , doc ) ;
885
+ return bound . inclusive ? comparison <= 0 : comparison < 0 ;
866
886
}
867
887
868
888
export function boundEquals ( left : Bound | null , right : Bound | null ) : boolean {
@@ -873,7 +893,7 @@ export function boundEquals(left: Bound | null, right: Bound | null): boolean {
873
893
}
874
894
875
895
if (
876
- left . before !== right . before ||
896
+ left . inclusive !== right . inclusive ||
877
897
left . position . length !== right . position . length
878
898
) {
879
899
return false ;
0 commit comments