@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.
- package/CHANGELOG.md +51 -0
- package/dist/migrations/db/migrations/1770213298299-storage-version.d.ts +3 -0
- package/dist/migrations/db/migrations/1770213298299-storage-version.js +29 -0
- package/dist/migrations/db/migrations/1770213298299-storage-version.js.map +1 -0
- package/dist/storage/MongoBucketStorage.d.ts +7 -15
- package/dist/storage/MongoBucketStorage.js +28 -53
- package/dist/storage/MongoBucketStorage.js.map +1 -1
- package/dist/storage/implementation/MongoBucketBatch.d.ts +12 -11
- package/dist/storage/implementation/MongoBucketBatch.js +199 -127
- package/dist/storage/implementation/MongoBucketBatch.js.map +1 -1
- package/dist/storage/implementation/MongoChecksums.d.ts +8 -5
- package/dist/storage/implementation/MongoChecksums.js +8 -4
- package/dist/storage/implementation/MongoChecksums.js.map +1 -1
- package/dist/storage/implementation/MongoCompactor.d.ts +2 -2
- package/dist/storage/implementation/MongoCompactor.js +52 -26
- package/dist/storage/implementation/MongoCompactor.js.map +1 -1
- package/dist/storage/implementation/MongoParameterCompactor.d.ts +2 -2
- package/dist/storage/implementation/MongoParameterCompactor.js.map +1 -1
- package/dist/storage/implementation/MongoPersistedSyncRulesContent.d.ts +2 -12
- package/dist/storage/implementation/MongoPersistedSyncRulesContent.js +20 -25
- package/dist/storage/implementation/MongoPersistedSyncRulesContent.js.map +1 -1
- package/dist/storage/implementation/MongoSyncBucketStorage.d.ts +7 -4
- package/dist/storage/implementation/MongoSyncBucketStorage.js +11 -8
- package/dist/storage/implementation/MongoSyncBucketStorage.js.map +1 -1
- package/dist/storage/implementation/MongoSyncRulesLock.d.ts +3 -3
- package/dist/storage/implementation/MongoSyncRulesLock.js.map +1 -1
- package/dist/storage/implementation/MongoWriteCheckpointAPI.d.ts +4 -4
- package/dist/storage/implementation/MongoWriteCheckpointAPI.js.map +1 -1
- package/dist/storage/implementation/OperationBatch.js +3 -2
- package/dist/storage/implementation/OperationBatch.js.map +1 -1
- package/dist/storage/implementation/PersistedBatch.d.ts +11 -4
- package/dist/storage/implementation/PersistedBatch.js +42 -11
- package/dist/storage/implementation/PersistedBatch.js.map +1 -1
- package/dist/storage/implementation/db.d.ts +35 -1
- package/dist/storage/implementation/db.js +99 -0
- package/dist/storage/implementation/db.js.map +1 -1
- package/dist/storage/implementation/models.d.ts +25 -1
- package/dist/storage/implementation/models.js +10 -1
- package/dist/storage/implementation/models.js.map +1 -1
- package/dist/storage/storage-index.d.ts +0 -1
- package/dist/storage/storage-index.js +0 -1
- package/dist/storage/storage-index.js.map +1 -1
- package/dist/utils/test-utils.d.ts +7 -5
- package/dist/utils/test-utils.js +17 -14
- package/dist/utils/test-utils.js.map +1 -1
- package/dist/utils/util.d.ts +2 -1
- package/dist/utils/util.js +15 -1
- package/dist/utils/util.js.map +1 -1
- package/package.json +7 -7
- package/src/migrations/db/migrations/1770213298299-storage-version.ts +44 -0
- package/src/storage/MongoBucketStorage.ts +44 -61
- package/src/storage/implementation/MongoBucketBatch.ts +253 -177
- package/src/storage/implementation/MongoChecksums.ts +19 -9
- package/src/storage/implementation/MongoCompactor.ts +62 -31
- package/src/storage/implementation/MongoParameterCompactor.ts +3 -3
- package/src/storage/implementation/MongoPersistedSyncRulesContent.ts +20 -34
- package/src/storage/implementation/MongoSyncBucketStorage.ts +32 -17
- package/src/storage/implementation/MongoSyncRulesLock.ts +3 -3
- package/src/storage/implementation/MongoWriteCheckpointAPI.ts +4 -4
- package/src/storage/implementation/OperationBatch.ts +3 -2
- package/src/storage/implementation/PersistedBatch.ts +42 -11
- package/src/storage/implementation/db.ts +129 -1
- package/src/storage/implementation/models.ts +39 -1
- package/src/storage/storage-index.ts +0 -1
- package/src/utils/test-utils.ts +18 -16
- package/src/utils/util.ts +17 -2
- package/test/src/__snapshots__/storage.test.ts.snap +198 -22
- package/test/src/__snapshots__/storage_compacting.test.ts.snap +17 -0
- package/test/src/__snapshots__/storage_sync.test.ts.snap +2211 -21
- package/test/src/storage.test.ts +9 -7
- package/test/src/storage_compacting.test.ts +33 -24
- package/test/src/storage_sync.test.ts +31 -15
- package/test/src/util.ts +4 -1
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/storage/implementation/MongoPersistedSyncRules.d.ts +0 -10
- package/dist/storage/implementation/MongoPersistedSyncRules.js +0 -17
- package/dist/storage/implementation/MongoPersistedSyncRules.js.map +0 -1
- package/src/storage/implementation/MongoPersistedSyncRules.ts +0 -20
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
import { SqlSyncRules } from '@powersync/service-sync-rules';
|
|
2
|
-
|
|
3
1
|
import { GetIntanceOptions, storage } from '@powersync/service-core';
|
|
4
2
|
|
|
5
|
-
import {
|
|
3
|
+
import { ErrorCode, ServiceError } from '@powersync/lib-services-framework';
|
|
6
4
|
import { v4 as uuid } from 'uuid';
|
|
7
5
|
|
|
8
6
|
import * as lib_mongo from '@powersync/lib-service-mongodb';
|
|
9
7
|
import { mongo } from '@powersync/lib-service-mongodb';
|
|
10
8
|
|
|
11
9
|
import { PowerSyncMongo } from './implementation/db.js';
|
|
12
|
-
import { SyncRuleDocument } from './implementation/models.js';
|
|
10
|
+
import { getMongoStorageConfig, SyncRuleDocument } from './implementation/models.js';
|
|
13
11
|
import { MongoPersistedSyncRulesContent } from './implementation/MongoPersistedSyncRulesContent.js';
|
|
14
|
-
import { MongoSyncBucketStorage
|
|
12
|
+
import { MongoSyncBucketStorage } from './implementation/MongoSyncBucketStorage.js';
|
|
15
13
|
import { generateSlotName } from '../utils/util.js';
|
|
14
|
+
import { MongoChecksumOptions } from './implementation/MongoChecksums.js';
|
|
15
|
+
|
|
16
|
+
export interface MongoBucketStorageOptions {
|
|
17
|
+
checksumOptions?: Omit<MongoChecksumOptions, 'storageConfig'>;
|
|
18
|
+
}
|
|
16
19
|
|
|
17
|
-
export class MongoBucketStorage
|
|
18
|
-
extends BaseObserver<storage.BucketStorageFactoryListener>
|
|
19
|
-
implements storage.BucketStorageFactory
|
|
20
|
-
{
|
|
20
|
+
export class MongoBucketStorage extends storage.BucketStorageFactory {
|
|
21
21
|
private readonly client: mongo.MongoClient;
|
|
22
22
|
private readonly session: mongo.ClientSession;
|
|
23
23
|
// TODO: This is still Postgres specific and needs to be reworked
|
|
@@ -32,7 +32,7 @@ export class MongoBucketStorage
|
|
|
32
32
|
options: {
|
|
33
33
|
slot_name_prefix: string;
|
|
34
34
|
},
|
|
35
|
-
private internalOptions?:
|
|
35
|
+
private internalOptions?: MongoBucketStorageOptions
|
|
36
36
|
) {
|
|
37
37
|
super();
|
|
38
38
|
this.client = db.client;
|
|
@@ -50,10 +50,22 @@ export class MongoBucketStorage
|
|
|
50
50
|
if ((typeof id as any) == 'bigint') {
|
|
51
51
|
id = Number(id);
|
|
52
52
|
}
|
|
53
|
-
const
|
|
53
|
+
const storageConfig = (syncRules as MongoPersistedSyncRulesContent).getStorageConfig();
|
|
54
|
+
const storage = new MongoSyncBucketStorage(
|
|
55
|
+
this,
|
|
56
|
+
id,
|
|
57
|
+
syncRules as MongoPersistedSyncRulesContent,
|
|
58
|
+
slot_name,
|
|
59
|
+
undefined,
|
|
60
|
+
{
|
|
61
|
+
...this.internalOptions,
|
|
62
|
+
storageConfig
|
|
63
|
+
}
|
|
64
|
+
);
|
|
54
65
|
if (!options?.skipLifecycleHooks) {
|
|
55
66
|
this.iterateListeners((cb) => cb.syncStorageCreated?.(storage));
|
|
56
67
|
}
|
|
68
|
+
|
|
57
69
|
storage.registerListener({
|
|
58
70
|
batchStarted: (batch) => {
|
|
59
71
|
batch.registerListener({
|
|
@@ -81,33 +93,13 @@ export class MongoBucketStorage
|
|
|
81
93
|
};
|
|
82
94
|
}
|
|
83
95
|
|
|
84
|
-
async configureSyncRules(options: storage.UpdateSyncRulesOptions) {
|
|
85
|
-
const next = await this.getNextSyncRulesContent();
|
|
86
|
-
const active = await this.getActiveSyncRulesContent();
|
|
87
|
-
|
|
88
|
-
if (next?.sync_rules_content == options.content) {
|
|
89
|
-
logger.info('Sync rules from configuration unchanged');
|
|
90
|
-
return { updated: false };
|
|
91
|
-
} else if (next == null && active?.sync_rules_content == options.content) {
|
|
92
|
-
logger.info('Sync rules from configuration unchanged');
|
|
93
|
-
return { updated: false };
|
|
94
|
-
} else {
|
|
95
|
-
logger.info('Sync rules updated from configuration');
|
|
96
|
-
const persisted_sync_rules = await this.updateSyncRules(options);
|
|
97
|
-
return { updated: true, persisted_sync_rules, lock: persisted_sync_rules.current_lock ?? undefined };
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
96
|
async restartReplication(sync_rules_group_id: number) {
|
|
102
97
|
const next = await this.getNextSyncRulesContent();
|
|
103
98
|
const active = await this.getActiveSyncRulesContent();
|
|
104
99
|
|
|
105
100
|
if (next != null && next.id == sync_rules_group_id) {
|
|
106
101
|
// We need to redo the "next" sync rules
|
|
107
|
-
await this.updateSyncRules(
|
|
108
|
-
content: next.sync_rules_content,
|
|
109
|
-
validate: false
|
|
110
|
-
});
|
|
102
|
+
await this.updateSyncRules(next.asUpdateOptions());
|
|
111
103
|
// Pro-actively stop replicating
|
|
112
104
|
await this.db.sync_rules.updateOne(
|
|
113
105
|
{
|
|
@@ -123,10 +115,7 @@ export class MongoBucketStorage
|
|
|
123
115
|
await this.db.notifyCheckpoint();
|
|
124
116
|
} else if (next == null && active?.id == sync_rules_group_id) {
|
|
125
117
|
// Slot removed for "active" sync rules, while there is no "next" one.
|
|
126
|
-
await this.updateSyncRules(
|
|
127
|
-
content: active.sync_rules_content,
|
|
128
|
-
validate: false
|
|
129
|
-
});
|
|
118
|
+
await this.updateSyncRules(active.asUpdateOptions());
|
|
130
119
|
|
|
131
120
|
// In this case we keep the old one as active for clients, so that that existing clients
|
|
132
121
|
// can still get the latest data while we replicate the new ones.
|
|
@@ -163,18 +152,9 @@ export class MongoBucketStorage
|
|
|
163
152
|
}
|
|
164
153
|
|
|
165
154
|
async updateSyncRules(options: storage.UpdateSyncRulesOptions): Promise<MongoPersistedSyncRulesContent> {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
// No schema-based validation at this point
|
|
170
|
-
schema: undefined,
|
|
171
|
-
defaultSchema: 'not_applicable', // Not needed for validation
|
|
172
|
-
throwOnError: true
|
|
173
|
-
});
|
|
174
|
-
} else {
|
|
175
|
-
// We do not validate sync rules at this point.
|
|
176
|
-
// That is done when using the sync rules, so that the diagnostics API can report the errors.
|
|
177
|
-
}
|
|
155
|
+
const storageVersion = options.storageVersion ?? storage.CURRENT_STORAGE_VERSION;
|
|
156
|
+
const storageConfig = getMongoStorageConfig(storageVersion);
|
|
157
|
+
await this.db.initializeStorageVersion(storageConfig);
|
|
178
158
|
|
|
179
159
|
let rules: MongoPersistedSyncRulesContent | undefined = undefined;
|
|
180
160
|
|
|
@@ -207,7 +187,9 @@ export class MongoBucketStorage
|
|
|
207
187
|
|
|
208
188
|
const doc: SyncRuleDocument = {
|
|
209
189
|
_id: id,
|
|
210
|
-
|
|
190
|
+
storage_version: storageVersion,
|
|
191
|
+
content: options.config.yaml,
|
|
192
|
+
serialized_plan: options.config.plan,
|
|
211
193
|
last_checkpoint: null,
|
|
212
194
|
last_checkpoint_lsn: null,
|
|
213
195
|
no_checkpoint_before: null,
|
|
@@ -246,11 +228,6 @@ export class MongoBucketStorage
|
|
|
246
228
|
return new MongoPersistedSyncRulesContent(this.db, doc);
|
|
247
229
|
}
|
|
248
230
|
|
|
249
|
-
async getActiveSyncRules(options: storage.ParseSyncRulesOptions): Promise<storage.PersistedSyncRules | null> {
|
|
250
|
-
const content = await this.getActiveSyncRulesContent();
|
|
251
|
-
return content?.parsed(options) ?? null;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
231
|
async getNextSyncRulesContent(): Promise<MongoPersistedSyncRulesContent | null> {
|
|
255
232
|
const doc = await this.db.sync_rules.findOne(
|
|
256
233
|
{
|
|
@@ -265,11 +242,6 @@ export class MongoBucketStorage
|
|
|
265
242
|
return new MongoPersistedSyncRulesContent(this.db, doc);
|
|
266
243
|
}
|
|
267
244
|
|
|
268
|
-
async getNextSyncRules(options: storage.ParseSyncRulesOptions): Promise<storage.PersistedSyncRules | null> {
|
|
269
|
-
const content = await this.getNextSyncRulesContent();
|
|
270
|
-
return content?.parsed(options) ?? null;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
245
|
async getReplicatingSyncRules(): Promise<storage.PersistedSyncRulesContent[]> {
|
|
274
246
|
const docs = await this.db.sync_rules
|
|
275
247
|
.find({
|
|
@@ -353,7 +325,7 @@ export class MongoBucketStorage
|
|
|
353
325
|
.toArray()
|
|
354
326
|
.catch(ignoreNotExisting);
|
|
355
327
|
|
|
356
|
-
const
|
|
328
|
+
const v1_replication_aggregate = await this.db.current_data
|
|
357
329
|
.aggregate([
|
|
358
330
|
{
|
|
359
331
|
$collStats: {
|
|
@@ -364,10 +336,21 @@ export class MongoBucketStorage
|
|
|
364
336
|
.toArray()
|
|
365
337
|
.catch(ignoreNotExisting);
|
|
366
338
|
|
|
339
|
+
const v3_replication_aggregate = await this.db.v3_current_data
|
|
340
|
+
.aggregate([
|
|
341
|
+
{
|
|
342
|
+
$collStats: {
|
|
343
|
+
storageStats: {}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
])
|
|
347
|
+
.toArray()
|
|
348
|
+
.catch(ignoreNotExisting);
|
|
367
349
|
return {
|
|
368
350
|
operations_size_bytes: Number(operations_aggregate[0].storageStats.size),
|
|
369
351
|
parameters_size_bytes: Number(parameters_aggregate[0].storageStats.size),
|
|
370
|
-
replication_size_bytes:
|
|
352
|
+
replication_size_bytes:
|
|
353
|
+
Number(v1_replication_aggregate[0].storageStats.size) + Number(v3_replication_aggregate[0].storageStats.size)
|
|
371
354
|
};
|
|
372
355
|
}
|
|
373
356
|
|