@@ -500,26 +500,25 @@ export function targetGetSegmentCount(target: Target): number {
500
500
let hasArraySegment = false ;
501
501
502
502
for ( const filter of target . filters ) {
503
- // TODO(orquery): Use the flattened filters here
504
- const fieldFilter = filter as FieldFilter ;
505
-
506
- // __name__ is not an explicit segment of any index, so we don't need to
507
- // count it.
508
- if ( fieldFilter . field . isKeyField ( ) ) {
509
- continue ;
510
- }
503
+ for ( const subFilter of filter . getFlattenedFilters ( ) ) {
504
+ // __name__ is not an explicit segment of any index, so we don't need to
505
+ // count it.
506
+ if ( subFilter . field . isKeyField ( ) ) {
507
+ continue ;
508
+ }
511
509
512
- // ARRAY_CONTAINS or ARRAY_CONTAINS_ANY filters must be counted separately.
513
- // For instance, it is possible to have an index for "a ARRAY a ASC". Even
514
- // though these are on the same field, they should be counted as two
515
- // separate segments in an index.
516
- if (
517
- fieldFilter . op === Operator . ARRAY_CONTAINS ||
518
- fieldFilter . op === Operator . ARRAY_CONTAINS_ANY
519
- ) {
520
- hasArraySegment = true ;
521
- } else {
522
- fields = fields . add ( fieldFilter . field ) ;
510
+ // ARRAY_CONTAINS or ARRAY_CONTAINS_ANY filters must be counted separately.
511
+ // For instance, it is possible to have an index for "a ARRAY a ASC". Even
512
+ // though these are on the same field, they should be counted as two
513
+ // separate segments in an index.
514
+ if (
515
+ subFilter . op === Operator . ARRAY_CONTAINS ||
516
+ subFilter . op === Operator . ARRAY_CONTAINS_ANY
517
+ ) {
518
+ hasArraySegment = true ;
519
+ } else {
520
+ fields = fields . add ( subFilter . field ) ;
521
+ }
523
522
}
524
523
}
525
524
@@ -534,12 +533,16 @@ export function targetGetSegmentCount(target: Target): number {
534
533
return fields . size + ( hasArraySegment ? 1 : 0 ) ;
535
534
}
536
535
536
+ export function targetHasLimit ( target : Target ) : boolean {
537
+ return target . limit !== null ;
538
+ }
539
+
537
540
export abstract class Filter {
538
541
abstract matches ( doc : Document ) : boolean ;
539
542
540
543
abstract getFlattenedFilters ( ) : readonly FieldFilter [ ] ;
541
544
542
- abstract getFilters ( ) : readonly Filter [ ] ;
545
+ abstract getFilters ( ) : Filter [ ] ;
543
546
544
547
abstract getFirstInequalityField ( ) : FieldPath | null ;
545
548
}
@@ -702,7 +705,7 @@ export class FieldFilter extends Filter {
702
705
return [ this ] ;
703
706
}
704
707
705
- getFilters ( ) : readonly Filter [ ] {
708
+ getFilters ( ) : Filter [ ] {
706
709
return [ this ] ;
707
710
}
708
711
@@ -753,8 +756,9 @@ export class CompositeFilter extends Filter {
753
756
return this . memoizedFlattenedFilters ;
754
757
}
755
758
756
- getFilters ( ) : readonly Filter [ ] {
757
- return this . filters ;
759
+ // Returns a mutable copy of `this.filters`
760
+ getFilters ( ) : Filter [ ] {
761
+ return Object . assign ( [ ] , this . filters ) ;
758
762
}
759
763
760
764
getFirstInequalityField ( ) : FieldPath | null {
@@ -782,12 +786,31 @@ export class CompositeFilter extends Filter {
782
786
}
783
787
}
784
788
789
+ /**
790
+ * Returns a new composite filter that contains all filter from
791
+ * `compositeFilter` plus all the given filters in `otherFilters`.
792
+ * TODO(orquery) move compositeFilterWithAddedFilters to filter.ts in future refactor
793
+ */
794
+ export function compositeFilterWithAddedFilters (
795
+ compositeFilter : CompositeFilter ,
796
+ otherFilters : Filter [ ]
797
+ ) : CompositeFilter {
798
+ const mergedFilters = compositeFilter . filters . concat ( otherFilters ) ;
799
+ return CompositeFilter . create ( mergedFilters , compositeFilter . op ) ;
800
+ }
801
+
785
802
export function compositeFilterIsConjunction (
786
803
compositeFilter : CompositeFilter
787
804
) : boolean {
788
805
return compositeFilter . op === CompositeOperator . AND ;
789
806
}
790
807
808
+ export function compositeFilterIsDisjunction (
809
+ compositeFilter : CompositeFilter
810
+ ) : boolean {
811
+ return compositeFilter . op === CompositeOperator . OR ;
812
+ }
813
+
791
814
/**
792
815
* Returns true if this filter is a conjunction of field filters only. Returns false otherwise.
793
816
*/
@@ -881,9 +904,28 @@ export function compositeFilterEquals(
881
904
/** Returns a debug description for `filter`. */
882
905
export function stringifyFilter ( filter : Filter ) : string {
883
906
debugAssert (
884
- filter instanceof FieldFilter ,
885
- 'stringifyFilter() only supports FieldFilters'
907
+ filter instanceof FieldFilter || filter instanceof CompositeFilter ,
908
+ 'stringifyFilter() only supports FieldFilters and CompositeFilters '
886
909
) ;
910
+ if ( filter instanceof FieldFilter ) {
911
+ return stringifyFieldFilter ( filter ) ;
912
+ } else if ( filter instanceof CompositeFilter ) {
913
+ return stringifyCompositeFilter ( filter ) ;
914
+ } else {
915
+ return 'Filter' ;
916
+ }
917
+ }
918
+
919
+ export function stringifyCompositeFilter ( filter : CompositeFilter ) : string {
920
+ return (
921
+ filter . op . toString ( ) +
922
+ ` {` +
923
+ filter . getFilters ( ) . map ( stringifyFilter ) . join ( ' ,' ) +
924
+ '}'
925
+ ) ;
926
+ }
927
+
928
+ export function stringifyFieldFilter ( filter : FieldFilter ) : string {
887
929
return `${ filter . field . canonicalString ( ) } ${ filter . op } ${ canonicalId (
888
930
filter . value
889
931
) } `;
0 commit comments