@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,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 { BaseObserver, ErrorCode, logger, ServiceError } from '@powersync/lib-services-framework';
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, MongoSyncBucketStorageOptions } from './implementation/MongoSyncBucketStorage.js';
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?: MongoSyncBucketStorageOptions
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 storage = new MongoSyncBucketStorage(this, id, syncRules, slot_name, undefined, this.internalOptions);
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
- if (options.validate) {
167
- // Parse and validate before applying any changes
168
- SqlSyncRules.fromYaml(options.content, {
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
- content: options.content,
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 replication_aggregate = await this.db.current_data
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: Number(replication_aggregate[0].storageStats.size)
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