@powersync/service-core-tests 0.16.0 → 0.17.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/dist/test-utils/AbstractStreamTestContext.d.ts +6 -5
  3. package/dist/test-utils/AbstractStreamTestContext.js +26 -22
  4. package/dist/test-utils/AbstractStreamTestContext.js.map +1 -1
  5. package/dist/test-utils/StorageDataHelpers.d.ts +5 -5
  6. package/dist/test-utils/StorageDataHelpers.js.map +1 -1
  7. package/dist/test-utils/bucket-validation.d.ts +3 -3
  8. package/dist/test-utils/bucket-validation.js +3 -3
  9. package/dist/test-utils/general-utils.d.ts +13 -2
  10. package/dist/test-utils/general-utils.js +24 -3
  11. package/dist/test-utils/general-utils.js.map +1 -1
  12. package/dist/tests/register-compacting-tests.js +28 -21
  13. package/dist/tests/register-compacting-tests.js.map +1 -1
  14. package/dist/tests/register-data-storage-checkpoint-tests.js +8 -2
  15. package/dist/tests/register-data-storage-checkpoint-tests.js.map +1 -1
  16. package/dist/tests/register-data-storage-data-tests.js +148 -101
  17. package/dist/tests/register-data-storage-data-tests.js.map +1 -1
  18. package/dist/tests/register-data-storage-parameter-tests.js +44 -42
  19. package/dist/tests/register-data-storage-parameter-tests.js.map +1 -1
  20. package/dist/tests/register-sync-tests.js +141 -8
  21. package/dist/tests/register-sync-tests.js.map +1 -1
  22. package/dist/tests/util.d.ts +2 -2
  23. package/dist/tests/util.js.map +1 -1
  24. package/package.json +6 -7
  25. package/src/test-utils/AbstractStreamTestContext.ts +29 -24
  26. package/src/test-utils/StorageDataHelpers.ts +7 -6
  27. package/src/test-utils/bucket-validation.ts +3 -3
  28. package/src/test-utils/general-utils.ts +35 -7
  29. package/src/tests/register-compacting-tests.ts +45 -22
  30. package/src/tests/register-data-storage-checkpoint-tests.ts +12 -2
  31. package/src/tests/register-data-storage-data-tests.ts +210 -107
  32. package/src/tests/register-data-storage-parameter-tests.ts +58 -42
  33. package/src/tests/register-sync-tests.ts +159 -8
  34. package/src/tests/util.ts +2 -2
  35. package/tsconfig.json +1 -4
  36. package/tsconfig.tsbuildinfo +1 -1
@@ -27,13 +27,13 @@ export function registerDataStorageDataTests(config) {
27
27
  const storageVersion = config.storageVersion ?? storage.CURRENT_STORAGE_VERSION;
28
28
  test('removing row', async () => {
29
29
  await using factory = await generateStorageFactory();
30
- const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
30
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(factory, updateSyncRulesFromYaml(`
31
31
  bucket_definitions:
32
32
  global:
33
33
  data:
34
34
  - SELECT id, description FROM "%"
35
35
  `, { storageVersion }));
36
- const bucketStorage = factory.getInstance(syncRules);
36
+ const bucketStorage = factory.getInstance(replicationStream);
37
37
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
38
38
  const testTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
39
39
  await writer.markAllSnapshotDone('1/1');
@@ -54,7 +54,7 @@ bucket_definitions:
54
54
  await writer.commit('1/1');
55
55
  const { checkpoint } = await bucketStorage.getCheckpoint();
56
56
  const request = bucketRequest(syncRules, 'global[]');
57
- const batch = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(checkpoint, [request]));
57
+ const batch = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(test_utils.testCheckpoint(checkpoint), [request]));
58
58
  const data = batch[0].chunkData.data.map((d) => {
59
59
  return {
60
60
  op: d.op,
@@ -68,7 +68,9 @@ bucket_definitions:
68
68
  { op: 'PUT', object_id: 'test1', checksum: c1 },
69
69
  { op: 'REMOVE', object_id: 'test1', checksum: c2 }
70
70
  ]);
71
- const checksums = [...(await bucketStorage.getChecksums(checkpoint, [request])).values()];
71
+ const checksums = [
72
+ ...(await bucketStorage.getChecksums(test_utils.testCheckpoint(checkpoint), [request])).values()
73
+ ];
72
74
  expect(checksums).toEqual([
73
75
  {
74
76
  bucket: request.bucket,
@@ -79,13 +81,13 @@ bucket_definitions:
79
81
  });
80
82
  test('insert after delete in new batch', async () => {
81
83
  await using factory = await generateStorageFactory();
82
- const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
84
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(factory, updateSyncRulesFromYaml(`
83
85
  bucket_definitions:
84
86
  global:
85
87
  data:
86
88
  - SELECT id, description FROM "%"
87
89
  `, { storageVersion }));
88
- const bucketStorage = factory.getInstance(syncRules);
90
+ const bucketStorage = factory.getInstance(replicationStream);
89
91
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
90
92
  const testTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
91
93
  await writer.markAllSnapshotDone('1/1');
@@ -107,7 +109,7 @@ bucket_definitions:
107
109
  await writer.commit('2/1');
108
110
  const { checkpoint } = await bucketStorage.getCheckpoint();
109
111
  const request = bucketRequest(syncRules, 'global[]');
110
- const batch = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(checkpoint, [request]));
112
+ const batch = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(test_utils.testCheckpoint(checkpoint), [request]));
111
113
  const data = batch[0].chunkData.data.map((d) => {
112
114
  return {
113
115
  op: d.op,
@@ -117,7 +119,9 @@ bucket_definitions:
117
119
  });
118
120
  const c1 = 2871785649;
119
121
  expect(data).toEqual([{ op: 'PUT', object_id: 'test1', checksum: c1 }]);
120
- const checksums = [...(await bucketStorage.getChecksums(checkpoint, [request])).values()];
122
+ const checksums = [
123
+ ...(await bucketStorage.getChecksums(test_utils.testCheckpoint(checkpoint), [request])).values()
124
+ ];
121
125
  expect(checksums).toEqual([
122
126
  {
123
127
  bucket: request.bucket,
@@ -129,13 +133,13 @@ bucket_definitions:
129
133
  test('update after delete in new batch', async () => {
130
134
  // Update after delete may not be common, but the storage layer should handle it in an eventually-consistent way.
131
135
  await using factory = await generateStorageFactory();
132
- const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
136
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(factory, updateSyncRulesFromYaml(`
133
137
  bucket_definitions:
134
138
  global:
135
139
  data:
136
140
  - SELECT id, description FROM "%"
137
141
  `, { storageVersion }));
138
- const bucketStorage = factory.getInstance(syncRules);
142
+ const bucketStorage = factory.getInstance(replicationStream);
139
143
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
140
144
  const testTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
141
145
  await writer.markAllSnapshotDone('1/1');
@@ -161,7 +165,7 @@ bucket_definitions:
161
165
  await writer.commit('2/1');
162
166
  const { checkpoint } = await bucketStorage.getCheckpoint();
163
167
  const request = bucketRequest(syncRules, 'global[]');
164
- const batch = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(checkpoint, [request]));
168
+ const batch = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(test_utils.testCheckpoint(checkpoint), [request]));
165
169
  const data = batch[0].chunkData.data.map((d) => {
166
170
  return {
167
171
  op: d.op,
@@ -171,7 +175,9 @@ bucket_definitions:
171
175
  });
172
176
  const c1 = 2871785649;
173
177
  expect(data).toEqual([{ op: 'PUT', object_id: 'test1', checksum: c1 }]);
174
- const checksums = [...(await bucketStorage.getChecksums(checkpoint, [request])).values()];
178
+ const checksums = [
179
+ ...(await bucketStorage.getChecksums(test_utils.testCheckpoint(checkpoint), [request])).values()
180
+ ];
175
181
  expect(checksums).toEqual([
176
182
  {
177
183
  bucket: request.bucket,
@@ -182,7 +188,7 @@ bucket_definitions:
182
188
  });
183
189
  test('insert after delete in same batch', async () => {
184
190
  await using factory = await generateStorageFactory();
185
- const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
191
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(factory, updateSyncRulesFromYaml(`
186
192
  bucket_definitions:
187
193
  global:
188
194
  data:
@@ -190,7 +196,7 @@ bucket_definitions:
190
196
  `, {
191
197
  storageVersion
192
198
  }));
193
- const bucketStorage = factory.getInstance(syncRules);
199
+ const bucketStorage = factory.getInstance(replicationStream);
194
200
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
195
201
  const testTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
196
202
  await writer.markAllSnapshotDone('1/1');
@@ -211,7 +217,7 @@ bucket_definitions:
211
217
  await writer.commit('1/1');
212
218
  const { checkpoint } = await bucketStorage.getCheckpoint();
213
219
  const request = bucketRequest(syncRules, 'global[]');
214
- const batch = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(checkpoint, [request]));
220
+ const batch = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(test_utils.testCheckpoint(checkpoint), [request]));
215
221
  const data = batch[0].chunkData.data.map((d) => {
216
222
  return {
217
223
  op: d.op,
@@ -221,7 +227,9 @@ bucket_definitions:
221
227
  });
222
228
  const c1 = 2871785649;
223
229
  expect(data).toEqual([{ op: 'PUT', object_id: 'test1', checksum: c1 }]);
224
- const checksums = [...(await bucketStorage.getChecksums(checkpoint, [request])).values()];
230
+ const checksums = [
231
+ ...(await bucketStorage.getChecksums(test_utils.testCheckpoint(checkpoint), [request])).values()
232
+ ];
225
233
  expect(checksums).toEqual([
226
234
  {
227
235
  bucket: request.bucket,
@@ -232,7 +240,7 @@ bucket_definitions:
232
240
  });
233
241
  test('(insert, delete, insert), (delete)', async () => {
234
242
  await using factory = await generateStorageFactory();
235
- const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
243
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(factory, updateSyncRulesFromYaml(`
236
244
  bucket_definitions:
237
245
  global:
238
246
  data:
@@ -240,7 +248,7 @@ bucket_definitions:
240
248
  `, {
241
249
  storageVersion
242
250
  }));
243
- const bucketStorage = factory.getInstance(syncRules);
251
+ const bucketStorage = factory.getInstance(replicationStream);
244
252
  {
245
253
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
246
254
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
@@ -283,7 +291,7 @@ bucket_definitions:
283
291
  }
284
292
  const { checkpoint } = await bucketStorage.getCheckpoint();
285
293
  const request = bucketRequest(syncRules, 'global[]');
286
- const batch = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(checkpoint, [request]));
294
+ const batch = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(test_utils.testCheckpoint(checkpoint), [request]));
287
295
  expect(reduceBucket(batch[0].chunkData.data).slice(1)).toEqual([]);
288
296
  const data = batch[0].chunkData.data.map((d) => {
289
297
  return {
@@ -296,7 +304,7 @@ bucket_definitions:
296
304
  });
297
305
  test('changing client ids', async () => {
298
306
  await using factory = await generateStorageFactory();
299
- const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
307
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(factory, updateSyncRulesFromYaml(`
300
308
  bucket_definitions:
301
309
  global:
302
310
  data:
@@ -304,7 +312,7 @@ bucket_definitions:
304
312
  `, {
305
313
  storageVersion
306
314
  }));
307
- const bucketStorage = factory.getInstance(syncRules);
315
+ const bucketStorage = factory.getInstance(replicationStream);
308
316
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
309
317
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
310
318
  await writer.markAllSnapshotDone('1/1');
@@ -340,7 +348,7 @@ bucket_definitions:
340
348
  });
341
349
  await writer.commit('1/1');
342
350
  const { checkpoint } = await bucketStorage.getCheckpoint();
343
- const batch = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(checkpoint, [bucketRequest(syncRules, 'global[]')]));
351
+ const batch = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(test_utils.testCheckpoint(checkpoint), [bucketRequest(syncRules, 'global[]')]));
344
352
  const data = batch[0].chunkData.data.map((d) => {
345
353
  return {
346
354
  op: d.op,
@@ -356,7 +364,7 @@ bucket_definitions:
356
364
  });
357
365
  test('re-apply delete', async () => {
358
366
  await using factory = await generateStorageFactory();
359
- const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
367
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(factory, updateSyncRulesFromYaml(`
360
368
  bucket_definitions:
361
369
  global:
362
370
  data:
@@ -364,7 +372,7 @@ bucket_definitions:
364
372
  `, {
365
373
  storageVersion
366
374
  }));
367
- const bucketStorage = factory.getInstance(syncRules);
375
+ const bucketStorage = factory.getInstance(replicationStream);
368
376
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
369
377
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
370
378
  await writer.markAllSnapshotDone('1/1');
@@ -392,7 +400,7 @@ bucket_definitions:
392
400
  await writer.flush();
393
401
  const { checkpoint } = await bucketStorage.getCheckpoint();
394
402
  const request = bucketRequest(syncRules, 'global[]');
395
- const batch = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(checkpoint, [request]));
403
+ const batch = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(test_utils.testCheckpoint(checkpoint), [request]));
396
404
  const data = batch[0].chunkData.data.map((d) => {
397
405
  return {
398
406
  op: d.op,
@@ -406,7 +414,9 @@ bucket_definitions:
406
414
  { op: 'PUT', object_id: 'test1', checksum: c1 },
407
415
  { op: 'REMOVE', object_id: 'test1', checksum: c2 }
408
416
  ]);
409
- const checksums = [...(await bucketStorage.getChecksums(checkpoint, [request])).values()];
417
+ const checksums = [
418
+ ...(await bucketStorage.getChecksums(test_utils.testCheckpoint(checkpoint), [request])).values()
419
+ ];
410
420
  expect(checksums).toEqual([
411
421
  {
412
422
  bucket: bucketRequest(syncRules, 'global[]').bucket,
@@ -417,13 +427,13 @@ bucket_definitions:
417
427
  });
418
428
  test('re-apply update + delete', async () => {
419
429
  await using factory = await generateStorageFactory();
420
- const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
430
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(factory, updateSyncRulesFromYaml(`
421
431
  bucket_definitions:
422
432
  global:
423
433
  data:
424
434
  - SELECT id, description FROM "%"
425
435
  `, { storageVersion }));
426
- const bucketStorage = factory.getInstance(syncRules);
436
+ const bucketStorage = factory.getInstance(replicationStream);
427
437
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
428
438
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
429
439
  await writer.markAllSnapshotDone('1/1');
@@ -489,7 +499,7 @@ bucket_definitions:
489
499
  await writer.commit('2/1');
490
500
  const { checkpoint } = await bucketStorage.getCheckpoint();
491
501
  const request = bucketRequest(syncRules, 'global[]');
492
- const batch = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(checkpoint, [request]));
502
+ const batch = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(test_utils.testCheckpoint(checkpoint), [request]));
493
503
  const data = batch[0].chunkData.data.map((d) => {
494
504
  return {
495
505
  op: d.op,
@@ -505,7 +515,9 @@ bucket_definitions:
505
515
  { op: 'PUT', object_id: 'test1', checksum: c1 },
506
516
  { op: 'REMOVE', object_id: 'test1', checksum: c2 }
507
517
  ]);
508
- const checksums = [...(await bucketStorage.getChecksums(checkpoint, [request])).values()];
518
+ const checksums = [
519
+ ...(await bucketStorage.getChecksums(test_utils.testCheckpoint(checkpoint), [request])).values()
520
+ ];
509
521
  expect(checksums).toEqual([
510
522
  {
511
523
  bucket: bucketRequest(syncRules, 'global[]').bucket,
@@ -523,13 +535,13 @@ bucket_definitions:
523
535
  // 1. Not getting the correct "current_data" state for each operation.
524
536
  // 2. Output order not being correct.
525
537
  await using factory = await generateStorageFactory();
526
- const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
538
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(factory, updateSyncRulesFromYaml(`
527
539
  bucket_definitions:
528
540
  global:
529
541
  data:
530
542
  - SELECT id, description FROM "test"
531
543
  `, { storageVersion }));
532
- const bucketStorage = factory.getInstance(syncRules);
544
+ const bucketStorage = factory.getInstance(replicationStream);
533
545
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
534
546
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
535
547
  // Pre-setup
@@ -627,7 +639,7 @@ bucket_definitions:
627
639
  const result2 = await writer.flush();
628
640
  const checkpoint2 = result2.flushed_op;
629
641
  const request = bucketRequest(syncRules, 'global[]', checkpoint1);
630
- const batch = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(checkpoint2, [request]));
642
+ const batch = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(test_utils.testCheckpoint(checkpoint2), [request]));
631
643
  const data = batch[0].chunkData.data.map((d) => {
632
644
  return {
633
645
  op: d.op,
@@ -659,7 +671,7 @@ bucket_definitions:
659
671
  ]);
660
672
  }
661
673
  await using factory = await generateStorageFactory();
662
- const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
674
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(factory, updateSyncRulesFromYaml(`
663
675
  bucket_definitions:
664
676
  global:
665
677
  data:
@@ -667,7 +679,7 @@ bucket_definitions:
667
679
  `, {
668
680
  storageVersion
669
681
  }));
670
- const bucketStorage = factory.getInstance(syncRules);
682
+ const bucketStorage = factory.getInstance(replicationStream);
671
683
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
672
684
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id', 'description'], config);
673
685
  // Pre-setup
@@ -713,7 +725,7 @@ bucket_definitions:
713
725
  const result3 = await writer.flush();
714
726
  const checkpoint3 = result3.flushed_op;
715
727
  const request = bucketRequest(syncRules, 'global[]');
716
- const batch = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(checkpoint3, [{ ...request, start: checkpoint1 }]));
728
+ const batch = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(test_utils.testCheckpoint(checkpoint3), [{ ...request, start: checkpoint1 }]));
717
729
  const data = batch[0].chunkData.data.map((d) => {
718
730
  return {
719
731
  op: d.op,
@@ -755,7 +767,7 @@ bucket_definitions:
755
767
  ]);
756
768
  }
757
769
  await using factory = await generateStorageFactory();
758
- const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
770
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(factory, updateSyncRulesFromYaml(`
759
771
  bucket_definitions:
760
772
  global:
761
773
  data:
@@ -763,7 +775,7 @@ bucket_definitions:
763
775
  `, {
764
776
  storageVersion
765
777
  }));
766
- const bucketStorage = factory.getInstance(syncRules);
778
+ const bucketStorage = factory.getInstance(replicationStream);
767
779
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
768
780
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id', 'description'], config);
769
781
  // Pre-setup
@@ -809,7 +821,7 @@ bucket_definitions:
809
821
  const result3 = await writer.flush();
810
822
  const checkpoint3 = result3.flushed_op;
811
823
  const request = bucketRequest(syncRules, 'global[]');
812
- const batch = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(checkpoint3, [{ ...request, start: checkpoint1 }]));
824
+ const batch = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(test_utils.testCheckpoint(checkpoint3), [{ ...request, start: checkpoint1 }]));
813
825
  const data = batch[0].chunkData.data.map((d) => {
814
826
  return {
815
827
  op: d.op,
@@ -842,7 +854,7 @@ bucket_definitions:
842
854
  // The specific batch splits is an implementation detail of the storage driver,
843
855
  // and the test will have to updated when other implementations are added.
844
856
  await using factory = await generateStorageFactory();
845
- const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
857
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(factory, updateSyncRulesFromYaml(`
846
858
  bucket_definitions:
847
859
  global:
848
860
  data:
@@ -850,7 +862,7 @@ bucket_definitions:
850
862
  `, {
851
863
  storageVersion
852
864
  }));
853
- const bucketStorage = factory.getInstance(syncRules);
865
+ const bucketStorage = factory.getInstance(replicationStream);
854
866
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
855
867
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
856
868
  await writer.markAllSnapshotDone('1/1');
@@ -898,7 +910,7 @@ bucket_definitions:
898
910
  chunkLimitBytes: 16 * 1024 * 1024
899
911
  };
900
912
  const request = bucketRequest(syncRules, 'global[]');
901
- const batch1 = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(checkpoint, [request], options));
913
+ const batch1 = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(test_utils.testCheckpoint(checkpoint), [request], options));
902
914
  expect(test_utils.getBatchData(batch1)).toEqual([
903
915
  { op_id: '1', op: 'PUT', object_id: 'test1', checksum: 2871785649 },
904
916
  { op_id: '2', op: 'PUT', object_id: 'large1', checksum: 454746904 }
@@ -908,7 +920,7 @@ bucket_definitions:
908
920
  has_more: true,
909
921
  next_after: '2'
910
922
  });
911
- const batch2 = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(checkpoint, [{ ...request, start: BigInt(batch1[0].chunkData.next_after) }], options));
923
+ const batch2 = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(test_utils.testCheckpoint(checkpoint), [{ ...request, start: BigInt(batch1[0].chunkData.next_after) }], options));
912
924
  expect(test_utils.getBatchData(batch2)).toEqual([
913
925
  { op_id: '3', op: 'PUT', object_id: 'large2', checksum: 1795508474 },
914
926
  { op_id: '4', op: 'PUT', object_id: 'test3', checksum: 1359888332 }
@@ -918,14 +930,14 @@ bucket_definitions:
918
930
  has_more: false,
919
931
  next_after: '4'
920
932
  });
921
- const batch3 = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(checkpoint, [{ ...request, start: BigInt(batch2[0].chunkData.next_after) }], options));
933
+ const batch3 = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(test_utils.testCheckpoint(checkpoint), [{ ...request, start: BigInt(batch2[0].chunkData.next_after) }], options));
922
934
  expect(test_utils.getBatchData(batch3)).toEqual([]);
923
935
  expect(test_utils.getBatchMeta(batch3)).toEqual(null);
924
936
  });
925
937
  test('long batch', async () => {
926
938
  // Test syncing a batch of data that is limited by count.
927
939
  await using factory = await generateStorageFactory();
928
- const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
940
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(factory, updateSyncRulesFromYaml(`
929
941
  bucket_definitions:
930
942
  global:
931
943
  data:
@@ -933,7 +945,7 @@ bucket_definitions:
933
945
  `, {
934
946
  storageVersion
935
947
  }));
936
- const bucketStorage = factory.getInstance(syncRules);
948
+ const bucketStorage = factory.getInstance(replicationStream);
937
949
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
938
950
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
939
951
  await writer.markAllSnapshotDone('1/1');
@@ -951,7 +963,7 @@ bucket_definitions:
951
963
  await writer.commit('1/1');
952
964
  const { checkpoint } = await bucketStorage.getCheckpoint();
953
965
  const request = bucketRequest(syncRules, 'global[]');
954
- const batch1 = await test_utils.oneFromAsync(bucketStorage.getBucketDataBatch(checkpoint, [request], { limit: 4 }));
966
+ const batch1 = await test_utils.oneFromAsync(bucketStorage.getBucketDataBatch(test_utils.testCheckpoint(checkpoint), [request], { limit: 4 }));
955
967
  expect(test_utils.getBatchData(batch1)).toEqual([
956
968
  { op_id: '1', op: 'PUT', object_id: 'test1', checksum: 2871785649 },
957
969
  { op_id: '2', op: 'PUT', object_id: 'test2', checksum: 730027011 },
@@ -963,7 +975,7 @@ bucket_definitions:
963
975
  has_more: true,
964
976
  next_after: '4'
965
977
  });
966
- const batch2 = await test_utils.oneFromAsync(bucketStorage.getBucketDataBatch(checkpoint, [{ ...request, start: BigInt(batch1.chunkData.next_after) }], {
978
+ const batch2 = await test_utils.oneFromAsync(bucketStorage.getBucketDataBatch(test_utils.testCheckpoint(checkpoint), [{ ...request, start: BigInt(batch1.chunkData.next_after) }], {
967
979
  limit: 4
968
980
  }));
969
981
  expect(test_utils.getBatchData(batch2)).toEqual([
@@ -975,7 +987,7 @@ bucket_definitions:
975
987
  has_more: false,
976
988
  next_after: '6'
977
989
  });
978
- const batch3 = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(checkpoint, [{ ...request, start: BigInt(batch2.chunkData.next_after) }], {
990
+ const batch3 = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(test_utils.testCheckpoint(checkpoint), [{ ...request, start: BigInt(batch2.chunkData.next_after) }], {
979
991
  limit: 4
980
992
  }));
981
993
  expect(test_utils.getBatchData(batch3)).toEqual([]);
@@ -984,7 +996,7 @@ bucket_definitions:
984
996
  describe('batch has_more', () => {
985
997
  const setup = async (options) => {
986
998
  await using factory = await generateStorageFactory();
987
- const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
999
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(factory, updateSyncRulesFromYaml(`
988
1000
  bucket_definitions:
989
1001
  global1:
990
1002
  data:
@@ -993,7 +1005,7 @@ bucket_definitions:
993
1005
  data:
994
1006
  - SELECT id, description FROM test WHERE bucket = 'global2'
995
1007
  `, { storageVersion }));
996
- const bucketStorage = factory.getInstance(syncRules);
1008
+ const bucketStorage = factory.getInstance(replicationStream);
997
1009
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
998
1010
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
999
1011
  await writer.markAllSnapshotDone('1/1');
@@ -1013,7 +1025,7 @@ bucket_definitions:
1013
1025
  const { checkpoint } = await bucketStorage.getCheckpoint();
1014
1026
  const global1Request = bucketRequest(syncRules, 'global1[]', 0n);
1015
1027
  const global2Request = bucketRequest(syncRules, 'global2[]', 0n);
1016
- const batch = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(checkpoint, [global1Request, global2Request], options));
1028
+ const batch = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(test_utils.testCheckpoint(checkpoint), [global1Request, global2Request], options));
1017
1029
  return { batch, global1Request, global2Request };
1018
1030
  };
1019
1031
  test('batch has_more (1)', async () => {
@@ -1074,34 +1086,59 @@ bucket_definitions:
1074
1086
  test('batch has_more (3)', async () => {
1075
1087
  // 50 bytes is more than 1 row, less than 2 rows
1076
1088
  const { batch, global1Request, global2Request } = await setup({ limit: 3, chunkLimitBytes: 50 });
1077
- expect(batch.length).toEqual(3);
1078
- expect(batch[0].chunkData.bucket).toEqual(global1Request.bucket);
1079
- expect(batch[1].chunkData.bucket).toEqual(global2Request.bucket);
1080
- expect(batch[2].chunkData.bucket).toEqual(global2Request.bucket);
1081
- expect(test_utils.getBatchData(batch[0])).toEqual([
1082
- { op_id: '1', op: 'PUT', object_id: 'test1', checksum: 2871785649 }
1083
- ]);
1084
- expect(test_utils.getBatchData(batch[1])).toEqual([
1085
- { op_id: '2', op: 'PUT', object_id: 'test2', checksum: 730027011 }
1086
- ]);
1087
- expect(test_utils.getBatchData(batch[2])).toEqual([
1088
- { op_id: '3', op: 'PUT', object_id: 'test3', checksum: 1359888332 }
1089
- ]);
1090
- expect(test_utils.getBatchMeta(batch[0])).toEqual({
1091
- after: '0',
1092
- has_more: false,
1093
- next_after: '1'
1094
- });
1095
- expect(test_utils.getBatchMeta(batch[1])).toEqual({
1096
- after: '0',
1097
- has_more: true,
1098
- next_after: '2'
1099
- });
1100
- expect(test_utils.getBatchMeta(batch[2])).toEqual({
1101
- after: '2',
1102
- has_more: true,
1103
- next_after: '3'
1104
- });
1089
+ if (config.compressedBucketStorage) {
1090
+ // In v3+, ops in the same bucket share a document, so ops 2 and 3 (global2) are batched together
1091
+ expect(batch.length).toEqual(2);
1092
+ expect(batch[0].chunkData.bucket).toEqual(global1Request.bucket);
1093
+ expect(batch[1].chunkData.bucket).toEqual(global2Request.bucket);
1094
+ expect(test_utils.getBatchData(batch[0])).toEqual([
1095
+ { op_id: '1', op: 'PUT', object_id: 'test1', checksum: 2871785649 }
1096
+ ]);
1097
+ expect(test_utils.getBatchData(batch[1])).toEqual([
1098
+ { op_id: '2', op: 'PUT', object_id: 'test2', checksum: 730027011 },
1099
+ { op_id: '3', op: 'PUT', object_id: 'test3', checksum: 1359888332 }
1100
+ ]);
1101
+ expect(test_utils.getBatchMeta(batch[0])).toEqual({
1102
+ after: '0',
1103
+ has_more: false,
1104
+ next_after: '1'
1105
+ });
1106
+ expect(test_utils.getBatchMeta(batch[1])).toEqual({
1107
+ after: '0',
1108
+ has_more: true,
1109
+ next_after: '3'
1110
+ });
1111
+ }
1112
+ else {
1113
+ expect(batch.length).toEqual(3);
1114
+ expect(batch[0].chunkData.bucket).toEqual(global1Request.bucket);
1115
+ expect(batch[1].chunkData.bucket).toEqual(global2Request.bucket);
1116
+ expect(batch[2].chunkData.bucket).toEqual(global2Request.bucket);
1117
+ expect(test_utils.getBatchData(batch[0])).toEqual([
1118
+ { op_id: '1', op: 'PUT', object_id: 'test1', checksum: 2871785649 }
1119
+ ]);
1120
+ expect(test_utils.getBatchData(batch[1])).toEqual([
1121
+ { op_id: '2', op: 'PUT', object_id: 'test2', checksum: 730027011 }
1122
+ ]);
1123
+ expect(test_utils.getBatchData(batch[2])).toEqual([
1124
+ { op_id: '3', op: 'PUT', object_id: 'test3', checksum: 1359888332 }
1125
+ ]);
1126
+ expect(test_utils.getBatchMeta(batch[0])).toEqual({
1127
+ after: '0',
1128
+ has_more: false,
1129
+ next_after: '1'
1130
+ });
1131
+ expect(test_utils.getBatchMeta(batch[1])).toEqual({
1132
+ after: '0',
1133
+ has_more: true,
1134
+ next_after: '2'
1135
+ });
1136
+ expect(test_utils.getBatchMeta(batch[2])).toEqual({
1137
+ after: '2',
1138
+ has_more: true,
1139
+ next_after: '3'
1140
+ });
1141
+ }
1105
1142
  });
1106
1143
  });
1107
1144
  test('empty storage metrics', async () => {
@@ -1125,7 +1162,7 @@ bucket_definitions:
1125
1162
  // but large enough in size to be split over multiple returned chunks.
1126
1163
  // Similar to the above test, but splits over 1MB chunks.
1127
1164
  await using factory = await generateStorageFactory();
1128
- const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
1165
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(factory, updateSyncRulesFromYaml(`
1129
1166
  bucket_definitions:
1130
1167
  global:
1131
1168
  data:
@@ -1134,7 +1171,7 @@ bucket_definitions:
1134
1171
  `, {
1135
1172
  storageVersion
1136
1173
  }));
1137
- const bucketStorage = factory.getInstance(syncRules);
1174
+ const bucketStorage = factory.getInstance(replicationStream);
1138
1175
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
1139
1176
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config, 1);
1140
1177
  const sourceTableIgnore = await test_utils.resolveTestTable(writer, 'test_ignore', ['id'], config, 2);
@@ -1166,7 +1203,7 @@ bucket_definitions:
1166
1203
  });
1167
1204
  test('unchanged checksums', async () => {
1168
1205
  await using factory = await generateStorageFactory();
1169
- const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
1206
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(factory, updateSyncRulesFromYaml(`
1170
1207
  bucket_definitions:
1171
1208
  global:
1172
1209
  data:
@@ -1174,7 +1211,7 @@ bucket_definitions:
1174
1211
  `, {
1175
1212
  storageVersion
1176
1213
  }));
1177
- const bucketStorage = factory.getInstance(syncRules);
1214
+ const bucketStorage = factory.getInstance(replicationStream);
1178
1215
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
1179
1216
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
1180
1217
  await writer.markAllSnapshotDone('1/1');
@@ -1190,21 +1227,25 @@ bucket_definitions:
1190
1227
  await writer.commit('1/1');
1191
1228
  const { checkpoint } = await bucketStorage.getCheckpoint();
1192
1229
  const request = bucketRequest(syncRules, 'global[]');
1193
- const checksums = [...(await bucketStorage.getChecksums(checkpoint, [request])).values()];
1230
+ const checksums = [
1231
+ ...(await bucketStorage.getChecksums(test_utils.testCheckpoint(checkpoint), [request])).values()
1232
+ ];
1194
1233
  expect(checksums).toEqual([{ bucket: request.bucket, checksum: 1917136889, count: 1 }]);
1195
- const checksums2 = [...(await bucketStorage.getChecksums(checkpoint + 1n, [request])).values()];
1234
+ const checksums2 = [
1235
+ ...(await bucketStorage.getChecksums(test_utils.testCheckpoint(checkpoint + 1n), [request])).values()
1236
+ ];
1196
1237
  expect(checksums2).toEqual([{ bucket: request.bucket, checksum: 1917136889, count: 1 }]);
1197
1238
  });
1198
1239
  testChecksumBatching(config);
1199
1240
  test('empty checkpoints (1)', async () => {
1200
1241
  await using factory = await generateStorageFactory();
1201
- const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
1242
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(factory, updateSyncRulesFromYaml(`
1202
1243
  bucket_definitions:
1203
1244
  global:
1204
1245
  data:
1205
1246
  - SELECT id, description FROM "%"
1206
1247
  `, { storageVersion }));
1207
- const bucketStorage = factory.getInstance(syncRules);
1248
+ const bucketStorage = factory.getInstance(replicationStream);
1208
1249
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
1209
1250
  await writer.markAllSnapshotDone('1/1');
1210
1251
  await writer.commit('1/1');
@@ -1224,7 +1265,7 @@ bucket_definitions:
1224
1265
  });
1225
1266
  test('empty checkpoints (2)', async () => {
1226
1267
  await using factory = await generateStorageFactory();
1227
- const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
1268
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(factory, updateSyncRulesFromYaml(`
1228
1269
  bucket_definitions:
1229
1270
  global:
1230
1271
  data:
@@ -1232,7 +1273,7 @@ bucket_definitions:
1232
1273
  `, {
1233
1274
  storageVersion
1234
1275
  }));
1235
- const bucketStorage = factory.getInstance(syncRules);
1276
+ const bucketStorage = factory.getInstance(replicationStream);
1236
1277
  await using writer1 = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
1237
1278
  await using writer2 = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
1238
1279
  const sourceTable = await test_utils.resolveTestTable(writer2, 'test', ['id'], config);
@@ -1263,7 +1304,7 @@ bucket_definitions:
1263
1304
  });
1264
1305
  test('empty checkpoints (sync rule activation)', async () => {
1265
1306
  await using factory = await generateStorageFactory();
1266
- const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
1307
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(factory, updateSyncRulesFromYaml(`
1267
1308
  bucket_definitions:
1268
1309
  global:
1269
1310
  data:
@@ -1271,7 +1312,7 @@ bucket_definitions:
1271
1312
  `, {
1272
1313
  storageVersion
1273
1314
  }));
1274
- const bucketStorage = factory.getInstance(syncRules);
1315
+ const bucketStorage = factory.getInstance(replicationStream);
1275
1316
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
1276
1317
  const result1 = await writer.commit('1/1', { createEmptyCheckpoints: false });
1277
1318
  expect(result1).toEqual({ checkpointBlocked: true, checkpointCreated: false });
@@ -1290,8 +1331,8 @@ bucket_definitions:
1290
1331
  // Now, the checkpoint should advance the sync rules active.
1291
1332
  const cp2 = await bucketStorage.getCheckpoint();
1292
1333
  expect(cp2.lsn).toEqual('3/1');
1293
- const activeSyncRules = await factory.getActiveSyncRulesContent();
1294
- expect(activeSyncRules?.id).toEqual(syncRules.id);
1334
+ const activeSyncRules = await factory.getActiveSyncConfig();
1335
+ expect(activeSyncRules?.content.replicationStreamId).toEqual(syncRules.replicationStreamId);
1295
1336
  // At this point, it should be a truely empty checkpoint
1296
1337
  const result4 = await writer.commit('4/1', { createEmptyCheckpoints: false });
1297
1338
  expect(result4).toEqual({ checkpointBlocked: false, checkpointCreated: false });
@@ -1301,7 +1342,7 @@ bucket_definitions:
1301
1342
  });
1302
1343
  test.runIf(storageVersion >= 3)('deleting while streaming', async () => {
1303
1344
  await using factory = await generateStorageFactory();
1304
- const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
1345
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(factory, updateSyncRulesFromYaml(`
1305
1346
  bucket_definitions:
1306
1347
  global:
1307
1348
  data:
@@ -1309,7 +1350,7 @@ bucket_definitions:
1309
1350
  `, {
1310
1351
  storageVersion
1311
1352
  }));
1312
- const bucketStorage = factory.getInstance(syncRules);
1353
+ const bucketStorage = factory.getInstance(replicationStream);
1313
1354
  await using snapshotWriter = await bucketStorage.createWriter({
1314
1355
  ...test_utils.BATCH_OPTIONS,
1315
1356
  skipExistingRows: true
@@ -1344,7 +1385,7 @@ bucket_definitions:
1344
1385
  await streamingWriter.keepalive('3/1');
1345
1386
  const cp = await bucketStorage.getCheckpoint();
1346
1387
  expect(cp.lsn).toEqual('3/1');
1347
- const data = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(cp.checkpoint, [bucketRequest(syncRules, 'global[]')]));
1388
+ const data = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(test_utils.testCheckpoint(cp.checkpoint), [bucketRequest(syncRules, 'global[]')]));
1348
1389
  expect(data).toEqual([]);
1349
1390
  });
1350
1391
  }
@@ -1357,7 +1398,7 @@ export function testChecksumBatching(config) {
1357
1398
  const storageVersion = config.storageVersion ?? CURRENT_STORAGE_VERSION;
1358
1399
  test('checksums for multiple buckets', async () => {
1359
1400
  await using factory = await config.factory();
1360
- const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
1401
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(factory, updateSyncRulesFromYaml(`
1361
1402
  bucket_definitions:
1362
1403
  user:
1363
1404
  parameters: select request.user_id() as user_id
@@ -1366,7 +1407,7 @@ bucket_definitions:
1366
1407
  `, {
1367
1408
  storageVersion
1368
1409
  }));
1369
- const bucketStorage = factory.getInstance(syncRules);
1410
+ const bucketStorage = factory.getInstance(replicationStream);
1370
1411
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
1371
1412
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
1372
1413
  await writer.markAllSnapshotDone('1/1');
@@ -1391,7 +1432,9 @@ bucket_definitions:
1391
1432
  const users = ['u1', 'u2', 'u3', 'u4'];
1392
1433
  const expectedChecksums = [346204588, 5261081, 134760718, -302639724];
1393
1434
  const bucketRequests = users.map((user) => bucketRequest(syncRules, `user["${user}"]`));
1394
- const checksums = [...(await bucketStorage.getChecksums(checkpoint, bucketRequests)).values()];
1435
+ const checksums = [
1436
+ ...(await bucketStorage.getChecksums(test_utils.testCheckpoint(checkpoint), bucketRequests)).values()
1437
+ ];
1395
1438
  checksums.sort((a, b) => a.bucket.localeCompare(b.bucket));
1396
1439
  const expected = bucketRequests.map((request, index) => ({
1397
1440
  bucket: request.bucket,
@@ -1411,7 +1454,11 @@ streams:
1411
1454
  invalid:
1412
1455
  query: UPDATE test SET foo = 'bar' RETURNING *
1413
1456
  `));
1414
- const { errors } = deployed.parsed({ defaultSchema: 'ignored' }).syncConfigWithErrors;
1457
+ const [deployedContent] = deployed.syncConfigContent;
1458
+ expect(deployedContent).toBeDefined();
1459
+ const [deployedConfig] = deployedContent.parsed({ defaultSchema: 'ignored' }).syncConfigs;
1460
+ expect(deployedConfig).toBeDefined();
1461
+ const { errors } = deployedConfig;
1415
1462
  expect(errors).toHaveLength(1);
1416
1463
  expect(errors[0].message).toStrictEqual('Expected a SELECT statement');
1417
1464
  expect(errors[0].location).toStrictEqual({