@@ -9,22 +9,30 @@ import {
99} from '@powersync/lib-services-framework' ;
1010import {
1111 BroadcastIterable ,
12+ getLookupBucketDefinitionName ,
1213 ReplicationCheckpoint ,
1314 storage ,
1415 utils ,
1516 WatchWriteCheckpointOptions
1617} from '@powersync/service-core' ;
1718import { SqliteJsonRow , SqliteJsonValue , SqlSyncRules } from '@powersync/service-sync-rules' ;
1819import * as bson from 'bson' ;
20+ import { wrapWithAbort } from 'ix/asynciterable/operators/withabort.js' ;
1921import * as timers from 'timers/promises' ;
2022import { MongoBucketStorage } from '../MongoBucketStorage.js' ;
2123import { PowerSyncMongo } from './db.js' ;
22- import { BucketDataDocument , BucketDataKey , SourceKey , SyncRuleCheckpointState , SyncRuleDocument } from './models.js' ;
24+ import {
25+ BucketDataDocument ,
26+ BucketDataKey ,
27+ BucketParameterDocument ,
28+ SourceKey ,
29+ SyncRuleCheckpointState ,
30+ SyncRuleDocument
31+ } from './models.js' ;
2332import { MongoBucketBatch } from './MongoBucketBatch.js' ;
2433import { MongoCompactor } from './MongoCompactor.js' ;
2534import { MongoWriteCheckpointAPI } from './MongoWriteCheckpointAPI.js' ;
2635import { idPrefixFilter , mapOpEntry , readSingleBatch } from './util.js' ;
27- import { wrapWithAbort } from 'ix/asynciterable/operators/withabort.js' ;
2836
2937export class MongoSyncBucketStorage
3038 extends DisposableObserver < storage . SyncRulesBucketStorageListener >
@@ -734,7 +742,10 @@ export class MongoSyncBucketStorage
734742 }
735743 } else if ( update . ns . coll == this . db . bucket_data . collectionName ) {
736744 const bucket = ( update . documentKey . _id as unknown as BucketDataKey ) . b ;
737- yield { bucket : bucket } ;
745+ yield { dataBucket : bucket } ;
746+ } else if ( update . ns . coll == this . db . bucket_parameters . collectionName && update . fullDocument != null ) {
747+ const bucketDefinition = getLookupBucketDefinitionName ( ( update . fullDocument as BucketParameterDocument ) . lookup ) ;
748+ yield { parameterBucketDefinition : bucketDefinition } ;
738749 }
739750 }
740751 }
@@ -757,15 +768,24 @@ export class MongoSyncBucketStorage
757768 for await ( const event of iter ) {
758769 if ( filter ) {
759770 if ( event . invalidate ) {
760- shouldUpdate ||= filter ( {
761- invalidate : true
762- } ) ;
771+ shouldUpdate =
772+ filter ( {
773+ invalidate : true
774+ } ) || shouldUpdate ;
763775 }
764776
765- if ( event . bucket ) {
766- shouldUpdate ||= filter ( {
767- bucket : event . bucket
768- } ) ;
777+ if ( event . dataBucket ) {
778+ shouldUpdate =
779+ filter ( {
780+ changedDataBucket : event . dataBucket
781+ } ) || shouldUpdate ;
782+ }
783+
784+ if ( event . parameterBucketDefinition ) {
785+ shouldUpdate =
786+ filter ( {
787+ changedParameterBucketDefinition : event . parameterBucketDefinition
788+ } ) || shouldUpdate ;
769789 }
770790 }
771791
@@ -836,23 +856,57 @@ export class MongoSyncBucketStorage
836856
837857 private getChangeStreamPipeline ( ) {
838858 const syncRulesId = this . group_id ;
859+ const parsedSyncRules = this . getParsedSyncRules ( {
860+ // Not applicable here
861+ defaultSchema : 'default'
862+ } ) ;
863+ const staticBucketDefinitions = parsedSyncRules . getStaticBucketDefinitionList ( ) ;
864+ const staticBucketFilters = staticBucketDefinitions . map ( ( name ) => {
865+ return {
866+ // Check that the docuemnt starts with bucket name
867+ 'documentKey._id.b' : {
868+ $gte : name + '[' ,
869+ $lt : name + '[\uFFFF'
870+ }
871+ } ;
872+ } ) ;
873+
874+ let filters : mongo . Document [ ] = [
875+ // sync_rules events
876+ {
877+ 'ns.coll' : this . db . sync_rules . collectionName ,
878+ 'documentKey._id' : syncRulesId ,
879+ operationType : { $in : [ 'insert' , 'update' , 'replace' ] }
880+ } ,
881+ // bucket_data events
882+ {
883+ 'ns.coll' : this . db . bucket_data . collectionName ,
884+ 'documentKey._id.g' : syncRulesId ,
885+ operationType : 'insert' ,
886+ $or : staticBucketFilters
887+ } ,
888+ // bucket_parameters events
889+ {
890+ 'ns.coll' : this . db . bucket_parameters . collectionName ,
891+ 'fullDocument.key.g' : syncRulesId ,
892+ operationType : 'insert'
893+ }
894+ ] ;
895+
896+ if ( staticBucketFilters . length > 0 ) {
897+ // bucket_data events, only if there are static bucket definitions
898+ filters . push ( {
899+ 'ns.coll' : this . db . bucket_data . collectionName ,
900+ 'documentKey._id.g' : syncRulesId ,
901+ operationType : 'insert' ,
902+ $or : staticBucketFilters
903+ } ) ;
904+ }
905+
839906 const pipeline : mongo . Document [ ] = [
840907 {
841908 $match : {
842- $or : [
843- // sync_rules events
844- {
845- 'ns.coll' : this . db . sync_rules . collectionName ,
846- 'documentKey._id' : syncRulesId ,
847- operationType : { $in : [ 'insert' , 'update' , 'replace' ] }
848- } ,
849- // bucket_data events
850- {
851- 'ns.coll' : this . db . bucket_data . collectionName ,
852- 'documentKey._id.g' : syncRulesId ,
853- operationType : 'insert'
854- }
855- ]
909+ $or : filters
856910 }
857911 } ,
858912 {
@@ -865,6 +919,10 @@ export class MongoSyncBucketStorage
865919 // For sync_rules, this contains the sync_rules id
866920 'documentKey._id' : 1 ,
867921
922+ // For bucket_parameters
923+ 'fullDocument.key' : 1 ,
924+ 'fullDocument.lookup' : 1 ,
925+
868926 // For sync_rules events
869927 'updateDescription.updatedFields.state' : 1 ,
870928 'updateDescription.updatedFields.last_checkpoint' : 1 ,
@@ -882,6 +940,7 @@ export class MongoSyncBucketStorage
882940
883941interface BucketCheckpointEvent {
884942 checkpoint ?: ReplicationCheckpoint ;
885- bucket ?: string ;
943+ dataBucket ?: string ;
944+ parameterBucketDefinition ?: string ;
886945 invalidate ?: boolean ;
887946}
0 commit comments