@@ -39,6 +39,8 @@ import {
39
39
localStoreAllocateTarget ,
40
40
localStoreApplyBundledDocuments ,
41
41
localStoreApplyRemoteEventToLocalCache ,
42
+ localStoreConfigureFieldIndexes ,
43
+ localStoreDeleteAllFieldIndexes ,
42
44
localStoreExecuteQuery ,
43
45
localStoreGetHighestUnacknowledgedBatchId ,
44
46
localStoreGetTargetData ,
@@ -77,7 +79,14 @@ import {
77
79
MutationBatch ,
78
80
MutationBatchResult
79
81
} from '../../../src/model/mutation_batch' ;
82
+ import {
83
+ FieldIndex ,
84
+ IndexKind ,
85
+ IndexSegment ,
86
+ IndexState
87
+ } from '../../../src/model/field_index' ;
80
88
import { ObjectValue } from '../../../src/model/object_value' ;
89
+ import { FieldPath } from '../../../src/model/path' ;
81
90
import { serverTimestamp } from '../../../src/model/server_timestamps' ;
82
91
import { ServerTimestampTransform } from '../../../src/model/transform_operation' ;
83
92
import { BundleMetadata as ProtoBundleMetadata } from '../../../src/protos/firestore_bundle_proto' ;
@@ -367,6 +376,22 @@ class LocalStoreTester {
367
376
return this ;
368
377
}
369
378
379
+ afterDeleteAllFieldIndexes ( ) : LocalStoreTester {
380
+ this . prepareNextStep ( ) ;
381
+ this . promiseChain = this . promiseChain . then ( ( ) =>
382
+ localStoreDeleteAllFieldIndexes ( this . localStore )
383
+ ) ;
384
+ return this ;
385
+ }
386
+
387
+ afterConfigureFieldIndexes ( fieldIndexes : FieldIndex [ ] ) : LocalStoreTester {
388
+ this . prepareNextStep ( ) ;
389
+ this . promiseChain = this . promiseChain . then ( ( ) =>
390
+ localStoreConfigureFieldIndexes ( this . localStore , fieldIndexes )
391
+ ) ;
392
+ return this ;
393
+ }
394
+
370
395
afterBackfillIndexes ( options ?: {
371
396
maxDocumentsToProcess ?: number ;
372
397
} ) : LocalStoreTester {
@@ -648,6 +673,18 @@ function compareDocsWithCreateTime(
648
673
) ;
649
674
}
650
675
676
+ function fieldIndex (
677
+ collectionGroup : string ,
678
+ indexId : number ,
679
+ indexState : IndexState ,
680
+ field : string ,
681
+ kind : IndexKind
682
+ ) : FieldIndex {
683
+ const fieldPath = new FieldPath ( field . split ( '.' ) ) ;
684
+ const segments = [ new IndexSegment ( fieldPath , kind ) ] ;
685
+ return new FieldIndex ( indexId , collectionGroup , segments , indexState ) ;
686
+ }
687
+
651
688
describe ( 'LocalStore w/ Memory Persistence' , ( ) => {
652
689
async function initialize ( ) : Promise < LocalStoreComponents > {
653
690
const queryEngine = new CountingQueryEngine ( ) ;
@@ -2987,4 +3024,78 @@ function indexedDbLocalStoreTests(
2987
3024
. toReturnChanged ( 'coll/a' , 'coll/f' )
2988
3025
. finish ( ) ;
2989
3026
} ) ;
3027
+
3028
+ it ( 'delete all indexes works with index auto creation' , ( ) => {
3029
+ const query_ = query ( 'coll' , filter ( 'value' , '==' , 'match' ) ) ;
3030
+ return (
3031
+ expectLocalStore ( )
3032
+ . afterAllocatingQuery ( query_ )
3033
+ . toReturnTargetId ( 2 )
3034
+ . afterIndexAutoCreationConfigure ( {
3035
+ isEnabled : true ,
3036
+ indexAutoCreationMinCollectionSize : 0 ,
3037
+ relativeIndexReadCostPerDocument : 2
3038
+ } )
3039
+ . afterRemoteEvents ( [
3040
+ docAddedRemoteEvent ( doc ( 'coll/a' , 10 , { value : 'match' } ) , [ 2 ] , [ ] ) ,
3041
+ docAddedRemoteEvent (
3042
+ doc ( 'coll/b' , 10 , { value : Number . NaN } ) ,
3043
+ [ 2 ] ,
3044
+ [ ]
3045
+ ) ,
3046
+ docAddedRemoteEvent ( doc ( 'coll/c' , 10 , { value : null } ) , [ 2 ] , [ ] ) ,
3047
+ docAddedRemoteEvent (
3048
+ doc ( 'coll/d' , 10 , { value : 'mismatch' } ) ,
3049
+ [ 2 ] ,
3050
+ [ ]
3051
+ ) ,
3052
+ docAddedRemoteEvent ( doc ( 'coll/e' , 10 , { value : 'match' } ) , [ 2 ] , [ ] )
3053
+ ] )
3054
+ // First time query is running without indexes.
3055
+ // Based on current heuristic, collection document counts (5) >
3056
+ // 2 * resultSize (2).
3057
+ // Full matched index should be created.
3058
+ . afterExecutingQuery ( query_ )
3059
+ . toHaveRead ( { documentsByKey : 0 , documentsByCollection : 2 } )
3060
+ . toReturnChanged ( 'coll/a' , 'coll/e' )
3061
+ . afterIndexAutoCreationConfigure ( { isEnabled : false } )
3062
+ . afterBackfillIndexes ( )
3063
+ . afterExecutingQuery ( query_ )
3064
+ . toHaveRead ( { documentsByKey : 2 , documentsByCollection : 0 } )
3065
+ . toReturnChanged ( 'coll/a' , 'coll/e' )
3066
+ . afterDeleteAllFieldIndexes ( )
3067
+ . afterExecutingQuery ( query_ )
3068
+ . toHaveRead ( { documentsByKey : 0 , documentsByCollection : 2 } )
3069
+ . toReturnChanged ( 'coll/a' , 'coll/e' )
3070
+ . finish ( )
3071
+ ) ;
3072
+ } ) ;
3073
+
3074
+ it ( 'delete all indexes works with manual added indexes' , ( ) => {
3075
+ const query_ = query ( 'coll' , filter ( 'matches' , '==' , true ) ) ;
3076
+ return expectLocalStore ( )
3077
+ . afterConfigureFieldIndexes ( [
3078
+ fieldIndex (
3079
+ 'coll' ,
3080
+ 0 ,
3081
+ IndexState . empty ( ) ,
3082
+ 'matches' ,
3083
+ IndexKind . ASCENDING
3084
+ )
3085
+ ] )
3086
+ . afterAllocatingQuery ( query_ )
3087
+ . toReturnTargetId ( 2 )
3088
+ . afterRemoteEvents ( [
3089
+ docAddedRemoteEvent ( doc ( 'coll/a' , 10 , { matches : true } ) , [ 2 ] , [ ] )
3090
+ ] )
3091
+ . afterBackfillIndexes ( )
3092
+ . afterExecutingQuery ( query_ )
3093
+ . toHaveRead ( { documentsByKey : 1 , documentsByCollection : 0 } )
3094
+ . toReturnChanged ( 'coll/a' )
3095
+ . afterDeleteAllFieldIndexes ( )
3096
+ . afterExecutingQuery ( query_ )
3097
+ . toHaveRead ( { documentsByKey : 0 , documentsByCollection : 1 } )
3098
+ . toReturnChanged ( 'coll/a' )
3099
+ . finish ( ) ;
3100
+ } ) ;
2990
3101
}
0 commit comments