@powersync/service-module-mongodb-storage 0.15.4 → 0.17.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 (202) hide show
  1. package/CHANGELOG.md +69 -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 +8 -6
  7. package/dist/storage/MongoBucketStorage.js +153 -66
  8. package/dist/storage/MongoBucketStorage.js.map +1 -1
  9. package/dist/storage/implementation/BucketDefinitionMapping.d.ts +15 -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/CheckpointState.d.ts +20 -0
  13. package/dist/storage/implementation/CheckpointState.js +31 -0
  14. package/dist/storage/implementation/CheckpointState.js.map +1 -0
  15. package/dist/storage/implementation/MongoBucketBatch.d.ts +48 -35
  16. package/dist/storage/implementation/MongoBucketBatch.js +118 -379
  17. package/dist/storage/implementation/MongoBucketBatch.js.map +1 -1
  18. package/dist/storage/implementation/MongoBucketBatchShared.d.ts +5 -0
  19. package/dist/storage/implementation/MongoBucketBatchShared.js +8 -0
  20. package/dist/storage/implementation/MongoBucketBatchShared.js.map +1 -0
  21. package/dist/storage/implementation/MongoChecksums.d.ts +29 -17
  22. package/dist/storage/implementation/MongoChecksums.js +13 -72
  23. package/dist/storage/implementation/MongoChecksums.js.map +1 -1
  24. package/dist/storage/implementation/MongoCompactor.d.ts +98 -58
  25. package/dist/storage/implementation/MongoCompactor.js +229 -296
  26. package/dist/storage/implementation/MongoCompactor.js.map +1 -1
  27. package/dist/storage/implementation/MongoParameterCompactor.d.ts +11 -6
  28. package/dist/storage/implementation/MongoParameterCompactor.js +11 -8
  29. package/dist/storage/implementation/MongoParameterCompactor.js.map +1 -1
  30. package/dist/storage/implementation/MongoPersistedSyncRules.d.ts +14 -0
  31. package/dist/storage/implementation/MongoPersistedSyncRules.js +67 -0
  32. package/dist/storage/implementation/MongoPersistedSyncRules.js.map +1 -0
  33. package/dist/storage/implementation/MongoPersistedSyncRulesContent.d.ts +22 -5
  34. package/dist/storage/implementation/MongoPersistedSyncRulesContent.js +56 -13
  35. package/dist/storage/implementation/MongoPersistedSyncRulesContent.js.map +1 -1
  36. package/dist/storage/implementation/MongoSyncBucketStorage.d.ts +61 -32
  37. package/dist/storage/implementation/MongoSyncBucketStorage.js +85 -523
  38. package/dist/storage/implementation/MongoSyncBucketStorage.js.map +1 -1
  39. package/dist/storage/implementation/MongoSyncRulesLock.d.ts +10 -4
  40. package/dist/storage/implementation/MongoSyncRulesLock.js +19 -13
  41. package/dist/storage/implementation/MongoSyncRulesLock.js.map +1 -1
  42. package/dist/storage/implementation/MongoWriteCheckpointAPI.js +1 -1
  43. package/dist/storage/implementation/MongoWriteCheckpointAPI.js.map +1 -1
  44. package/dist/storage/implementation/OperationBatch.js +1 -1
  45. package/dist/storage/implementation/SyncRuleStateUpdate.d.ts +14 -0
  46. package/dist/storage/implementation/SyncRuleStateUpdate.js +36 -0
  47. package/dist/storage/implementation/SyncRuleStateUpdate.js.map +1 -0
  48. package/dist/storage/implementation/common/BucketDataDoc.d.ts +35 -0
  49. package/dist/storage/implementation/common/BucketDataDoc.js +2 -0
  50. package/dist/storage/implementation/common/BucketDataDoc.js.map +1 -0
  51. package/dist/storage/implementation/common/MongoSyncBucketStorageContext.d.ts +13 -0
  52. package/dist/storage/implementation/common/MongoSyncBucketStorageContext.js +2 -0
  53. package/dist/storage/implementation/common/MongoSyncBucketStorageContext.js.map +1 -0
  54. package/dist/storage/implementation/common/PersistedBatch.d.ts +108 -0
  55. package/dist/storage/implementation/common/PersistedBatch.js +237 -0
  56. package/dist/storage/implementation/common/PersistedBatch.js.map +1 -0
  57. package/dist/storage/implementation/common/SingleBucketStore.d.ts +54 -0
  58. package/dist/storage/implementation/common/SingleBucketStore.js +3 -0
  59. package/dist/storage/implementation/common/SingleBucketStore.js.map +1 -0
  60. package/dist/storage/implementation/common/SourceRecordStore.d.ts +35 -0
  61. package/dist/storage/implementation/common/SourceRecordStore.js +2 -0
  62. package/dist/storage/implementation/common/SourceRecordStore.js.map +1 -0
  63. package/dist/storage/implementation/common/VersionedPowerSyncMongoBase.d.ts +27 -0
  64. package/dist/storage/implementation/common/VersionedPowerSyncMongoBase.js +57 -0
  65. package/dist/storage/implementation/common/VersionedPowerSyncMongoBase.js.map +1 -0
  66. package/dist/storage/implementation/createMongoSyncBucketStorage.d.ts +7 -0
  67. package/dist/storage/implementation/createMongoSyncBucketStorage.js +9 -0
  68. package/dist/storage/implementation/createMongoSyncBucketStorage.js.map +1 -0
  69. package/dist/storage/implementation/db.d.ts +41 -36
  70. package/dist/storage/implementation/db.js +77 -99
  71. package/dist/storage/implementation/db.js.map +1 -1
  72. package/dist/storage/implementation/models.d.ts +79 -66
  73. package/dist/storage/implementation/models.js +20 -1
  74. package/dist/storage/implementation/models.js.map +1 -1
  75. package/dist/storage/implementation/v1/MongoBucketBatchV1.d.ts +27 -0
  76. package/dist/storage/implementation/v1/MongoBucketBatchV1.js +407 -0
  77. package/dist/storage/implementation/v1/MongoBucketBatchV1.js.map +1 -0
  78. package/dist/storage/implementation/v1/MongoChecksumsV1.d.ts +12 -0
  79. package/dist/storage/implementation/v1/MongoChecksumsV1.js +56 -0
  80. package/dist/storage/implementation/v1/MongoChecksumsV1.js.map +1 -0
  81. package/dist/storage/implementation/v1/MongoCompactorV1.d.ts +23 -0
  82. package/dist/storage/implementation/v1/MongoCompactorV1.js +52 -0
  83. package/dist/storage/implementation/v1/MongoCompactorV1.js.map +1 -0
  84. package/dist/storage/implementation/v1/MongoParameterCompactorV1.d.ts +9 -0
  85. package/dist/storage/implementation/v1/MongoParameterCompactorV1.js +20 -0
  86. package/dist/storage/implementation/v1/MongoParameterCompactorV1.js.map +1 -0
  87. package/dist/storage/implementation/v1/MongoSyncBucketStorageV1.d.ts +50 -0
  88. package/dist/storage/implementation/v1/MongoSyncBucketStorageV1.js +354 -0
  89. package/dist/storage/implementation/v1/MongoSyncBucketStorageV1.js.map +1 -0
  90. package/dist/storage/implementation/v1/PersistedBatchV1.d.ts +25 -0
  91. package/dist/storage/implementation/v1/PersistedBatchV1.js +183 -0
  92. package/dist/storage/implementation/v1/PersistedBatchV1.js.map +1 -0
  93. package/dist/storage/implementation/v1/SingleBucketStoreV1.d.ts +18 -0
  94. package/dist/storage/implementation/v1/SingleBucketStoreV1.js +57 -0
  95. package/dist/storage/implementation/v1/SingleBucketStoreV1.js.map +1 -0
  96. package/dist/storage/implementation/v1/SourceRecordStoreV1.d.ts +19 -0
  97. package/dist/storage/implementation/v1/SourceRecordStoreV1.js +105 -0
  98. package/dist/storage/implementation/v1/SourceRecordStoreV1.js.map +1 -0
  99. package/dist/storage/implementation/v1/VersionedPowerSyncMongoV1.d.ts +12 -0
  100. package/dist/storage/implementation/v1/VersionedPowerSyncMongoV1.js +20 -0
  101. package/dist/storage/implementation/v1/VersionedPowerSyncMongoV1.js.map +1 -0
  102. package/dist/storage/implementation/v1/models.d.ts +45 -0
  103. package/dist/storage/implementation/v1/models.js +37 -0
  104. package/dist/storage/implementation/v1/models.js.map +1 -0
  105. package/dist/storage/implementation/v3/MongoBucketBatchV3.d.ts +30 -0
  106. package/dist/storage/implementation/v3/MongoBucketBatchV3.js +463 -0
  107. package/dist/storage/implementation/v3/MongoBucketBatchV3.js.map +1 -0
  108. package/dist/storage/implementation/v3/MongoChecksumsV3.d.ts +15 -0
  109. package/dist/storage/implementation/v3/MongoChecksumsV3.js +84 -0
  110. package/dist/storage/implementation/v3/MongoChecksumsV3.js.map +1 -0
  111. package/dist/storage/implementation/v3/MongoCompactorV3.d.ts +23 -0
  112. package/dist/storage/implementation/v3/MongoCompactorV3.js +68 -0
  113. package/dist/storage/implementation/v3/MongoCompactorV3.js.map +1 -0
  114. package/dist/storage/implementation/v3/MongoParameterCompactorV3.d.ts +9 -0
  115. package/dist/storage/implementation/v3/MongoParameterCompactorV3.js +18 -0
  116. package/dist/storage/implementation/v3/MongoParameterCompactorV3.js.map +1 -0
  117. package/dist/storage/implementation/v3/MongoParameterLookupV3.d.ts +4 -0
  118. package/dist/storage/implementation/v3/MongoParameterLookupV3.js +9 -0
  119. package/dist/storage/implementation/v3/MongoParameterLookupV3.js.map +1 -0
  120. package/dist/storage/implementation/v3/MongoSyncBucketStorageV3.d.ts +63 -0
  121. package/dist/storage/implementation/v3/MongoSyncBucketStorageV3.js +508 -0
  122. package/dist/storage/implementation/v3/MongoSyncBucketStorageV3.js.map +1 -0
  123. package/dist/storage/implementation/v3/PersistedBatchV3.d.ts +28 -0
  124. package/dist/storage/implementation/v3/PersistedBatchV3.js +259 -0
  125. package/dist/storage/implementation/v3/PersistedBatchV3.js.map +1 -0
  126. package/dist/storage/implementation/v3/SingleBucketStoreV3.d.ts +18 -0
  127. package/dist/storage/implementation/v3/SingleBucketStoreV3.js +48 -0
  128. package/dist/storage/implementation/v3/SingleBucketStoreV3.js.map +1 -0
  129. package/dist/storage/implementation/v3/SourceRecordStoreV3.d.ts +22 -0
  130. package/dist/storage/implementation/v3/SourceRecordStoreV3.js +164 -0
  131. package/dist/storage/implementation/v3/SourceRecordStoreV3.js.map +1 -0
  132. package/dist/storage/implementation/v3/VersionedPowerSyncMongoV3.d.ts +22 -0
  133. package/dist/storage/implementation/v3/VersionedPowerSyncMongoV3.js +74 -0
  134. package/dist/storage/implementation/v3/VersionedPowerSyncMongoV3.js.map +1 -0
  135. package/dist/storage/implementation/v3/models.d.ts +101 -0
  136. package/dist/storage/implementation/v3/models.js +34 -0
  137. package/dist/storage/implementation/v3/models.js.map +1 -0
  138. package/dist/storage/storage-index.d.ts +6 -3
  139. package/dist/storage/storage-index.js +6 -3
  140. package/dist/storage/storage-index.js.map +1 -1
  141. package/dist/utils/util.d.ts +10 -3
  142. package/dist/utils/util.js +24 -3
  143. package/dist/utils/util.js.map +1 -1
  144. package/package.json +9 -9
  145. package/src/migrations/db/migrations/1688556755264-initial-sync-rules.ts +1 -1
  146. package/src/migrations/db/migrations/1702295701188-sync-rule-state.ts +7 -7
  147. package/src/storage/MongoBucketStorage.ts +254 -99
  148. package/src/storage/implementation/BucketDefinitionMapping.ts +75 -0
  149. package/src/storage/implementation/CheckpointState.ts +59 -0
  150. package/src/storage/implementation/MongoBucketBatch.ts +182 -490
  151. package/src/storage/implementation/MongoBucketBatchShared.ts +11 -0
  152. package/src/storage/implementation/MongoChecksums.ts +53 -75
  153. package/src/storage/implementation/MongoCompactor.ts +374 -404
  154. package/src/storage/implementation/MongoParameterCompactor.ts +37 -24
  155. package/src/storage/implementation/MongoPersistedSyncRules.ts +82 -0
  156. package/src/storage/implementation/MongoPersistedSyncRulesContent.ts +78 -16
  157. package/src/storage/implementation/MongoSyncBucketStorage.ts +179 -628
  158. package/src/storage/implementation/MongoSyncRulesLock.ts +20 -16
  159. package/src/storage/implementation/MongoWriteCheckpointAPI.ts +3 -1
  160. package/src/storage/implementation/OperationBatch.ts +1 -1
  161. package/src/storage/implementation/SyncRuleStateUpdate.ts +38 -0
  162. package/src/storage/implementation/common/BucketDataDoc.ts +37 -0
  163. package/src/storage/implementation/common/MongoSyncBucketStorageContext.ts +15 -0
  164. package/src/storage/implementation/common/PersistedBatch.ts +364 -0
  165. package/src/storage/implementation/common/SingleBucketStore.ts +63 -0
  166. package/src/storage/implementation/common/SourceRecordStore.ts +48 -0
  167. package/src/storage/implementation/common/VersionedPowerSyncMongoBase.ts +80 -0
  168. package/src/storage/implementation/createMongoSyncBucketStorage.ts +25 -0
  169. package/src/storage/implementation/db.ts +110 -131
  170. package/src/storage/implementation/models.ts +102 -79
  171. package/src/storage/implementation/v1/MongoBucketBatchV1.ts +509 -0
  172. package/src/storage/implementation/v1/MongoChecksumsV1.ts +75 -0
  173. package/src/storage/implementation/v1/MongoCompactorV1.ts +93 -0
  174. package/src/storage/implementation/v1/MongoParameterCompactorV1.ts +26 -0
  175. package/src/storage/implementation/v1/MongoSyncBucketStorageV1.ts +543 -0
  176. package/src/storage/implementation/v1/PersistedBatchV1.ts +229 -0
  177. package/src/storage/implementation/v1/SingleBucketStoreV1.ts +74 -0
  178. package/src/storage/implementation/v1/SourceRecordStoreV1.ts +156 -0
  179. package/src/storage/implementation/v1/VersionedPowerSyncMongoV1.ts +28 -0
  180. package/src/storage/implementation/v1/models.ts +99 -0
  181. package/src/storage/implementation/v3/MongoBucketBatchV3.ts +607 -0
  182. package/src/storage/implementation/v3/MongoChecksumsV3.ts +120 -0
  183. package/src/storage/implementation/v3/MongoCompactorV3.ts +107 -0
  184. package/src/storage/implementation/v3/MongoParameterCompactorV3.ts +24 -0
  185. package/src/storage/implementation/v3/MongoParameterLookupV3.ts +11 -0
  186. package/src/storage/implementation/v3/MongoSyncBucketStorageV3.ts +678 -0
  187. package/src/storage/implementation/v3/PersistedBatchV3.ts +317 -0
  188. package/src/storage/implementation/v3/SingleBucketStoreV3.ts +68 -0
  189. package/src/storage/implementation/v3/SourceRecordStoreV3.ts +226 -0
  190. package/src/storage/implementation/v3/VersionedPowerSyncMongoV3.ts +117 -0
  191. package/src/storage/implementation/v3/models.ts +164 -0
  192. package/src/storage/storage-index.ts +6 -3
  193. package/src/utils/util.ts +34 -5
  194. package/test/src/storage_compacting.test.ts +57 -29
  195. package/test/src/storage_sync.test.ts +767 -5
  196. package/test/src/storeCurrentData.test.ts +211 -0
  197. package/test/tsconfig.json +0 -1
  198. package/tsconfig.tsbuildinfo +1 -1
  199. package/dist/storage/implementation/PersistedBatch.d.ts +0 -71
  200. package/dist/storage/implementation/PersistedBatch.js +0 -354
  201. package/dist/storage/implementation/PersistedBatch.js.map +0 -1
  202. package/src/storage/implementation/PersistedBatch.ts +0 -432
@@ -0,0 +1,543 @@
1
+ import * as lib_mongo from '@powersync/lib-service-mongodb';
2
+ import { mongo } from '@powersync/lib-service-mongodb';
3
+ import { ServiceAssertionError } from '@powersync/lib-services-framework';
4
+ import {
5
+ CheckpointChanges,
6
+ deserializeParameterLookup,
7
+ GetCheckpointChangesOptions,
8
+ InternalOpId,
9
+ internalToExternalOpId,
10
+ maxLsn,
11
+ ParameterSetLimitExceededError,
12
+ ProtocolOpId,
13
+ storage,
14
+ utils
15
+ } from '@powersync/service-core';
16
+ import { JSONBig } from '@powersync/service-jsonbig';
17
+ import { ParameterLookupRows, ScopedParameterLookup, SqliteJsonRow } from '@powersync/service-sync-rules';
18
+ import * as bson from 'bson';
19
+ import { idPrefixFilter, mapOpEntry, readSingleBatch, setSessionSnapshotTime } from '../../../utils/util.js';
20
+ import { MongoBucketStorage } from '../../MongoBucketStorage.js';
21
+ import {
22
+ MongoSyncBucketStorageCheckpoint,
23
+ MongoSyncBucketStorageContext
24
+ } from '../common/MongoSyncBucketStorageContext.js';
25
+ import { SourceKey } from '../models.js';
26
+ import { MongoBucketBatchOptions } from '../MongoBucketBatch.js';
27
+ import { MongoChecksums } from '../MongoChecksums.js';
28
+ import { MongoCompactOptions, MongoCompactor } from '../MongoCompactor.js';
29
+ import { MongoParameterCompactor } from '../MongoParameterCompactor.js';
30
+ import { MongoPersistedSyncRulesContentV1 } from '../MongoPersistedSyncRulesContent.js';
31
+ import { MongoSyncBucketStorage, MongoSyncBucketStorageOptions } from '../MongoSyncBucketStorage.js';
32
+ import {
33
+ BucketDataDocumentV1,
34
+ BucketDataKeyV1,
35
+ BucketStateDocument,
36
+ loadBucketDataDocumentV1,
37
+ SyncRuleDocumentV1
38
+ } from './models.js';
39
+ import { MongoBucketBatchV1 } from './MongoBucketBatchV1.js';
40
+ import { MongoChecksumsV1 } from './MongoChecksumsV1.js';
41
+ import { MongoCompactorV1 } from './MongoCompactorV1.js';
42
+ import { MongoParameterCompactorV1 } from './MongoParameterCompactorV1.js';
43
+ import { VersionedPowerSyncMongoV1 } from './VersionedPowerSyncMongoV1.js';
44
+
45
+ export class MongoSyncBucketStorageV1 extends MongoSyncBucketStorage {
46
+ // Declare types to be more specific
47
+ declare readonly db: VersionedPowerSyncMongoV1;
48
+ declare readonly checksums: MongoChecksumsV1;
49
+
50
+ constructor(
51
+ factory: MongoBucketStorage,
52
+ group_id: number,
53
+ sync_rules: MongoPersistedSyncRulesContentV1,
54
+ slot_name: string,
55
+ writeCheckpointMode: storage.WriteCheckpointMode | undefined,
56
+ options: MongoSyncBucketStorageOptions
57
+ ) {
58
+ super(factory, group_id, sync_rules, slot_name, writeCheckpointMode, options);
59
+ }
60
+
61
+ protected async initializeVersionStorage(): Promise<void> {}
62
+
63
+ protected createWriterImpl(batchOptions: MongoBucketBatchOptions): storage.BucketStorageBatch {
64
+ return new MongoBucketBatchV1(batchOptions);
65
+ }
66
+
67
+ protected async fetchCheckpointState(
68
+ session: mongo.ClientSession
69
+ ): Promise<{ checkpoint: bigint; lsn: string | null } | null> {
70
+ const doc = (await this.db.sync_rules.findOne(
71
+ { _id: this.group_id },
72
+ {
73
+ session,
74
+ projection: { _id: 1, state: 1, last_checkpoint: 1, last_checkpoint_lsn: 1, snapshot_done: 1 }
75
+ }
76
+ )) as SyncRuleDocumentV1;
77
+ if (!doc?.snapshot_done || ![storage.SyncRuleState.ACTIVE, storage.SyncRuleState.ERRORED].includes(doc.state)) {
78
+ return null;
79
+ }
80
+ return {
81
+ checkpoint: doc.last_checkpoint ?? 0n,
82
+ lsn: doc.last_checkpoint_lsn ?? null
83
+ };
84
+ }
85
+
86
+ protected async getWriterSyncState() {
87
+ const doc = (await this.db.sync_rules.findOne(
88
+ {
89
+ _id: this.group_id
90
+ },
91
+ { projection: { last_checkpoint_lsn: 1, keepalive_op: 1, snapshot_lsn: 1 } }
92
+ )) as SyncRuleDocumentV1;
93
+ const checkpointLsn = doc?.last_checkpoint_lsn ?? null;
94
+ return {
95
+ lastCheckpointLsn: checkpointLsn,
96
+ resumeFromLsn: maxLsn(checkpointLsn, doc?.snapshot_lsn),
97
+ keepaliveOp: doc?.keepalive_op ? BigInt(doc.keepalive_op) : null,
98
+ syncConfigId: null
99
+ };
100
+ }
101
+
102
+ protected async terminateSyncRuleState(): Promise<void> {
103
+ await this.db.sync_rules.updateOne(
104
+ {
105
+ _id: this.group_id
106
+ },
107
+ {
108
+ $set: {
109
+ state: storage.SyncRuleState.TERMINATED,
110
+ persisted_lsn: null,
111
+ snapshot_done: false
112
+ }
113
+ }
114
+ );
115
+ }
116
+
117
+ protected async getStatusImpl(): Promise<storage.SyncRuleStatus> {
118
+ const doc = (await this.db.sync_rules.findOne(
119
+ {
120
+ _id: this.group_id
121
+ },
122
+ {
123
+ projection: {
124
+ snapshot_done: 1,
125
+ last_checkpoint_lsn: 1,
126
+ state: 1,
127
+ snapshot_lsn: 1,
128
+ keepalive_op: 1
129
+ }
130
+ }
131
+ )) as SyncRuleDocumentV1;
132
+ if (doc == null) {
133
+ throw new ServiceAssertionError('Cannot find replication stream status');
134
+ }
135
+
136
+ return {
137
+ snapshot_done: doc.snapshot_done,
138
+ snapshot_lsn: doc.snapshot_lsn ?? null,
139
+ active: doc.state == storage.SyncRuleState.ACTIVE,
140
+ checkpoint_lsn: doc.last_checkpoint_lsn,
141
+ keepalive_op: doc.keepalive_op == null ? null : BigInt(doc.keepalive_op)
142
+ };
143
+ }
144
+
145
+ protected async clearSyncRuleState(): Promise<void> {
146
+ await this.db.sync_rules.updateOne(
147
+ {
148
+ _id: this.group_id
149
+ },
150
+ {
151
+ $set: {
152
+ snapshot_done: false,
153
+ persisted_lsn: null,
154
+ last_checkpoint_lsn: null,
155
+ last_checkpoint: null,
156
+ no_checkpoint_before: null
157
+ },
158
+ $unset: {
159
+ snapshot_lsn: 1
160
+ }
161
+ },
162
+ { maxTimeMS: lib_mongo.db.MONGO_CLEAR_OPERATION_TIMEOUT_MS }
163
+ );
164
+ }
165
+
166
+ protected createMongoChecksums(options: MongoSyncBucketStorageOptions): MongoChecksums {
167
+ return new MongoChecksumsV1(this.db, this.group_id, {
168
+ ...options.checksumOptions,
169
+ storageConfig: options?.storageConfig,
170
+ mapping: this.sync_rules.mapping
171
+ });
172
+ }
173
+
174
+ createMongoCompactor(options: MongoCompactOptions): MongoCompactor {
175
+ return new MongoCompactorV1(this, this.db, options);
176
+ }
177
+
178
+ protected createMongoParameterCompactor(
179
+ checkpoint: InternalOpId,
180
+ options: storage.CompactOptions
181
+ ): MongoParameterCompactor {
182
+ return new MongoParameterCompactorV1(this.db, this.group_id, checkpoint, options);
183
+ }
184
+
185
+ protected override get versionContext(): MongoSyncBucketStorageContext<VersionedPowerSyncMongoV1> {
186
+ return {
187
+ db: this.db,
188
+ group_id: this.group_id,
189
+ mapping: this.mapping
190
+ };
191
+ }
192
+
193
+ protected getParameterSetsImpl(
194
+ checkpoint: MongoSyncBucketStorageCheckpoint,
195
+ lookups: ScopedParameterLookup[],
196
+ limit: number
197
+ ): Promise<ParameterLookupRows[]> {
198
+ return getParameterSetsV1(this.versionContext, checkpoint, lookups, limit);
199
+ }
200
+
201
+ protected getBucketDataBatchImpl(
202
+ checkpoint: utils.InternalOpId,
203
+ dataBuckets: storage.BucketDataRequest[],
204
+ options?: storage.BucketDataBatchOptions
205
+ ): AsyncIterable<storage.SyncBucketDataChunk> {
206
+ return getBucketDataBatchV1(this.versionContext, checkpoint, dataBuckets, options);
207
+ }
208
+
209
+ protected async clearBucketData(signal?: AbortSignal): Promise<void> {
210
+ await this.clearDeleteMany(
211
+ 'bucket data',
212
+ () =>
213
+ this.db.bucket_data.deleteMany(
214
+ {
215
+ _id: idPrefixFilter<BucketDataKeyV1>({ g: this.group_id }, ['b', 'o'])
216
+ },
217
+ { maxTimeMS: lib_mongo.db.MONGO_CLEAR_OPERATION_TIMEOUT_MS }
218
+ ),
219
+ signal
220
+ );
221
+ }
222
+
223
+ protected async clearParameterIndexes(signal?: AbortSignal): Promise<void> {
224
+ await this.clearDeleteMany(
225
+ 'parameter index',
226
+ () =>
227
+ this.db.parameterIndexV1.deleteMany(
228
+ {
229
+ 'key.g': this.group_id
230
+ },
231
+ { maxTimeMS: lib_mongo.db.MONGO_CLEAR_OPERATION_TIMEOUT_MS }
232
+ ),
233
+ signal
234
+ );
235
+ }
236
+
237
+ protected async clearSourceRecords(signal?: AbortSignal): Promise<void> {
238
+ await this.clearDeleteMany(
239
+ 'source records',
240
+ () =>
241
+ this.db.sourceRecordsV1.deleteMany(
242
+ {
243
+ _id: idPrefixFilter<SourceKey>({ g: this.group_id }, ['t', 'k'])
244
+ },
245
+ { maxTimeMS: lib_mongo.db.MONGO_CLEAR_OPERATION_TIMEOUT_MS }
246
+ ),
247
+ signal
248
+ );
249
+ }
250
+
251
+ protected async clearBucketState(signal?: AbortSignal): Promise<void> {
252
+ await this.clearDeleteMany(
253
+ 'bucket state',
254
+ () =>
255
+ this.db.bucketStateV1.deleteMany(
256
+ {
257
+ _id: idPrefixFilter<BucketStateDocument['_id']>({ g: this.group_id }, ['b'])
258
+ },
259
+ { maxTimeMS: lib_mongo.db.MONGO_CLEAR_OPERATION_TIMEOUT_MS }
260
+ ),
261
+ signal
262
+ );
263
+ }
264
+
265
+ protected async clearSourceTables(signal?: AbortSignal): Promise<void> {
266
+ await this.clearDeleteMany(
267
+ 'source tables',
268
+ () =>
269
+ this.db.commonSourceTables(this.group_id).deleteMany(
270
+ {
271
+ group_id: this.group_id
272
+ },
273
+ { maxTimeMS: lib_mongo.db.MONGO_CLEAR_OPERATION_TIMEOUT_MS }
274
+ ),
275
+ signal
276
+ );
277
+ }
278
+
279
+ protected getDataBucketChangesImpl(
280
+ options: GetCheckpointChangesOptions
281
+ ): Promise<Pick<CheckpointChanges, 'updatedDataBuckets' | 'invalidateDataBuckets'>> {
282
+ return getDataBucketChangesV1(this.versionContext, options);
283
+ }
284
+
285
+ protected getParameterBucketChangesImpl(
286
+ options: GetCheckpointChangesOptions
287
+ ): Promise<Pick<CheckpointChanges, 'updatedParameterLookups' | 'invalidateParameterBuckets'>> {
288
+ return getParameterBucketChangesV1(this.versionContext, options);
289
+ }
290
+ }
291
+
292
+ export async function getParameterSetsV1(
293
+ ctx: MongoSyncBucketStorageContext<VersionedPowerSyncMongoV1>,
294
+ checkpoint: MongoSyncBucketStorageCheckpoint,
295
+ lookups: ScopedParameterLookup[],
296
+ limit: number
297
+ ): Promise<ParameterLookupRows[]> {
298
+ return ctx.db.client.withSession({ snapshot: true }, async (session) => {
299
+ setSessionSnapshotTime(session, checkpoint.snapshotTime);
300
+ const lookupFilter = lookups.map((lookup) => {
301
+ return storage.serializeLookup(lookup);
302
+ });
303
+
304
+ const rows = await ctx.db.parameterIndexV1
305
+ .aggregate<{ lookup: number; bucket_parameters: SqliteJsonRow }>(
306
+ [
307
+ {
308
+ $match: {
309
+ 'key.g': ctx.group_id,
310
+ lookup: { $in: lookupFilter },
311
+ _id: { $lte: checkpoint.checkpoint }
312
+ }
313
+ },
314
+ {
315
+ $set: {
316
+ index: { $indexOfArray: [lookupFilter, '$lookup'] }
317
+ }
318
+ },
319
+ {
320
+ $sort: {
321
+ _id: -1
322
+ }
323
+ },
324
+ {
325
+ $group: {
326
+ _id: { key: '$key', lookup: '$index' },
327
+ bucket_parameters: {
328
+ $first: '$bucket_parameters'
329
+ }
330
+ }
331
+ },
332
+ {
333
+ $project: {
334
+ _id: false,
335
+ lookup: '$_id.lookup',
336
+ bucket_parameters: true
337
+ }
338
+ },
339
+ { $unwind: '$bucket_parameters' },
340
+ {
341
+ $limit: limit + 1
342
+ }
343
+ ],
344
+ {
345
+ session,
346
+ readConcern: 'snapshot',
347
+ maxTimeMS: lib_mongo.db.MONGO_OPERATION_TIMEOUT_MS
348
+ }
349
+ )
350
+ .toArray()
351
+ .catch((e) => {
352
+ throw lib_mongo.mapQueryError(e, 'while evaluating parameter queries');
353
+ });
354
+
355
+ if (rows.length > limit) {
356
+ throw new ParameterSetLimitExceededError(limit);
357
+ }
358
+
359
+ const byLookup = Map.groupBy(rows, (row) => lookups[row.lookup]);
360
+ const results: ParameterLookupRows[] = [];
361
+ byLookup.forEach((value, lookup) => results.push({ lookup, rows: value.map((r) => r.bucket_parameters) }));
362
+ return results;
363
+ });
364
+ }
365
+
366
+ export async function* getBucketDataBatchV1(
367
+ ctx: MongoSyncBucketStorageContext<VersionedPowerSyncMongoV1>,
368
+ checkpoint: utils.InternalOpId,
369
+ dataBuckets: storage.BucketDataRequest[],
370
+ options?: storage.BucketDataBatchOptions
371
+ ): AsyncIterable<storage.SyncBucketDataChunk> {
372
+ if (dataBuckets.length == 0) {
373
+ return;
374
+ }
375
+ let filters: mongo.Filter<BucketDataDocumentV1>[] = [];
376
+ const bucketMap = new Map(dataBuckets.map((request) => [request.bucket, request.start]));
377
+
378
+ if (checkpoint == null) {
379
+ throw new Error('checkpoint is null');
380
+ }
381
+ const end = checkpoint;
382
+ for (let { bucket: name, start } of dataBuckets) {
383
+ filters.push({
384
+ _id: {
385
+ $gt: {
386
+ g: ctx.group_id,
387
+ b: name,
388
+ o: start
389
+ },
390
+ $lte: {
391
+ g: ctx.group_id,
392
+ b: name,
393
+ o: end as any
394
+ }
395
+ }
396
+ });
397
+ }
398
+
399
+ const batchLimit = options?.limit ?? storage.DEFAULT_DOCUMENT_BATCH_LIMIT;
400
+ const chunkSizeLimitBytes = options?.chunkLimitBytes ?? storage.DEFAULT_DOCUMENT_CHUNK_LIMIT_BYTES;
401
+
402
+ const cursor = ctx.db.bucket_data.find(
403
+ {
404
+ $or: filters
405
+ },
406
+ {
407
+ session: undefined,
408
+ sort: { _id: 1 },
409
+ limit: batchLimit,
410
+ batchSize: batchLimit + 1,
411
+ raw: true,
412
+ maxTimeMS: lib_mongo.db.MONGO_OPERATION_TIMEOUT_MS
413
+ }
414
+ ) as unknown as mongo.FindCursor<Buffer>;
415
+
416
+ let { data, hasMore: batchHasMore } = await readSingleBatch(cursor).catch((e) => {
417
+ throw lib_mongo.mapQueryError(e, 'while reading bucket data');
418
+ });
419
+ if (data.length == batchLimit) {
420
+ batchHasMore = true;
421
+ }
422
+
423
+ let chunkSizeBytes = 0;
424
+ let currentChunk: utils.SyncBucketData | null = null;
425
+ let targetOp: InternalOpId | null = null;
426
+
427
+ for (let rawData of data) {
428
+ const row = loadBucketDataDocumentV1(
429
+ bson.deserialize(rawData, storage.BSON_DESERIALIZE_INTERNAL_OPTIONS) as BucketDataDocumentV1
430
+ );
431
+ const bucket = row.bucketKey.bucket;
432
+
433
+ if (currentChunk == null || currentChunk.bucket != bucket || chunkSizeBytes >= chunkSizeLimitBytes) {
434
+ let start: ProtocolOpId | undefined = undefined;
435
+ if (currentChunk != null) {
436
+ if (currentChunk.bucket == bucket) {
437
+ currentChunk.has_more = true;
438
+ start = currentChunk.next_after;
439
+ }
440
+
441
+ const yieldChunk = currentChunk;
442
+ currentChunk = null;
443
+ chunkSizeBytes = 0;
444
+ yield { chunkData: yieldChunk, targetOp: targetOp };
445
+ targetOp = null;
446
+ }
447
+
448
+ if (start == null) {
449
+ const startOpId = bucketMap.get(bucket);
450
+ if (startOpId == null) {
451
+ throw new Error(`data for unexpected bucket: ${bucket}`);
452
+ }
453
+ start = internalToExternalOpId(startOpId);
454
+ }
455
+ currentChunk = {
456
+ bucket,
457
+ after: start,
458
+ has_more: false,
459
+ data: [],
460
+ next_after: start
461
+ };
462
+ targetOp = null;
463
+ }
464
+
465
+ const entry = mapOpEntry(row);
466
+
467
+ if (row.target_op != null && (targetOp == null || row.target_op > targetOp)) {
468
+ targetOp = row.target_op;
469
+ }
470
+
471
+ currentChunk.data.push(entry);
472
+ currentChunk.next_after = entry.op_id;
473
+ chunkSizeBytes += rawData.byteLength;
474
+ }
475
+
476
+ if (currentChunk != null) {
477
+ const yieldChunk = currentChunk;
478
+ yieldChunk.has_more = batchHasMore;
479
+ yield { chunkData: yieldChunk, targetOp: targetOp };
480
+ }
481
+ }
482
+
483
+ export async function getDataBucketChangesV1(
484
+ ctx: MongoSyncBucketStorageContext<VersionedPowerSyncMongoV1>,
485
+ options: GetCheckpointChangesOptions
486
+ ): Promise<Pick<CheckpointChanges, 'updatedDataBuckets' | 'invalidateDataBuckets'>> {
487
+ const limit = 1000;
488
+ const bucketStateUpdates = await ctx.db.bucketStateV1
489
+ .find(
490
+ {
491
+ '_id.g': ctx.group_id,
492
+ last_op: { $gt: options.lastCheckpoint.checkpoint }
493
+ },
494
+ {
495
+ projection: {
496
+ '_id.b': 1
497
+ },
498
+ limit: limit + 1,
499
+ batchSize: limit + 2,
500
+ singleBatch: true
501
+ }
502
+ )
503
+ .toArray();
504
+
505
+ const buckets = bucketStateUpdates.map((doc) => doc._id.b);
506
+ const invalidateDataBuckets = buckets.length > limit;
507
+
508
+ return {
509
+ invalidateDataBuckets,
510
+ updatedDataBuckets: invalidateDataBuckets ? new Set<string>() : new Set(buckets)
511
+ };
512
+ }
513
+
514
+ export async function getParameterBucketChangesV1(
515
+ ctx: MongoSyncBucketStorageContext<VersionedPowerSyncMongoV1>,
516
+ options: GetCheckpointChangesOptions
517
+ ): Promise<Pick<CheckpointChanges, 'updatedParameterLookups' | 'invalidateParameterBuckets'>> {
518
+ const limit = 1000;
519
+ const parameterUpdates = await ctx.db.parameterIndexV1
520
+ .find(
521
+ {
522
+ _id: { $gt: options.lastCheckpoint.checkpoint, $lte: options.nextCheckpoint.checkpoint },
523
+ 'key.g': ctx.group_id
524
+ },
525
+ {
526
+ projection: {
527
+ lookup: 1
528
+ },
529
+ limit: limit + 1,
530
+ batchSize: limit + 2,
531
+ singleBatch: true
532
+ }
533
+ )
534
+ .toArray();
535
+ const invalidateParameterUpdates = parameterUpdates.length > limit;
536
+
537
+ return {
538
+ invalidateParameterBuckets: invalidateParameterUpdates,
539
+ updatedParameterLookups: invalidateParameterUpdates
540
+ ? new Set<string>()
541
+ : new Set<string>(parameterUpdates.map((p) => JSONBig.stringify(deserializeParameterLookup(p.lookup))))
542
+ };
543
+ }