@powersync/service-module-mongodb-storage 0.23.2 → 0.24.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.
- package/CHANGELOG.md +45 -0
- package/LICENSE +201 -67
- package/dist/storage/MongoBucketStorage.d.ts +1 -0
- package/dist/storage/MongoBucketStorage.js +45 -83
- package/dist/storage/MongoBucketStorage.js.map +1 -1
- package/dist/storage/implementation/MongoBucketBatch.d.ts +60 -39
- package/dist/storage/implementation/MongoBucketBatch.js +123 -296
- package/dist/storage/implementation/MongoBucketBatch.js.map +1 -1
- package/dist/storage/implementation/MongoOpIdAllocator.d.ts +6 -1
- package/dist/storage/implementation/MongoOpIdAllocator.js +12 -5
- package/dist/storage/implementation/MongoOpIdAllocator.js.map +1 -1
- package/dist/storage/implementation/MongoParsedSyncConfigSet.d.ts +7 -0
- package/dist/storage/implementation/MongoParsedSyncConfigSet.js +28 -2
- package/dist/storage/implementation/MongoParsedSyncConfigSet.js.map +1 -1
- package/dist/storage/implementation/MongoReplicationOptions.d.ts +27 -0
- package/dist/storage/implementation/MongoReplicationOptions.js +26 -0
- package/dist/storage/implementation/MongoReplicationOptions.js.map +1 -0
- package/dist/storage/implementation/MongoSyncBucketStorage.js +2 -3
- package/dist/storage/implementation/MongoSyncBucketStorage.js.map +1 -1
- package/dist/storage/implementation/MongoSyncRulesLock.d.ts +15 -2
- package/dist/storage/implementation/MongoSyncRulesLock.js +36 -14
- package/dist/storage/implementation/MongoSyncRulesLock.js.map +1 -1
- package/dist/storage/implementation/common/BatchOperationBuffer.d.ts +79 -0
- package/dist/storage/implementation/common/BatchOperationBuffer.js +286 -0
- package/dist/storage/implementation/common/BatchOperationBuffer.js.map +1 -0
- package/dist/storage/implementation/common/PersistedBatch.d.ts +10 -103
- package/dist/storage/implementation/common/PersistedBatch.js +1 -291
- package/dist/storage/implementation/common/PersistedBatch.js.map +1 -1
- package/dist/storage/implementation/common/PreparedPublication.d.ts +43 -0
- package/dist/storage/implementation/common/PreparedPublication.js +2 -0
- package/dist/storage/implementation/common/PreparedPublication.js.map +1 -0
- package/dist/storage/implementation/common/SourceRecordStore.d.ts +0 -2
- package/dist/storage/implementation/v1/MongoBucketBatchV1.d.ts +17 -13
- package/dist/storage/implementation/v1/MongoBucketBatchV1.js +259 -18
- package/dist/storage/implementation/v1/MongoBucketBatchV1.js.map +1 -1
- package/dist/storage/implementation/v1/PersistedBatchV1.d.ts +21 -15
- package/dist/storage/implementation/v1/PersistedBatchV1.js +58 -24
- package/dist/storage/implementation/v1/PersistedBatchV1.js.map +1 -1
- package/dist/storage/implementation/v1/SourceRecordStoreV1.d.ts +0 -2
- package/dist/storage/implementation/v1/SourceRecordStoreV1.js +0 -3
- package/dist/storage/implementation/v1/SourceRecordStoreV1.js.map +1 -1
- package/dist/storage/implementation/v3/MongoBucketBatchV3.d.ts +25 -14
- package/dist/storage/implementation/v3/MongoBucketBatchV3.js +350 -23
- package/dist/storage/implementation/v3/MongoBucketBatchV3.js.map +1 -1
- package/dist/storage/implementation/v3/MongoCompactorV3.d.ts +1 -0
- package/dist/storage/implementation/v3/MongoCompactorV3.js +10 -4
- package/dist/storage/implementation/v3/MongoCompactorV3.js.map +1 -1
- package/dist/storage/implementation/v3/MongoSyncBucketStorageV3.js +39 -28
- package/dist/storage/implementation/v3/MongoSyncBucketStorageV3.js.map +1 -1
- package/dist/storage/implementation/v3/PersistedBatchV3.d.ts +46 -24
- package/dist/storage/implementation/v3/PersistedBatchV3.js +159 -83
- package/dist/storage/implementation/v3/PersistedBatchV3.js.map +1 -1
- package/dist/storage/implementation/v3/SourceRecordStoreV3.d.ts +12 -0
- package/dist/storage/implementation/v3/SourceRecordStoreV3.js +41 -13
- package/dist/storage/implementation/v3/SourceRecordStoreV3.js.map +1 -1
- package/dist/storage/implementation/v3/object-storage/BucketDataObjectStorage.d.ts +4 -0
- package/dist/storage/implementation/v3/object-storage/BucketDataObjectStorage.js +4 -0
- package/dist/storage/implementation/v3/object-storage/BucketDataObjectStorage.js.map +1 -1
- package/dist/storage/implementation/v3/object-storage/ObjectStorageLifecycle.d.ts +27 -2
- package/dist/storage/implementation/v3/object-storage/ObjectStorageLifecycle.js +61 -5
- package/dist/storage/implementation/v3/object-storage/ObjectStorageLifecycle.js.map +1 -1
- package/package.json +9 -10
- package/src/storage/MongoBucketStorage.ts +55 -122
- package/src/storage/implementation/MongoBucketBatch.ts +185 -392
- package/src/storage/implementation/MongoOpIdAllocator.ts +12 -5
- package/src/storage/implementation/MongoParsedSyncConfigSet.ts +40 -1
- package/src/storage/implementation/MongoReplicationOptions.ts +28 -0
- package/src/storage/implementation/MongoSyncBucketStorage.ts +2 -3
- package/src/storage/implementation/MongoSyncRulesLock.ts +39 -17
- package/src/storage/implementation/common/BatchOperationBuffer.ts +353 -0
- package/src/storage/implementation/common/PersistedBatch.ts +12 -390
- package/src/storage/implementation/common/PreparedPublication.ts +49 -0
- package/src/storage/implementation/common/SourceRecordStore.ts +0 -2
- package/src/storage/implementation/v1/MongoBucketBatchV1.ts +339 -27
- package/src/storage/implementation/v1/PersistedBatchV1.ts +74 -32
- package/src/storage/implementation/v1/SourceRecordStoreV1.ts +0 -5
- package/src/storage/implementation/v3/MongoBucketBatchV3.ts +430 -32
- package/src/storage/implementation/v3/MongoCompactorV3.ts +13 -4
- package/src/storage/implementation/v3/MongoSyncBucketStorageV3.ts +43 -29
- package/src/storage/implementation/v3/PersistedBatchV3.ts +209 -108
- package/src/storage/implementation/v3/SourceRecordStoreV3.ts +45 -15
- package/src/storage/implementation/v3/object-storage/BucketDataObjectStorage.ts +9 -0
- package/src/storage/implementation/v3/object-storage/ObjectStorageLifecycle.ts +79 -5
- package/test/src/checkpoint_cleanup.test.ts +75 -0
- package/test/src/concurrent_writers.test.ts +127 -53
- package/test/src/helpers/PublicationCommandMonitor.ts +119 -0
- package/test/src/helpers/concurrentWriter.mjs +2 -2
- package/test/src/invalid_sync_config.test.ts +9 -0
- package/test/src/object_storage_lifecycle.test.ts +72 -2
- package/test/src/prepared_publication.test.ts +388 -0
- package/test/src/replication_preparation.test.ts +829 -0
- package/test/src/replication_publication_baseline.test.ts +203 -0
- package/test/src/replication_publication_batching.test.ts +212 -0
- package/test/src/replication_uploads.test.ts +393 -0
- package/test/src/source_table_config.test.ts +4 -4
- package/test/src/storage_object_storage_inline_threshold.test.ts +1 -1
- package/test/src/storage_s3_compaction_lifecycle.test.ts +93 -1
- package/test/src/storage_sync.test.ts +101 -2
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { MongoSyncBucketStorageV3 } from '@module/storage/implementation/v3/MongoSyncBucketStorageV3.js';
|
|
2
|
+
import { ReplicationAbortedError } from '@powersync/lib-services-framework';
|
|
2
3
|
import {
|
|
3
4
|
deserializeParameterLookup,
|
|
4
5
|
JwtPayload,
|
|
@@ -7,7 +8,7 @@ import {
|
|
|
7
8
|
updateSyncRulesFromYaml
|
|
8
9
|
} from '@powersync/service-core';
|
|
9
10
|
import { bucketRequest, getTestStorage, register, test_utils } from '@powersync/service-core-tests';
|
|
10
|
-
import { RequestParameters, ScopedParameterLookup
|
|
11
|
+
import { parseSyncConfig, RequestParameters, ScopedParameterLookup } from '@powersync/service-sync-rules';
|
|
11
12
|
import * as bson from 'bson';
|
|
12
13
|
import { describe, expect, test } from 'vitest';
|
|
13
14
|
import { MongoBucketStorage } from '../../src/storage/MongoBucketStorage.js';
|
|
@@ -72,7 +73,7 @@ function objectIdGenerator(id: string) {
|
|
|
72
73
|
* `ResolveTablesOptions.parsedSyncConfig`.
|
|
73
74
|
*/
|
|
74
75
|
function parsedSyncConfigSetFor(yaml: string, storageVersion: number) {
|
|
75
|
-
const parsed =
|
|
76
|
+
const parsed = parseSyncConfig(yaml, test_utils.PARSE_OPTIONS);
|
|
76
77
|
// These fixtures are legacy Sync Rules, which always report a deprecation warning.
|
|
77
78
|
expect(parsed.errors.filter((error) => error.type !== 'warning')).toEqual([]);
|
|
78
79
|
return new MongoParsedSyncConfigSet(1, getMongoStorageConfig(storageVersion), 'test_slot', [
|
|
@@ -939,6 +940,70 @@ event_definitions:
|
|
|
939
940
|
expect(deserializeParameterLookup(parameterEntry!.lookup)).toEqual(['shape-check']);
|
|
940
941
|
});
|
|
941
942
|
|
|
943
|
+
test.runIf(storageVersion >= 3)('fetches parameter sets beyond the aggregation stage limit', async () => {
|
|
944
|
+
await using factory = await storageConfig.factory();
|
|
945
|
+
const syncRules = await factory.updateSyncRules(
|
|
946
|
+
updateSyncRulesFromYaml(
|
|
947
|
+
/* yaml */ `
|
|
948
|
+
# Parameter lookup batching regression fixture.
|
|
949
|
+
config:
|
|
950
|
+
edition: 3
|
|
951
|
+
streams:
|
|
952
|
+
by_owner:
|
|
953
|
+
auto_subscribe: true
|
|
954
|
+
query: |
|
|
955
|
+
SELECT * FROM test
|
|
956
|
+
WHERE id IN (SELECT owner_id FROM test WHERE id = auth.parameter('test'))
|
|
957
|
+
`,
|
|
958
|
+
{ storageVersion }
|
|
959
|
+
)
|
|
960
|
+
);
|
|
961
|
+
const bucketStorage = await getTestStorage(factory, syncRules);
|
|
962
|
+
await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
|
|
963
|
+
const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id'], INITIALIZED_MONGO_STORAGE_FACTORY);
|
|
964
|
+
|
|
965
|
+
for (const id of ['row-first', 'row-middle', 'row-last']) {
|
|
966
|
+
await writer.save({
|
|
967
|
+
sourceTable,
|
|
968
|
+
tag: storage.SaveOperationTag.INSERT,
|
|
969
|
+
after: { id, description: id, owner_id: `user-${id}` },
|
|
970
|
+
afterReplicaId: test_utils.rid(id)
|
|
971
|
+
});
|
|
972
|
+
}
|
|
973
|
+
await writer.markAllSnapshotDone('1/1');
|
|
974
|
+
await writer.commit('1/1');
|
|
975
|
+
|
|
976
|
+
const parsed = syncRules.syncConfigContent[0].parsed(test_utils.PARSE_OPTIONS);
|
|
977
|
+
const [parameterSource] = [...parsed.syncConfigs[0].config.bucketParameterLookupSources];
|
|
978
|
+
const scope = parsed.hydrationState.getParameterIndexLookupScope(parameterSource);
|
|
979
|
+
|
|
980
|
+
// MongoDB rejects aggregation pipelines with more than 1000 stages, and each
|
|
981
|
+
// lookup after the first adds a $unionWith stage (#873).
|
|
982
|
+
const lookups: ScopedParameterLookup[] = [];
|
|
983
|
+
for (let i = 0; i < 996; i++) {
|
|
984
|
+
let id = `missing-${i}`;
|
|
985
|
+
if (i == 0) {
|
|
986
|
+
id = 'row-first';
|
|
987
|
+
} else if (i == 900) {
|
|
988
|
+
id = 'row-middle';
|
|
989
|
+
} else if (i == 995) {
|
|
990
|
+
id = 'row-last';
|
|
991
|
+
}
|
|
992
|
+
lookups.push(ScopedParameterLookup.direct(scope, [id]));
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
const checkpoint = await bucketStorage.getCheckpoint();
|
|
996
|
+
const parameterSets = await checkpoint.getParameterSets(lookups, 1000);
|
|
997
|
+
|
|
998
|
+
expect(parameterSets.length).toEqual(3);
|
|
999
|
+
await expect(checkpoint.getParameterSets(lookups, 2)).rejects.toThrow('Too many parameter results');
|
|
1000
|
+
expect(await checkpoint.getParameterSets(lookups, 3)).toEqual(parameterSets);
|
|
1001
|
+
const rowsByKey = new Map(parameterSets.map((set) => [set.lookup.indexKey[0], set.rows]));
|
|
1002
|
+
expect(rowsByKey.get('row-first')).toEqual([{ '0': 'user-row-first' }]);
|
|
1003
|
+
expect(rowsByKey.get('row-middle')).toEqual([{ '0': 'user-row-middle' }]);
|
|
1004
|
+
expect(rowsByKey.get('row-last')).toEqual([{ '0': 'user-row-last' }]);
|
|
1005
|
+
});
|
|
1006
|
+
|
|
942
1007
|
test.runIf(storageVersion >= 3)('replaces an existing deploying sync config', async () => {
|
|
943
1008
|
await using factory = await storageConfig.factory();
|
|
944
1009
|
|
|
@@ -1343,6 +1408,22 @@ streams:
|
|
|
1343
1408
|
expect(updatedActiveStorage.replicationStream.replicationJobId).toContain(
|
|
1344
1409
|
(await factory.getActiveSyncConfig())!.content.syncConfigId
|
|
1345
1410
|
);
|
|
1411
|
+
|
|
1412
|
+
// The full-stream writer still holds the old config's definition mapping.
|
|
1413
|
+
// Both metadata writes and the next checkpoint must exit so a replacement
|
|
1414
|
+
// job can load only live mappings.
|
|
1415
|
+
await expect(
|
|
1416
|
+
secondWriter.resolveTables({
|
|
1417
|
+
connection_id: 1,
|
|
1418
|
+
source: sourceDescriptor('todos', { objectId: 'todos-relation-after-activation' }),
|
|
1419
|
+
idGenerator: objectIdGenerator('6544e3899293153fa7b3835e')
|
|
1420
|
+
})
|
|
1421
|
+
).rejects.toBeInstanceOf(ReplicationAbortedError);
|
|
1422
|
+
await expect(secondWriter.commit('3/1')).rejects.toBeInstanceOf(ReplicationAbortedError);
|
|
1423
|
+
const persistedStream = (await (factory as MongoBucketStorage).db.sync_rules.findOne({
|
|
1424
|
+
_id: first.replicationStreamId
|
|
1425
|
+
})) as ReplicationStreamDocumentV3;
|
|
1426
|
+
expect(persistedStream.resume_lsn).toBe('2/1');
|
|
1346
1427
|
}
|
|
1347
1428
|
);
|
|
1348
1429
|
|
|
@@ -1870,6 +1951,24 @@ streams:
|
|
|
1870
1951
|
}
|
|
1871
1952
|
);
|
|
1872
1953
|
|
|
1954
|
+
test.runIf(storageVersion >= 3)('storage metrics collect sizes across union batches', async () => {
|
|
1955
|
+
await using factory = await storageConfig.factory();
|
|
1956
|
+
const mongoFactory = factory as MongoBucketStorage;
|
|
1957
|
+
const before = await factory.getStorageMetrics();
|
|
1958
|
+
let expectedSize = 0;
|
|
1959
|
+
for (let index = 0; index < 101; index++) {
|
|
1960
|
+
const collection = mongoFactory.db.db.collection(`bucket_data_999_metrics_${index}`);
|
|
1961
|
+
await collection.insertOne({ value: 'x'.repeat(index + 1) });
|
|
1962
|
+
const [stats] = await collection.aggregate([{ $collStats: { storageStats: {} } }]).toArray();
|
|
1963
|
+
expectedSize += Number(stats.storageStats.size);
|
|
1964
|
+
}
|
|
1965
|
+
|
|
1966
|
+
const after = await factory.getStorageMetrics();
|
|
1967
|
+
expect(after.operations_size_bytes - before.operations_size_bytes).toBe(expectedSize);
|
|
1968
|
+
expect(after.parameters_size_bytes).toBe(before.parameters_size_bytes);
|
|
1969
|
+
expect(after.replication_size_bytes).toBe(before.replication_size_bytes);
|
|
1970
|
+
});
|
|
1971
|
+
|
|
1873
1972
|
test.runIf(storageVersion < 3)('storage metrics include v1 current_data', async () => {
|
|
1874
1973
|
await using factory = await storageConfig.factory();
|
|
1875
1974
|
const syncRules = await factory.updateSyncRules(
|