@powersync/service-module-mongodb-storage 0.18.3 → 0.20.0

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 (145) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/dist/migrations/db/migrations/1782950400000-checkpoint-requested-at-index.d.ts +3 -0
  3. package/dist/migrations/db/migrations/1782950400000-checkpoint-requested-at-index.js +41 -0
  4. package/dist/migrations/db/migrations/1782950400000-checkpoint-requested-at-index.js.map +1 -0
  5. package/dist/storage/MongoBucketStorage.d.ts +5 -1
  6. package/dist/storage/MongoBucketStorage.js +5 -1
  7. package/dist/storage/MongoBucketStorage.js.map +1 -1
  8. package/dist/storage/implementation/MongoBucketBatch.d.ts +3 -0
  9. package/dist/storage/implementation/MongoBucketBatch.js.map +1 -1
  10. package/dist/storage/implementation/MongoCompactor.d.ts +15 -19
  11. package/dist/storage/implementation/MongoCompactor.js +68 -260
  12. package/dist/storage/implementation/MongoCompactor.js.map +1 -1
  13. package/dist/storage/implementation/MongoStorageProvider.js +26 -3
  14. package/dist/storage/implementation/MongoStorageProvider.js.map +1 -1
  15. package/dist/storage/implementation/MongoSyncBucketStorage.d.ts +10 -4
  16. package/dist/storage/implementation/MongoSyncBucketStorage.js +13 -12
  17. package/dist/storage/implementation/MongoSyncBucketStorage.js.map +1 -1
  18. package/dist/storage/implementation/MongoWriteCheckpointAPI.d.ts +2 -1
  19. package/dist/storage/implementation/MongoWriteCheckpointAPI.js +146 -34
  20. package/dist/storage/implementation/MongoWriteCheckpointAPI.js.map +1 -1
  21. package/dist/storage/implementation/common/PersistedBatch.d.ts +6 -0
  22. package/dist/storage/implementation/common/PersistedBatch.js +15 -8
  23. package/dist/storage/implementation/common/PersistedBatch.js.map +1 -1
  24. package/dist/storage/implementation/models.d.ts +20 -0
  25. package/dist/storage/implementation/models.js.map +1 -1
  26. package/dist/storage/implementation/v1/MongoBucketBatchV1.d.ts +4 -0
  27. package/dist/storage/implementation/v1/MongoBucketBatchV1.js +58 -84
  28. package/dist/storage/implementation/v1/MongoBucketBatchV1.js.map +1 -1
  29. package/dist/storage/implementation/v1/MongoCompactorV1.d.ts +11 -2
  30. package/dist/storage/implementation/v1/MongoCompactorV1.js +250 -1
  31. package/dist/storage/implementation/v1/MongoCompactorV1.js.map +1 -1
  32. package/dist/storage/implementation/v1/MongoSyncBucketStorageV1.js +19 -11
  33. package/dist/storage/implementation/v1/MongoSyncBucketStorageV1.js.map +1 -1
  34. package/dist/storage/implementation/v1/SingleBucketStoreV1.d.ts +9 -10
  35. package/dist/storage/implementation/v1/SingleBucketStoreV1.js +2 -8
  36. package/dist/storage/implementation/v1/SingleBucketStoreV1.js.map +1 -1
  37. package/dist/storage/implementation/v3/BucketDataContextV3.d.ts +13 -0
  38. package/dist/storage/implementation/v3/BucketDataContextV3.js +23 -0
  39. package/dist/storage/implementation/v3/BucketDataContextV3.js.map +1 -0
  40. package/dist/storage/implementation/v3/MongoBucketBatchV3.js +35 -23
  41. package/dist/storage/implementation/v3/MongoBucketBatchV3.js.map +1 -1
  42. package/dist/storage/implementation/v3/MongoChecksumsV3.d.ts +1 -0
  43. package/dist/storage/implementation/v3/MongoChecksumsV3.js +59 -103
  44. package/dist/storage/implementation/v3/MongoChecksumsV3.js.map +1 -1
  45. package/dist/storage/implementation/v3/MongoCompactorV3.d.ts +23 -2
  46. package/dist/storage/implementation/v3/MongoCompactorV3.js +354 -219
  47. package/dist/storage/implementation/v3/MongoCompactorV3.js.map +1 -1
  48. package/dist/storage/implementation/v3/MongoStoppedSyncConfigCleanup.d.ts +5 -0
  49. package/dist/storage/implementation/v3/MongoStoppedSyncConfigCleanup.js +12 -11
  50. package/dist/storage/implementation/v3/MongoStoppedSyncConfigCleanup.js.map +1 -1
  51. package/dist/storage/implementation/v3/MongoSyncBucketStorageV3.d.ts +5 -3
  52. package/dist/storage/implementation/v3/MongoSyncBucketStorageV3.js +108 -106
  53. package/dist/storage/implementation/v3/MongoSyncBucketStorageV3.js.map +1 -1
  54. package/dist/storage/implementation/v3/PersistedBatchV3.d.ts +5 -2
  55. package/dist/storage/implementation/v3/PersistedBatchV3.js +53 -15
  56. package/dist/storage/implementation/v3/PersistedBatchV3.js.map +1 -1
  57. package/dist/storage/implementation/v3/VersionedPowerSyncMongoV3.d.ts +2 -1
  58. package/dist/storage/implementation/v3/VersionedPowerSyncMongoV3.js +3 -0
  59. package/dist/storage/implementation/v3/VersionedPowerSyncMongoV3.js.map +1 -1
  60. package/dist/storage/implementation/v3/bucket-format.d.ts +10 -1
  61. package/dist/storage/implementation/v3/bucket-format.js +28 -9
  62. package/dist/storage/implementation/v3/bucket-format.js.map +1 -1
  63. package/dist/storage/implementation/v3/chunking.js +3 -1
  64. package/dist/storage/implementation/v3/chunking.js.map +1 -1
  65. package/dist/storage/implementation/v3/models.d.ts +43 -2
  66. package/dist/storage/implementation/v3/models.js.map +1 -1
  67. package/dist/storage/implementation/v3/object-storage/BucketDataObjectStorage.d.ts +21 -0
  68. package/dist/storage/implementation/v3/object-storage/BucketDataObjectStorage.js +44 -0
  69. package/dist/storage/implementation/v3/object-storage/BucketDataObjectStorage.js.map +1 -0
  70. package/dist/storage/implementation/v3/object-storage/ObjectStorage.d.ts +30 -0
  71. package/dist/storage/implementation/v3/object-storage/ObjectStorage.js +12 -0
  72. package/dist/storage/implementation/v3/object-storage/ObjectStorage.js.map +1 -0
  73. package/dist/storage/implementation/v3/object-storage/ObjectStorageLifecycle.d.ts +70 -0
  74. package/dist/storage/implementation/v3/object-storage/ObjectStorageLifecycle.js +146 -0
  75. package/dist/storage/implementation/v3/object-storage/ObjectStorageLifecycle.js.map +1 -0
  76. package/dist/storage/implementation/v3/object-storage/S3ObjectStorage.d.ts +42 -0
  77. package/dist/storage/implementation/v3/object-storage/S3ObjectStorage.js +285 -0
  78. package/dist/storage/implementation/v3/object-storage/S3ObjectStorage.js.map +1 -0
  79. package/dist/storage/implementation/v3/source-table-utils.d.ts +9 -1
  80. package/dist/storage/implementation/v3/source-table-utils.js +20 -21
  81. package/dist/storage/implementation/v3/source-table-utils.js.map +1 -1
  82. package/dist/types/types.d.ts +35 -0
  83. package/dist/types/types.js +35 -1
  84. package/dist/types/types.js.map +1 -1
  85. package/dist/utils/test-utils.js +3 -1
  86. package/dist/utils/test-utils.js.map +1 -1
  87. package/dist/utils/util.d.ts +8 -1
  88. package/dist/utils/util.js +125 -2
  89. package/dist/utils/util.js.map +1 -1
  90. package/package.json +10 -7
  91. package/src/migrations/db/migrations/1782950400000-checkpoint-requested-at-index.ts +55 -0
  92. package/src/storage/MongoBucketStorage.ts +10 -2
  93. package/src/storage/implementation/MongoBucketBatch.ts +4 -0
  94. package/src/storage/implementation/MongoCompactor.ts +90 -314
  95. package/src/storage/implementation/MongoStorageProvider.ts +32 -3
  96. package/src/storage/implementation/MongoSyncBucketStorage.ts +23 -22
  97. package/src/storage/implementation/MongoWriteCheckpointAPI.ts +164 -37
  98. package/src/storage/implementation/common/PersistedBatch.ts +22 -10
  99. package/src/storage/implementation/models.ts +20 -0
  100. package/src/storage/implementation/v1/MongoBucketBatchV1.ts +76 -96
  101. package/src/storage/implementation/v1/MongoCompactorV1.ts +292 -8
  102. package/src/storage/implementation/v1/MongoSyncBucketStorageV1.ts +53 -40
  103. package/src/storage/implementation/v1/SingleBucketStoreV1.ts +18 -27
  104. package/src/storage/implementation/v3/BucketDataContextV3.ts +32 -0
  105. package/src/storage/implementation/v3/MongoBucketBatchV3.ts +40 -23
  106. package/src/storage/implementation/v3/MongoChecksumsV3.ts +75 -105
  107. package/src/storage/implementation/v3/MongoCompactorV3.ts +456 -258
  108. package/src/storage/implementation/v3/MongoStoppedSyncConfigCleanup.ts +21 -19
  109. package/src/storage/implementation/v3/MongoSyncBucketStorageV3.ts +122 -126
  110. package/src/storage/implementation/v3/PersistedBatchV3.ts +69 -16
  111. package/src/storage/implementation/v3/VersionedPowerSyncMongoV3.ts +5 -0
  112. package/src/storage/implementation/v3/bucket-format.ts +36 -9
  113. package/src/storage/implementation/v3/chunking.ts +3 -1
  114. package/src/storage/implementation/v3/models.ts +45 -1
  115. package/src/storage/implementation/v3/object-storage/BucketDataObjectStorage.ts +54 -0
  116. package/src/storage/implementation/v3/object-storage/ObjectStorage.ts +29 -0
  117. package/src/storage/implementation/v3/object-storage/ObjectStorageLifecycle.ts +171 -0
  118. package/src/storage/implementation/v3/object-storage/S3ObjectStorage.ts +343 -0
  119. package/src/storage/implementation/v3/source-table-utils.ts +43 -35
  120. package/src/types/types.ts +42 -1
  121. package/src/utils/test-utils.ts +3 -1
  122. package/src/utils/util.ts +182 -4
  123. package/test/src/__snapshots__/storage_sync.test.ts.snap +1 -583
  124. package/test/src/cleanup-stopped-sync-configs.test.ts +24 -1
  125. package/test/src/helpers/MemoryObjectStorage.ts +53 -0
  126. package/test/src/helpers/s3TestFactory.ts +69 -0
  127. package/test/src/object_storage_lifecycle.test.ts +59 -0
  128. package/test/src/setup.ts +6 -1
  129. package/test/src/storage.test.ts +216 -2
  130. package/test/src/storage_compacting.test.ts +176 -187
  131. package/test/src/storage_object_storage_inline_threshold.test.ts +116 -0
  132. package/test/src/storage_s3_checksums.test.ts +191 -0
  133. package/test/src/storage_s3_compaction_lifecycle.test.ts +417 -0
  134. package/test/src/storage_s3_reading.test.ts +526 -0
  135. package/test/src/storage_s3_writing.test.ts +135 -0
  136. package/test/src/storage_sync.test.ts +124 -5
  137. package/tsconfig.tsbuildinfo +1 -1
  138. package/dist/storage/implementation/common/SingleBucketStore.d.ts +0 -54
  139. package/dist/storage/implementation/common/SingleBucketStore.js +0 -3
  140. package/dist/storage/implementation/common/SingleBucketStore.js.map +0 -1
  141. package/dist/storage/implementation/v3/SingleBucketStoreV3.d.ts +0 -18
  142. package/dist/storage/implementation/v3/SingleBucketStoreV3.js +0 -84
  143. package/dist/storage/implementation/v3/SingleBucketStoreV3.js.map +0 -1
  144. package/src/storage/implementation/common/SingleBucketStore.ts +0 -63
  145. package/src/storage/implementation/v3/SingleBucketStoreV3.ts +0 -108
@@ -119,6 +119,35 @@ function registerSyncStorageTests(storageConfig: storage.TestStorageConfig, stor
119
119
  storageVersion,
120
120
  tableIdStrings: storageConfig.tableIdStrings
121
121
  });
122
+
123
+ test('updates source metadata on an existing resolved table', async () => {
124
+ await using factory = await storageConfig.factory();
125
+ const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(MINIMAL_SYNC_RULES, { storageVersion }));
126
+ const bucketStorage = factory.getInstance(syncRules);
127
+ await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
128
+ const source = sourceDescriptor('test');
129
+
130
+ const initial = await writer.resolveTables({ connection_id: 1, source });
131
+ expect(initial.tables[0].sourceMetadata).toBeNull();
132
+
133
+ const sourceMetadata = { captureTableObjectId: 42 };
134
+ const updated = await writer.resolveTables({
135
+ connection_id: 1,
136
+ source,
137
+ reconcileSourceTables: ({ candidates }) => ({
138
+ compatibleTables: candidates.map((candidate) => candidate.withSourceMetadata(sourceMetadata)),
139
+ incompatibleTables: [],
140
+ newTableValues: { sourceMetadata }
141
+ })
142
+ });
143
+
144
+ expect(updated.tables.map((table) => table.id.toString())).toEqual(
145
+ initial.tables.map((table) => table.id.toString())
146
+ );
147
+ expect(updated.tables[0].sourceMetadata).toEqual(sourceMetadata);
148
+ expect((await writer.getSourceTableStatus(updated.tables[0]))?.sourceMetadata).toEqual(sourceMetadata);
149
+ });
150
+
122
151
  // The split of returned results can vary depending on storage drivers
123
152
  test('large batch (2)', async () => {
124
153
  // Test syncing a batch of data that is small in count,
@@ -191,7 +220,7 @@ function registerSyncStorageTests(storageConfig: storage.TestStorageConfig, stor
191
220
  const checkpoint = flushResult!.flushed_op;
192
221
 
193
222
  const options: storage.BucketDataBatchOptions = {};
194
- const batch1 = await test_utils.fromAsync(
223
+ const batch1 = await test_utils.getBatchArray(
195
224
  bucketStorage.getBucketDataBatch(
196
225
  test_utils.testCheckpoint(checkpoint),
197
226
  [bucketRequest(syncRulesContent, 'global[]', 0n)],
@@ -208,7 +237,7 @@ function registerSyncStorageTests(storageConfig: storage.TestStorageConfig, stor
208
237
  next_after: '2'
209
238
  });
210
239
 
211
- const batch2 = await test_utils.fromAsync(
240
+ const batch2 = await test_utils.getBatchArray(
212
241
  bucketStorage.getBucketDataBatch(
213
242
  test_utils.testCheckpoint(checkpoint),
214
243
  [bucketRequest(syncRulesContent, 'global[]', batch1[0].chunkData.next_after)],
@@ -224,7 +253,7 @@ function registerSyncStorageTests(storageConfig: storage.TestStorageConfig, stor
224
253
  next_after: '3'
225
254
  });
226
255
 
227
- const batch3 = await test_utils.fromAsync(
256
+ const batch3 = await test_utils.getBatchArray(
228
257
  bucketStorage.getBucketDataBatch(
229
258
  test_utils.testCheckpoint(checkpoint),
230
259
  [bucketRequest(syncRulesContent, 'global[]', batch2[0].chunkData.next_after)],
@@ -1467,6 +1496,96 @@ streams:
1467
1496
  expect(await mongoFactory.db.current_data.countDocuments({ '_id.g': syncRules.replicationStreamId })).toBe(0);
1468
1497
  });
1469
1498
 
1499
+ test.runIf(storageVersion < 3)(
1500
+ 'clear removes large v1 current_data sets without affecting other streams',
1501
+ async () => {
1502
+ await using factory = await storageConfig.factory();
1503
+ const syncRules = await factory.updateSyncRules(
1504
+ updateSyncRulesFromYaml(MINIMAL_SYNC_RULES, {
1505
+ storageVersion
1506
+ })
1507
+ );
1508
+ const bucketStorage = factory.getInstance(syncRules);
1509
+ const mongoFactory = factory as MongoBucketStorage;
1510
+ const sourceTableId = new bson.ObjectId();
1511
+ const documents = Array.from({ length: 10_002 }, (_, index) => ({
1512
+ _id: {
1513
+ g: syncRules.replicationStreamId,
1514
+ t: sourceTableId,
1515
+ k: index
1516
+ },
1517
+ data: new bson.Binary(),
1518
+ buckets: [],
1519
+ lookups: []
1520
+ }));
1521
+ await mongoFactory.db.current_data.insertMany([
1522
+ ...documents,
1523
+ {
1524
+ _id: {
1525
+ g: syncRules.replicationStreamId + 1,
1526
+ t: sourceTableId,
1527
+ k: 0
1528
+ },
1529
+ data: new bson.Binary(),
1530
+ buckets: [],
1531
+ lookups: []
1532
+ }
1533
+ ]);
1534
+
1535
+ await bucketStorage.clear();
1536
+
1537
+ expect(await mongoFactory.db.current_data.countDocuments({ '_id.g': syncRules.replicationStreamId })).toBe(0);
1538
+ expect(await mongoFactory.db.current_data.countDocuments({ '_id.g': syncRules.replicationStreamId + 1 })).toBe(1);
1539
+ }
1540
+ );
1541
+
1542
+ test.runIf(storageVersion < 3)(
1543
+ 'clear removes large v1 parameter index sets without affecting other streams',
1544
+ async () => {
1545
+ await using factory = await storageConfig.factory();
1546
+ const syncRules = await factory.updateSyncRules(
1547
+ updateSyncRulesFromYaml(MINIMAL_SYNC_RULES, {
1548
+ storageVersion
1549
+ })
1550
+ );
1551
+ const bucketStorage = factory.getInstance(syncRules);
1552
+ const mongoFactory = factory as MongoBucketStorage;
1553
+ const sourceTableId = new bson.ObjectId();
1554
+ const documents = Array.from({ length: 10_002 }, (_, index) => ({
1555
+ _id: BigInt(index * 2),
1556
+ key: {
1557
+ g: syncRules.replicationStreamId,
1558
+ t: sourceTableId,
1559
+ k: index
1560
+ },
1561
+ lookup: new bson.Binary(),
1562
+ bucket_parameters: []
1563
+ }));
1564
+ await mongoFactory.db.bucket_parameters.insertMany([
1565
+ ...documents,
1566
+ {
1567
+ _id: 1n,
1568
+ key: {
1569
+ g: syncRules.replicationStreamId + 1,
1570
+ t: sourceTableId,
1571
+ k: 0
1572
+ },
1573
+ lookup: new bson.Binary(),
1574
+ bucket_parameters: []
1575
+ }
1576
+ ]);
1577
+
1578
+ await bucketStorage.clear();
1579
+
1580
+ expect(await mongoFactory.db.bucket_parameters.countDocuments({ 'key.g': syncRules.replicationStreamId })).toBe(
1581
+ 0
1582
+ );
1583
+ expect(
1584
+ await mongoFactory.db.bucket_parameters.countDocuments({ 'key.g': syncRules.replicationStreamId + 1 })
1585
+ ).toBe(1);
1586
+ }
1587
+ );
1588
+
1470
1589
  test.runIf(storageVersion < 3)('storage metrics include v1 current_data', async () => {
1471
1590
  await using factory = await storageConfig.factory();
1472
1591
  const syncRules = await factory.updateSyncRules(
@@ -1747,7 +1866,7 @@ describe('sync - mongodb', () => {
1747
1866
  async function getFilteredOps(start: number, checkpoint: number): Promise<bigint[]> {
1748
1867
  const { syncRules, bucketStorage } = await setupFilteringTest();
1749
1868
  const request = bucketRequest(syncRules.syncConfigContent[0], 'global[]', BigInt(start));
1750
- const batch = await test_utils.fromAsync(
1869
+ const batch = await test_utils.getBatchArray(
1751
1870
  bucketStorage.getBucketDataBatch(test_utils.testCheckpoint(BigInt(checkpoint)), [request])
1752
1871
  );
1753
1872
  const ops = batch.flatMap((b) => b.chunkData.data.map((d) => BigInt(d.op_id)));
@@ -1894,7 +2013,7 @@ describe('sync - mongodb', () => {
1894
2013
  const roundRequests = requests
1895
2014
  .filter((request) => pending.has(request.bucket))
1896
2015
  .map((request) => ({ ...request, start: positions.get(request.bucket)! }));
1897
- const batch = await test_utils.fromAsync(
2016
+ const batch = await test_utils.getBatchArray(
1898
2017
  bucketStorage.getBucketDataBatch(test_utils.testCheckpoint(end), roundRequests)
1899
2018
  );
1900
2019
  let anyHasMore = false;