@powersync/service-module-mongodb-storage 0.22.0 → 0.23.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.
- package/CHANGELOG.md +26 -0
- package/dist/storage/MongoBucketStorage.d.ts +5 -1
- package/dist/storage/MongoBucketStorage.js +30 -6
- package/dist/storage/MongoBucketStorage.js.map +1 -1
- package/dist/storage/implementation/MongoBucketBatch.d.ts +23 -10
- package/dist/storage/implementation/MongoBucketBatch.js +132 -88
- package/dist/storage/implementation/MongoBucketBatch.js.map +1 -1
- package/dist/storage/implementation/MongoCompactor.d.ts +2 -0
- package/dist/storage/implementation/MongoCompactor.js.map +1 -1
- package/dist/storage/implementation/MongoIdSequence.d.ts +10 -1
- package/dist/storage/implementation/MongoIdSequence.js +14 -1
- package/dist/storage/implementation/MongoIdSequence.js.map +1 -1
- package/dist/storage/implementation/MongoOpIdAllocator.d.ts +27 -0
- package/dist/storage/implementation/MongoOpIdAllocator.js +97 -0
- package/dist/storage/implementation/MongoOpIdAllocator.js.map +1 -0
- package/dist/storage/implementation/MongoSyncBucketStorage.d.ts +5 -0
- package/dist/storage/implementation/MongoSyncBucketStorage.js +17 -0
- package/dist/storage/implementation/MongoSyncBucketStorage.js.map +1 -1
- package/dist/storage/implementation/MongoSyncRulesLock.d.ts +26 -2
- package/dist/storage/implementation/MongoSyncRulesLock.js +38 -1
- package/dist/storage/implementation/MongoSyncRulesLock.js.map +1 -1
- package/dist/storage/implementation/db.js +1 -0
- package/dist/storage/implementation/db.js.map +1 -1
- package/dist/storage/implementation/v1/MongoBucketBatchV1.d.ts +5 -0
- package/dist/storage/implementation/v1/MongoBucketBatchV1.js +136 -133
- package/dist/storage/implementation/v1/MongoBucketBatchV1.js.map +1 -1
- package/dist/storage/implementation/v1/MongoSyncBucketStorageV1.js +1 -1
- package/dist/storage/implementation/v1/MongoSyncBucketStorageV1.js.map +1 -1
- package/dist/storage/implementation/v3/MongoBucketBatchV3.d.ts +5 -1
- package/dist/storage/implementation/v3/MongoBucketBatchV3.js +131 -148
- package/dist/storage/implementation/v3/MongoBucketBatchV3.js.map +1 -1
- package/dist/storage/implementation/v3/MongoCompactorV3.d.ts +4 -3
- package/dist/storage/implementation/v3/MongoCompactorV3.js +14 -10
- package/dist/storage/implementation/v3/MongoCompactorV3.js.map +1 -1
- package/dist/storage/implementation/v3/compact-utils.d.ts +3 -2
- package/dist/storage/implementation/v3/compact-utils.js +12 -5
- package/dist/storage/implementation/v3/compact-utils.js.map +1 -1
- package/dist/storage/implementation/v3/models.d.ts +1 -1
- package/dist/utils/test-utils.d.ts +2 -1
- package/dist/utils/test-utils.js +4 -3
- package/dist/utils/test-utils.js.map +1 -1
- package/package.json +7 -7
- package/src/storage/MongoBucketStorage.ts +35 -7
- package/src/storage/implementation/MongoBucketBatch.ts +201 -110
- package/src/storage/implementation/MongoCompactor.ts +2 -0
- package/src/storage/implementation/MongoIdSequence.ts +21 -1
- package/src/storage/implementation/MongoOpIdAllocator.ts +105 -0
- package/src/storage/implementation/MongoSyncBucketStorage.ts +19 -0
- package/src/storage/implementation/MongoSyncRulesLock.ts +56 -3
- package/src/storage/implementation/db.ts +1 -0
- package/src/storage/implementation/models.ts +1 -0
- package/src/storage/implementation/v1/MongoBucketBatchV1.ts +150 -152
- package/src/storage/implementation/v1/MongoSyncBucketStorageV1.ts +1 -1
- package/src/storage/implementation/v3/MongoBucketBatchV3.ts +167 -194
- package/src/storage/implementation/v3/MongoCompactorV3.ts +19 -22
- package/src/storage/implementation/v3/compact-utils.ts +16 -7
- package/src/storage/implementation/v3/models.ts +1 -1
- package/src/utils/test-utils.ts +5 -3
- package/test/src/__snapshots__/storage.test.ts.snap +102 -2
- package/test/src/__snapshots__/storage_compacting.test.ts.snap +2 -2
- package/test/src/__snapshots__/storage_sync.test.ts.snap +12 -12
- package/test/src/cleanup-stopped-sync-configs.test.ts +19 -13
- package/test/src/compact-utils.test.ts +33 -8
- package/test/src/concurrent_writers.test.ts +599 -0
- package/test/src/helpers/concurrentWriter.mjs +29 -0
- package/test/src/helpers/s3TestFactory.ts +12 -12
- package/test/src/object_storage_usage.test.ts +2 -1
- package/test/src/parameter_compacting_v1.test.ts +2 -2
- package/test/src/parameter_compacting_v3.test.ts +2 -2
- package/test/src/parameter_compaction_fence.test.ts +3 -3
- package/test/src/storage.test.ts +32 -33
- package/test/src/storage_compacting.test.ts +147 -21
- package/test/src/storage_object_storage_inline_threshold.test.ts +3 -3
- package/test/src/storage_s3_checksums.test.ts +4 -4
- package/test/src/storage_s3_compaction_lifecycle.test.ts +8 -8
- package/test/src/storage_s3_reading.test.ts +4 -4
- package/test/src/storage_s3_writing.test.ts +3 -3
- package/test/src/storage_sync.test.ts +52 -46
- package/test/src/storeCurrentData.test.ts +5 -5
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -8,6 +8,7 @@ import { VersionedPowerSyncMongoV3 } from '@module/storage/implementation/v3/Ver
|
|
|
8
8
|
import * as lib_mongo from '@powersync/lib-service-mongodb';
|
|
9
9
|
import { mongo } from '@powersync/lib-service-mongodb';
|
|
10
10
|
import { updateSyncRulesFromYaml } from '@powersync/service-core';
|
|
11
|
+
import { getTestStorage } from '@powersync/service-core-tests';
|
|
11
12
|
import { BucketDefinitionId } from '@powersync/service-sync-rules';
|
|
12
13
|
import { describe, expect, test } from 'vitest';
|
|
13
14
|
import { INITIALIZED_MONGO_STORAGE_FACTORY } from './util.js';
|
|
@@ -33,7 +34,7 @@ type UsageEntry = {
|
|
|
33
34
|
async function withUsageContext<T>(callback: (context: UsageContext) => Promise<T>): Promise<T> {
|
|
34
35
|
await using factory = await INITIALIZED_MONGO_STORAGE_FACTORY.factory();
|
|
35
36
|
const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(SYNC_RULES_YAML, { storageVersion: 3 }));
|
|
36
|
-
const bucketStorage = factory
|
|
37
|
+
const bucketStorage = (await getTestStorage(factory, syncRules)) as MongoSyncBucketStorage;
|
|
37
38
|
const db = bucketStorage.db as VersionedPowerSyncMongoV3;
|
|
38
39
|
const definitionId = syncRules.syncConfigContent[0].mapping.allBucketDefinitionIds()[0];
|
|
39
40
|
return callback({ db, bucketStorage, definitionId });
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { storage, updateSyncRulesFromYaml } from '@powersync/service-core';
|
|
2
|
-
import { test_utils } from '@powersync/service-core-tests';
|
|
2
|
+
import { getTestStorage, test_utils } from '@powersync/service-core-tests';
|
|
3
3
|
import * as bson from 'bson';
|
|
4
4
|
import { describe, expect, test } from 'vitest';
|
|
5
5
|
import type { SyncRuleDocumentV1 } from '../../src/storage/implementation/v1/models.js';
|
|
@@ -20,7 +20,7 @@ async function createActiveStorage() {
|
|
|
20
20
|
const syncRules = await factory.updateSyncRules(
|
|
21
21
|
updateSyncRulesFromYaml(PARAMETER_RULES, { storageVersion: storage.STORAGE_VERSION_2 })
|
|
22
22
|
);
|
|
23
|
-
const processingStorage = factory
|
|
23
|
+
const processingStorage = await getTestStorage(factory, syncRules);
|
|
24
24
|
await using writer = await processingStorage.createWriter(test_utils.BATCH_OPTIONS);
|
|
25
25
|
await writer.markAllSnapshotDone('1/1');
|
|
26
26
|
await writer.commit('1/1');
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { storage, updateSyncRulesFromYaml } from '@powersync/service-core';
|
|
2
|
-
import { test_utils } from '@powersync/service-core-tests';
|
|
2
|
+
import { getTestStorage, test_utils } from '@powersync/service-core-tests';
|
|
3
3
|
import * as bson from 'bson';
|
|
4
4
|
import { describe, expect, test } from 'vitest';
|
|
5
5
|
import { MongoParameterCompactorV3 } from '../../src/storage/implementation/v3/MongoParameterCompactorV3.js';
|
|
@@ -31,7 +31,7 @@ async function createActiveStorage(rules = PARAMETER_RULES) {
|
|
|
31
31
|
const syncRules = await factory.updateSyncRules(
|
|
32
32
|
updateSyncRulesFromYaml(rules, { storageVersion: storage.STORAGE_VERSION_3 })
|
|
33
33
|
);
|
|
34
|
-
const processingStorage = factory
|
|
34
|
+
const processingStorage = await getTestStorage(factory, syncRules);
|
|
35
35
|
await using writer = await processingStorage.createWriter(test_utils.BATCH_OPTIONS);
|
|
36
36
|
await writer.markAllSnapshotDone('1/1');
|
|
37
37
|
await writer.commit('1/1');
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { mongo } from '@powersync/lib-service-mongodb';
|
|
2
2
|
import { InternalOpId, storage, updateSyncRulesFromYaml } from '@powersync/service-core';
|
|
3
|
-
import { test_utils } from '@powersync/service-core-tests';
|
|
3
|
+
import { getTestStorage, test_utils } from '@powersync/service-core-tests';
|
|
4
4
|
import { describe, expect, test } from 'vitest';
|
|
5
5
|
import type { VersionedPowerSyncMongo } from '../../src/storage/implementation/db.js';
|
|
6
6
|
import type { SyncRuleDocumentBase } from '../../src/storage/implementation/models.js';
|
|
@@ -83,7 +83,7 @@ describe('parameter compaction invalidation fence', () => {
|
|
|
83
83
|
*/
|
|
84
84
|
async function replicateParameterHistory(factory: storage.BucketStorageFactory) {
|
|
85
85
|
const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(PARAMETER_RULES, { storageVersion }));
|
|
86
|
-
const processingStorage = factory
|
|
86
|
+
const processingStorage = await getTestStorage(factory, syncRules);
|
|
87
87
|
const writer = await processingStorage.createWriter(test_utils.BATCH_OPTIONS);
|
|
88
88
|
const testTable = await test_utils.resolveTestTable(writer, 'test', ['id'], INITIALIZED_MONGO_STORAGE_FACTORY);
|
|
89
89
|
|
|
@@ -196,7 +196,7 @@ describe('parameter compaction invalidation fence', () => {
|
|
|
196
196
|
// which is the only record of t2's lookup.
|
|
197
197
|
//
|
|
198
198
|
// A separate storage instance is used to get a cold checkpoint-changes cache.
|
|
199
|
-
const coldStorage = (factory as MongoBucketStorage
|
|
199
|
+
const coldStorage = await getTestStorage(factory as MongoBucketStorage, replicationStream);
|
|
200
200
|
const atSnapshot = await coldStorage.getCheckpointChanges({
|
|
201
201
|
lastCheckpoint: checkpoint1,
|
|
202
202
|
nextCheckpoint: checkpoint3
|
package/test/src/storage.test.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { mongoTestStorageFactoryGenerator } from '@module/utils/test-utils.js';
|
|
2
2
|
import { mongo } from '@powersync/lib-service-mongodb';
|
|
3
3
|
import { storage, updateSyncRulesFromYaml } from '@powersync/service-core';
|
|
4
|
-
import { compactActive, register, test_utils } from '@powersync/service-core-tests';
|
|
4
|
+
import { compactActive, getTestStorage, register, test_utils } from '@powersync/service-core-tests';
|
|
5
5
|
import { describe, expect, test } from 'vitest';
|
|
6
6
|
import { MongoSyncBucketStorage } from '../../src/storage/implementation/createMongoSyncBucketStorage.js';
|
|
7
7
|
import { VersionedPowerSyncMongoV3 } from '../../src/storage/implementation/v3/VersionedPowerSyncMongoV3.js';
|
|
@@ -35,7 +35,7 @@ bucket_definitions:
|
|
|
35
35
|
{ storageVersion }
|
|
36
36
|
)
|
|
37
37
|
);
|
|
38
|
-
const bucketStorage = factory
|
|
38
|
+
const bucketStorage = await getTestStorage(factory, syncRules);
|
|
39
39
|
|
|
40
40
|
// user1 has no existing row, so this covers updateMany with upsert.
|
|
41
41
|
// The initial request stores checkpoint id 42 at source head 5/0.
|
|
@@ -144,7 +144,8 @@ bucket_definitions:
|
|
|
144
144
|
user_id: 'custom1',
|
|
145
145
|
checkpoint: 52n
|
|
146
146
|
});
|
|
147
|
-
|
|
147
|
+
// A custom-checkpoint-only commit uses the combined final flush path too.
|
|
148
|
+
await writer.commit('8/1');
|
|
148
149
|
const customGenerated = await factory.db.custom_write_checkpoints.findOne({ user_id: 'custom1' });
|
|
149
150
|
expect(customGenerated).not.toBeNull();
|
|
150
151
|
expect(customGenerated?.checkpoint_requested_at).toBeUndefined();
|
|
@@ -179,7 +180,7 @@ event_definitions:
|
|
|
179
180
|
{ storageVersion }
|
|
180
181
|
)
|
|
181
182
|
);
|
|
182
|
-
const bucketStorage = factory
|
|
183
|
+
const bucketStorage = await getTestStorage(factory, syncRules);
|
|
183
184
|
const db = bucketStorage.db as VersionedPowerSyncMongoV3;
|
|
184
185
|
const activeSyncConfig = bucketStorage.getParsedSyncRules({ defaultSchema: 'public' });
|
|
185
186
|
const eventA = activeSyncConfig.eventDescriptors.find((event) => event.name == 'checkpoint_a')!;
|
|
@@ -228,7 +229,7 @@ event_definitions:
|
|
|
228
229
|
|
|
229
230
|
writer.addCustomWriteCheckpoint({ user_id: 'user1', checkpoint: 5n, event_id: eventAId });
|
|
230
231
|
writer.addCustomWriteCheckpoint({ user_id: 'user1', checkpoint: 8n, event_id: eventBId });
|
|
231
|
-
|
|
232
|
+
// Collections must be prepared before the combined flush/checkpoint transaction.
|
|
232
233
|
await writer.keepalive('5/0');
|
|
233
234
|
|
|
234
235
|
const eventACollection = db.customCheckpointRequests({
|
|
@@ -296,7 +297,7 @@ event_definitions:
|
|
|
296
297
|
// A fresh storage instance has an empty initialization cache, just like
|
|
297
298
|
// one created after a service restart. Recreating the existing indexes
|
|
298
299
|
// must be idempotent before another checkpoint is written.
|
|
299
|
-
const freshBucketStorage = factory
|
|
300
|
+
const freshBucketStorage = await getTestStorage(factory, syncRules);
|
|
300
301
|
await using freshWriter = await freshBucketStorage.createWriter(test_utils.BATCH_OPTIONS);
|
|
301
302
|
freshWriter.addCustomWriteCheckpoint({
|
|
302
303
|
user_id: 'after-restart',
|
|
@@ -336,7 +337,7 @@ event_definitions:
|
|
|
336
337
|
updateSyncRulesFromYaml(syncConfigYaml("kind = 'write'", false), { storageVersion })
|
|
337
338
|
);
|
|
338
339
|
const firstEventId = first.syncConfigContent[0].mapping.eventDefinitionIdByName('write_checkpoints');
|
|
339
|
-
const firstStorage = factory
|
|
340
|
+
const firstStorage = await getTestStorage(factory, first);
|
|
340
341
|
await using firstWriter = await firstStorage.createWriter(test_utils.BATCH_OPTIONS);
|
|
341
342
|
firstWriter.addCustomWriteCheckpoint({ user_id: 'user1', checkpoint: 5n, event_id: firstEventId });
|
|
342
343
|
await firstWriter.markAllSnapshotDone('1/1');
|
|
@@ -348,7 +349,9 @@ event_definitions:
|
|
|
348
349
|
const unchangedEventId = unchanged.syncConfigContent[1].mapping.eventDefinitionIdByName('write_checkpoints');
|
|
349
350
|
expect(unchangedEventId).toBe(firstEventId);
|
|
350
351
|
|
|
351
|
-
await using unchangedWriter = await
|
|
352
|
+
await using unchangedWriter = await (
|
|
353
|
+
await getTestStorage(factory, unchanged)
|
|
354
|
+
).createWriter(test_utils.BATCH_OPTIONS);
|
|
352
355
|
await unchangedWriter.markAllSnapshotDone('2/1');
|
|
353
356
|
await unchangedWriter.commit('2/1');
|
|
354
357
|
|
|
@@ -369,7 +372,9 @@ event_definitions:
|
|
|
369
372
|
const changedEventId = changed.syncConfigContent[1].mapping.eventDefinitionIdByName('write_checkpoints');
|
|
370
373
|
expect(changedEventId).not.toBe(unchangedEventId);
|
|
371
374
|
|
|
372
|
-
await using changedWriter = await
|
|
375
|
+
await using changedWriter = await (
|
|
376
|
+
await getTestStorage(factory, changed)
|
|
377
|
+
).createWriter(test_utils.BATCH_OPTIONS);
|
|
373
378
|
changedWriter.addCustomWriteCheckpoint({ user_id: 'user1', checkpoint: 9n, event_id: changedEventId });
|
|
374
379
|
await changedWriter.flush();
|
|
375
380
|
|
|
@@ -415,7 +420,7 @@ bucket_definitions:
|
|
|
415
420
|
{ storageVersion }
|
|
416
421
|
)
|
|
417
422
|
);
|
|
418
|
-
const bucketStorage = factory
|
|
423
|
+
const bucketStorage = await getTestStorage(factory, syncRules);
|
|
419
424
|
|
|
420
425
|
// Replicate an extremely rare possibility where there are multiple records
|
|
421
426
|
await factory.db.write_checkpoints.insertMany([
|
|
@@ -486,26 +491,20 @@ bucket_definitions:
|
|
|
486
491
|
|
|
487
492
|
describe('Sync Bucket Validation', register.registerBucketValidationTests);
|
|
488
493
|
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
checksumOptions: {
|
|
507
|
-
bucketBatchLimit: 1,
|
|
508
|
-
operationBatchLimit: 100
|
|
509
|
-
}
|
|
510
|
-
})
|
|
511
|
-
));
|
|
494
|
+
for (const storageVersion of TEST_STORAGE_VERSIONS) {
|
|
495
|
+
for (const [name, checksumOptions] of [
|
|
496
|
+
['split operations', { bucketBatchLimit: 100, operationBatchLimit: 1 }],
|
|
497
|
+
['split buckets', { bucketBatchLimit: 1, operationBatchLimit: 100 }]
|
|
498
|
+
] as const) {
|
|
499
|
+
describe(`Mongo Sync Bucket Storage - ${name} - v${storageVersion}`, () =>
|
|
500
|
+
register.registerDataStorageDataTests({
|
|
501
|
+
...mongoTestStorageFactoryGenerator({
|
|
502
|
+
url: env.MONGO_TEST_URL,
|
|
503
|
+
isCI: env.CI,
|
|
504
|
+
checksumOptions
|
|
505
|
+
}),
|
|
506
|
+
storageVersion,
|
|
507
|
+
compressedBucketStorage: storageVersion >= 3
|
|
508
|
+
}));
|
|
509
|
+
}
|
|
510
|
+
}
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
SyncRulesBucketStorage,
|
|
18
18
|
updateSyncRulesFromYaml
|
|
19
19
|
} from '@powersync/service-core';
|
|
20
|
-
import { bucketRequest, compactActive, register, test_utils } from '@powersync/service-core-tests';
|
|
20
|
+
import { bucketRequest, compactActive, getTestStorage, register, test_utils } from '@powersync/service-core-tests';
|
|
21
21
|
import * as bson from 'bson';
|
|
22
22
|
import { describe, expect, test, vi } from 'vitest';
|
|
23
23
|
import { env } from './env.js';
|
|
@@ -106,7 +106,7 @@ bucket_definitions:
|
|
|
106
106
|
{ storageVersion }
|
|
107
107
|
)
|
|
108
108
|
);
|
|
109
|
-
const bucketStorage = factory
|
|
109
|
+
const bucketStorage = await getTestStorage(factory, syncRules);
|
|
110
110
|
const syncRulesContent = syncRules.syncConfigContent[0];
|
|
111
111
|
const { checkpoint } = await populate(bucketStorage, 1);
|
|
112
112
|
|
|
@@ -164,15 +164,16 @@ bucket_definitions:
|
|
|
164
164
|
{ storageVersion }
|
|
165
165
|
)
|
|
166
166
|
);
|
|
167
|
-
const bucketStorage = factory
|
|
167
|
+
const bucketStorage = await getTestStorage(factory, syncRules);
|
|
168
168
|
const syncRulesContent = syncRules.syncConfigContent[0];
|
|
169
169
|
|
|
170
170
|
await populate(bucketStorage, 2);
|
|
171
171
|
const { checkpoint } = await bucketStorage.getCheckpoint();
|
|
172
172
|
|
|
173
|
-
// V3's initial lite pass
|
|
173
|
+
// Force V3's initial lite pass to process these small buckets for cache verification.
|
|
174
174
|
// Earlier storage versions use the default minimum-change threshold.
|
|
175
175
|
const result0 = await bucketStorage.compactInitialReplication({
|
|
176
|
+
forceChunkCompaction: true,
|
|
176
177
|
maxOpId: checkpoint
|
|
177
178
|
});
|
|
178
179
|
expect(result0.buckets).toEqual(storageVersion >= storage.STORAGE_VERSION_3 ? 2 : 0);
|
|
@@ -180,6 +181,7 @@ bucket_definitions:
|
|
|
180
181
|
// For V1/V2, lower the threshold to populate the checksum cache. V3 has
|
|
181
182
|
// already updated its compacted state, so another initial pass is a no-op.
|
|
182
183
|
const result1 = await bucketStorage.compactInitialReplication({
|
|
184
|
+
forceChunkCompaction: true,
|
|
183
185
|
maxOpId: checkpoint,
|
|
184
186
|
minBucketChanges: 1
|
|
185
187
|
});
|
|
@@ -187,6 +189,7 @@ bucket_definitions:
|
|
|
187
189
|
|
|
188
190
|
// Repeating it stays a no-op.
|
|
189
191
|
const result2 = await bucketStorage.compactInitialReplication({
|
|
192
|
+
forceChunkCompaction: true,
|
|
190
193
|
maxOpId: checkpoint,
|
|
191
194
|
minBucketChanges: 1
|
|
192
195
|
});
|
|
@@ -214,6 +217,7 @@ bucket_definitions:
|
|
|
214
217
|
.createMongoCompactor({
|
|
215
218
|
maxOpId: checkpoint,
|
|
216
219
|
compactChunksOnly: true,
|
|
220
|
+
forceChunkCompaction: true,
|
|
217
221
|
minCompactChunkIntervalMs: 1
|
|
218
222
|
})
|
|
219
223
|
.compact();
|
|
@@ -223,7 +227,10 @@ bucket_definitions:
|
|
|
223
227
|
|
|
224
228
|
test('v3 repeated initial chunk compaction reschedules overdue full work beyond the current run', async () => {
|
|
225
229
|
const { bucketStorage, checkpoint } = await setup(storage.STORAGE_VERSION_3);
|
|
226
|
-
const firstResult = await bucketStorage.compactInitialReplication({
|
|
230
|
+
const firstResult = await bucketStorage.compactInitialReplication({
|
|
231
|
+
forceChunkCompaction: true,
|
|
232
|
+
maxOpId: checkpoint
|
|
233
|
+
});
|
|
227
234
|
expect(firstResult.buckets).toBe(2);
|
|
228
235
|
|
|
229
236
|
const bucketStateCollection = (bucketStorage.db as VersionedPowerSyncMongoV3).bucketState(
|
|
@@ -243,6 +250,7 @@ bucket_definitions:
|
|
|
243
250
|
.aggregate<{ now: Date }>([{ $documents: [{}] }, { $project: { _id: 0, now: '$$NOW' } }])
|
|
244
251
|
.toArray();
|
|
245
252
|
const result = await bucketStorage.compactInitialReplication({
|
|
253
|
+
forceChunkCompaction: true,
|
|
246
254
|
maxOpId: checkpoint,
|
|
247
255
|
signal: AbortSignal.timeout(2_000)
|
|
248
256
|
});
|
|
@@ -289,7 +297,11 @@ bucket_definitions:
|
|
|
289
297
|
});
|
|
290
298
|
|
|
291
299
|
describe('Mongo Sync Parameter Storage Compact', () => {
|
|
292
|
-
|
|
300
|
+
for (const storageVersion of TEST_STORAGE_VERSIONS) {
|
|
301
|
+
describe(`storage v${storageVersion}`, () => {
|
|
302
|
+
register.registerParameterCompactTests({ ...INITIALIZED_MONGO_STORAGE_FACTORY, storageVersion });
|
|
303
|
+
});
|
|
304
|
+
}
|
|
293
305
|
});
|
|
294
306
|
|
|
295
307
|
/**
|
|
@@ -348,7 +360,7 @@ bucket_definitions:
|
|
|
348
360
|
{ storageVersion: 3 }
|
|
349
361
|
)
|
|
350
362
|
);
|
|
351
|
-
const bucketStorage = factory
|
|
363
|
+
const bucketStorage = (await getTestStorage(factory, syncRules)) as MongoSyncBucketStorage;
|
|
352
364
|
const db = bucketStorage.db as VersionedPowerSyncMongoV3;
|
|
353
365
|
const mapping = syncRules.syncConfigContent[0].mapping;
|
|
354
366
|
const definitionId = mapping.allBucketDefinitionIds()[0];
|
|
@@ -388,6 +400,91 @@ bucket_definitions:
|
|
|
388
400
|
});
|
|
389
401
|
}
|
|
390
402
|
|
|
403
|
+
test.each([1, 7])(
|
|
404
|
+
'initial compaction bulk-reschedules buckets with %s chunks without reading data',
|
|
405
|
+
async (chunks) => {
|
|
406
|
+
const { bucketStorage, collection, bucketStateCollection, ctx, sourceTableId, db } = await setupV3Storage();
|
|
407
|
+
const documents = Array.from({ length: chunks }, (_, index) =>
|
|
408
|
+
serializeBucketData(BUCKET, [makeOp(index + 1, String(index), 'data', ctx, sourceTableId)])
|
|
409
|
+
);
|
|
410
|
+
await insertDocs(collection, documents);
|
|
411
|
+
await bucketStateCollection.insertOne({
|
|
412
|
+
_id: { d: ctx.definitionId, b: BUCKET },
|
|
413
|
+
last_op: BigInt(chunks),
|
|
414
|
+
next_compact_check: new Date(0),
|
|
415
|
+
// Even overdue full compaction must not force a small initial chunk merge.
|
|
416
|
+
first_uncompacted_write: new Date(0),
|
|
417
|
+
bucket_stats: { count: chunks, bytes: BigInt(documents.reduce((sum, doc) => sum + doc.size, 0)), chunks }
|
|
418
|
+
});
|
|
419
|
+
const claim = vi.spyOn(CompactionLease, 'claim');
|
|
420
|
+
const data = vi.spyOn(db, 'bucketData');
|
|
421
|
+
try {
|
|
422
|
+
expect(await bucketStorage.compactInitialReplication({ maxOpId: BigInt(chunks) })).toEqual({ buckets: 0 });
|
|
423
|
+
expect(claim).not.toHaveBeenCalled();
|
|
424
|
+
expect(data).not.toHaveBeenCalled();
|
|
425
|
+
const state = await bucketStateCollection.findOne({ _id: { d: ctx.definitionId, b: BUCKET } });
|
|
426
|
+
expect(state?.compacted_state).toBeUndefined();
|
|
427
|
+
expect(state?.compact_lease).toBeUndefined();
|
|
428
|
+
expect(state?.last_full_compact).toBeUndefined();
|
|
429
|
+
expect(state!.next_compact_check!.getTime()).toBeGreaterThan(Date.now());
|
|
430
|
+
expect(await collection.find().toArray()).toEqual(documents);
|
|
431
|
+
} finally {
|
|
432
|
+
claim.mockRestore();
|
|
433
|
+
data.mockRestore();
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
);
|
|
437
|
+
|
|
438
|
+
test('initial compaction rechecks the chunk threshold after claiming', async () => {
|
|
439
|
+
const { bucketStorage, collection, bucketStateCollection, ctx, sourceTableId, db } = await setupV3Storage();
|
|
440
|
+
const documents = Array.from({ length: 8 }, (_, index) =>
|
|
441
|
+
serializeBucketData(BUCKET, [makeOp(index + 1, String(index), 'data', ctx, sourceTableId)])
|
|
442
|
+
);
|
|
443
|
+
await insertDocs(collection, documents);
|
|
444
|
+
const bytes = BigInt(documents.reduce((sum, doc) => sum + doc.size, 0));
|
|
445
|
+
await bucketStateCollection.insertOne({
|
|
446
|
+
_id: { d: ctx.definitionId, b: BUCKET },
|
|
447
|
+
last_op: 8n,
|
|
448
|
+
next_compact_check: new Date(0),
|
|
449
|
+
first_uncompacted_write: new Date(),
|
|
450
|
+
bucket_stats: { count: 8, bytes, chunks: 8 }
|
|
451
|
+
});
|
|
452
|
+
const originalClaim = CompactionLease.claim.bind(CompactionLease);
|
|
453
|
+
const claim = vi.spyOn(CompactionLease, 'claim').mockImplementationOnce(async (...args) => {
|
|
454
|
+
// Another compactor finishes before we acquire the lease, leaving one
|
|
455
|
+
// new chunk beyond its cached prefix instead of the eight we selected.
|
|
456
|
+
await bucketStateCollection.updateOne(
|
|
457
|
+
{ _id: { d: ctx.definitionId, b: BUCKET } },
|
|
458
|
+
{
|
|
459
|
+
$set: {
|
|
460
|
+
compacted_state: {
|
|
461
|
+
op_id: 7n,
|
|
462
|
+
checksum: 196n,
|
|
463
|
+
count: 7,
|
|
464
|
+
bytes: bytes - BigInt(documents[7].size),
|
|
465
|
+
chunks: 7,
|
|
466
|
+
at: new Date()
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
);
|
|
471
|
+
return originalClaim(...args);
|
|
472
|
+
});
|
|
473
|
+
const data = vi.spyOn(db, 'bucketData');
|
|
474
|
+
try {
|
|
475
|
+
expect(await bucketStorage.compactInitialReplication({ maxOpId: 8n })).toEqual({ buckets: 0 });
|
|
476
|
+
expect(claim).toHaveBeenCalledTimes(1);
|
|
477
|
+
expect(data).not.toHaveBeenCalled();
|
|
478
|
+
const state = await bucketStateCollection.findOne({ _id: { d: ctx.definitionId, b: BUCKET } });
|
|
479
|
+
expect(state?.compacted_state?.op_id).toBe(7n);
|
|
480
|
+
expect(state?.compact_lease).toBeUndefined();
|
|
481
|
+
expect(state!.next_compact_check!.getTime()).toBeGreaterThan(Date.now());
|
|
482
|
+
} finally {
|
|
483
|
+
claim.mockRestore();
|
|
484
|
+
data.mockRestore();
|
|
485
|
+
}
|
|
486
|
+
});
|
|
487
|
+
|
|
391
488
|
test('a successful lease renewal clears a transient renewal error', async () => {
|
|
392
489
|
const { bucketStateCollection, ctx } = await setupV3Storage();
|
|
393
490
|
await insertBucketState(bucketStateCollection, ctx.definitionId, 1n);
|
|
@@ -449,7 +546,7 @@ bucket_definitions:
|
|
|
449
546
|
);
|
|
450
547
|
|
|
451
548
|
await (bucketStorage as MongoSyncBucketStorage)
|
|
452
|
-
.createMongoCompactor({ maxOpId: 2n, compactChunksOnly: true })
|
|
549
|
+
.createMongoCompactor({ maxOpId: 2n, compactChunksOnly: true, forceChunkCompaction: true })
|
|
453
550
|
.compact();
|
|
454
551
|
|
|
455
552
|
const [badState, goodState] = await Promise.all([
|
|
@@ -493,6 +590,7 @@ bucket_definitions:
|
|
|
493
590
|
.createMongoCompactor({
|
|
494
591
|
maxOpId: 2n,
|
|
495
592
|
compactChunksOnly: true,
|
|
593
|
+
forceChunkCompaction: true,
|
|
496
594
|
signal: abortController.signal,
|
|
497
595
|
logger: testLogger
|
|
498
596
|
})
|
|
@@ -896,7 +994,7 @@ bucket_definitions:
|
|
|
896
994
|
{ storageVersion: 3 }
|
|
897
995
|
)
|
|
898
996
|
);
|
|
899
|
-
const bucketStorage = factory
|
|
997
|
+
const bucketStorage = (await getTestStorage(factory, syncRules)) as MongoSyncBucketStorage;
|
|
900
998
|
const db = bucketStorage.db as VersionedPowerSyncMongoV3;
|
|
901
999
|
const mapping = syncRules.syncConfigContent[0].mapping;
|
|
902
1000
|
const definitionId = mapping.allBucketDefinitionIds()[0];
|
|
@@ -1073,7 +1171,7 @@ bucket_definitions:
|
|
|
1073
1171
|
{ storageVersion: 3 }
|
|
1074
1172
|
)
|
|
1075
1173
|
);
|
|
1076
|
-
const bucketStorage = factory
|
|
1174
|
+
const bucketStorage = (await getTestStorage(factory, syncRules)) as MongoSyncBucketStorage;
|
|
1077
1175
|
const db = bucketStorage.db as VersionedPowerSyncMongoV3;
|
|
1078
1176
|
const mapping = syncRules.syncConfigContent[0].mapping;
|
|
1079
1177
|
const definitionId = mapping.allBucketDefinitionIds()[0];
|
|
@@ -1466,7 +1564,7 @@ bucket_definitions:
|
|
|
1466
1564
|
{ storageVersion: 3 }
|
|
1467
1565
|
)
|
|
1468
1566
|
);
|
|
1469
|
-
const bucketStorage = factory
|
|
1567
|
+
const bucketStorage = (await getTestStorage(factory, syncRules)) as MongoSyncBucketStorage;
|
|
1470
1568
|
const db = bucketStorage.db as VersionedPowerSyncMongoV3;
|
|
1471
1569
|
const mapping = syncRules.syncConfigContent[0].mapping;
|
|
1472
1570
|
const definitionId = mapping.allBucketDefinitionIds()[0];
|
|
@@ -1655,7 +1753,7 @@ bucket_definitions:
|
|
|
1655
1753
|
{ storageVersion: 3 }
|
|
1656
1754
|
)
|
|
1657
1755
|
);
|
|
1658
|
-
const bucketStorage = factory
|
|
1756
|
+
const bucketStorage = (await getTestStorage(factory, syncRules)) as MongoSyncBucketStorage;
|
|
1659
1757
|
const db = bucketStorage.db as VersionedPowerSyncMongoV3;
|
|
1660
1758
|
const definitionId = bucketStorage.storageIds.bucketDefinitionIds[0];
|
|
1661
1759
|
const collection = db.bucketData(bucketStorage.replicationStreamId, definitionId);
|
|
@@ -1752,6 +1850,29 @@ bucket_definitions:
|
|
|
1752
1850
|
expect(state?.bucket_stats).toEqual({ count: 4, bytes, chunks: documents.length });
|
|
1753
1851
|
}
|
|
1754
1852
|
|
|
1853
|
+
test('initial compaction merges eight chunks immediately without full compaction', async () => {
|
|
1854
|
+
const { bucketStorage, collection, bucketStateCollection, ctx, sourceTableId } = await setupV3();
|
|
1855
|
+
const inputs = Array.from({ length: 8 }, (_, index) =>
|
|
1856
|
+
serializeBucketData(BUCKET, [makeOp(index + 1, 'A', 'data', ctx, sourceTableId)])
|
|
1857
|
+
);
|
|
1858
|
+
await insertDocs(collection, inputs);
|
|
1859
|
+
await bucketStateCollection.insertOne({
|
|
1860
|
+
_id: { d: ctx.definitionId, b: BUCKET },
|
|
1861
|
+
last_op: 8n,
|
|
1862
|
+
next_compact_check: new Date(),
|
|
1863
|
+
first_uncompacted_write: new Date(0),
|
|
1864
|
+
bucket_stats: { count: 8, bytes: BigInt(inputs.reduce((sum, doc) => sum + doc.size, 0)), chunks: 8 }
|
|
1865
|
+
});
|
|
1866
|
+
|
|
1867
|
+
expect(await bucketStorage.compactInitialReplication({ maxOpId: 8n })).toEqual({ buckets: 1 });
|
|
1868
|
+
const documents = await collection.find({ '_id.b': BUCKET }).toArray();
|
|
1869
|
+
expect(documents).toHaveLength(1);
|
|
1870
|
+
expect(documents[0].ops!.map((op) => op.o)).toEqual([1n, 2n, 3n, 4n, 5n, 6n, 7n, 8n]);
|
|
1871
|
+
const state = await bucketStateCollection.findOne({ _id: { d: ctx.definitionId, b: BUCKET } });
|
|
1872
|
+
expect(state?.compacted_state).toMatchObject({ op_id: 8n, count: 8, checksum: 252n });
|
|
1873
|
+
expect(state?.last_full_compact).toBeUndefined();
|
|
1874
|
+
});
|
|
1875
|
+
|
|
1755
1876
|
test('initial compaction merges small chunks and refreshes bucket metadata', async () => {
|
|
1756
1877
|
const { bucketStorage, collection, bucketStateCollection, ctx, sourceTableId } = await setupV3();
|
|
1757
1878
|
await insertDocs(collection, [
|
|
@@ -1760,7 +1881,7 @@ bucket_definitions:
|
|
|
1760
1881
|
]);
|
|
1761
1882
|
await insertBucketState(bucketStateCollection, ctx.definitionId, 4n);
|
|
1762
1883
|
|
|
1763
|
-
const result = await bucketStorage.compactInitialReplication({ maxOpId: 4n });
|
|
1884
|
+
const result = await bucketStorage.compactInitialReplication({ forceChunkCompaction: true, maxOpId: 4n });
|
|
1764
1885
|
|
|
1765
1886
|
expect(result).toEqual({ buckets: 1 });
|
|
1766
1887
|
const documents = await collection.find({ '_id.b': BUCKET }).sort({ '_id.o': 1 }).toArray();
|
|
@@ -1827,7 +1948,7 @@ bucket_definitions:
|
|
|
1827
1948
|
Array.from({ length: 2 }, () =>
|
|
1828
1949
|
bucketStorage.factory
|
|
1829
1950
|
.getInstance(syncRules)
|
|
1830
|
-
.compactInitialReplication({ maxOpId: 2n, signal: controller.signal })
|
|
1951
|
+
.compactInitialReplication({ forceChunkCompaction: true, maxOpId: 2n, signal: controller.signal })
|
|
1831
1952
|
)
|
|
1832
1953
|
).finally(() => {
|
|
1833
1954
|
settled = true;
|
|
@@ -1858,7 +1979,9 @@ bucket_definitions:
|
|
|
1858
1979
|
expect(results.every((result) => result.status === 'rejected')).toBe(true);
|
|
1859
1980
|
expect(await bucketStateCollection.countDocuments({ compact_lease: { $exists: true } })).toBe(0);
|
|
1860
1981
|
// Cancellation must return all worker slots.
|
|
1861
|
-
expect(await bucketStorage.compactInitialReplication({ maxOpId: 2n })).toEqual({
|
|
1982
|
+
expect(await bucketStorage.compactInitialReplication({ forceChunkCompaction: true, maxOpId: 2n })).toEqual({
|
|
1983
|
+
buckets: bucketCount
|
|
1984
|
+
});
|
|
1862
1985
|
} else {
|
|
1863
1986
|
expect(results.every((result) => result.status === 'fulfilled')).toBe(true);
|
|
1864
1987
|
expect(results.reduce((sum, result) => sum + (result.status === 'fulfilled' ? result.value.buckets : 0), 0)).toBe(
|
|
@@ -2048,7 +2171,7 @@ bucket_definitions:
|
|
|
2048
2171
|
}
|
|
2049
2172
|
});
|
|
2050
2173
|
|
|
2051
|
-
const result = await bucketStorage.compactInitialReplication({ maxOpId: 4n });
|
|
2174
|
+
const result = await bucketStorage.compactInitialReplication({ forceChunkCompaction: true, maxOpId: 4n });
|
|
2052
2175
|
|
|
2053
2176
|
expect(result).toEqual({ buckets: 1 });
|
|
2054
2177
|
const expectedStats = {
|
|
@@ -2167,9 +2290,9 @@ bucket_definitions:
|
|
|
2167
2290
|
bucket_stats: { count: 4, bytes: 200n, chunks: 4 }
|
|
2168
2291
|
});
|
|
2169
2292
|
|
|
2170
|
-
await expect(
|
|
2171
|
-
|
|
2172
|
-
);
|
|
2293
|
+
await expect(
|
|
2294
|
+
bucketStorage.createMongoCompactor({ maxOpId: 4n, compactChunksOnly: true, forceChunkCompaction: true }).compact()
|
|
2295
|
+
).resolves.toBe(1);
|
|
2173
2296
|
|
|
2174
2297
|
const currentDocuments = await collection.find({ '_id.b': BUCKET }).sort({ '_id.o': 1 }).toArray();
|
|
2175
2298
|
expect(currentDocuments.flatMap((document) => document.ops!.map((op) => op.o))).toEqual([1n, 3n, 4n]);
|
|
@@ -2189,7 +2312,8 @@ bucket_definitions:
|
|
|
2189
2312
|
const { bucketStorage, collection, bucketStateCollection, ctx } = await setupCompactedTail();
|
|
2190
2313
|
const failedCompactor = bucketStorage.createMongoCompactor({
|
|
2191
2314
|
maxOpId: 4n,
|
|
2192
|
-
compactChunksOnly: true
|
|
2315
|
+
compactChunksOnly: true,
|
|
2316
|
+
forceChunkCompaction: true
|
|
2193
2317
|
});
|
|
2194
2318
|
const originalFlush = (failedCompactor as any).flushCompactionGroup.bind(failedCompactor);
|
|
2195
2319
|
const flushSpy = vi
|
|
@@ -2210,7 +2334,9 @@ bucket_definitions:
|
|
|
2210
2334
|
{ $set: { next_compact_check: new Date(0) } }
|
|
2211
2335
|
);
|
|
2212
2336
|
|
|
2213
|
-
const result = await bucketStorage
|
|
2337
|
+
const result = await bucketStorage
|
|
2338
|
+
.createMongoCompactor({ maxOpId: 4n, compactChunksOnly: true, forceChunkCompaction: true })
|
|
2339
|
+
.compact();
|
|
2214
2340
|
|
|
2215
2341
|
expect(result).toBe(1);
|
|
2216
2342
|
await expectRecoveredCompactedTail(collection, bucketStateCollection, ctx.definitionId);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { mongoTestStorageFactoryGenerator } from '@module/utils/test-utils.js';
|
|
2
2
|
import { storage, updateSyncRulesFromYaml } from '@powersync/service-core';
|
|
3
|
-
import { bucketRequest, test_utils } from '@powersync/service-core-tests';
|
|
3
|
+
import { bucketRequest, getTestStorage, test_utils } from '@powersync/service-core-tests';
|
|
4
4
|
import { describe, expect, test } from 'vitest';
|
|
5
5
|
import { DEFAULT_INLINE_THRESHOLD_BYTES } from '../../src/storage/implementation/common/PersistedBatch.js';
|
|
6
6
|
import { MongoSyncBucketStorage } from '../../src/storage/implementation/createMongoSyncBucketStorage.js';
|
|
@@ -31,7 +31,7 @@ describe('Object storage inline threshold', () => {
|
|
|
31
31
|
const { memoryStorage, factoryGen } = s3Factory();
|
|
32
32
|
await using factory = await factoryGen.factory();
|
|
33
33
|
const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(SYNC_RULES_YAML, { storageVersion: 3 }));
|
|
34
|
-
const bucketStorage = factory
|
|
34
|
+
const bucketStorage = (await getTestStorage(factory, syncRules)) as MongoSyncBucketStorage;
|
|
35
35
|
expect(bucketStorage.inlineThresholdBytes).toBe(DEFAULT_INLINE_THRESHOLD_BYTES);
|
|
36
36
|
|
|
37
37
|
await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
|
|
@@ -77,7 +77,7 @@ describe('Object storage inline threshold', () => {
|
|
|
77
77
|
const { memoryStorage, factoryGen } = s3Factory(256);
|
|
78
78
|
await using factory = await factoryGen.factory();
|
|
79
79
|
const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(SYNC_RULES_YAML, { storageVersion: 3 }));
|
|
80
|
-
const bucketStorage = factory
|
|
80
|
+
const bucketStorage = (await getTestStorage(factory, syncRules)) as MongoSyncBucketStorage;
|
|
81
81
|
expect(bucketStorage.inlineThresholdBytes).toBe(256);
|
|
82
82
|
|
|
83
83
|
await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
storage,
|
|
5
5
|
updateSyncRulesFromYaml
|
|
6
6
|
} from '@powersync/service-core';
|
|
7
|
-
import { bucketRequest, compactActive, test_utils } from '@powersync/service-core-tests';
|
|
7
|
+
import { bucketRequest, compactActive, getTestStorage, test_utils } from '@powersync/service-core-tests';
|
|
8
8
|
import { describe, expect, test } from 'vitest';
|
|
9
9
|
import { MongoSyncBucketStorage } from '../../src/storage/implementation/createMongoSyncBucketStorage.js';
|
|
10
10
|
import { VersionedPowerSyncMongoV3 } from '../../src/storage/implementation/v3/VersionedPowerSyncMongoV3.js';
|
|
@@ -28,7 +28,7 @@ describe('V3 checksums with S3 object storage', () => {
|
|
|
28
28
|
const { factoryGen } = s3Factory();
|
|
29
29
|
await using factory = await factoryGen.factory();
|
|
30
30
|
const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(SYNC_RULES_YAML, { storageVersion: 3 }));
|
|
31
|
-
const bucketStorage = factory
|
|
31
|
+
const bucketStorage = (await getTestStorage(factory, syncRules)) as MongoSyncBucketStorage;
|
|
32
32
|
const db = bucketStorage.db as VersionedPowerSyncMongoV3;
|
|
33
33
|
|
|
34
34
|
const request = bucketRequest(syncRules.syncConfigContent[0], 'global[]', 0n);
|
|
@@ -75,7 +75,7 @@ describe('V3 checksums with S3 object storage', () => {
|
|
|
75
75
|
const { factoryGen } = s3Factory();
|
|
76
76
|
await using factory = await factoryGen.factory();
|
|
77
77
|
const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(SYNC_RULES_YAML, { storageVersion: 3 }));
|
|
78
|
-
const bucketStorage = factory
|
|
78
|
+
const bucketStorage = (await getTestStorage(factory, syncRules)) as MongoSyncBucketStorage;
|
|
79
79
|
const db = bucketStorage.db as VersionedPowerSyncMongoV3;
|
|
80
80
|
|
|
81
81
|
const request = bucketRequest(syncRules.syncConfigContent[0], 'global[]', 0n);
|
|
@@ -114,7 +114,7 @@ describe('V3 checksums with S3 object storage', () => {
|
|
|
114
114
|
const { factoryGen } = s3Factory();
|
|
115
115
|
await using factory = await factoryGen.factory();
|
|
116
116
|
const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(SYNC_RULES_YAML, { storageVersion: 3 }));
|
|
117
|
-
const bucketStorage = factory
|
|
117
|
+
const bucketStorage = (await getTestStorage(factory, syncRules)) as MongoSyncBucketStorage;
|
|
118
118
|
const db = bucketStorage.db as VersionedPowerSyncMongoV3;
|
|
119
119
|
|
|
120
120
|
const request = bucketRequest(syncRules.syncConfigContent[0], 'global[]', 0n);
|