@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,230 @@
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 * as bson from 'bson';
5
+
6
+ import { BucketDataSource } from '@powersync/service-sync-rules';
7
+ import { mongoTableId } from '../../../utils/util.js';
8
+ import { BucketDefinitionId } from '../BucketDefinitionMapping.js';
9
+ import { EMPTY_DATA } from '../MongoBucketBatchShared.js';
10
+ import {
11
+ BucketStateUpdate,
12
+ PersistedBatch,
13
+ SaveParameterDataOptions,
14
+ UpsertCurrentDataOptions
15
+ } from '../common/PersistedBatch.js';
16
+ import { LEGACY_BUCKET_DATA_DEFINITION_ID, LEGACY_BUCKET_PARAMETER_INDEX_ID, SourceKey } from '../models.js';
17
+ import { VersionedPowerSyncMongoV1 } from './VersionedPowerSyncMongoV1.js';
18
+ import {
19
+ BucketParameterDocument,
20
+ BucketStateDocumentV1,
21
+ CurrentDataDocument,
22
+ serializeBucketDataV1,
23
+ taggedBucketParameterDocumentToV1
24
+ } from './models.js';
25
+
26
+ export class PersistedBatchV1 extends PersistedBatch {
27
+ declare protected readonly db: VersionedPowerSyncMongoV1;
28
+
29
+ currentData: mongo.AnyBulkWriteOperation<CurrentDataDocument>[] = [];
30
+
31
+ protected checkDefinitionId(_definitionId: BucketDefinitionId | null): BucketDefinitionId {
32
+ // V1 storage doesn't persist the id, and we don't use it.
33
+ return LEGACY_BUCKET_DATA_DEFINITION_ID;
34
+ }
35
+
36
+ protected getBucketDefinitionId(_bucketSource: BucketDataSource): BucketDefinitionId {
37
+ return LEGACY_BUCKET_DATA_DEFINITION_ID;
38
+ }
39
+
40
+ saveParameterData(data: SaveParameterDataOptions) {
41
+ const { sourceTable, sourceKey, evaluated } = data;
42
+ const remaining_lookups = new Map<string, bson.Binary>();
43
+
44
+ for (let lookup of data.existing_lookups) {
45
+ if (lookup.indexId != null) {
46
+ throw new ReplicationAssertionError('Unexpected v3 lookup when incrementalReprocessing is disabled');
47
+ }
48
+ remaining_lookups.set(lookup.lookup.toString('base64'), lookup.lookup);
49
+ }
50
+
51
+ for (let result of evaluated) {
52
+ const binLookup = storage.serializeLookup(result.lookup);
53
+ remaining_lookups.delete(binLookup.toString('base64'));
54
+
55
+ const op_id = data.op_seq.next();
56
+ this.debugLastOpId = op_id;
57
+ const values: BucketParameterDocument = {
58
+ _id: op_id,
59
+ key: {
60
+ g: this.group_id,
61
+ t: mongoTableId(sourceTable.id),
62
+ k: sourceKey
63
+ },
64
+ lookup: binLookup,
65
+ bucket_parameters: result.bucketParameters
66
+ };
67
+ this.bucketParameters.push({
68
+ ...values,
69
+ index: LEGACY_BUCKET_PARAMETER_INDEX_ID
70
+ });
71
+
72
+ this.currentSize += 200;
73
+ }
74
+
75
+ for (let lookup of remaining_lookups.values()) {
76
+ const op_id = data.op_seq.next();
77
+ this.debugLastOpId = op_id;
78
+ const values: BucketParameterDocument = {
79
+ _id: op_id,
80
+ key: {
81
+ g: this.group_id,
82
+ t: mongoTableId(sourceTable.id),
83
+ k: sourceKey
84
+ },
85
+ lookup,
86
+ bucket_parameters: []
87
+ };
88
+ this.bucketParameters.push({
89
+ ...values,
90
+ index: LEGACY_BUCKET_PARAMETER_INDEX_ID
91
+ });
92
+
93
+ this.currentSize += 200;
94
+ }
95
+ }
96
+
97
+ hardDeleteCurrentData(sourceTableId: bson.ObjectId, replicaId: storage.ReplicaId) {
98
+ this.currentData.push({
99
+ deleteOne: {
100
+ filter: { _id: this.currentDataId(sourceTableId, replicaId) }
101
+ }
102
+ });
103
+ this.currentSize += 50;
104
+ }
105
+
106
+ softDeleteCurrentData(sourceTableId: bson.ObjectId, replicaId: storage.ReplicaId, _checkpointGreaterThan: bigint) {
107
+ this.hardDeleteCurrentData(sourceTableId, replicaId);
108
+ }
109
+
110
+ upsertCurrentData(values: UpsertCurrentDataOptions) {
111
+ const buckets = values.buckets.map((bucket) => {
112
+ if (bucket.definitionId != null) {
113
+ throw new ReplicationAssertionError('Unexpected v3 bucket when incrementalReprocessing is disabled');
114
+ }
115
+ return {
116
+ bucket: bucket.bucket,
117
+ table: bucket.table,
118
+ id: bucket.id
119
+ };
120
+ });
121
+ const lookups = values.lookups.map((lookup) => {
122
+ if (lookup.indexId != null) {
123
+ throw new ReplicationAssertionError('Unexpected v3 lookup when incrementalReprocessing is disabled');
124
+ }
125
+ return lookup.lookup;
126
+ });
127
+
128
+ this.currentData.push({
129
+ updateOne: {
130
+ filter: { _id: this.currentDataId(values.sourceTableId, values.replicaId) },
131
+ update: {
132
+ $set: {
133
+ data: values.data ?? EMPTY_DATA,
134
+ buckets,
135
+ lookups
136
+ }
137
+ },
138
+ upsert: true
139
+ }
140
+ });
141
+ this.currentSize += (values.data?.length() ?? 0) + 100;
142
+ }
143
+
144
+ protected get currentDataCount() {
145
+ return this.currentData.length;
146
+ }
147
+
148
+ protected async flushBucketData(session: mongo.ClientSession) {
149
+ await this.db.bucketDataV1.bulkWrite(
150
+ this.bucketData.map((document) => ({
151
+ insertOne: {
152
+ document: serializeBucketDataV1(document)
153
+ }
154
+ })),
155
+ {
156
+ session,
157
+ ordered: false
158
+ }
159
+ );
160
+ }
161
+
162
+ protected async flushBucketParameters(session: mongo.ClientSession) {
163
+ await this.db.parameterIndexV1.bulkWrite(
164
+ this.bucketParameters.map((document) => ({
165
+ insertOne: {
166
+ document: taggedBucketParameterDocumentToV1(document)
167
+ }
168
+ })),
169
+ {
170
+ session,
171
+ ordered: false
172
+ }
173
+ );
174
+ }
175
+
176
+ protected async flushCurrentData(session: mongo.ClientSession) {
177
+ if (this.currentData.length == 0) {
178
+ return;
179
+ }
180
+
181
+ await this.db.sourceRecordsV1.bulkWrite(this.currentData, {
182
+ session,
183
+ ordered: true
184
+ });
185
+ }
186
+
187
+ protected async flushBucketStates(session: mongo.ClientSession) {
188
+ await this.db.bucketStateV1.bulkWrite(this.getBucketStateUpdates(), {
189
+ session,
190
+ ordered: false
191
+ });
192
+ }
193
+
194
+ protected resetCurrentData() {
195
+ this.currentData = [];
196
+ }
197
+
198
+ private getBucketStateUpdates(): mongo.AnyBulkWriteOperation<BucketStateDocumentV1>[] {
199
+ return Array.from(this.bucketStates.values()).map((state: BucketStateUpdate) => {
200
+ return {
201
+ updateOne: {
202
+ filter: {
203
+ _id: {
204
+ g: this.group_id,
205
+ b: state.bucket
206
+ }
207
+ },
208
+ update: {
209
+ $set: {
210
+ last_op: state.lastOp
211
+ },
212
+ $inc: {
213
+ 'estimate_since_compact.count': state.incrementCount,
214
+ 'estimate_since_compact.bytes': state.incrementBytes
215
+ }
216
+ },
217
+ upsert: true
218
+ }
219
+ } satisfies mongo.AnyBulkWriteOperation<BucketStateDocumentV1>;
220
+ });
221
+ }
222
+
223
+ private currentDataId(sourceTableId: bson.ObjectId, replicaId: storage.ReplicaId): SourceKey {
224
+ return {
225
+ g: this.group_id,
226
+ t: sourceTableId,
227
+ k: replicaId
228
+ };
229
+ }
230
+ }
@@ -0,0 +1,74 @@
1
+ import { mongo } from '@powersync/lib-service-mongodb';
2
+ import { InternalOpId } from '@powersync/service-core';
3
+ import { BucketDataDoc, BucketKey } from '../common/BucketDataDoc.js';
4
+ import {
5
+ BucketDataDocumentGeneric,
6
+ BucketDataDocumentGenericId,
7
+ SingleBucketStore
8
+ } from '../common/SingleBucketStore.js';
9
+ import { BucketDataProperties } from '../models.js';
10
+ import { VersionedPowerSyncMongoV1 } from './VersionedPowerSyncMongoV1.js';
11
+ import { BucketDataDocumentV1, BucketDataKeyV1, serializeBucketDataV1 } from './models.js';
12
+
13
+ export class SingleBucketStoreV1 implements SingleBucketStore {
14
+ public readonly collection: mongo.Collection<BucketDataDocumentGeneric>;
15
+
16
+ constructor(
17
+ private db: VersionedPowerSyncMongoV1,
18
+ public readonly key: BucketKey
19
+ ) {
20
+ this.collection = db.bucketDataV1 as unknown as mongo.Collection<BucketDataDocumentGeneric>;
21
+ }
22
+
23
+ docId(o: InternalOpId): BucketDataDocumentGenericId {
24
+ // `satisfies BucketDataKeyV1` checks that we use the correct type for V1 storage
25
+ // `as anyt` is to allow casting to the interface virtual type
26
+ return {
27
+ g: this.key.replicationStreamId,
28
+ b: this.key.bucket,
29
+ o
30
+ } satisfies BucketDataKeyV1 as any;
31
+ }
32
+
33
+ get minId(): BucketDataDocumentGenericId {
34
+ return {
35
+ g: this.key.replicationStreamId,
36
+ b: this.key.bucket,
37
+ o: new mongo.MinKey()
38
+ } as any;
39
+ }
40
+
41
+ get maxId(): BucketDataDocumentGenericId {
42
+ return {
43
+ g: this.key.replicationStreamId,
44
+ b: this.key.bucket,
45
+ o: new mongo.MaxKey()
46
+ } as any;
47
+ }
48
+
49
+ toPersistedDocument(source: Omit<BucketDataDoc, 'bucketKey'>): BucketDataDocumentGeneric {
50
+ return serializeBucketDataV1({ bucketKey: this.key, ...source }) as unknown as BucketDataDocumentGeneric;
51
+ }
52
+
53
+ fromPersistedDocument(doc: BucketDataDocumentGeneric): BucketDataDoc {
54
+ const document = doc as unknown as BucketDataDocumentV1;
55
+ const { _id, ...rest } = document;
56
+ return {
57
+ bucketKey: this.key,
58
+ o: _id.o,
59
+ ...rest
60
+ };
61
+ }
62
+
63
+ fromPartialPersistedDocument<T extends keyof BucketDataProperties>(
64
+ doc: Pick<BucketDataDocumentGeneric, '_id' | T>
65
+ ): Pick<BucketDataDoc, 'bucketKey' | 'o' | T> {
66
+ const document = doc as Pick<BucketDataDocumentV1, '_id' | T>;
67
+ const { _id, ...rest } = document;
68
+ return {
69
+ bucketKey: this.key,
70
+ o: _id.o,
71
+ ...rest
72
+ } as Pick<BucketDataDoc, 'bucketKey' | 'o' | T>;
73
+ }
74
+ }
@@ -0,0 +1,156 @@
1
+ import { mongo } from '@powersync/lib-service-mongodb';
2
+ import { Logger } from '@powersync/lib-services-framework';
3
+ import { storage } from '@powersync/service-core';
4
+ import { EvaluatedParameters, EvaluatedRow } from '@powersync/service-sync-rules';
5
+ import * as bson from 'bson';
6
+ import { idPrefixFilter } from '../../../utils/util.js';
7
+ import { cacheKey } from '../OperationBatch.js';
8
+ import {
9
+ LoadedSourceRecord,
10
+ SourceRecordLookupEntry,
11
+ SourceRecordLookupState,
12
+ SourceRecordStore
13
+ } from '../common/SourceRecordStore.js';
14
+ import { SourceKey } from '../models.js';
15
+ import { VersionedPowerSyncMongoV1 } from './VersionedPowerSyncMongoV1.js';
16
+ import { CurrentDataDocument } from './models.js';
17
+
18
+ export class SourceRecordStoreV1 implements SourceRecordStore {
19
+ constructor(
20
+ private readonly db: VersionedPowerSyncMongoV1,
21
+ private readonly groupId: number
22
+ ) {}
23
+
24
+ mapEvaluatedBuckets(evaluated: EvaluatedRow[]): LoadedSourceRecord['buckets'] {
25
+ return evaluated.map((entry) => ({
26
+ definitionId: null,
27
+ bucket: entry.bucket,
28
+ table: entry.table,
29
+ id: entry.id
30
+ }));
31
+ }
32
+
33
+ mapParameterLookups(paramEvaluated: EvaluatedParameters[]): SourceRecordLookupState[] {
34
+ return paramEvaluated.map((entry) => ({
35
+ indexId: null,
36
+ lookup: storage.serializeLookup(entry.lookup)
37
+ }));
38
+ }
39
+
40
+ private createId(sourceTableId: bson.ObjectId, replicaId: storage.ReplicaId): SourceKey {
41
+ return {
42
+ g: this.groupId,
43
+ t: sourceTableId,
44
+ k: replicaId
45
+ } satisfies SourceKey;
46
+ }
47
+
48
+ private createLoadedDocument(
49
+ sourceTableId: bson.ObjectId,
50
+ id: SourceKey,
51
+ data: bson.Binary | null,
52
+ buckets: CurrentDataDocument['buckets'],
53
+ lookups: CurrentDataDocument['lookups']
54
+ ): LoadedSourceRecord {
55
+ return {
56
+ sourceTableId,
57
+ replicaId: id.k,
58
+ data,
59
+ buckets: buckets.map((bucket) => ({
60
+ definitionId: null,
61
+ bucket: bucket.bucket,
62
+ table: bucket.table,
63
+ id: bucket.id
64
+ })),
65
+ lookups: lookups.map((lookup) => ({
66
+ indexId: null,
67
+ lookup
68
+ })),
69
+ cacheKey: cacheKey(sourceTableId, id.k)
70
+ };
71
+ }
72
+
73
+ async loadSizes(session: mongo.ClientSession, entries: SourceRecordLookupEntry[]): Promise<Map<string, number>> {
74
+ const sizes = new Map<string, number>();
75
+ const sizeCursor: mongo.AggregationCursor<CurrentDataDocument & { size: number }> =
76
+ this.db.sourceRecordsV1.aggregate(
77
+ [
78
+ {
79
+ $match: {
80
+ _id: {
81
+ $in: entries.map((entry) => this.createId(entry.sourceTableId, entry.replicaId) as SourceKey)
82
+ }
83
+ }
84
+ },
85
+ {
86
+ $project: {
87
+ _id: 1,
88
+ size: { $bsonSize: '$$ROOT' }
89
+ }
90
+ }
91
+ ],
92
+ { session }
93
+ );
94
+ for await (const doc of sizeCursor.stream()) {
95
+ sizes.set(cacheKey(doc._id.t, doc._id.k), doc.size);
96
+ }
97
+ return sizes;
98
+ }
99
+
100
+ async loadDocuments(
101
+ session: mongo.ClientSession,
102
+ entries: SourceRecordLookupEntry[],
103
+ idsOnly: boolean
104
+ ): Promise<Map<string, LoadedSourceRecord>> {
105
+ const documents = new Map<string, LoadedSourceRecord>();
106
+ const projection = idsOnly ? { _id: 1 } : undefined;
107
+ const cursor = this.db.sourceRecordsV1.find(
108
+ {
109
+ _id: {
110
+ $in: entries.map((entry) => this.createId(entry.sourceTableId, entry.replicaId) as SourceKey)
111
+ }
112
+ },
113
+ { session, projection }
114
+ );
115
+ for await (const doc of cursor.stream()) {
116
+ const loaded = this.createLoadedDocument(
117
+ doc._id.t,
118
+ doc._id,
119
+ idsOnly ? null : doc.data,
120
+ idsOnly ? [] : doc.buckets,
121
+ idsOnly ? [] : doc.lookups
122
+ );
123
+ documents.set(loaded.cacheKey, loaded);
124
+ }
125
+ return documents;
126
+ }
127
+
128
+ async loadTruncateBatch(
129
+ session: mongo.ClientSession,
130
+ sourceTableId: bson.ObjectId,
131
+ limit: number
132
+ ): Promise<LoadedSourceRecord[]> {
133
+ const cursor = this.db.sourceRecordsV1.find(
134
+ {
135
+ _id: idPrefixFilter<SourceKey>({ g: this.groupId, t: sourceTableId }, ['k']),
136
+ pending_delete: { $exists: false }
137
+ },
138
+ {
139
+ projection: {
140
+ _id: 1,
141
+ buckets: 1,
142
+ lookups: 1
143
+ },
144
+ limit,
145
+ session
146
+ }
147
+ );
148
+ return (await cursor.toArray()).map((doc) =>
149
+ this.createLoadedDocument(sourceTableId, doc._id, null, doc.buckets, doc.lookups)
150
+ );
151
+ }
152
+
153
+ async postCommitCleanup(_lastCheckpoint: bigint, _logger: Logger): Promise<void> {
154
+ // No-op for V1.
155
+ }
156
+ }
@@ -0,0 +1,28 @@
1
+ import { mongo } from '@powersync/lib-service-mongodb';
2
+ import { BaseVersionedPowerSyncMongo } from '../common/VersionedPowerSyncMongoBase.js';
3
+ import { CommonSourceTableDocument } from '../models.js';
4
+ import { BucketDataDocumentV1, BucketParameterDocument, BucketStateDocumentV1, CurrentDataDocument } from './models.js';
5
+
6
+ export class VersionedPowerSyncMongoV1 extends BaseVersionedPowerSyncMongo {
7
+ get sourceRecordsV1(): mongo.Collection<CurrentDataDocument> {
8
+ return this.upstream.current_data;
9
+ }
10
+
11
+ get bucketStateV1(): mongo.Collection<BucketStateDocumentV1> {
12
+ return this.upstream.bucket_state;
13
+ }
14
+
15
+ commonSourceTables(_replicationStreamId: number): mongo.Collection<CommonSourceTableDocument> {
16
+ return this.upstream.source_tables as any as mongo.Collection<CommonSourceTableDocument>;
17
+ }
18
+
19
+ async initializeStreamStorage(_replicationStreamId: number): Promise<void> {}
20
+
21
+ get bucketDataV1(): mongo.Collection<BucketDataDocumentV1> {
22
+ return this.upstream.bucket_data;
23
+ }
24
+
25
+ get parameterIndexV1(): mongo.Collection<BucketParameterDocument> {
26
+ return this.upstream.bucket_parameters;
27
+ }
28
+ }
@@ -0,0 +1,84 @@
1
+ import * as bson from 'bson';
2
+ import { BucketDataDoc } from '../common/BucketDataDoc.js';
3
+ import {
4
+ BucketDataDocumentBase,
5
+ BucketParameterDocumentBase,
6
+ BucketStateDocumentBase,
7
+ CurrentBucket,
8
+ LEGACY_BUCKET_DATA_DEFINITION_ID,
9
+ SourceKey,
10
+ SourceTableDocument,
11
+ TaggedBucketParameterDocument
12
+ } from '../models.js';
13
+
14
+ export interface BucketDataKeyV1 {
15
+ /** group_id */
16
+ g: number;
17
+ /** bucket name */
18
+ b: string;
19
+ /** op_id */
20
+ o: bigint;
21
+ }
22
+
23
+ export interface CurrentDataDocument {
24
+ _id: SourceKey;
25
+ data: bson.Binary;
26
+ buckets: CurrentBucket[];
27
+ lookups: bson.Binary[];
28
+ }
29
+
30
+ export interface BucketParameterDocument extends BucketParameterDocumentBase<SourceKey> {}
31
+
32
+ export interface BucketDataDocumentV1 extends BucketDataDocumentBase {
33
+ _id: BucketDataKeyV1;
34
+ }
35
+
36
+ export function serializeBucketDataV1(document: BucketDataDoc): BucketDataDocumentV1 {
37
+ const { bucketKey, o } = document;
38
+ return {
39
+ _id: {
40
+ g: bucketKey.replicationStreamId,
41
+ b: bucketKey.bucket,
42
+ o: o
43
+ },
44
+ // List fields directly, so that we don't accidentally persist any unknown fields
45
+ op: document.op,
46
+ source_table: document.source_table,
47
+ source_key: document.source_key,
48
+ table: document.table,
49
+ row_id: document.row_id,
50
+ checksum: document.checksum,
51
+ data: document.data,
52
+ target_op: document.target_op
53
+ };
54
+ }
55
+
56
+ export function loadBucketDataDocumentV1(doc: BucketDataDocumentV1): BucketDataDoc {
57
+ const { _id, ...rest } = doc;
58
+ return {
59
+ bucketKey: {
60
+ replicationStreamId: _id.g,
61
+ definitionId: LEGACY_BUCKET_DATA_DEFINITION_ID,
62
+ bucket: _id.b
63
+ },
64
+ o: _id.o,
65
+ ...rest
66
+ };
67
+ }
68
+
69
+ export function taggedBucketParameterDocumentToV1(document: TaggedBucketParameterDocument): BucketParameterDocument {
70
+ const { index: _index, ...rest } = document;
71
+ return rest as BucketParameterDocument;
72
+ }
73
+
74
+ export interface SourceTableDocumentV1 extends SourceTableDocument {
75
+ group_id: number;
76
+ }
77
+
78
+ export interface BucketStateDocumentV1 extends BucketStateDocumentBase {
79
+ _id: BucketStateDocumentBase['_id'] & {
80
+ g: number;
81
+ };
82
+ }
83
+
84
+ export type BucketStateDocument = BucketStateDocumentV1;
@@ -0,0 +1,44 @@
1
+ import * as lib_mongo from '@powersync/lib-service-mongodb';
2
+ import { storage } from '@powersync/service-core';
3
+ import { mongoTableId } from '../../../utils/util.js';
4
+ import { MongoBucketBatch, MongoBucketBatchOptions } from '../MongoBucketBatch.js';
5
+ import { PersistedBatch } from '../common/PersistedBatch.js';
6
+ import { SourceRecordStore } from '../common/SourceRecordStore.js';
7
+ import { PersistedBatchV3 } from './PersistedBatchV3.js';
8
+ import { SourceRecordStoreV3 } from './SourceRecordStoreV3.js';
9
+ import { VersionedPowerSyncMongoV3 } from './VersionedPowerSyncMongoV3.js';
10
+
11
+ export class MongoBucketBatchV3 extends MongoBucketBatch {
12
+ declare public readonly db: VersionedPowerSyncMongoV3;
13
+
14
+ private readonly store: SourceRecordStore;
15
+
16
+ constructor(options: MongoBucketBatchOptions) {
17
+ super(options);
18
+ this.store = new SourceRecordStoreV3(this.db, this.group_id, this.mapping);
19
+ }
20
+
21
+ protected createPersistedBatch(writtenSize: number): PersistedBatch {
22
+ return new PersistedBatchV3(this.db, this.group_id, this.mapping, writtenSize, {
23
+ logger: this.logger
24
+ });
25
+ }
26
+
27
+ protected get sourceRecordStore(): SourceRecordStore {
28
+ return this.store;
29
+ }
30
+
31
+ protected async cleanupDroppedSourceTables(sourceTables: storage.SourceTable[]) {
32
+ for (const table of sourceTables) {
33
+ await this.db
34
+ .sourceRecordsV3(this.group_id, mongoTableId(table.id))
35
+ .drop()
36
+ .catch((error) => {
37
+ if (lib_mongo.isMongoServerError(error) && error.codeName === 'NamespaceNotFound') {
38
+ return;
39
+ }
40
+ throw error;
41
+ });
42
+ }
43
+ }
44
+ }