Skip to content

Commit f84f277

Browse files
committed
Workaround for booleans; log the filters.
1 parent aa0ee8b commit f84f277

4 files changed

Lines changed: 27 additions & 31 deletions

File tree

modules/module-mongodb/src/replication/MongoSnapshotQuery.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import { mongo } from '@powersync/lib-service-mongodb';
22
import { ReplicationAssertionError } from '@powersync/lib-services-framework';
33
import { bson } from '@powersync/service-core';
4-
import { MongoExpression, StaticFilter } from '@powersync/service-sync-rules';
5-
import { staticFilterToMongoExpression } from './staticFilters.js';
4+
import { MongoExpression } from '@powersync/service-sync-rules';
65

76
/**
87
* Performs a collection snapshot query, chunking by ranges of _id.
@@ -21,15 +20,13 @@ export class ChunkedSnapshotQuery implements AsyncDisposable {
2120
collection: mongo.Collection;
2221
batchSize: number;
2322
key?: Uint8Array | null;
24-
filter?: StaticFilter;
23+
filter?: MongoExpression;
2524
}) {
2625
this.lastKey = options.key ? bson.deserialize(options.key, { useBigInt64: true })._id : null;
2726
this.lastCursor = null;
2827
this.collection = options.collection;
2928
this.batchSize = options.batchSize;
30-
if (options.filter) {
31-
this.filter = staticFilterToMongoExpression(options.filter);
32-
}
29+
this.filter = options.filter ?? null;
3330
}
3431

3532
async nextChunk(): Promise<{ docs: mongo.Document[]; lastKey: Uint8Array } | { docs: []; lastKey: null }> {

modules/module-mongodb/src/replication/MongoSnapshotter.ts

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ import { MongoManager } from './MongoManager.js';
2020
import { constructAfterRecord, createCheckpoint, getMongoRelation, STANDALONE_CHECKPOINT_ID } from './MongoRelation.js';
2121
import { ChunkedSnapshotQuery } from './MongoSnapshotQuery.js';
2222
import { CHECKPOINTS_COLLECTION } from './replication-utils.js';
23+
import { staticFilterToMongoExpression } from './staticFilters.js';
24+
import { JSONBig } from '@powersync/service-jsonbig';
2325

2426
export interface MongoSnapshotterOptions {
2527
connections: MongoManager;
@@ -281,19 +283,22 @@ export class MongoSnapshotter {
281283
let at = table.snapshotStatus?.replicatedCount ?? 0;
282284
const db = this.client.db(table.schema);
283285
const collection = db.collection(table.name);
284-
console.log('snapshot with filter', table.pattern?.filter, table.pattern);
286+
287+
const mongoFilter = table.pattern?.filter ? staticFilterToMongoExpression(table.pattern.filter) : null;
288+
const filterLog = mongoFilter ? ` | filter: ${JSONBig.stringify(mongoFilter)}` : '';
289+
285290
await using query = new ChunkedSnapshotQuery({
286291
collection,
287292
key: table.snapshotStatus?.lastKey,
288293
batchSize: this.snapshotChunkLength,
289-
filter: table.pattern?.filter
294+
filter: mongoFilter
290295
});
291296
if (query.lastKey != null) {
292297
this.logger.info(
293-
`Replicating ${table.qualifiedName} ${table.formatSnapshotProgress()} - resuming at _id > ${query.lastKey}`
298+
`Replicating ${table.qualifiedName} ${table.formatSnapshotProgress()} - resuming at _id > ${query.lastKey}${filterLog}`
294299
);
295300
} else {
296-
this.logger.info(`Replicating ${table.qualifiedName} ${table.formatSnapshotProgress()}`);
301+
this.logger.info(`Replicating ${table.qualifiedName} ${table.formatSnapshotProgress()}${filterLog}`);
297302
}
298303

299304
let lastBatch = performance.now();
@@ -355,21 +360,6 @@ export class MongoSnapshotter {
355360
return rowProcessor.applyRowContext<never>(inputRow);
356361
}
357362

358-
private async getCollectionInfo(db: string, name: string): Promise<mongo.CollectionInfo | undefined> {
359-
const collection = (
360-
await this.client
361-
.db(db)
362-
.listCollections(
363-
{
364-
name: name
365-
},
366-
{ nameOnly: false }
367-
)
368-
.toArray()
369-
)[0];
370-
return collection;
371-
}
372-
373363
private async checkPostImages(db: string, collectionInfo: mongo.CollectionInfo) {
374364
if (!this.usePostImages) {
375365
// Nothing to check

modules/module-mongodb/src/replication/staticFilters.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,23 @@ export function staticFilterToMongoExpression(
7272
switch (operator) {
7373
case '=':
7474
case '==':
75+
case 'IS':
76+
// Big hack to support boolean values coerced to integers.
77+
if ('value' in node.right && node.right.value == 0n) {
78+
return { $in: [leftExpr, [0n, false]] };
79+
} else if ('value' in node.right && node.right.value == 1n) {
80+
return { $in: [leftExpr, [1n, true]] };
81+
}
7582
return { $eq: [leftExpr, rightExpr] };
7683
case '!=':
7784
case '<>':
85+
case 'IS NOT':
86+
// Big hack to support boolean values coerced to integers.
87+
if ('value' in node.right && node.right.value == 0n) {
88+
return { $nin: [leftExpr, [0n, false]] };
89+
} else if ('value' in node.right && node.right.value == 1n) {
90+
return { $nin: [leftExpr, [1n, true]] };
91+
}
7892
return { $ne: [leftExpr, rightExpr] };
7993
case '<':
8094
return { $lt: [leftExpr, rightExpr] };
@@ -84,10 +98,6 @@ export function staticFilterToMongoExpression(
8498
return { $gt: [leftExpr, rightExpr] };
8599
case '>=':
86100
return { $gte: [leftExpr, rightExpr] };
87-
case 'IS':
88-
return { $eq: [leftExpr, rightExpr] };
89-
case 'IS NOT':
90-
return { $ne: [leftExpr, rightExpr] };
91101
case 'IN': {
92102
if (parseJsonArrayForIn && 'value' in node.right) {
93103
const value = node.right.value;
@@ -108,7 +118,7 @@ export function staticFilterToMongoExpression(
108118
return { $in: [leftExpr, rightExpr] };
109119
}
110120
default:
111-
throw new Error(`Operator not supported: ${node.operator}`);
121+
return ANY;
112122
}
113123
}
114124

packages/service-core-tests/src/test-utils/general-utils.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,6 @@ export function bucketRequest(
143143
throw new Error('Failed to find global bucket');
144144
}
145145
const bucketName = hydrationState.getBucketSourceScope(source).bucketPrefix + parameters;
146-
console.log('query for bucket', bucketName);
147146
return {
148147
bucket: bucketName,
149148
start: BigInt(start ?? 0n),

0 commit comments

Comments
 (0)