@powersync/service-module-mongodb 0.10.4 → 0.12.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.
@@ -1,6 +1,7 @@
1
1
  import { mongo } from '@powersync/lib-service-mongodb';
2
2
  import { storage } from '@powersync/service-core';
3
- import { JSONBig, JsonContainer } from '@powersync/service-jsonbig';
3
+ import { JsonContainer } from '@powersync/service-jsonbig';
4
+ import { CustomArray, CustomObject, CustomSqliteValue, DateTimeValue } from '@powersync/service-sync-rules';
4
5
  import { ErrorCode, ServiceError } from '@powersync/lib-services-framework';
5
6
  import { MongoLSN } from '../common/MongoLSN.js';
6
7
  import { CHECKPOINTS_COLLECTION } from './replication-utils.js';
@@ -10,7 +11,7 @@ export function getMongoRelation(source) {
10
11
  schema: source.db,
11
12
  // Not relevant for MongoDB - we use db + coll name as the identifier
12
13
  objectId: undefined,
13
- replicationColumns: [{ name: '_id' }]
14
+ replicaIdColumns: [{ name: '_id' }]
14
15
  };
15
16
  }
16
17
  /**
@@ -18,7 +19,7 @@ export function getMongoRelation(source) {
18
19
  */
19
20
  export function getCacheIdentifier(source) {
20
21
  if (source instanceof storage.SourceTable) {
21
- return `${source.schema}.${source.table}`;
22
+ return `${source.schema}.${source.name}`;
22
23
  }
23
24
  return `${source.schema}.${source.name}`;
24
25
  }
@@ -63,7 +64,8 @@ export function toMongoSyncRulesValue(data) {
63
64
  return data.toHexString();
64
65
  }
65
66
  else if (data instanceof Date) {
66
- return data.toISOString().replace('T', ' ');
67
+ const isoString = data.toISOString();
68
+ return new DateTimeValue(isoString);
67
69
  }
68
70
  else if (data instanceof mongo.Binary) {
69
71
  return new Uint8Array(data.buffer);
@@ -81,8 +83,7 @@ export function toMongoSyncRulesValue(data) {
81
83
  return JSON.stringify({ pattern: data.source, options: data.flags });
82
84
  }
83
85
  else if (Array.isArray(data)) {
84
- // We may be able to avoid some parse + stringify cycles here for JsonSqliteContainer.
85
- return JSONBig.stringify(data.map((element) => filterJsonData(element)));
86
+ return new CustomArray(data, filterJsonData);
86
87
  }
87
88
  else if (data instanceof Uint8Array) {
88
89
  return data;
@@ -91,18 +92,14 @@ export function toMongoSyncRulesValue(data) {
91
92
  return data.toString();
92
93
  }
93
94
  else if (typeof data == 'object') {
94
- let record = {};
95
- for (let key of Object.keys(data)) {
96
- record[key] = filterJsonData(data[key]);
97
- }
98
- return JSONBig.stringify(record);
95
+ return new CustomObject(data, filterJsonData);
99
96
  }
100
97
  else {
101
98
  return null;
102
99
  }
103
100
  }
104
101
  const DEPTH_LIMIT = 20;
105
- function filterJsonData(data, depth = 0) {
102
+ function filterJsonData(data, context, depth = 0) {
106
103
  const autoBigNum = true;
107
104
  if (depth > DEPTH_LIMIT) {
108
105
  // This is primarily to prevent infinite recursion
@@ -135,7 +132,8 @@ function filterJsonData(data, depth = 0) {
135
132
  return data;
136
133
  }
137
134
  else if (data instanceof Date) {
138
- return data.toISOString().replace('T', ' ');
135
+ const isoString = data.toISOString();
136
+ return new DateTimeValue(isoString).toSqliteValue(context);
139
137
  }
140
138
  else if (data instanceof mongo.ObjectId) {
141
139
  return data.toHexString();
@@ -159,11 +157,14 @@ function filterJsonData(data, depth = 0) {
159
157
  return { pattern: data.source, options: data.flags };
160
158
  }
161
159
  else if (Array.isArray(data)) {
162
- return data.map((element) => filterJsonData(element, depth + 1));
160
+ return data.map((element) => filterJsonData(element, context, depth + 1));
163
161
  }
164
162
  else if (ArrayBuffer.isView(data)) {
165
163
  return undefined;
166
164
  }
165
+ else if (data instanceof CustomSqliteValue) {
166
+ return data.toSqliteValue(context);
167
+ }
167
168
  else if (data instanceof JsonContainer) {
168
169
  // Can be stringified directly when using our JSONBig implementation
169
170
  return data;
@@ -171,7 +172,7 @@ function filterJsonData(data, depth = 0) {
171
172
  else if (typeof data == 'object') {
172
173
  let record = {};
173
174
  for (let key of Object.keys(data)) {
174
- record[key] = filterJsonData(data[key], depth + 1);
175
+ record[key] = filterJsonData(data[key], context, depth + 1);
175
176
  }
176
177
  return record;
177
178
  }
@@ -1 +1 @@
1
- {"version":3,"file":"MongoRelation.js","sourceRoot":"","sources":["../../src/replication/MongoRelation.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"MongoRelation.js","sourceRoot":"","sources":["../../src/replication/MongoRelation.ts"],"names":[],"mappings":"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"}
@@ -32,17 +32,17 @@ export async function checkSourceConfiguration(connectionManager) {
32
32
  const missingCheckpointActions = REQUIRED_CHECKPOINT_PERMISSIONS.filter((action) => !checkpointsActions.has(action));
33
33
  if (missingCheckpointActions.length > 0) {
34
34
  const fullName = `${db.databaseName}.${CHECKPOINTS_COLLECTION}`;
35
- throw new ServiceError(ErrorCode.PSYNC_S1307, `MongoDB user does not have the required ${missingCheckpointActions.map((a) => `"${a}"`).join(', ')} priviledge(s) on "${fullName}".`);
35
+ throw new ServiceError(ErrorCode.PSYNC_S1307, `MongoDB user does not have the required ${missingCheckpointActions.map((a) => `"${a}"`).join(', ')} privilege(s) on "${fullName}".`);
36
36
  }
37
37
  if (connectionManager.options.postImages == PostImagesOption.AUTO_CONFIGURE) {
38
38
  // This checks that we have collMod on _any_ collection in the db.
39
39
  // This is not a complete check, but does give a basic sanity-check for testing the connection.
40
40
  if (!anyCollectionActions.has('collMod')) {
41
- throw new ServiceError(ErrorCode.PSYNC_S1307, `MongoDB user does not have the required "collMod" priviledge on "${db.databaseName}", required for "post_images: auto_configure".`);
41
+ throw new ServiceError(ErrorCode.PSYNC_S1307, `MongoDB user does not have the required "collMod" privilege on "${db.databaseName}", required for "post_images: auto_configure".`);
42
42
  }
43
43
  }
44
44
  if (!anyCollectionActions.has('listCollections')) {
45
- throw new ServiceError(ErrorCode.PSYNC_S1307, `MongoDB user does not have the required "listCollections" priviledge on "${db.databaseName}".`);
45
+ throw new ServiceError(ErrorCode.PSYNC_S1307, `MongoDB user does not have the required "listCollections" privilege on "${db.databaseName}".`);
46
46
  }
47
47
  }
48
48
  else {
@@ -1 +1 @@
1
- {"version":3,"file":"replication-utils.js","sourceRoot":"","sources":["../../src/replication/replication-utils.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"replication-utils.js","sourceRoot":"","sources":["../../src/replication/replication-utils.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -2,9 +2,9 @@
2
2
  "name": "@powersync/service-module-mongodb",
3
3
  "repository": "https://github.com/powersync-ja/powersync-service",
4
4
  "types": "dist/index.d.ts",
5
- "version": "0.10.4",
5
+ "version": "0.12.0",
6
6
  "main": "dist/index.js",
7
- "license": "FSL-1.1-Apache-2.0",
7
+ "license": "FSL-1.1-ALv2",
8
8
  "type": "module",
9
9
  "publishConfig": {
10
10
  "access": "public"
@@ -25,17 +25,17 @@
25
25
  "bson": "^6.10.3",
26
26
  "ts-codec": "^1.3.0",
27
27
  "uuid": "^11.1.0",
28
- "@powersync/lib-service-mongodb": "0.6.2",
29
- "@powersync/lib-services-framework": "0.7.1",
30
- "@powersync/service-core": "1.13.4",
31
- "@powersync/service-jsonbig": "0.17.10",
32
- "@powersync/service-sync-rules": "0.27.0",
33
- "@powersync/service-types": "0.12.1"
28
+ "@powersync/lib-service-mongodb": "0.6.4",
29
+ "@powersync/lib-services-framework": "0.7.3",
30
+ "@powersync/service-core": "1.15.0",
31
+ "@powersync/service-jsonbig": "0.17.11",
32
+ "@powersync/service-sync-rules": "0.29.0",
33
+ "@powersync/service-types": "0.13.0"
34
34
  },
35
35
  "devDependencies": {
36
- "@powersync/service-core-tests": "0.10.4",
37
- "@powersync/service-module-mongodb-storage": "0.10.4",
38
- "@powersync/service-module-postgres-storage": "0.8.4"
36
+ "@powersync/service-core-tests": "0.12.0",
37
+ "@powersync/service-module-mongodb-storage": "0.12.0",
38
+ "@powersync/service-module-postgres-storage": "0.10.0"
39
39
  },
40
40
  "scripts": {
41
41
  "build": "tsc -b",
@@ -5,7 +5,7 @@ import * as sync_rules from '@powersync/service-sync-rules';
5
5
  import * as service_types from '@powersync/service-types';
6
6
 
7
7
  import { MongoManager } from '../replication/MongoManager.js';
8
- import { constructAfterRecord, createCheckpoint, STANDALONE_CHECKPOINT_ID } from '../replication/MongoRelation.js';
8
+ import { constructAfterRecord, STANDALONE_CHECKPOINT_ID } from '../replication/MongoRelation.js';
9
9
  import { CHECKPOINTS_COLLECTION } from '../replication/replication-utils.js';
10
10
  import * as types from '../types/types.js';
11
11
  import { escapeRegExp } from '../utils.js';
@@ -137,15 +137,15 @@ export class MongoRouteAPIAdapter implements api.RouteAPI {
137
137
  if (tablePattern.isWildcard) {
138
138
  patternResult.tables = [];
139
139
  for (let collection of collections) {
140
- const sourceTable = new SourceTable(
141
- 0,
142
- this.connectionTag,
143
- collection.name,
144
- schema,
145
- collection.name,
146
- [],
147
- true
148
- );
140
+ const sourceTable = new SourceTable({
141
+ id: 0,
142
+ connectionTag: this.connectionTag,
143
+ objectId: collection.name,
144
+ schema: schema,
145
+ name: collection.name,
146
+ replicaIdColumns: [],
147
+ snapshotComplete: true
148
+ });
149
149
  let errors: service_types.ReplicationError[] = [];
150
150
  if (collection.type == 'view') {
151
151
  errors.push({ level: 'warning', message: `Collection ${schema}.${tablePattern.name} is a view` });
@@ -164,15 +164,15 @@ export class MongoRouteAPIAdapter implements api.RouteAPI {
164
164
  });
165
165
  }
166
166
  } else {
167
- const sourceTable = new SourceTable(
168
- 0,
169
- this.connectionTag,
170
- tablePattern.name,
171
- schema,
172
- tablePattern.name,
173
- [],
174
- true
175
- );
167
+ const sourceTable = new SourceTable({
168
+ id: 0,
169
+ connectionTag: this.connectionTag,
170
+ objectId: tablePattern.name,
171
+ schema: schema,
172
+ name: tablePattern.name,
173
+ replicaIdColumns: [],
174
+ snapshotComplete: true
175
+ });
176
176
 
177
177
  const syncData = sqlSyncRules.tableSyncsData(sourceTable);
178
178
  const syncParameters = sqlSyncRules.tableSyncsParameters(sourceTable);
@@ -10,6 +10,7 @@ import {
10
10
  ServiceError
11
11
  } from '@powersync/lib-services-framework';
12
12
  import {
13
+ InternalOpId,
13
14
  MetricsEngine,
14
15
  RelationCache,
15
16
  SaveOperationTag,
@@ -17,7 +18,7 @@ import {
17
18
  SourceTable,
18
19
  storage
19
20
  } from '@powersync/service-core';
20
- import { DatabaseInputRow, SqliteRow, SqlSyncRules, TablePattern } from '@powersync/service-sync-rules';
21
+ import { DatabaseInputRow, SqliteInputRow, SqliteRow, SqlSyncRules, TablePattern } from '@powersync/service-sync-rules';
21
22
  import { ReplicationMetric } from '@powersync/service-types';
22
23
  import { MongoLSN } from '../common/MongoLSN.js';
23
24
  import { PostImagesOption } from '../types/types.js';
@@ -215,9 +216,14 @@ export class ChangeStream {
215
216
 
216
217
  async estimatedCountNumber(table: storage.SourceTable): Promise<number> {
217
218
  const db = this.client.db(table.schema);
218
- return await db.collection(table.table).estimatedDocumentCount();
219
+ return await db.collection(table.name).estimatedDocumentCount();
219
220
  }
220
221
 
222
+ /**
223
+ * This gets a LSN before starting a snapshot, which we can resume streaming from after the snapshot.
224
+ *
225
+ * This LSN can survive initial replication restarts.
226
+ */
221
227
  private async getSnapshotLsn(): Promise<string> {
222
228
  const hello = await this.defaultDb.command({ hello: 1 });
223
229
  // Basic sanity check
@@ -292,6 +298,9 @@ export class ChangeStream {
292
298
  );
293
299
  }
294
300
 
301
+ /**
302
+ * Given a snapshot LSN, validate that we can read from it, by opening a change stream.
303
+ */
295
304
  private async validateSnapshotLsn(lsn: string) {
296
305
  await using streamManager = this.openChangeStream({ lsn: lsn, maxAwaitTimeMs: 0 });
297
306
  const { stream } = streamManager;
@@ -309,7 +318,7 @@ export class ChangeStream {
309
318
  const sourceTables = this.sync_rules.getSourceTables();
310
319
  await this.client.connect();
311
320
 
312
- await this.storage.startBatch(
321
+ const flushResult = await this.storage.startBatch(
313
322
  {
314
323
  logger: this.logger,
315
324
  zeroLSN: MongoLSN.ZERO.comparable,
@@ -321,7 +330,7 @@ export class ChangeStream {
321
330
  if (snapshotLsn == null) {
322
331
  // First replication attempt - get a snapshot and store the timestamp
323
332
  snapshotLsn = await this.getSnapshotLsn();
324
- await batch.setSnapshotLsn(snapshotLsn);
333
+ await batch.setResumeLsn(snapshotLsn);
325
334
  this.logger.info(`Marking snapshot at ${snapshotLsn}`);
326
335
  } else {
327
336
  this.logger.info(`Resuming snapshot at ${snapshotLsn}`);
@@ -359,13 +368,23 @@ export class ChangeStream {
359
368
  await this.snapshotTable(batch, table);
360
369
  await batch.markSnapshotDone([table], MongoLSN.ZERO.comparable);
361
370
 
362
- await touch();
371
+ this.touch();
363
372
  }
364
373
 
365
- this.logger.info(`Snapshot commit at ${snapshotLsn}`);
374
+ // The checkpoint here is a marker - we need to replicate up to at least this
375
+ // point before the data can be considered consistent.
376
+ // We could do this for each individual table, but may as well just do it once for the entire snapshot.
377
+ const checkpoint = await createCheckpoint(this.client, this.defaultDb, STANDALONE_CHECKPOINT_ID);
378
+ await batch.markSnapshotDone([], checkpoint);
379
+
380
+ // This will not create a consistent checkpoint yet, but will persist the op.
381
+ // Actual checkpoint will be created when streaming replication caught up.
366
382
  await batch.commit(snapshotLsn);
383
+
384
+ this.logger.info(`Snapshot done. Need to replicate from ${snapshotLsn} to ${checkpoint} to be consistent`);
367
385
  }
368
386
  );
387
+ return { lastOpId: flushResult?.flushed_op };
369
388
  }
370
389
 
371
390
  private async setupCheckpointsCollection() {
@@ -422,7 +441,7 @@ export class ChangeStream {
422
441
  return { $match: { ns: { $in: $inFilters } }, multipleDatabases };
423
442
  }
424
443
 
425
- static *getQueryData(results: Iterable<DatabaseInputRow>): Generator<SqliteRow> {
444
+ static *getQueryData(results: Iterable<DatabaseInputRow>): Generator<SqliteInputRow> {
426
445
  for (let row of results) {
427
446
  yield constructAfterRecord(row);
428
447
  }
@@ -432,7 +451,7 @@ export class ChangeStream {
432
451
  const totalEstimatedCount = await this.estimatedCountNumber(table);
433
452
  let at = table.snapshotStatus?.replicatedCount ?? 0;
434
453
  const db = this.client.db(table.schema);
435
- const collection = db.collection(table.table);
454
+ const collection = db.collection(table.name);
436
455
  await using query = new ChunkedSnapshotQuery({
437
456
  collection,
438
457
  key: table.snapshotStatus?.lastKey,
@@ -492,7 +511,7 @@ export class ChangeStream {
492
511
  this.logger.info(
493
512
  `Replicating ${table.qualifiedName} ${table.formatSnapshotProgress()} in ${duration.toFixed(0)}ms`
494
513
  );
495
- await touch();
514
+ this.touch();
496
515
  }
497
516
  // In case the loop was interrupted, make sure we await the last promise.
498
517
  await nextChunkPromise;
@@ -656,7 +675,6 @@ export class ChangeStream {
656
675
  try {
657
676
  // If anything errors here, the entire replication process is halted, and
658
677
  // all connections automatically closed, including this one.
659
-
660
678
  await this.initReplication();
661
679
  await this.streamChanges();
662
680
  } catch (e) {
@@ -673,7 +691,15 @@ export class ChangeStream {
673
691
  // Snapshot LSN is not present, so we need to start replication from scratch.
674
692
  await this.storage.clear({ signal: this.abort_signal });
675
693
  }
676
- await this.initialReplication(result.snapshotLsn);
694
+ const { lastOpId } = await this.initialReplication(result.snapshotLsn);
695
+ if (lastOpId != null) {
696
+ // Populate the cache _after_ initial replication, but _before_ we switch to this sync rules.
697
+ await this.storage.populatePersistentChecksumCache({
698
+ signal: this.abort_signal,
699
+ // No checkpoint yet, but we do have the opId.
700
+ maxOpId: lastOpId
701
+ });
702
+ }
677
703
  }
678
704
  }
679
705
 
@@ -757,19 +783,20 @@ export class ChangeStream {
757
783
  }
758
784
 
759
785
  async streamChangesInternal() {
760
- // Auto-activate as soon as initial replication is done
761
- await this.storage.autoActivate();
762
-
763
786
  await this.storage.startBatch(
764
787
  {
765
788
  logger: this.logger,
766
789
  zeroLSN: MongoLSN.ZERO.comparable,
767
790
  defaultSchema: this.defaultDb.databaseName,
791
+ // We get a complete postimage for every change, so we don't need to store the current data.
768
792
  storeCurrentData: false
769
793
  },
770
794
  async (batch) => {
771
- const { lastCheckpointLsn } = batch;
772
- const lastLsn = MongoLSN.fromSerialized(lastCheckpointLsn!);
795
+ const { resumeFromLsn } = batch;
796
+ if (resumeFromLsn == null) {
797
+ throw new ReplicationAssertionError(`No LSN found to resume from`);
798
+ }
799
+ const lastLsn = MongoLSN.fromSerialized(resumeFromLsn);
773
800
  const startAfter = lastLsn?.timestamp;
774
801
 
775
802
  // It is normal for this to be a minute or two old when there is a low volume
@@ -778,7 +805,7 @@ export class ChangeStream {
778
805
 
779
806
  this.logger.info(`Resume streaming at ${startAfter?.inspect()} / ${lastLsn} | Token age: ${tokenAgeSeconds}s`);
780
807
 
781
- await using streamManager = this.openChangeStream({ lsn: lastCheckpointLsn });
808
+ await using streamManager = this.openChangeStream({ lsn: resumeFromLsn });
782
809
  const { stream, filters } = streamManager;
783
810
  if (this.abort_signal.aborted) {
784
811
  await stream.close();
@@ -797,6 +824,7 @@ export class ChangeStream {
797
824
  let splitDocument: mongo.ChangeStreamDocument | null = null;
798
825
 
799
826
  let flexDbNameWorkaroundLogged = false;
827
+ let changesSinceLastCheckpoint = 0;
800
828
 
801
829
  let lastEmptyResume = performance.now();
802
830
 
@@ -831,7 +859,7 @@ export class ChangeStream {
831
859
  if (waitForCheckpointLsn == null && performance.now() - lastEmptyResume > 60_000) {
832
860
  const { comparable: lsn, timestamp } = MongoLSN.fromResumeToken(stream.resumeToken);
833
861
  await batch.keepalive(lsn);
834
- await touch();
862
+ this.touch();
835
863
  lastEmptyResume = performance.now();
836
864
  // Log the token update. This helps as a general "replication is still active" message in the logs.
837
865
  // This token would typically be around 10s behind.
@@ -843,7 +871,7 @@ export class ChangeStream {
843
871
  continue;
844
872
  }
845
873
 
846
- await touch();
874
+ this.touch();
847
875
 
848
876
  if (startAfter != null && originalChangeDocument.clusterTime?.lte(startAfter)) {
849
877
  continue;
@@ -966,6 +994,7 @@ export class ChangeStream {
966
994
  if (didCommit) {
967
995
  this.oldestUncommittedChange = null;
968
996
  this.isStartingReplication = false;
997
+ changesSinceLastCheckpoint = 0;
969
998
  }
970
999
  } else if (
971
1000
  changeDocument.operationType == 'insert' ||
@@ -988,7 +1017,21 @@ export class ChangeStream {
988
1017
  if (this.oldestUncommittedChange == null && changeDocument.clusterTime != null) {
989
1018
  this.oldestUncommittedChange = timestampToDate(changeDocument.clusterTime);
990
1019
  }
991
- await this.writeChange(batch, table, changeDocument);
1020
+ const flushResult = await this.writeChange(batch, table, changeDocument);
1021
+ changesSinceLastCheckpoint += 1;
1022
+ if (flushResult != null && changesSinceLastCheckpoint >= 20_000) {
1023
+ // When we are catching up replication after an initial snapshot, there may be a very long delay
1024
+ // before we do a commit(). In that case, we need to periodically persist the resume LSN, so
1025
+ // we don't restart from scratch if we restart replication.
1026
+ // The same could apply if we need to catch up on replication after some downtime.
1027
+ const { comparable: lsn } = new MongoLSN({
1028
+ timestamp: changeDocument.clusterTime!,
1029
+ resume_token: changeDocument._id
1030
+ });
1031
+ this.logger.info(`Updating resume LSN to ${lsn} after ${changesSinceLastCheckpoint} changes`);
1032
+ await batch.setResumeLsn(lsn);
1033
+ changesSinceLastCheckpoint = 0;
1034
+ }
992
1035
  }
993
1036
  } else if (changeDocument.operationType == 'drop') {
994
1037
  const rel = getMongoRelation(changeDocument.ns);
@@ -1036,13 +1079,18 @@ export class ChangeStream {
1036
1079
  }
1037
1080
  return Date.now() - this.oldestUncommittedChange.getTime();
1038
1081
  }
1039
- }
1040
1082
 
1041
- async function touch() {
1042
- // FIXME: The hosted Kubernetes probe does not actually check the timestamp on this.
1043
- // FIXME: We need a timeout of around 5+ minutes in Kubernetes if we do start checking the timestamp,
1044
- // or reduce PING_INTERVAL here.
1045
- return container.probes.touch();
1083
+ private lastTouchedAt = performance.now();
1084
+
1085
+ private touch() {
1086
+ if (performance.now() - this.lastTouchedAt > 1_000) {
1087
+ this.lastTouchedAt = performance.now();
1088
+ // Update the probes, but don't wait for it
1089
+ container.probes.touch().catch((e) => {
1090
+ this.logger.error(`Failed to touch the container probe: ${e.message}`, e);
1091
+ });
1092
+ }
1093
+ }
1046
1094
  }
1047
1095
 
1048
1096
  function mapChangeStreamError(e: any) {
@@ -1,7 +1,18 @@
1
1
  import { mongo } from '@powersync/lib-service-mongodb';
2
2
  import { storage } from '@powersync/service-core';
3
3
  import { JSONBig, JsonContainer } from '@powersync/service-jsonbig';
4
- import { SqliteRow, SqliteValue } from '@powersync/service-sync-rules';
4
+ import {
5
+ CompatibilityContext,
6
+ CustomArray,
7
+ CustomObject,
8
+ CustomSqliteValue,
9
+ DatabaseInputValue,
10
+ SqliteInputRow,
11
+ SqliteInputValue,
12
+ SqliteRow,
13
+ SqliteValue,
14
+ DateTimeValue
15
+ } from '@powersync/service-sync-rules';
5
16
 
6
17
  import { ErrorCode, ServiceError } from '@powersync/lib-services-framework';
7
18
  import { MongoLSN } from '../common/MongoLSN.js';
@@ -13,7 +24,7 @@ export function getMongoRelation(source: mongo.ChangeStreamNameSpace): storage.S
13
24
  schema: source.db,
14
25
  // Not relevant for MongoDB - we use db + coll name as the identifier
15
26
  objectId: undefined,
16
- replicationColumns: [{ name: '_id' }]
27
+ replicaIdColumns: [{ name: '_id' }]
17
28
  } satisfies storage.SourceEntityDescriptor;
18
29
  }
19
30
 
@@ -22,20 +33,20 @@ export function getMongoRelation(source: mongo.ChangeStreamNameSpace): storage.S
22
33
  */
23
34
  export function getCacheIdentifier(source: storage.SourceEntityDescriptor | storage.SourceTable): string {
24
35
  if (source instanceof storage.SourceTable) {
25
- return `${source.schema}.${source.table}`;
36
+ return `${source.schema}.${source.name}`;
26
37
  }
27
38
  return `${source.schema}.${source.name}`;
28
39
  }
29
40
 
30
- export function constructAfterRecord(document: mongo.Document): SqliteRow {
31
- let record: SqliteRow = {};
41
+ export function constructAfterRecord(document: mongo.Document): SqliteInputRow {
42
+ let record: SqliteInputRow = {};
32
43
  for (let key of Object.keys(document)) {
33
44
  record[key] = toMongoSyncRulesValue(document[key]);
34
45
  }
35
46
  return record;
36
47
  }
37
48
 
38
- export function toMongoSyncRulesValue(data: any): SqliteValue {
49
+ export function toMongoSyncRulesValue(data: any): SqliteInputValue {
39
50
  const autoBigNum = true;
40
51
  if (data === null) {
41
52
  return null;
@@ -60,7 +71,8 @@ export function toMongoSyncRulesValue(data: any): SqliteValue {
60
71
  } else if (data instanceof mongo.UUID) {
61
72
  return data.toHexString();
62
73
  } else if (data instanceof Date) {
63
- return data.toISOString().replace('T', ' ');
74
+ const isoString = data.toISOString();
75
+ return new DateTimeValue(isoString);
64
76
  } else if (data instanceof mongo.Binary) {
65
77
  return new Uint8Array(data.buffer);
66
78
  } else if (data instanceof mongo.Long) {
@@ -72,18 +84,13 @@ export function toMongoSyncRulesValue(data: any): SqliteValue {
72
84
  } else if (data instanceof RegExp) {
73
85
  return JSON.stringify({ pattern: data.source, options: data.flags });
74
86
  } else if (Array.isArray(data)) {
75
- // We may be able to avoid some parse + stringify cycles here for JsonSqliteContainer.
76
- return JSONBig.stringify(data.map((element) => filterJsonData(element)));
87
+ return new CustomArray(data, filterJsonData);
77
88
  } else if (data instanceof Uint8Array) {
78
89
  return data;
79
90
  } else if (data instanceof JsonContainer) {
80
91
  return data.toString();
81
92
  } else if (typeof data == 'object') {
82
- let record: Record<string, any> = {};
83
- for (let key of Object.keys(data)) {
84
- record[key] = filterJsonData(data[key]);
85
- }
86
- return JSONBig.stringify(record);
93
+ return new CustomObject(data, filterJsonData);
87
94
  } else {
88
95
  return null;
89
96
  }
@@ -91,7 +98,7 @@ export function toMongoSyncRulesValue(data: any): SqliteValue {
91
98
 
92
99
  const DEPTH_LIMIT = 20;
93
100
 
94
- function filterJsonData(data: any, depth = 0): any {
101
+ function filterJsonData(data: any, context: CompatibilityContext, depth = 0): any {
95
102
  const autoBigNum = true;
96
103
  if (depth > DEPTH_LIMIT) {
97
104
  // This is primarily to prevent infinite recursion
@@ -117,7 +124,8 @@ function filterJsonData(data: any, depth = 0): any {
117
124
  } else if (typeof data == 'bigint') {
118
125
  return data;
119
126
  } else if (data instanceof Date) {
120
- return data.toISOString().replace('T', ' ');
127
+ const isoString = data.toISOString();
128
+ return new DateTimeValue(isoString).toSqliteValue(context);
121
129
  } else if (data instanceof mongo.ObjectId) {
122
130
  return data.toHexString();
123
131
  } else if (data instanceof mongo.UUID) {
@@ -133,16 +141,18 @@ function filterJsonData(data: any, depth = 0): any {
133
141
  } else if (data instanceof RegExp) {
134
142
  return { pattern: data.source, options: data.flags };
135
143
  } else if (Array.isArray(data)) {
136
- return data.map((element) => filterJsonData(element, depth + 1));
144
+ return data.map((element) => filterJsonData(element, context, depth + 1));
137
145
  } else if (ArrayBuffer.isView(data)) {
138
146
  return undefined;
147
+ } else if (data instanceof CustomSqliteValue) {
148
+ return data.toSqliteValue(context);
139
149
  } else if (data instanceof JsonContainer) {
140
150
  // Can be stringified directly when using our JSONBig implementation
141
151
  return data;
142
152
  } else if (typeof data == 'object') {
143
153
  let record: Record<string, any> = {};
144
154
  for (let key of Object.keys(data)) {
145
- record[key] = filterJsonData(data[key], depth + 1);
155
+ record[key] = filterJsonData(data[key], context, depth + 1);
146
156
  }
147
157
  return record;
148
158
  } else {