@@ -1067,4 +1067,87 @@ streams:
10671067 expect ( foundLookupA ) . toBeTruthy ( ) ;
10681068 expect ( foundLookupB ) . toBeTruthy ( ) ;
10691069 } ) ;
1070+
1071+ test ( 'sync streams preserve duplicate downstream lookups with different provenance' , async ( ) => {
1072+ await using factory = await generateStorageFactory ( ) ;
1073+ const syncRules = await factory . updateSyncRules (
1074+ updateSyncRulesFromYaml (
1075+ `
1076+ config:
1077+ edition: 3
1078+ streams:
1079+ stream:
1080+ auto_subscribe: true
1081+ query: |
1082+ SELECT a.*
1083+ FROM a, b, c
1084+ WHERE a.x = b.x
1085+ AND a.z = c.z
1086+ AND b.y = c.y
1087+ AND c.u = auth.user_id()
1088+ ` ,
1089+ {
1090+ storageVersion
1091+ }
1092+ )
1093+ ) ;
1094+ const bucketStorage = factory . getInstance ( syncRules ) ;
1095+ const sync_rules = syncRules . parsed ( test_utils . PARSE_OPTIONS ) . hydratedSyncRules ( ) ;
1096+
1097+ await using writer = await bucketStorage . createWriter ( test_utils . BATCH_OPTIONS ) ;
1098+ const tableB = await test_utils . resolveTestTable ( writer , 'b' , [ 'id' ] , config ) ;
1099+ const tableC = await test_utils . resolveTestTable ( writer , 'c' , [ 'id' ] , config ) ;
1100+
1101+ await writer . markAllSnapshotDone ( '1/1' ) ;
1102+ await writer . save ( {
1103+ sourceTable : tableB ,
1104+ tag : storage . SaveOperationTag . INSERT ,
1105+ after : {
1106+ id : 'b1' ,
1107+ y : 'shared-y' ,
1108+ x : 'x-from-shared-y'
1109+ } ,
1110+ afterReplicaId : test_utils . rid ( 'b1' )
1111+ } ) ;
1112+ await writer . save ( {
1113+ sourceTable : tableC ,
1114+ tag : storage . SaveOperationTag . INSERT ,
1115+ after : {
1116+ id : 'c1' ,
1117+ u : 'user1' ,
1118+ y : 'shared-y' ,
1119+ z : 'z1'
1120+ } ,
1121+ afterReplicaId : test_utils . rid ( 'c1' )
1122+ } ) ;
1123+ await writer . save ( {
1124+ sourceTable : tableC ,
1125+ tag : storage . SaveOperationTag . INSERT ,
1126+ after : {
1127+ id : 'c2' ,
1128+ u : 'user1' ,
1129+ y : 'shared-y' ,
1130+ z : 'z2'
1131+ } ,
1132+ afterReplicaId : test_utils . rid ( 'c2' )
1133+ } ) ;
1134+ await writer . commit ( '1/1' ) ;
1135+
1136+ const checkpoint = await bucketStorage . getCheckpoint ( ) ;
1137+ const parameters = new RequestParameters ( new JwtPayload ( { sub : 'user1' } ) , { } ) ;
1138+ const querier = sync_rules . getBucketParameterQuerier ( {
1139+ ...test_utils . querierOptions ( parameters )
1140+ } ) . querier ;
1141+
1142+ const buckets = await querier . queryDynamicBucketDescriptions ( {
1143+ async getParameterSets ( lookups ) {
1144+ return checkpoint . getParameterSets ( lookups , 1000 ) ;
1145+ }
1146+ } ) ;
1147+
1148+ expect ( buckets . map ( ( bucket ) => bucket . bucket ) . sort ( ) ) . toStrictEqual ( [
1149+ expect . stringMatching ( / s t r e a m .* \[ " x - f r o m - s h a r e d - y " , " z 1 " \] $ / ) ,
1150+ expect . stringMatching ( / s t r e a m .* \[ " x - f r o m - s h a r e d - y " , " z 2 " \] $ / )
1151+ ] ) ;
1152+ } ) ;
10701153}
0 commit comments