@powersync/service-module-mongodb-storage 0.15.4 → 0.16.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 (193) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/dist/migrations/db/migrations/1688556755264-initial-sync-rules.js +1 -1
  3. package/dist/migrations/db/migrations/1688556755264-initial-sync-rules.js.map +1 -1
  4. package/dist/migrations/db/migrations/1702295701188-sync-rule-state.js +2 -2
  5. package/dist/migrations/db/migrations/1702295701188-sync-rule-state.js.map +1 -1
  6. package/dist/storage/MongoBucketStorage.d.ts +2 -2
  7. package/dist/storage/MongoBucketStorage.js +47 -34
  8. package/dist/storage/MongoBucketStorage.js.map +1 -1
  9. package/dist/storage/implementation/BucketDefinitionMapping.d.ts +17 -0
  10. package/dist/storage/implementation/BucketDefinitionMapping.js +58 -0
  11. package/dist/storage/implementation/BucketDefinitionMapping.js.map +1 -0
  12. package/dist/storage/implementation/MongoBucketBatch.d.ts +16 -14
  13. package/dist/storage/implementation/MongoBucketBatch.js +80 -115
  14. package/dist/storage/implementation/MongoBucketBatch.js.map +1 -1
  15. package/dist/storage/implementation/MongoBucketBatchShared.d.ts +5 -0
  16. package/dist/storage/implementation/MongoBucketBatchShared.js +8 -0
  17. package/dist/storage/implementation/MongoBucketBatchShared.js.map +1 -0
  18. package/dist/storage/implementation/MongoChecksums.d.ts +28 -17
  19. package/dist/storage/implementation/MongoChecksums.js +13 -72
  20. package/dist/storage/implementation/MongoChecksums.js.map +1 -1
  21. package/dist/storage/implementation/MongoCompactor.d.ts +98 -58
  22. package/dist/storage/implementation/MongoCompactor.js +229 -296
  23. package/dist/storage/implementation/MongoCompactor.js.map +1 -1
  24. package/dist/storage/implementation/MongoParameterCompactor.d.ts +11 -6
  25. package/dist/storage/implementation/MongoParameterCompactor.js +11 -8
  26. package/dist/storage/implementation/MongoParameterCompactor.js.map +1 -1
  27. package/dist/storage/implementation/MongoPersistedSyncRules.d.ts +14 -0
  28. package/dist/storage/implementation/MongoPersistedSyncRules.js +64 -0
  29. package/dist/storage/implementation/MongoPersistedSyncRules.js.map +1 -0
  30. package/dist/storage/implementation/MongoPersistedSyncRulesContent.d.ts +3 -0
  31. package/dist/storage/implementation/MongoPersistedSyncRulesContent.js +9 -0
  32. package/dist/storage/implementation/MongoPersistedSyncRulesContent.js.map +1 -1
  33. package/dist/storage/implementation/MongoSyncBucketStorage.d.ts +47 -29
  34. package/dist/storage/implementation/MongoSyncBucketStorage.js +94 -387
  35. package/dist/storage/implementation/MongoSyncBucketStorage.js.map +1 -1
  36. package/dist/storage/implementation/MongoSyncRulesLock.d.ts +5 -3
  37. package/dist/storage/implementation/MongoSyncRulesLock.js +12 -10
  38. package/dist/storage/implementation/MongoSyncRulesLock.js.map +1 -1
  39. package/dist/storage/implementation/MongoWriteCheckpointAPI.js +1 -1
  40. package/dist/storage/implementation/MongoWriteCheckpointAPI.js.map +1 -1
  41. package/dist/storage/implementation/OperationBatch.js +1 -1
  42. package/dist/storage/implementation/common/BucketDataDoc.d.ts +35 -0
  43. package/dist/storage/implementation/common/BucketDataDoc.js +2 -0
  44. package/dist/storage/implementation/common/BucketDataDoc.js.map +1 -0
  45. package/dist/storage/implementation/common/MongoSyncBucketStorageContext.d.ts +13 -0
  46. package/dist/storage/implementation/common/MongoSyncBucketStorageContext.js +2 -0
  47. package/dist/storage/implementation/common/MongoSyncBucketStorageContext.js.map +1 -0
  48. package/dist/storage/implementation/common/PersistedBatch.d.ts +108 -0
  49. package/dist/storage/implementation/common/PersistedBatch.js +237 -0
  50. package/dist/storage/implementation/common/PersistedBatch.js.map +1 -0
  51. package/dist/storage/implementation/common/SingleBucketStore.d.ts +54 -0
  52. package/dist/storage/implementation/common/SingleBucketStore.js +3 -0
  53. package/dist/storage/implementation/common/SingleBucketStore.js.map +1 -0
  54. package/dist/storage/implementation/common/SourceRecordStore.d.ts +36 -0
  55. package/dist/storage/implementation/common/SourceRecordStore.js +2 -0
  56. package/dist/storage/implementation/common/SourceRecordStore.js.map +1 -0
  57. package/dist/storage/implementation/common/VersionedPowerSyncMongoBase.d.ts +27 -0
  58. package/dist/storage/implementation/common/VersionedPowerSyncMongoBase.js +57 -0
  59. package/dist/storage/implementation/common/VersionedPowerSyncMongoBase.js.map +1 -0
  60. package/dist/storage/implementation/createMongoSyncBucketStorage.d.ts +7 -0
  61. package/dist/storage/implementation/createMongoSyncBucketStorage.js +9 -0
  62. package/dist/storage/implementation/createMongoSyncBucketStorage.js.map +1 -0
  63. package/dist/storage/implementation/db.d.ts +32 -35
  64. package/dist/storage/implementation/db.js +77 -99
  65. package/dist/storage/implementation/db.js.map +1 -1
  66. package/dist/storage/implementation/models.d.ts +62 -33
  67. package/dist/storage/implementation/models.js +20 -1
  68. package/dist/storage/implementation/models.js.map +1 -1
  69. package/dist/storage/implementation/v1/MongoBucketBatchV1.d.ts +13 -0
  70. package/dist/storage/implementation/v1/MongoBucketBatchV1.js +22 -0
  71. package/dist/storage/implementation/v1/MongoBucketBatchV1.js.map +1 -0
  72. package/dist/storage/implementation/v1/MongoChecksumsV1.d.ts +12 -0
  73. package/dist/storage/implementation/v1/MongoChecksumsV1.js +56 -0
  74. package/dist/storage/implementation/v1/MongoChecksumsV1.js.map +1 -0
  75. package/dist/storage/implementation/v1/MongoCompactorV1.d.ts +23 -0
  76. package/dist/storage/implementation/v1/MongoCompactorV1.js +52 -0
  77. package/dist/storage/implementation/v1/MongoCompactorV1.js.map +1 -0
  78. package/dist/storage/implementation/v1/MongoParameterCompactorV1.d.ts +9 -0
  79. package/dist/storage/implementation/v1/MongoParameterCompactorV1.js +20 -0
  80. package/dist/storage/implementation/v1/MongoParameterCompactorV1.js.map +1 -0
  81. package/dist/storage/implementation/v1/MongoSyncBucketStorageV1.d.ts +41 -0
  82. package/dist/storage/implementation/v1/MongoSyncBucketStorageV1.js +283 -0
  83. package/dist/storage/implementation/v1/MongoSyncBucketStorageV1.js.map +1 -0
  84. package/dist/storage/implementation/v1/PersistedBatchV1.d.ts +26 -0
  85. package/dist/storage/implementation/v1/PersistedBatchV1.js +183 -0
  86. package/dist/storage/implementation/v1/PersistedBatchV1.js.map +1 -0
  87. package/dist/storage/implementation/v1/SingleBucketStoreV1.d.ts +18 -0
  88. package/dist/storage/implementation/v1/SingleBucketStoreV1.js +57 -0
  89. package/dist/storage/implementation/v1/SingleBucketStoreV1.js.map +1 -0
  90. package/dist/storage/implementation/v1/SourceRecordStoreV1.d.ts +19 -0
  91. package/dist/storage/implementation/v1/SourceRecordStoreV1.js +105 -0
  92. package/dist/storage/implementation/v1/SourceRecordStoreV1.js.map +1 -0
  93. package/dist/storage/implementation/v1/VersionedPowerSyncMongoV1.d.ts +12 -0
  94. package/dist/storage/implementation/v1/VersionedPowerSyncMongoV1.js +20 -0
  95. package/dist/storage/implementation/v1/VersionedPowerSyncMongoV1.js.map +1 -0
  96. package/dist/storage/implementation/v1/models.d.ts +34 -0
  97. package/dist/storage/implementation/v1/models.js +37 -0
  98. package/dist/storage/implementation/v1/models.js.map +1 -0
  99. package/dist/storage/implementation/v3/MongoBucketBatchV3.d.ts +13 -0
  100. package/dist/storage/implementation/v3/MongoBucketBatchV3.js +34 -0
  101. package/dist/storage/implementation/v3/MongoBucketBatchV3.js.map +1 -0
  102. package/dist/storage/implementation/v3/MongoChecksumsV3.d.ts +15 -0
  103. package/dist/storage/implementation/v3/MongoChecksumsV3.js +84 -0
  104. package/dist/storage/implementation/v3/MongoChecksumsV3.js.map +1 -0
  105. package/dist/storage/implementation/v3/MongoCompactorV3.d.ts +23 -0
  106. package/dist/storage/implementation/v3/MongoCompactorV3.js +68 -0
  107. package/dist/storage/implementation/v3/MongoCompactorV3.js.map +1 -0
  108. package/dist/storage/implementation/v3/MongoParameterCompactorV3.d.ts +9 -0
  109. package/dist/storage/implementation/v3/MongoParameterCompactorV3.js +18 -0
  110. package/dist/storage/implementation/v3/MongoParameterCompactorV3.js.map +1 -0
  111. package/dist/storage/implementation/v3/MongoParameterLookupV3.d.ts +5 -0
  112. package/dist/storage/implementation/v3/MongoParameterLookupV3.js +9 -0
  113. package/dist/storage/implementation/v3/MongoParameterLookupV3.js.map +1 -0
  114. package/dist/storage/implementation/v3/MongoSyncBucketStorageV3.d.ts +41 -0
  115. package/dist/storage/implementation/v3/MongoSyncBucketStorageV3.js +407 -0
  116. package/dist/storage/implementation/v3/MongoSyncBucketStorageV3.js.map +1 -0
  117. package/dist/storage/implementation/v3/PersistedBatchV3.d.ts +29 -0
  118. package/dist/storage/implementation/v3/PersistedBatchV3.js +259 -0
  119. package/dist/storage/implementation/v3/PersistedBatchV3.js.map +1 -0
  120. package/dist/storage/implementation/v3/SingleBucketStoreV3.d.ts +18 -0
  121. package/dist/storage/implementation/v3/SingleBucketStoreV3.js +48 -0
  122. package/dist/storage/implementation/v3/SingleBucketStoreV3.js.map +1 -0
  123. package/dist/storage/implementation/v3/SourceRecordStoreV3.d.ts +22 -0
  124. package/dist/storage/implementation/v3/SourceRecordStoreV3.js +164 -0
  125. package/dist/storage/implementation/v3/SourceRecordStoreV3.js.map +1 -0
  126. package/dist/storage/implementation/v3/VersionedPowerSyncMongoV3.d.ts +21 -0
  127. package/dist/storage/implementation/v3/VersionedPowerSyncMongoV3.js +71 -0
  128. package/dist/storage/implementation/v3/VersionedPowerSyncMongoV3.js.map +1 -0
  129. package/dist/storage/implementation/v3/models.d.ts +43 -0
  130. package/dist/storage/implementation/v3/models.js +34 -0
  131. package/dist/storage/implementation/v3/models.js.map +1 -0
  132. package/dist/storage/storage-index.d.ts +6 -3
  133. package/dist/storage/storage-index.js +6 -3
  134. package/dist/storage/storage-index.js.map +1 -1
  135. package/dist/utils/util.d.ts +10 -3
  136. package/dist/utils/util.js +24 -3
  137. package/dist/utils/util.js.map +1 -1
  138. package/package.json +9 -9
  139. package/src/migrations/db/migrations/1688556755264-initial-sync-rules.ts +1 -1
  140. package/src/migrations/db/migrations/1702295701188-sync-rule-state.ts +6 -6
  141. package/src/storage/MongoBucketStorage.ts +92 -59
  142. package/src/storage/implementation/BucketDefinitionMapping.ts +72 -0
  143. package/src/storage/implementation/MongoBucketBatch.ts +110 -144
  144. package/src/storage/implementation/MongoBucketBatchShared.ts +11 -0
  145. package/src/storage/implementation/MongoChecksums.ts +52 -75
  146. package/src/storage/implementation/MongoCompactor.ts +374 -404
  147. package/src/storage/implementation/MongoParameterCompactor.ts +37 -24
  148. package/src/storage/implementation/MongoPersistedSyncRules.ts +76 -0
  149. package/src/storage/implementation/MongoPersistedSyncRulesContent.ts +17 -0
  150. package/src/storage/implementation/MongoSyncBucketStorage.ts +181 -455
  151. package/src/storage/implementation/MongoSyncRulesLock.ts +11 -13
  152. package/src/storage/implementation/MongoWriteCheckpointAPI.ts +3 -1
  153. package/src/storage/implementation/OperationBatch.ts +1 -1
  154. package/src/storage/implementation/common/BucketDataDoc.ts +37 -0
  155. package/src/storage/implementation/common/MongoSyncBucketStorageContext.ts +15 -0
  156. package/src/storage/implementation/common/PersistedBatch.ts +364 -0
  157. package/src/storage/implementation/common/SingleBucketStore.ts +63 -0
  158. package/src/storage/implementation/common/SourceRecordStore.ts +49 -0
  159. package/src/storage/implementation/common/VersionedPowerSyncMongoBase.ts +80 -0
  160. package/src/storage/implementation/createMongoSyncBucketStorage.ts +25 -0
  161. package/src/storage/implementation/db.ts +105 -129
  162. package/src/storage/implementation/models.ts +82 -36
  163. package/src/storage/implementation/v1/MongoBucketBatchV1.ts +32 -0
  164. package/src/storage/implementation/v1/MongoChecksumsV1.ts +75 -0
  165. package/src/storage/implementation/v1/MongoCompactorV1.ts +93 -0
  166. package/src/storage/implementation/v1/MongoParameterCompactorV1.ts +26 -0
  167. package/src/storage/implementation/v1/MongoSyncBucketStorageV1.ts +448 -0
  168. package/src/storage/implementation/v1/PersistedBatchV1.ts +230 -0
  169. package/src/storage/implementation/v1/SingleBucketStoreV1.ts +74 -0
  170. package/src/storage/implementation/v1/SourceRecordStoreV1.ts +156 -0
  171. package/src/storage/implementation/v1/VersionedPowerSyncMongoV1.ts +28 -0
  172. package/src/storage/implementation/v1/models.ts +84 -0
  173. package/src/storage/implementation/v3/MongoBucketBatchV3.ts +44 -0
  174. package/src/storage/implementation/v3/MongoChecksumsV3.ts +120 -0
  175. package/src/storage/implementation/v3/MongoCompactorV3.ts +107 -0
  176. package/src/storage/implementation/v3/MongoParameterCompactorV3.ts +24 -0
  177. package/src/storage/implementation/v3/MongoParameterLookupV3.ts +12 -0
  178. package/src/storage/implementation/v3/MongoSyncBucketStorageV3.ts +550 -0
  179. package/src/storage/implementation/v3/PersistedBatchV3.ts +318 -0
  180. package/src/storage/implementation/v3/SingleBucketStoreV3.ts +68 -0
  181. package/src/storage/implementation/v3/SourceRecordStoreV3.ts +226 -0
  182. package/src/storage/implementation/v3/VersionedPowerSyncMongoV3.ts +112 -0
  183. package/src/storage/implementation/v3/models.ts +96 -0
  184. package/src/storage/storage-index.ts +6 -3
  185. package/src/utils/util.ts +34 -5
  186. package/test/src/storage_compacting.test.ts +57 -29
  187. package/test/src/storage_sync.test.ts +351 -5
  188. package/test/tsconfig.json +0 -1
  189. package/tsconfig.tsbuildinfo +1 -1
  190. package/dist/storage/implementation/PersistedBatch.d.ts +0 -71
  191. package/dist/storage/implementation/PersistedBatch.js +0 -354
  192. package/dist/storage/implementation/PersistedBatch.js.map +0 -1
  193. package/src/storage/implementation/PersistedBatch.ts +0 -432
@@ -0,0 +1,93 @@
1
+ import { mongo } from '@powersync/lib-service-mongodb';
2
+ import { ReplicationAssertionError } from '@powersync/lib-services-framework';
3
+ import { storage } from '@powersync/service-core';
4
+ import { BucketDefinitionId } from '../BucketDefinitionMapping.js';
5
+ import { SingleBucketStore } from '../common/SingleBucketStore.js';
6
+ import { BucketStateDocumentBase, LEGACY_BUCKET_DATA_DEFINITION_ID } from '../models.js';
7
+ import { DirtyBucket, MongoCompactor } from '../MongoCompactor.js';
8
+ import { BucketStateDocumentV1 } from './models.js';
9
+ import type { MongoSyncBucketStorageV1 } from './MongoSyncBucketStorageV1.js';
10
+ import { SingleBucketStoreV1 } from './SingleBucketStoreV1.js';
11
+ import { VersionedPowerSyncMongoV1 } from './VersionedPowerSyncMongoV1.js';
12
+
13
+ export class MongoCompactorV1 extends MongoCompactor {
14
+ // Override types to the more specific ones
15
+ declare protected readonly db: VersionedPowerSyncMongoV1;
16
+ declare protected readonly storage: MongoSyncBucketStorageV1;
17
+
18
+ public async *dirtyBucketBatches(options: {
19
+ minBucketChanges: number;
20
+ minChangeRatio: number;
21
+ }): AsyncGenerator<DirtyBucket[]> {
22
+ if (options.minBucketChanges <= 0) {
23
+ throw new ReplicationAssertionError('minBucketChanges must be >= 1');
24
+ }
25
+ // Previously, we used an index on {_id.g: 1, estimate_since_compact.count: 1} to only scan buckets with changes.
26
+ // That works well if there are only a small number of dirty buckets, but it causes repeated rescans while data is
27
+ // still changing. We now iterate through all V1 bucket_state rows for the group and filter after projecting.
28
+ yield* this.dirtyBucketBatchesForCollection(
29
+ this.db.bucketStateV1,
30
+ { g: this.group_id, b: new mongo.MinKey() as any },
31
+ { g: this.group_id, b: new mongo.MaxKey() as any },
32
+ options,
33
+ () => null
34
+ );
35
+ }
36
+
37
+ public async dirtyBucketBatchForChecksums(options: { minBucketChanges: number }): Promise<DirtyBucket[]> {
38
+ if (options.minBucketChanges <= 0) {
39
+ throw new ReplicationAssertionError('minBucketChanges must be >= 1');
40
+ }
41
+ // Unlike dirtyBucketBatches, this path is resumable after restart because populateChecksums resets
42
+ // estimate_since_compact as it progresses.
43
+ return this.dirtyBucketBatchForChecksumsForCollection(
44
+ this.db.bucketStateV1,
45
+ {
46
+ '_id.g': this.group_id,
47
+ 'estimate_since_compact.count': { $gte: options.minBucketChanges }
48
+ },
49
+ () => null
50
+ );
51
+ }
52
+
53
+ protected async writeBucketStateUpdates(): Promise<void> {
54
+ await this.db.bucketStateV1.bulkWrite(
55
+ this.bucketStateUpdates as mongo.AnyBulkWriteOperation<BucketStateDocumentV1>[],
56
+ { ordered: false }
57
+ );
58
+ }
59
+
60
+ protected async computeChecksumsForBuckets(
61
+ buckets: Pick<DirtyBucket, 'bucket' | 'definitionId'>[]
62
+ ): Promise<storage.PartialChecksumMap> {
63
+ return this.storage.checksums.computePartialChecksumsDirectByBucket(
64
+ buckets.map(({ bucket }) => ({
65
+ bucket,
66
+ end: this.maxOpId
67
+ }))
68
+ );
69
+ }
70
+
71
+ protected bucketStateFilter(
72
+ bucket: string,
73
+ _definitionId: BucketDefinitionId | null
74
+ ): mongo.Filter<BucketStateDocumentBase> {
75
+ return {
76
+ _id: {
77
+ g: this.group_id,
78
+ b: bucket
79
+ }
80
+ };
81
+ }
82
+
83
+ protected async getBucketDataContext(
84
+ bucket: string,
85
+ _definitionId: BucketDefinitionId | null
86
+ ): Promise<SingleBucketStore | null> {
87
+ return new SingleBucketStoreV1(this.db, {
88
+ replicationStreamId: this.group_id,
89
+ definitionId: LEGACY_BUCKET_DATA_DEFINITION_ID,
90
+ bucket
91
+ });
92
+ }
93
+ }
@@ -0,0 +1,26 @@
1
+ import { mongo } from '@powersync/lib-service-mongodb';
2
+ import { MongoParameterCompactor } from '../MongoParameterCompactor.js';
3
+ import { VersionedPowerSyncMongoV1 } from './VersionedPowerSyncMongoV1.js';
4
+
5
+ export class MongoParameterCompactorV1 extends MongoParameterCompactor {
6
+ declare protected readonly db: VersionedPowerSyncMongoV1;
7
+
8
+ protected async getCollections(): Promise<mongo.Collection<mongo.Document>[]> {
9
+ return [this.db.parameterIndexV1 as unknown as mongo.Collection<mongo.Document>];
10
+ }
11
+
12
+ protected collectionFilter(): mongo.Document {
13
+ return {
14
+ 'key.g': this.group_id
15
+ };
16
+ }
17
+
18
+ protected deleteFilter(doc: mongo.Document): mongo.Document {
19
+ return {
20
+ 'key.g': doc.key.g as number,
21
+ lookup: doc.lookup,
22
+ _id: { $lte: doc._id },
23
+ key: doc.key
24
+ };
25
+ }
26
+ }
@@ -0,0 +1,448 @@
1
+ import * as lib_mongo from '@powersync/lib-service-mongodb';
2
+ import { mongo } from '@powersync/lib-service-mongodb';
3
+ import {
4
+ CheckpointChanges,
5
+ deserializeParameterLookup,
6
+ GetCheckpointChangesOptions,
7
+ InternalOpId,
8
+ internalToExternalOpId,
9
+ ParameterSetLimitExceededError,
10
+ ProtocolOpId,
11
+ storage,
12
+ utils
13
+ } from '@powersync/service-core';
14
+ import { JSONBig } from '@powersync/service-jsonbig';
15
+ import { ParameterLookupRows, ScopedParameterLookup, SqliteJsonRow } from '@powersync/service-sync-rules';
16
+ import * as bson from 'bson';
17
+ import { idPrefixFilter, mapOpEntry, readSingleBatch, setSessionSnapshotTime } from '../../../utils/util.js';
18
+ import { MongoBucketStorage } from '../../MongoBucketStorage.js';
19
+ import {
20
+ MongoSyncBucketStorageCheckpoint,
21
+ MongoSyncBucketStorageContext
22
+ } from '../common/MongoSyncBucketStorageContext.js';
23
+ import { CommonSourceTableDocument, SourceKey } from '../models.js';
24
+ import { MongoBucketBatchOptions } from '../MongoBucketBatch.js';
25
+ import { MongoChecksums } from '../MongoChecksums.js';
26
+ import { MongoCompactOptions, MongoCompactor } from '../MongoCompactor.js';
27
+ import { MongoParameterCompactor } from '../MongoParameterCompactor.js';
28
+ import { MongoPersistedSyncRulesContent } from '../MongoPersistedSyncRulesContent.js';
29
+ import { MongoSyncBucketStorage, MongoSyncBucketStorageOptions } from '../MongoSyncBucketStorage.js';
30
+ import { BucketDataDocumentV1, BucketDataKeyV1, BucketStateDocument, loadBucketDataDocumentV1 } from './models.js';
31
+ import { MongoBucketBatchV1 } from './MongoBucketBatchV1.js';
32
+ import { MongoChecksumsV1 } from './MongoChecksumsV1.js';
33
+ import { MongoCompactorV1 } from './MongoCompactorV1.js';
34
+ import { MongoParameterCompactorV1 } from './MongoParameterCompactorV1.js';
35
+ import { VersionedPowerSyncMongoV1 } from './VersionedPowerSyncMongoV1.js';
36
+
37
+ export class MongoSyncBucketStorageV1 extends MongoSyncBucketStorage {
38
+ // Declare types to be more specific
39
+ declare readonly db: VersionedPowerSyncMongoV1;
40
+ declare readonly checksums: MongoChecksumsV1;
41
+
42
+ constructor(
43
+ factory: MongoBucketStorage,
44
+ group_id: number,
45
+ sync_rules: MongoPersistedSyncRulesContent,
46
+ slot_name: string,
47
+ writeCheckpointMode: storage.WriteCheckpointMode | undefined,
48
+ options: MongoSyncBucketStorageOptions
49
+ ) {
50
+ super(factory, group_id, sync_rules, slot_name, writeCheckpointMode, options);
51
+ }
52
+
53
+ protected async initializeVersionStorage(): Promise<void> {}
54
+
55
+ protected createWriterImpl(batchOptions: MongoBucketBatchOptions): storage.BucketStorageBatch {
56
+ return new MongoBucketBatchV1(batchOptions);
57
+ }
58
+
59
+ protected createMongoChecksums(options: MongoSyncBucketStorageOptions): MongoChecksums {
60
+ return new MongoChecksumsV1(this.db, this.group_id, {
61
+ ...options.checksumOptions,
62
+ storageConfig: options?.storageConfig,
63
+ mapping: this.sync_rules.mapping
64
+ });
65
+ }
66
+
67
+ createMongoCompactor(options: MongoCompactOptions): MongoCompactor {
68
+ return new MongoCompactorV1(this, this.db, options);
69
+ }
70
+
71
+ protected createMongoParameterCompactor(
72
+ checkpoint: InternalOpId,
73
+ options: storage.CompactOptions
74
+ ): MongoParameterCompactor {
75
+ return new MongoParameterCompactorV1(this.db, this.group_id, checkpoint, options);
76
+ }
77
+
78
+ protected sourceTableBaseId(): Partial<CommonSourceTableDocument> {
79
+ return { group_id: this.group_id };
80
+ }
81
+
82
+ protected augmentCreatedSourceTableDocument(
83
+ _createDoc: CommonSourceTableDocument,
84
+ _options: storage.ResolveTableOptions,
85
+ _candidateSourceTable: storage.SourceTable
86
+ ): void {}
87
+
88
+ protected async initializeResolvedSourceRecords(_sourceTableId: bson.ObjectId): Promise<void> {}
89
+
90
+ protected override get versionContext(): MongoSyncBucketStorageContext<VersionedPowerSyncMongoV1> {
91
+ return {
92
+ db: this.db,
93
+ group_id: this.group_id,
94
+ mapping: this.mapping
95
+ };
96
+ }
97
+
98
+ protected getParameterSetsImpl(
99
+ checkpoint: MongoSyncBucketStorageCheckpoint,
100
+ lookups: ScopedParameterLookup[],
101
+ limit: number
102
+ ): Promise<ParameterLookupRows[]> {
103
+ return getParameterSetsV1(this.versionContext, checkpoint, lookups, limit);
104
+ }
105
+
106
+ protected getBucketDataBatchImpl(
107
+ checkpoint: utils.InternalOpId,
108
+ dataBuckets: storage.BucketDataRequest[],
109
+ options?: storage.BucketDataBatchOptions
110
+ ): AsyncIterable<storage.SyncBucketDataChunk> {
111
+ return getBucketDataBatchV1(this.versionContext, checkpoint, dataBuckets, options);
112
+ }
113
+
114
+ protected async clearBucketData(signal?: AbortSignal): Promise<void> {
115
+ await this.clearDeleteMany(
116
+ 'bucket data',
117
+ () =>
118
+ this.db.bucket_data.deleteMany(
119
+ {
120
+ _id: idPrefixFilter<BucketDataKeyV1>({ g: this.group_id }, ['b', 'o'])
121
+ },
122
+ { maxTimeMS: lib_mongo.db.MONGO_CLEAR_OPERATION_TIMEOUT_MS }
123
+ ),
124
+ signal
125
+ );
126
+ }
127
+
128
+ protected async clearParameterIndexes(signal?: AbortSignal): Promise<void> {
129
+ await this.clearDeleteMany(
130
+ 'parameter index',
131
+ () =>
132
+ this.db.parameterIndexV1.deleteMany(
133
+ {
134
+ 'key.g': this.group_id
135
+ },
136
+ { maxTimeMS: lib_mongo.db.MONGO_CLEAR_OPERATION_TIMEOUT_MS }
137
+ ),
138
+ signal
139
+ );
140
+ }
141
+
142
+ protected async clearSourceRecords(signal?: AbortSignal): Promise<void> {
143
+ await this.clearDeleteMany(
144
+ 'source records',
145
+ () =>
146
+ this.db.sourceRecordsV1.deleteMany(
147
+ {
148
+ _id: idPrefixFilter<SourceKey>({ g: this.group_id }, ['t', 'k'])
149
+ },
150
+ { maxTimeMS: lib_mongo.db.MONGO_CLEAR_OPERATION_TIMEOUT_MS }
151
+ ),
152
+ signal
153
+ );
154
+ }
155
+
156
+ protected async clearBucketState(signal?: AbortSignal): Promise<void> {
157
+ await this.clearDeleteMany(
158
+ 'bucket state',
159
+ () =>
160
+ this.db.bucketStateV1.deleteMany(
161
+ {
162
+ _id: idPrefixFilter<BucketStateDocument['_id']>({ g: this.group_id }, ['b'])
163
+ },
164
+ { maxTimeMS: lib_mongo.db.MONGO_CLEAR_OPERATION_TIMEOUT_MS }
165
+ ),
166
+ signal
167
+ );
168
+ }
169
+
170
+ protected async clearSourceTables(signal?: AbortSignal): Promise<void> {
171
+ await this.clearDeleteMany(
172
+ 'source tables',
173
+ () =>
174
+ this.db.commonSourceTables(this.group_id).deleteMany(
175
+ {
176
+ group_id: this.group_id
177
+ },
178
+ { maxTimeMS: lib_mongo.db.MONGO_CLEAR_OPERATION_TIMEOUT_MS }
179
+ ),
180
+ signal
181
+ );
182
+ }
183
+
184
+ protected getDataBucketChangesImpl(
185
+ options: GetCheckpointChangesOptions
186
+ ): Promise<Pick<CheckpointChanges, 'updatedDataBuckets' | 'invalidateDataBuckets'>> {
187
+ return getDataBucketChangesV1(this.versionContext, options);
188
+ }
189
+
190
+ protected getParameterBucketChangesImpl(
191
+ options: GetCheckpointChangesOptions
192
+ ): Promise<Pick<CheckpointChanges, 'updatedParameterLookups' | 'invalidateParameterBuckets'>> {
193
+ return getParameterBucketChangesV1(this.versionContext, options);
194
+ }
195
+ }
196
+
197
+ export async function getParameterSetsV1(
198
+ ctx: MongoSyncBucketStorageContext<VersionedPowerSyncMongoV1>,
199
+ checkpoint: MongoSyncBucketStorageCheckpoint,
200
+ lookups: ScopedParameterLookup[],
201
+ limit: number
202
+ ): Promise<ParameterLookupRows[]> {
203
+ return ctx.db.client.withSession({ snapshot: true }, async (session) => {
204
+ setSessionSnapshotTime(session, checkpoint.snapshotTime);
205
+ const lookupFilter = lookups.map((lookup) => {
206
+ return storage.serializeLookup(lookup);
207
+ });
208
+
209
+ const rows = await ctx.db.parameterIndexV1
210
+ .aggregate<{ lookup: number; bucket_parameters: SqliteJsonRow }>(
211
+ [
212
+ {
213
+ $match: {
214
+ 'key.g': ctx.group_id,
215
+ lookup: { $in: lookupFilter },
216
+ _id: { $lte: checkpoint.checkpoint }
217
+ }
218
+ },
219
+ {
220
+ $set: {
221
+ index: { $indexOfArray: [lookupFilter, '$lookup'] }
222
+ }
223
+ },
224
+ {
225
+ $sort: {
226
+ _id: -1
227
+ }
228
+ },
229
+ {
230
+ $group: {
231
+ _id: { key: '$key', lookup: '$index' },
232
+ bucket_parameters: {
233
+ $first: '$bucket_parameters'
234
+ }
235
+ }
236
+ },
237
+ {
238
+ $project: {
239
+ _id: false,
240
+ lookup: '$_id.lookup',
241
+ bucket_parameters: true
242
+ }
243
+ },
244
+ { $unwind: '$bucket_parameters' },
245
+ {
246
+ $limit: limit + 1
247
+ }
248
+ ],
249
+ {
250
+ session,
251
+ readConcern: 'snapshot',
252
+ maxTimeMS: lib_mongo.db.MONGO_OPERATION_TIMEOUT_MS
253
+ }
254
+ )
255
+ .toArray()
256
+ .catch((e) => {
257
+ throw lib_mongo.mapQueryError(e, 'while evaluating parameter queries');
258
+ });
259
+
260
+ if (rows.length > limit) {
261
+ throw new ParameterSetLimitExceededError(limit);
262
+ }
263
+
264
+ const byLookup = Map.groupBy(rows, (row) => lookups[row.lookup]);
265
+ const results: ParameterLookupRows[] = [];
266
+ byLookup.forEach((value, lookup) => results.push({ lookup, rows: value.map((r) => r.bucket_parameters) }));
267
+ return results;
268
+ });
269
+ }
270
+
271
+ export async function* getBucketDataBatchV1(
272
+ ctx: MongoSyncBucketStorageContext<VersionedPowerSyncMongoV1>,
273
+ checkpoint: utils.InternalOpId,
274
+ dataBuckets: storage.BucketDataRequest[],
275
+ options?: storage.BucketDataBatchOptions
276
+ ): AsyncIterable<storage.SyncBucketDataChunk> {
277
+ if (dataBuckets.length == 0) {
278
+ return;
279
+ }
280
+ let filters: mongo.Filter<BucketDataDocumentV1>[] = [];
281
+ const bucketMap = new Map(dataBuckets.map((request) => [request.bucket, request.start]));
282
+
283
+ if (checkpoint == null) {
284
+ throw new Error('checkpoint is null');
285
+ }
286
+ const end = checkpoint;
287
+ for (let { bucket: name, start } of dataBuckets) {
288
+ filters.push({
289
+ _id: {
290
+ $gt: {
291
+ g: ctx.group_id,
292
+ b: name,
293
+ o: start
294
+ },
295
+ $lte: {
296
+ g: ctx.group_id,
297
+ b: name,
298
+ o: end as any
299
+ }
300
+ }
301
+ });
302
+ }
303
+
304
+ const batchLimit = options?.limit ?? storage.DEFAULT_DOCUMENT_BATCH_LIMIT;
305
+ const chunkSizeLimitBytes = options?.chunkLimitBytes ?? storage.DEFAULT_DOCUMENT_CHUNK_LIMIT_BYTES;
306
+
307
+ const cursor = ctx.db.bucket_data.find(
308
+ {
309
+ $or: filters
310
+ },
311
+ {
312
+ session: undefined,
313
+ sort: { _id: 1 },
314
+ limit: batchLimit,
315
+ batchSize: batchLimit + 1,
316
+ raw: true,
317
+ maxTimeMS: lib_mongo.db.MONGO_OPERATION_TIMEOUT_MS
318
+ }
319
+ ) as unknown as mongo.FindCursor<Buffer>;
320
+
321
+ let { data, hasMore: batchHasMore } = await readSingleBatch(cursor).catch((e) => {
322
+ throw lib_mongo.mapQueryError(e, 'while reading bucket data');
323
+ });
324
+ if (data.length == batchLimit) {
325
+ batchHasMore = true;
326
+ }
327
+
328
+ let chunkSizeBytes = 0;
329
+ let currentChunk: utils.SyncBucketData | null = null;
330
+ let targetOp: InternalOpId | null = null;
331
+
332
+ for (let rawData of data) {
333
+ const row = loadBucketDataDocumentV1(
334
+ bson.deserialize(rawData, storage.BSON_DESERIALIZE_INTERNAL_OPTIONS) as BucketDataDocumentV1
335
+ );
336
+ const bucket = row.bucketKey.bucket;
337
+
338
+ if (currentChunk == null || currentChunk.bucket != bucket || chunkSizeBytes >= chunkSizeLimitBytes) {
339
+ let start: ProtocolOpId | undefined = undefined;
340
+ if (currentChunk != null) {
341
+ if (currentChunk.bucket == bucket) {
342
+ currentChunk.has_more = true;
343
+ start = currentChunk.next_after;
344
+ }
345
+
346
+ const yieldChunk = currentChunk;
347
+ currentChunk = null;
348
+ chunkSizeBytes = 0;
349
+ yield { chunkData: yieldChunk, targetOp: targetOp };
350
+ targetOp = null;
351
+ }
352
+
353
+ if (start == null) {
354
+ const startOpId = bucketMap.get(bucket);
355
+ if (startOpId == null) {
356
+ throw new Error(`data for unexpected bucket: ${bucket}`);
357
+ }
358
+ start = internalToExternalOpId(startOpId);
359
+ }
360
+ currentChunk = {
361
+ bucket,
362
+ after: start,
363
+ has_more: false,
364
+ data: [],
365
+ next_after: start
366
+ };
367
+ targetOp = null;
368
+ }
369
+
370
+ const entry = mapOpEntry(row);
371
+
372
+ if (row.target_op != null && (targetOp == null || row.target_op > targetOp)) {
373
+ targetOp = row.target_op;
374
+ }
375
+
376
+ currentChunk.data.push(entry);
377
+ currentChunk.next_after = entry.op_id;
378
+ chunkSizeBytes += rawData.byteLength;
379
+ }
380
+
381
+ if (currentChunk != null) {
382
+ const yieldChunk = currentChunk;
383
+ yieldChunk.has_more = batchHasMore;
384
+ yield { chunkData: yieldChunk, targetOp: targetOp };
385
+ }
386
+ }
387
+
388
+ export async function getDataBucketChangesV1(
389
+ ctx: MongoSyncBucketStorageContext<VersionedPowerSyncMongoV1>,
390
+ options: GetCheckpointChangesOptions
391
+ ): Promise<Pick<CheckpointChanges, 'updatedDataBuckets' | 'invalidateDataBuckets'>> {
392
+ const limit = 1000;
393
+ const bucketStateUpdates = await ctx.db.bucketStateV1
394
+ .find(
395
+ {
396
+ '_id.g': ctx.group_id,
397
+ last_op: { $gt: options.lastCheckpoint.checkpoint }
398
+ },
399
+ {
400
+ projection: {
401
+ '_id.b': 1
402
+ },
403
+ limit: limit + 1,
404
+ batchSize: limit + 2,
405
+ singleBatch: true
406
+ }
407
+ )
408
+ .toArray();
409
+
410
+ const buckets = bucketStateUpdates.map((doc) => doc._id.b);
411
+ const invalidateDataBuckets = buckets.length > limit;
412
+
413
+ return {
414
+ invalidateDataBuckets,
415
+ updatedDataBuckets: invalidateDataBuckets ? new Set<string>() : new Set(buckets)
416
+ };
417
+ }
418
+
419
+ export async function getParameterBucketChangesV1(
420
+ ctx: MongoSyncBucketStorageContext<VersionedPowerSyncMongoV1>,
421
+ options: GetCheckpointChangesOptions
422
+ ): Promise<Pick<CheckpointChanges, 'updatedParameterLookups' | 'invalidateParameterBuckets'>> {
423
+ const limit = 1000;
424
+ const parameterUpdates = await ctx.db.parameterIndexV1
425
+ .find(
426
+ {
427
+ _id: { $gt: options.lastCheckpoint.checkpoint, $lte: options.nextCheckpoint.checkpoint },
428
+ 'key.g': ctx.group_id
429
+ },
430
+ {
431
+ projection: {
432
+ lookup: 1
433
+ },
434
+ limit: limit + 1,
435
+ batchSize: limit + 2,
436
+ singleBatch: true
437
+ }
438
+ )
439
+ .toArray();
440
+ const invalidateParameterUpdates = parameterUpdates.length > limit;
441
+
442
+ return {
443
+ invalidateParameterBuckets: invalidateParameterUpdates,
444
+ updatedParameterLookups: invalidateParameterUpdates
445
+ ? new Set<string>()
446
+ : new Set<string>(parameterUpdates.map((p) => JSONBig.stringify(deserializeParameterLookup(p.lookup))))
447
+ };
448
+ }