@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,112 @@
1
+ import { mongo } from '@powersync/lib-service-mongodb';
2
+ import { BucketDefinitionId, ParameterIndexId } from '../BucketDefinitionMapping.js';
3
+ import { BaseVersionedPowerSyncMongo } from '../common/VersionedPowerSyncMongoBase.js';
4
+ import { CommonSourceTableDocument } from '../models.js';
5
+ import {
6
+ BucketDataDocumentV3,
7
+ BucketParameterDocumentV3,
8
+ BucketStateDocumentV3,
9
+ CurrentDataDocumentV3,
10
+ SourceTableDocumentV3
11
+ } from './models.js';
12
+
13
+ export class VersionedPowerSyncMongoV3 extends BaseVersionedPowerSyncMongo {
14
+ sourceRecordsV3(replicationStreamId: number, sourceTableId: mongo.ObjectId): mongo.Collection<CurrentDataDocumentV3> {
15
+ const collectionName = this.sourceRecordsCollectionName(replicationStreamId, sourceTableId);
16
+ return this.db.collection<CurrentDataDocumentV3>(collectionName);
17
+ }
18
+
19
+ async listSourceRecordCollectionsV3(replicationStreamId: number): Promise<mongo.Collection<CurrentDataDocumentV3>[]> {
20
+ return this.listCollectionsByPrefix<CurrentDataDocumentV3>(`source_records_${replicationStreamId}_`);
21
+ }
22
+
23
+ async initializeSourceRecordsCollection(replicationStreamId: number, sourceTableId: mongo.ObjectId) {
24
+ await this.sourceRecordsV3(replicationStreamId, sourceTableId).createIndex(
25
+ {
26
+ pending_delete: 1
27
+ },
28
+ {
29
+ partialFilterExpression: { pending_delete: { $exists: true } },
30
+ name: 'pending_delete'
31
+ }
32
+ );
33
+ }
34
+
35
+ commonSourceTables(replicationStreamId: number): mongo.Collection<CommonSourceTableDocument> {
36
+ return this.sourceTablesV3(replicationStreamId) as mongo.Collection<CommonSourceTableDocument>;
37
+ }
38
+
39
+ bucketStateV3(replicationStreamId: number): mongo.Collection<BucketStateDocumentV3> {
40
+ return this.db.collection(`bucket_state_${replicationStreamId}`);
41
+ }
42
+
43
+ parameterIndexV3(
44
+ replicationStreamId: number,
45
+ indexId: ParameterIndexId
46
+ ): mongo.Collection<BucketParameterDocumentV3> {
47
+ return this.db.collection(`parameter_index_${replicationStreamId}_${indexId}`);
48
+ }
49
+
50
+ sourceTablesV3(replicationStreamId: number): mongo.Collection<SourceTableDocumentV3> {
51
+ return this.db.collection<SourceTableDocumentV3>(this.sourceTableCollectionName(replicationStreamId));
52
+ }
53
+
54
+ async initializeStreamStorage(replicationStreamId: number) {
55
+ const sourceTables = this.sourceTablesV3(replicationStreamId);
56
+ const bucketState = this.bucketStateV3(replicationStreamId);
57
+ await sourceTables.createIndex(
58
+ {
59
+ connection_id: 1,
60
+ schema_name: 1,
61
+ table_name: 1,
62
+ relation_id: 1
63
+ },
64
+ {
65
+ name: 'source_lookup'
66
+ }
67
+ );
68
+ await sourceTables.createIndex(
69
+ {
70
+ latest_pending_delete: 1
71
+ },
72
+ {
73
+ partialFilterExpression: { latest_pending_delete: { $exists: true } },
74
+ name: 'latest_pending_delete'
75
+ }
76
+ );
77
+ await bucketState.createIndex(
78
+ {
79
+ last_op: 1
80
+ },
81
+ { name: 'bucket_updates', unique: true }
82
+ );
83
+ await bucketState.createIndex(
84
+ {
85
+ 'estimate_since_compact.count': -1
86
+ },
87
+ { name: 'dirty_count' }
88
+ );
89
+ }
90
+
91
+ bucketDataV3(replicationStreamId: number, definitionId: BucketDefinitionId) {
92
+ return this.db.collection<BucketDataDocumentV3>(`bucket_data_${replicationStreamId}_${definitionId}`);
93
+ }
94
+
95
+ listBucketDataCollectionsV3(replicationStreamId: number) {
96
+ return this.upstream.listBucketDataCollectionsV3(replicationStreamId);
97
+ }
98
+
99
+ async listParameterIndexCollectionsV3(
100
+ replicationStreamId: number
101
+ ): Promise<{ collection: mongo.Collection<BucketParameterDocumentV3>; indexId: ParameterIndexId }[]> {
102
+ const prefix = `parameter_index_${replicationStreamId}_`;
103
+ const collections = await this.db.listCollections({ name: new RegExp(`^${prefix}`) }, { nameOnly: true }).toArray();
104
+
105
+ return collections
106
+ .filter((collection) => collection.name.startsWith(prefix))
107
+ .map((collection) => ({
108
+ collection: this.db.collection<BucketParameterDocumentV3>(collection.name),
109
+ indexId: collection.name.slice(prefix.length)
110
+ }));
111
+ }
112
+ }
@@ -0,0 +1,96 @@
1
+ import { InternalOpId } from '@powersync/service-core';
2
+ import * as bson from 'bson';
3
+ import { BucketDefinitionId, ParameterIndexId } from '../BucketDefinitionMapping.js';
4
+ import { BucketDataDoc, BucketKey } from '../common/BucketDataDoc.js';
5
+ import {
6
+ BucketDataDocumentBase,
7
+ BucketDataKey,
8
+ BucketParameterDocumentBase,
9
+ BucketStateDocumentBase,
10
+ CurrentBucket,
11
+ ReplicaId,
12
+ SourceTableDocument,
13
+ SourceTableKey,
14
+ TaggedBucketParameterDocument
15
+ } from '../models.js';
16
+
17
+ export interface CurrentBucketV3 extends CurrentBucket {
18
+ def: BucketDefinitionId;
19
+ }
20
+
21
+ export interface RecordedLookupV3 {
22
+ i: ParameterIndexId;
23
+ l: bson.Binary;
24
+ }
25
+
26
+ export interface CurrentDataDocumentV3 {
27
+ _id: ReplicaId;
28
+ data: bson.Binary | null;
29
+ buckets: CurrentBucketV3[];
30
+ lookups: RecordedLookupV3[];
31
+ /**
32
+ * If set, this can be deleted, once there is a consistent checkpoint >= pending_delete.
33
+ *
34
+ * This must only be set if buckets = [], lookups = [].
35
+ */
36
+ pending_delete?: bigint;
37
+ }
38
+
39
+ export interface BucketParameterDocumentV3 extends BucketParameterDocumentBase<SourceTableKey> {}
40
+
41
+ export type BucketDataKeyV3 = BucketDataKey;
42
+
43
+ export interface BucketDataDocumentV3 extends BucketDataDocumentBase {
44
+ _id: BucketDataKeyV3;
45
+ }
46
+
47
+ export function serializeBucketDataV3(document: BucketDataDoc): BucketDataDocumentV3 {
48
+ const { bucketKey, o } = document;
49
+ return {
50
+ _id: {
51
+ b: bucketKey.bucket,
52
+ o: o
53
+ },
54
+ // List fields directly, so that we don't accidentally persist any unknown fields
55
+ op: document.op,
56
+ source_table: document.source_table,
57
+ source_key: document.source_key,
58
+ table: document.table,
59
+ row_id: document.row_id,
60
+ checksum: document.checksum,
61
+ data: document.data,
62
+ target_op: document.target_op
63
+ };
64
+ }
65
+
66
+ export function loadBucketDataDocumentV3(
67
+ context: Pick<BucketKey, 'replicationStreamId' | 'definitionId'>,
68
+ doc: BucketDataDocumentV3
69
+ ): BucketDataDoc {
70
+ const { _id, ...rest } = doc;
71
+ return {
72
+ bucketKey: {
73
+ ...context,
74
+ bucket: _id.b
75
+ },
76
+ o: _id.o,
77
+ ...rest
78
+ };
79
+ }
80
+
81
+ export function taggedBucketParameterDocumentToV3(document: TaggedBucketParameterDocument): BucketParameterDocumentV3 {
82
+ const { index: _index, ...rest } = document;
83
+ return rest as BucketParameterDocumentV3;
84
+ }
85
+
86
+ export interface SourceTableDocumentV3 extends SourceTableDocument {
87
+ bucket_data_source_ids: BucketDefinitionId[];
88
+ parameter_lookup_source_ids: ParameterIndexId[];
89
+ latest_pending_delete?: InternalOpId | undefined;
90
+ }
91
+
92
+ export interface BucketStateDocumentV3 extends BucketStateDocumentBase {
93
+ _id: BucketStateDocumentBase['_id'] & {
94
+ d: BucketDefinitionId;
95
+ };
96
+ }
@@ -1,14 +1,17 @@
1
1
  export * as test_utils from '../utils/test-utils.js';
2
2
  export * from '../utils/util.js';
3
+ export * from './implementation/BucketDefinitionMapping.js';
4
+ export * from './implementation/common/PersistedBatch.js';
5
+ export * from './implementation/createMongoSyncBucketStorage.js';
3
6
  export * from './implementation/db.js';
4
7
  export * from './implementation/models.js';
5
- export * from './implementation/MongoBucketBatch.js';
6
8
  export * from './implementation/MongoIdSequence.js';
9
+ export * from './implementation/MongoPersistedSyncRules.js';
7
10
  export * from './implementation/MongoPersistedSyncRulesContent.js';
8
11
  export * from './implementation/MongoStorageProvider.js';
9
- export * from './implementation/MongoSyncBucketStorage.js';
10
12
  export * from './implementation/MongoSyncRulesLock.js';
11
13
  export * from './implementation/OperationBatch.js';
12
- export * from './implementation/PersistedBatch.js';
14
+ export * from './implementation/v1/models.js';
15
+ export * from './implementation/v3/models.js';
13
16
  export * from './MongoBucketStorage.js';
14
17
  export * from './MongoReportStorage.js';
package/src/utils/util.ts CHANGED
@@ -1,10 +1,12 @@
1
+ import * as lib_mongo from '@powersync/lib-service-mongodb';
1
2
  import { mongo } from '@powersync/lib-service-mongodb';
2
- import { ServiceAssertionError } from '@powersync/lib-services-framework';
3
+ import { ReplicationAbortedError, ServiceAssertionError } from '@powersync/lib-services-framework';
3
4
  import { storage, utils } from '@powersync/service-core';
4
5
  import * as bson from 'bson';
5
6
  import * as crypto from 'crypto';
7
+ import * as timers from 'node:timers/promises';
6
8
  import * as uuid from 'uuid';
7
- import { BucketDataDocument } from '../storage/implementation/models.js';
9
+ import { BucketDataDoc } from '../storage/implementation/common/BucketDataDoc.js';
8
10
 
9
11
  export function idPrefixFilter<T>(prefix: Partial<T>, rest: (keyof T)[]): mongo.Condition<T> {
10
12
  let filter = {
@@ -69,10 +71,10 @@ export async function readSingleBatch<T>(cursor: mongo.AbstractCursor<T>): Promi
69
71
  }
70
72
  }
71
73
 
72
- export function mapOpEntry(row: BucketDataDocument): utils.OplogEntry {
74
+ export function mapOpEntry(row: BucketDataDoc): utils.OplogEntry {
73
75
  if (row.op == 'PUT' || row.op == 'REMOVE') {
74
76
  return {
75
- op_id: utils.internalToExternalOpId(row._id.o),
77
+ op_id: utils.internalToExternalOpId(row.o),
76
78
  op: row.op,
77
79
  object_type: row.table,
78
80
  object_id: row.row_id,
@@ -84,7 +86,7 @@ export function mapOpEntry(row: BucketDataDocument): utils.OplogEntry {
84
86
  // MOVE, CLEAR
85
87
 
86
88
  return {
87
- op_id: utils.internalToExternalOpId(row._id.o),
89
+ op_id: utils.internalToExternalOpId(row.o),
88
90
  op: row.op,
89
91
  checksum: Number(row.checksum)
90
92
  };
@@ -129,6 +131,33 @@ export function setSessionSnapshotTime(session: mongo.ClientSession, time: bson.
129
131
  }
130
132
  }
131
133
 
134
+ export async function retryOnMongoMaxTimeMSExpired<T>(
135
+ operation: () => Promise<T>,
136
+ options: {
137
+ signal?: AbortSignal;
138
+ abortMessage?: string;
139
+ retryDelayMs: number;
140
+ onRetry?: (retryCount: number) => void;
141
+ }
142
+ ): Promise<T> {
143
+ let retryCount = 0;
144
+ while (true) {
145
+ if (options.signal?.aborted) {
146
+ throw new ReplicationAbortedError(options.abortMessage ?? 'Aborted MongoDB operation', options.signal.reason);
147
+ }
148
+ try {
149
+ return await operation();
150
+ } catch (e) {
151
+ if (!lib_mongo.isMongoServerError(e) || e.codeName !== 'MaxTimeMSExpired') {
152
+ throw e;
153
+ }
154
+ retryCount += 1;
155
+ options.onRetry?.(retryCount);
156
+ await timers.setTimeout(options.retryDelayMs);
157
+ }
158
+ }
159
+ }
160
+
132
161
  export const createPaginatedConnectionQuery = async <T extends mongo.Document>(
133
162
  query: mongo.Filter<T>,
134
163
  collection: mongo.Collection<T>,
@@ -1,7 +1,7 @@
1
+ import { VersionedPowerSyncMongoV3 } from '@module/storage/implementation/v3/VersionedPowerSyncMongoV3.js';
1
2
  import { storage, SyncRulesBucketStorage, updateSyncRulesFromYaml } from '@powersync/service-core';
2
3
  import { bucketRequest, register, test_utils } from '@powersync/service-core-tests';
3
4
  import { describe, expect, test } from 'vitest';
4
- import { MongoCompactor } from '../../src/storage/implementation/MongoCompactor.js';
5
5
  import { INITIALIZED_MONGO_STORAGE_FACTORY } from './util.js';
6
6
 
7
7
  describe('Mongo Sync Bucket Storage Compact', () => {
@@ -64,9 +64,16 @@ bucket_definitions:
64
64
 
65
65
  test('full compact', async () => {
66
66
  const { bucketStorage, checkpoint, factory, syncRules } = await setup();
67
+ const storageDb = bucketStorage.db;
67
68
 
68
69
  // Simulate bucket_state from old version not being available
69
- await factory.db.bucket_state.deleteMany({});
70
+ if (storageDb.storageConfig.incrementalReprocessing) {
71
+ // This should actually never happen on V3, but we test this anyway.
72
+ // Can remove this if it causes issues in the future.
73
+ await (storageDb as VersionedPowerSyncMongoV3).bucketStateV3(bucketStorage.group_id).deleteMany({});
74
+ } else {
75
+ await factory.db.bucket_state.deleteMany({});
76
+ }
70
77
 
71
78
  await bucketStorage.compact({
72
79
  clearBatchLimit: 200,
@@ -95,10 +102,10 @@ bucket_definitions:
95
102
  });
96
103
 
97
104
  test('populatePersistentChecksumCache', async () => {
98
- // Populate old sync rules version
105
+ // Populate old replication stream
99
106
  const { factory } = await setup();
100
107
 
101
- // Now populate another version (bucket definition name changed)
108
+ // Now populate another replication stream (bucket definition name changed)
102
109
  const syncRules = await factory.updateSyncRules(
103
110
  updateSyncRulesFromYaml(`
104
111
  bucket_definitions:
@@ -108,6 +115,7 @@ bucket_definitions:
108
115
  `)
109
116
  );
110
117
  const bucketStorage = factory.getInstance(syncRules);
118
+ const storageDb = (bucketStorage as any).db;
111
119
 
112
120
  await populate(bucketStorage, 2);
113
121
  const { checkpoint } = await bucketStorage.getCheckpoint();
@@ -158,35 +166,54 @@ bucket_definitions:
158
166
  `)
159
167
  );
160
168
  const bucketStorage = factory.getInstance(syncRules);
169
+ const storageDb = bucketStorage.db;
161
170
 
162
171
  // This simulates bucket_state created using bigint bytes.
163
172
  // This typically happens when buckets get very large (> 2GiB). We don't want to create that much
164
173
  // data in the tests, so we directly insert the bucket_state here.
165
- await factory.db.bucket_state.insertOne({
166
- _id: {
167
- g: bucketStorage.group_id,
168
- b: 'global[]'
169
- },
170
- last_op: 5n,
171
- compacted_state: {
172
- op_id: 3n,
173
- count: 3,
174
- checksum: 0n,
175
- bytes: 7n
176
- },
177
- estimate_since_compact: {
178
- count: 2,
179
- bytes: 5n
180
- }
181
- });
182
-
183
- // This test uses a couple of internal APIs of the compactor - there is no simple way
184
- // to test this using the current public APIs.
185
- const compactor = new MongoCompactor(bucketStorage, (bucketStorage as any).db, {
186
- maxOpId: 5n
187
- });
188
-
189
- const dirtyBuckets = (compactor as any).dirtyBucketBatches({
174
+ if (storageDb.storageConfig.incrementalReprocessing) {
175
+ const bucketStateCollection = (storageDb as VersionedPowerSyncMongoV3).bucketStateV3(bucketStorage.group_id);
176
+ await bucketStateCollection.insertOne({
177
+ _id: {
178
+ d: '1',
179
+ b: 'global[]'
180
+ },
181
+ last_op: 5n,
182
+ compacted_state: {
183
+ op_id: 3n,
184
+ count: 3,
185
+ checksum: 0n,
186
+ bytes: 7n
187
+ },
188
+ estimate_since_compact: {
189
+ count: 2,
190
+ bytes: 5n
191
+ }
192
+ });
193
+ } else {
194
+ await factory.db.bucket_state.insertOne({
195
+ _id: {
196
+ g: bucketStorage.group_id,
197
+ b: 'global[]'
198
+ },
199
+ last_op: 5n,
200
+ compacted_state: {
201
+ op_id: 3n,
202
+ count: 3,
203
+ checksum: 0n,
204
+ bytes: 7n
205
+ },
206
+ estimate_since_compact: {
207
+ count: 2,
208
+ bytes: 5n
209
+ }
210
+ });
211
+ }
212
+
213
+ // This test uses a couple of "internal" APIs of the compactor.
214
+ const compactor = bucketStorage.createMongoCompactor({ maxOpId: 5n });
215
+
216
+ const dirtyBuckets = compactor.dirtyBucketBatches({
190
217
  minBucketChanges: 1,
191
218
  minChangeRatio: 0.39
192
219
  });
@@ -205,6 +232,7 @@ bucket_definitions:
205
232
  expect(checksumBuckets).toEqual([
206
233
  {
207
234
  bucket: 'global[]',
235
+ definitionId: storageDb.storageConfig.incrementalReprocessing ? '1' : null,
208
236
  estimatedCount: 5
209
237
  }
210
238
  ]);