@@ -105,28 +105,30 @@ export function canonifyTarget(target: Target): string {
105105 const targetImpl = debugCast ( target , TargetImpl ) ;
106106
107107 if ( targetImpl . memoizedCanonicalId === null ) {
108- let canonicalId = targetImpl . path . canonicalString ( ) ;
108+ let str = targetImpl . path . canonicalString ( ) ;
109109 if ( targetImpl . collectionGroup !== null ) {
110- canonicalId += '|cg:' + targetImpl . collectionGroup ;
110+ str += '|cg:' + targetImpl . collectionGroup ;
111111 }
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 ( ',' ) ;
116116
117117 if ( ! isNullOrUndefined ( targetImpl . limit ) ) {
118- canonicalId += '|l:' ;
119- canonicalId += targetImpl . limit ! ;
118+ str += '|l:' ;
119+ str += targetImpl . limit ! ;
120120 }
121121 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 ( ',' ) ;
124125 }
125126 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 ( ',' ) ;
128130 }
129- targetImpl . memoizedCanonicalId = canonicalId ;
131+ targetImpl . memoizedCanonicalId = str ;
130132 }
131133 return targetImpl . memoizedCanonicalId ;
132134}
@@ -150,10 +152,14 @@ export function stringifyTarget(target: Target): string {
150152 . join ( ', ' ) } ]`;
151153 }
152154 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 ( ',' ) ;
154158 }
155159 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 ( ',' ) ;
157163 }
158164 return `Target(${ str } )` ;
159165}
@@ -351,7 +357,7 @@ export function targetGetLowerBound(
351357 const cursorValue = target . startAt . position [ i ] ;
352358 if ( valuesMax ( segmentValue , cursorValue ) === cursorValue ) {
353359 segmentValue = cursorValue ;
354- segmentInclusive = ! target . startAt . before ;
360+ segmentInclusive = target . startAt . inclusive ;
355361 }
356362 break ;
357363 }
@@ -365,7 +371,7 @@ export function targetGetLowerBound(
365371 values . push ( segmentValue ) ;
366372 inclusive &&= segmentInclusive ;
367373 }
368- return new Bound ( values , ! inclusive ) ;
374+ return new Bound ( values , inclusive ) ;
369375}
370376/**
371377 * Returns an upper bound of field values that can be used as an ending point
@@ -436,7 +442,7 @@ export function targetGetUpperBound(
436442 const cursorValue = target . endAt . position [ i ] ;
437443 if ( valuesMin ( segmentValue , cursorValue ) === cursorValue ) {
438444 segmentValue = cursorValue ;
439- segmentInclusive = ! target . endAt . before ;
445+ segmentInclusive = target . endAt . inclusive ;
440446 }
441447 break ;
442448 }
@@ -451,7 +457,7 @@ export function targetGetUpperBound(
451457 inclusive &&= segmentInclusive ;
452458 }
453459
454- return new Bound ( values , ! inclusive ) ;
460+ return new Bound ( values , inclusive ) ;
455461}
456462
457463export abstract class Filter {
@@ -772,7 +778,6 @@ export class ArrayContainsAnyFilter extends FieldFilter {
772778 }
773779}
774780
775- // TODO(indexing): Change Bound.before to "inclusive"
776781/**
777782 * Represents a bound of a query.
778783 *
@@ -788,14 +793,7 @@ export class ArrayContainsAnyFilter extends FieldFilter {
788793 * just after the provided values.
789794 */
790795export 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 ) { }
799797}
800798
801799/**
@@ -821,15 +819,11 @@ export function orderByEquals(left: OrderBy, right: OrderBy): boolean {
821819 return left . dir === right . dir && left . field . isEqual ( right . field ) ;
822820}
823821
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 (
829823 bound : Bound ,
830824 orderBy : OrderBy [ ] ,
831825 doc : Document
832- ) : boolean {
826+ ) : number {
833827 debugAssert (
834828 bound . position . length <= orderBy . length ,
835829 "Bound has more components than query's orderBy"
@@ -862,7 +856,33 @@ export function sortsBeforeDocument(
862856 break ;
863857 }
864858 }
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 ;
866886}
867887
868888export function boundEquals ( left : Bound | null , right : Bound | null ) : boolean {
@@ -873,7 +893,7 @@ export function boundEquals(left: Bound | null, right: Bound | null): boolean {
873893 }
874894
875895 if (
876- left . before !== right . before ||
896+ left . inclusive !== right . inclusive ||
877897 left . position . length !== right . position . length
878898 ) {
879899 return false ;
0 commit comments