@powersync/service-module-mongodb-storage 0.13.2 → 0.15.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 (78) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/dist/migrations/db/migrations/1770213298299-storage-version.d.ts +3 -0
  3. package/dist/migrations/db/migrations/1770213298299-storage-version.js +29 -0
  4. package/dist/migrations/db/migrations/1770213298299-storage-version.js.map +1 -0
  5. package/dist/storage/MongoBucketStorage.d.ts +7 -15
  6. package/dist/storage/MongoBucketStorage.js +28 -53
  7. package/dist/storage/MongoBucketStorage.js.map +1 -1
  8. package/dist/storage/implementation/MongoBucketBatch.d.ts +12 -11
  9. package/dist/storage/implementation/MongoBucketBatch.js +199 -127
  10. package/dist/storage/implementation/MongoBucketBatch.js.map +1 -1
  11. package/dist/storage/implementation/MongoChecksums.d.ts +8 -5
  12. package/dist/storage/implementation/MongoChecksums.js +8 -4
  13. package/dist/storage/implementation/MongoChecksums.js.map +1 -1
  14. package/dist/storage/implementation/MongoCompactor.d.ts +2 -2
  15. package/dist/storage/implementation/MongoCompactor.js +52 -26
  16. package/dist/storage/implementation/MongoCompactor.js.map +1 -1
  17. package/dist/storage/implementation/MongoParameterCompactor.d.ts +2 -2
  18. package/dist/storage/implementation/MongoParameterCompactor.js.map +1 -1
  19. package/dist/storage/implementation/MongoPersistedSyncRulesContent.d.ts +2 -12
  20. package/dist/storage/implementation/MongoPersistedSyncRulesContent.js +20 -25
  21. package/dist/storage/implementation/MongoPersistedSyncRulesContent.js.map +1 -1
  22. package/dist/storage/implementation/MongoSyncBucketStorage.d.ts +7 -4
  23. package/dist/storage/implementation/MongoSyncBucketStorage.js +11 -8
  24. package/dist/storage/implementation/MongoSyncBucketStorage.js.map +1 -1
  25. package/dist/storage/implementation/MongoSyncRulesLock.d.ts +3 -3
  26. package/dist/storage/implementation/MongoSyncRulesLock.js.map +1 -1
  27. package/dist/storage/implementation/MongoWriteCheckpointAPI.d.ts +4 -4
  28. package/dist/storage/implementation/MongoWriteCheckpointAPI.js.map +1 -1
  29. package/dist/storage/implementation/OperationBatch.js +3 -2
  30. package/dist/storage/implementation/OperationBatch.js.map +1 -1
  31. package/dist/storage/implementation/PersistedBatch.d.ts +11 -4
  32. package/dist/storage/implementation/PersistedBatch.js +42 -11
  33. package/dist/storage/implementation/PersistedBatch.js.map +1 -1
  34. package/dist/storage/implementation/db.d.ts +35 -1
  35. package/dist/storage/implementation/db.js +99 -0
  36. package/dist/storage/implementation/db.js.map +1 -1
  37. package/dist/storage/implementation/models.d.ts +25 -1
  38. package/dist/storage/implementation/models.js +10 -1
  39. package/dist/storage/implementation/models.js.map +1 -1
  40. package/dist/storage/storage-index.d.ts +0 -1
  41. package/dist/storage/storage-index.js +0 -1
  42. package/dist/storage/storage-index.js.map +1 -1
  43. package/dist/utils/test-utils.d.ts +7 -5
  44. package/dist/utils/test-utils.js +17 -14
  45. package/dist/utils/test-utils.js.map +1 -1
  46. package/dist/utils/util.d.ts +2 -1
  47. package/dist/utils/util.js +15 -1
  48. package/dist/utils/util.js.map +1 -1
  49. package/package.json +7 -7
  50. package/src/migrations/db/migrations/1770213298299-storage-version.ts +44 -0
  51. package/src/storage/MongoBucketStorage.ts +44 -61
  52. package/src/storage/implementation/MongoBucketBatch.ts +253 -177
  53. package/src/storage/implementation/MongoChecksums.ts +19 -9
  54. package/src/storage/implementation/MongoCompactor.ts +62 -31
  55. package/src/storage/implementation/MongoParameterCompactor.ts +3 -3
  56. package/src/storage/implementation/MongoPersistedSyncRulesContent.ts +20 -34
  57. package/src/storage/implementation/MongoSyncBucketStorage.ts +32 -17
  58. package/src/storage/implementation/MongoSyncRulesLock.ts +3 -3
  59. package/src/storage/implementation/MongoWriteCheckpointAPI.ts +4 -4
  60. package/src/storage/implementation/OperationBatch.ts +3 -2
  61. package/src/storage/implementation/PersistedBatch.ts +42 -11
  62. package/src/storage/implementation/db.ts +129 -1
  63. package/src/storage/implementation/models.ts +39 -1
  64. package/src/storage/storage-index.ts +0 -1
  65. package/src/utils/test-utils.ts +18 -16
  66. package/src/utils/util.ts +17 -2
  67. package/test/src/__snapshots__/storage.test.ts.snap +198 -22
  68. package/test/src/__snapshots__/storage_compacting.test.ts.snap +17 -0
  69. package/test/src/__snapshots__/storage_sync.test.ts.snap +2211 -21
  70. package/test/src/storage.test.ts +9 -7
  71. package/test/src/storage_compacting.test.ts +33 -24
  72. package/test/src/storage_sync.test.ts +31 -15
  73. package/test/src/util.ts +4 -1
  74. package/tsconfig.tsbuildinfo +1 -1
  75. package/dist/storage/implementation/MongoPersistedSyncRules.d.ts +0 -10
  76. package/dist/storage/implementation/MongoPersistedSyncRules.js +0 -17
  77. package/dist/storage/implementation/MongoPersistedSyncRules.js.map +0 -1
  78. package/src/storage/implementation/MongoPersistedSyncRules.ts +0 -20
@@ -1,17 +1,19 @@
1
1
  import { register } from '@powersync/service-core-tests';
2
2
  import { describe } from 'vitest';
3
- import { INITIALIZED_MONGO_STORAGE_FACTORY } from './util.js';
3
+ import { INITIALIZED_MONGO_STORAGE_FACTORY, TEST_STORAGE_VERSIONS } from './util.js';
4
4
  import { env } from './env.js';
5
5
  import { mongoTestStorageFactoryGenerator } from '@module/utils/test-utils.js';
6
6
 
7
- describe('Mongo Sync Bucket Storage - Parameters', () =>
8
- register.registerDataStorageParameterTests(INITIALIZED_MONGO_STORAGE_FACTORY));
7
+ for (let storageVersion of TEST_STORAGE_VERSIONS) {
8
+ describe(`Mongo Sync Bucket Storage - Parameters - v${storageVersion}`, () =>
9
+ register.registerDataStorageParameterTests({ ...INITIALIZED_MONGO_STORAGE_FACTORY, storageVersion }));
9
10
 
10
- describe('Mongo Sync Bucket Storage - Data', () =>
11
- register.registerDataStorageDataTests(INITIALIZED_MONGO_STORAGE_FACTORY));
11
+ describe(`Mongo Sync Bucket Storage - Data - v${storageVersion}`, () =>
12
+ register.registerDataStorageDataTests({ ...INITIALIZED_MONGO_STORAGE_FACTORY, storageVersion }));
12
13
 
13
- describe('Mongo Sync Bucket Storage - Checkpoints', () =>
14
- register.registerDataStorageCheckpointTests(INITIALIZED_MONGO_STORAGE_FACTORY));
14
+ describe(`Mongo Sync Bucket Storage - Checkpoints - v${storageVersion}`, () =>
15
+ register.registerDataStorageCheckpointTests({ ...INITIALIZED_MONGO_STORAGE_FACTORY, storageVersion }));
16
+ }
15
17
 
16
18
  describe('Sync Bucket Validation', register.registerBucketValidationTests);
17
19
 
@@ -1,15 +1,18 @@
1
- import { register, TEST_TABLE, test_utils } from '@powersync/service-core-tests';
1
+ import { storage, SyncRulesBucketStorage, updateSyncRulesFromYaml } from '@powersync/service-core';
2
+ import { bucketRequest, register, test_utils } from '@powersync/service-core-tests';
2
3
  import { describe, expect, test } from 'vitest';
3
4
  import { INITIALIZED_MONGO_STORAGE_FACTORY } from './util.js';
4
- import { storage, SyncRulesBucketStorage } from '@powersync/service-core';
5
5
 
6
6
  describe('Mongo Sync Bucket Storage Compact', () => {
7
7
  register.registerCompactTests(INITIALIZED_MONGO_STORAGE_FACTORY);
8
+ const TEST_TABLE = test_utils.makeTestTable('test', ['id'], INITIALIZED_MONGO_STORAGE_FACTORY);
8
9
 
9
10
  describe('with blank bucket_state', () => {
10
11
  // This can happen when migrating from older service versions, that did not populate bucket_state yet.
11
12
  const populate = async (bucketStorage: SyncRulesBucketStorage) => {
12
13
  await bucketStorage.startBatch(test_utils.BATCH_OPTIONS, async (batch) => {
14
+ await batch.markAllSnapshotDone('1/1');
15
+
13
16
  await batch.save({
14
17
  sourceTable: TEST_TABLE,
15
18
  tag: storage.SaveOperationTag.INSERT,
@@ -37,23 +40,23 @@ describe('Mongo Sync Bucket Storage Compact', () => {
37
40
  };
38
41
 
39
42
  const setup = async () => {
40
- await using factory = await INITIALIZED_MONGO_STORAGE_FACTORY();
41
- const syncRules = await factory.updateSyncRules({
42
- content: `
43
+ await using factory = await INITIALIZED_MONGO_STORAGE_FACTORY.factory();
44
+ const syncRules = await factory.updateSyncRules(
45
+ updateSyncRulesFromYaml(`
43
46
  bucket_definitions:
44
47
  by_user:
45
48
  parameters: select request.user_id() as user_id
46
49
  data: [select * from test where owner_id = bucket.user_id]
47
- `
48
- });
50
+ `)
51
+ );
49
52
  const bucketStorage = factory.getInstance(syncRules);
50
53
  const { checkpoint } = await populate(bucketStorage);
51
54
 
52
- return { bucketStorage, checkpoint, factory };
55
+ return { bucketStorage, checkpoint, factory, syncRules };
53
56
  };
54
57
 
55
58
  test('full compact', async () => {
56
- const { bucketStorage, checkpoint, factory } = await setup();
59
+ const { bucketStorage, checkpoint, factory, syncRules } = await setup();
57
60
 
58
61
  // Simulate bucket_state from old version not being available
59
62
  await factory.db.bucket_state.deleteMany({});
@@ -68,14 +71,17 @@ bucket_definitions:
68
71
  signal: null as any
69
72
  });
70
73
 
71
- const checksumAfter = await bucketStorage.getChecksums(checkpoint, ['by_user["u1"]', 'by_user["u2"]']);
72
- expect(checksumAfter.get('by_user["u1"]')).toEqual({
73
- bucket: 'by_user["u1"]',
74
+ const users = ['u1', 'u2'];
75
+ const userRequests = users.map((user) => bucketRequest(syncRules, `by_user["${user}"]`));
76
+ const [u1Request, u2Request] = userRequests;
77
+ const checksumAfter = await bucketStorage.getChecksums(checkpoint, userRequests);
78
+ expect(checksumAfter.get(u1Request.bucket)).toEqual({
79
+ bucket: u1Request.bucket,
74
80
  checksum: -659469718,
75
81
  count: 1
76
82
  });
77
- expect(checksumAfter.get('by_user["u2"]')).toEqual({
78
- bucket: 'by_user["u2"]',
83
+ expect(checksumAfter.get(u2Request.bucket)).toEqual({
84
+ bucket: u2Request.bucket,
79
85
  checksum: 430217650,
80
86
  count: 1
81
87
  });
@@ -85,15 +91,15 @@ bucket_definitions:
85
91
  // Populate old sync rules version
86
92
  const { factory } = await setup();
87
93
 
88
- // Not populate another version (bucket definition name changed)
89
- const syncRules = await factory.updateSyncRules({
90
- content: `
94
+ // Now populate another version (bucket definition name changed)
95
+ const syncRules = await factory.updateSyncRules(
96
+ updateSyncRulesFromYaml(`
91
97
  bucket_definitions:
92
98
  by_user2:
93
99
  parameters: select request.user_id() as user_id
94
100
  data: [select * from test where owner_id = bucket.user_id]
95
- `
96
- });
101
+ `)
102
+ );
97
103
  const bucketStorage = factory.getInstance(syncRules);
98
104
 
99
105
  await populate(bucketStorage);
@@ -119,14 +125,17 @@ bucket_definitions:
119
125
  });
120
126
  expect(result2.buckets).toEqual(0);
121
127
 
122
- const checksumAfter = await bucketStorage.getChecksums(checkpoint, ['by_user2["u1"]', 'by_user2["u2"]']);
123
- expect(checksumAfter.get('by_user2["u1"]')).toEqual({
124
- bucket: 'by_user2["u1"]',
128
+ const users = ['u1', 'u2'];
129
+ const userRequests = users.map((user) => bucketRequest(syncRules, `by_user2["${user}"]`));
130
+ const [u1Request, u2Request] = userRequests;
131
+ const checksumAfter = await bucketStorage.getChecksums(checkpoint, userRequests);
132
+ expect(checksumAfter.get(u1Request.bucket)).toEqual({
133
+ bucket: u1Request.bucket,
125
134
  checksum: -659469718,
126
135
  count: 1
127
136
  });
128
- expect(checksumAfter.get('by_user2["u2"]')).toEqual({
129
- bucket: 'by_user2["u2"]',
137
+ expect(checksumAfter.get(u2Request.bucket)).toEqual({
138
+ bucket: u2Request.bucket,
130
139
  checksum: 430217650,
131
140
  count: 1
132
141
  });
@@ -1,26 +1,34 @@
1
- import { storage } from '@powersync/service-core';
2
- import { register, TEST_TABLE, test_utils } from '@powersync/service-core-tests';
1
+ import { storage, updateSyncRulesFromYaml } from '@powersync/service-core';
2
+ import { bucketRequest, register, test_utils } from '@powersync/service-core-tests';
3
3
  import { describe, expect, test } from 'vitest';
4
- import { INITIALIZED_MONGO_STORAGE_FACTORY } from './util.js';
4
+ import { INITIALIZED_MONGO_STORAGE_FACTORY, TEST_STORAGE_VERSIONS } from './util.js';
5
5
 
6
- describe('sync - mongodb', () => {
7
- register.registerSyncTests(INITIALIZED_MONGO_STORAGE_FACTORY);
6
+ function registerSyncStorageTests(storageConfig: storage.TestStorageConfig, storageVersion: number) {
7
+ register.registerSyncTests(storageConfig.factory, {
8
+ storageVersion,
9
+ tableIdStrings: storageConfig.tableIdStrings
10
+ });
11
+ const TEST_TABLE = test_utils.makeTestTable('test', ['id'], storageConfig);
8
12
 
9
13
  // The split of returned results can vary depending on storage drivers
10
14
  test('large batch (2)', async () => {
11
15
  // Test syncing a batch of data that is small in count,
12
16
  // but large enough in size to be split over multiple returned chunks.
13
17
  // Similar to the above test, but splits over 1MB chunks.
14
- const sync_rules = test_utils.testRules(
15
- `
18
+ await using factory = await storageConfig.factory();
19
+ const syncRules = await factory.updateSyncRules(
20
+ updateSyncRulesFromYaml(
21
+ `
16
22
  bucket_definitions:
17
23
  global:
18
24
  data:
19
25
  - SELECT id, description FROM "%"
20
- `
26
+ `,
27
+ { storageVersion }
28
+ )
21
29
  );
22
- await using factory = await INITIALIZED_MONGO_STORAGE_FACTORY();
23
- const bucketStorage = factory.getInstance(sync_rules);
30
+ const bucketStorage = factory.getInstance(syncRules);
31
+ const globalBucket = bucketRequest(syncRules, 'global[]');
24
32
 
25
33
  const result = await bucketStorage.startBatch(test_utils.BATCH_OPTIONS, async (batch) => {
26
34
  const sourceTable = TEST_TABLE;
@@ -72,9 +80,8 @@ describe('sync - mongodb', () => {
72
80
  const checkpoint = result!.flushed_op;
73
81
 
74
82
  const options: storage.BucketDataBatchOptions = {};
75
-
76
83
  const batch1 = await test_utils.fromAsync(
77
- bucketStorage.getBucketDataBatch(checkpoint, new Map([['global[]', 0n]]), options)
84
+ bucketStorage.getBucketDataBatch(checkpoint, [bucketRequest(syncRules, 'global[]', 0n)], options)
78
85
  );
79
86
  expect(test_utils.getBatchData(batch1)).toEqual([
80
87
  { op_id: '1', op: 'PUT', object_id: 'test1', checksum: 2871785649 },
@@ -89,7 +96,7 @@ describe('sync - mongodb', () => {
89
96
  const batch2 = await test_utils.fromAsync(
90
97
  bucketStorage.getBucketDataBatch(
91
98
  checkpoint,
92
- new Map([['global[]', BigInt(batch1[0].chunkData.next_after)]]),
99
+ [bucketRequest(syncRules, 'global[]', batch1[0].chunkData.next_after)],
93
100
  options
94
101
  )
95
102
  );
@@ -105,7 +112,7 @@ describe('sync - mongodb', () => {
105
112
  const batch3 = await test_utils.fromAsync(
106
113
  bucketStorage.getBucketDataBatch(
107
114
  checkpoint,
108
- new Map([['global[]', BigInt(batch2[0].chunkData.next_after)]]),
115
+ [bucketRequest(syncRules, 'global[]', batch2[0].chunkData.next_after)],
109
116
  options
110
117
  )
111
118
  );
@@ -120,9 +127,18 @@ describe('sync - mongodb', () => {
120
127
 
121
128
  // Test that the checksum type is correct.
122
129
  // Specifically, test that it never persisted as double.
123
- const checksumTypes = await factory.db.bucket_data
130
+ const mongoFactory = factory as any;
131
+ const checksumTypes = await mongoFactory.db.bucket_data
124
132
  .aggregate([{ $group: { _id: { $type: '$checksum' }, count: { $sum: 1 } } }])
125
133
  .toArray();
126
134
  expect(checksumTypes).toEqual([{ _id: 'long', count: 4 }]);
127
135
  });
136
+ }
137
+
138
+ describe('sync - mongodb', () => {
139
+ for (const storageVersion of TEST_STORAGE_VERSIONS) {
140
+ describe(`storage v${storageVersion}`, () => {
141
+ registerSyncStorageTests(INITIALIZED_MONGO_STORAGE_FACTORY, storageVersion);
142
+ });
143
+ }
128
144
  });
package/test/src/util.ts CHANGED
@@ -1,5 +1,6 @@
1
- import { env } from './env.js';
2
1
  import { mongoTestReportStorageFactoryGenerator, mongoTestStorageFactoryGenerator } from '@module/utils/test-utils.js';
2
+ import { SUPPORTED_STORAGE_VERSIONS } from '@powersync/service-core';
3
+ import { env } from './env.js';
3
4
 
4
5
  export const INITIALIZED_MONGO_STORAGE_FACTORY = mongoTestStorageFactoryGenerator({
5
6
  url: env.MONGO_TEST_URL,
@@ -10,3 +11,5 @@ export const INITIALIZED_MONGO_REPORT_STORAGE_FACTORY = mongoTestReportStorageFa
10
11
  url: env.MONGO_TEST_URL,
11
12
  isCI: env.CI
12
13
  });
14
+
15
+ export const TEST_STORAGE_VERSIONS = SUPPORTED_STORAGE_VERSIONS;