Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/swift-trains-behave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@powersync/service-module-mongodb-storage': minor
'@powersync/service-module-mongodb': minor
'@powersync/lib-service-mongodb': minor
---

Shared MongoDB dependency between modules. This should help avoid potential multiple versions of MongoDB being present in a project.
4 changes: 4 additions & 0 deletions libs/lib-mongodb/src/db/mongo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,7 @@ export async function waitForAuth(db: mongo.Db) {
}
}
}

export const isMongoServerError = (error: any): error is mongo.MongoServerError => {
return error instanceof mongo.MongoServerError || error?.name == 'MongoServerError';
};
3 changes: 3 additions & 0 deletions libs/lib-mongodb/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,6 @@ export * as locks from './locks/locks-index.js';

export * from './types/types.js';
export * as types from './types/types.js';

// Re-export mongodb which can avoid using multiple versions of Mongo in a project
export * as mongo from 'mongodb';
1 change: 0 additions & 1 deletion modules/module-mongodb-storage/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
"@powersync/service-sync-rules": "workspace:*",
"@powersync/service-types": "workspace:*",
"@powersync/lib-service-mongodb": "workspace:*",
"mongodb": "^6.11.0",
"bson": "^6.8.0",
"ts-codec": "^1.3.0",
"ix": "^5.0.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { mongo } from '@powersync/lib-service-mongodb';
import { migrations } from '@powersync/lib-services-framework';
import { Db } from 'mongodb';

import * as path from 'path';

/**
* A custom store for node-migrate which is used to save and load migrations that have
* been operated on to mongo.
*/
export const createMongoMigrationStore = (db: Db): migrations.MigrationStore => {
export const createMongoMigrationStore = (db: mongo.Db): migrations.MigrationStore => {
const collection = db.collection<migrations.MigrationState>('migrations');

return {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { SqlSyncRules } from '@powersync/service-sync-rules';
import { wrapWithAbort } from 'ix/asynciterable/operators/withabort.js';
import { LRUCache } from 'lru-cache/min';
import * as mongo from 'mongodb';
import * as timers from 'timers/promises';

import { storage, sync, utils } from '@powersync/service-core';
Expand All @@ -10,6 +9,8 @@ import { DisposableObserver, logger } from '@powersync/lib-services-framework';
import { v4 as uuid } from 'uuid';

import * as lib_mongo from '@powersync/lib-service-mongodb';
import { mongo } from '@powersync/lib-service-mongodb';

import { PowerSyncMongo } from './implementation/db.js';
import { SyncRuleDocument } from './implementation/models.js';
import { MongoPersistedSyncRulesContent } from './implementation/MongoPersistedSyncRulesContent.js';
Expand Down Expand Up @@ -285,7 +286,7 @@ export class MongoBucketStorage

async getStorageMetrics(): Promise<storage.StorageMetrics> {
const ignoreNotExiting = (e: unknown) => {
if (e instanceof mongo.MongoServerError && e.codeName == 'NamespaceNotFound') {
if (lib_mongo.isMongoServerError(e) && e.codeName == 'NamespaceNotFound') {
// Collection doesn't exist - return 0
return [{ storageStats: { size: 0 } }];
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { mongo } from '@powersync/lib-service-mongodb';
import { SqlEventDescriptor, SqliteRow, SqlSyncRules } from '@powersync/service-sync-rules';
import * as bson from 'bson';
import * as mongo from 'mongodb';

import { container, DisposableObserver, errors, logger } from '@powersync/lib-services-framework';
import { SaveOperationTag, storage, utils } from '@powersync/service-core';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { mongo } from '@powersync/lib-service-mongodb';
import { logger } from '@powersync/lib-services-framework';
import { storage, utils } from '@powersync/service-core';
import { AnyBulkWriteOperation, MaxKey, MinKey } from 'mongodb';

import { PowerSyncMongo } from './db.js';
import { BucketDataDocument, BucketDataKey } from './models.js';
import { cacheKey } from './OperationBatch.js';
Expand Down Expand Up @@ -49,7 +50,7 @@ const DEFAULT_MOVE_BATCH_QUERY_LIMIT = 10_000;
const DEFAULT_MEMORY_LIMIT_MB = 64;

export class MongoCompactor {
private updates: AnyBulkWriteOperation<BucketDataDocument>[] = [];
private updates: mongo.AnyBulkWriteOperation<BucketDataDocument>[] = [];

private idLimitBytes: number;
private moveBatchLimit: number;
Expand Down Expand Up @@ -94,12 +95,12 @@ export class MongoCompactor {

let currentState: CurrentBucketState | null = null;

let bucketLower: string | MinKey;
let bucketUpper: string | MaxKey;
let bucketLower: string | mongo.MinKey;
let bucketUpper: string | mongo.MaxKey;

if (bucket == null) {
bucketLower = new MinKey();
bucketUpper = new MaxKey();
bucketLower = new mongo.MinKey();
bucketUpper = new mongo.MaxKey();
} else if (bucket.includes('[')) {
// Exact bucket name
bucketLower = bucket;
Expand All @@ -114,14 +115,14 @@ export class MongoCompactor {
const lowerBound: BucketDataKey = {
g: this.group_id,
b: bucketLower as string,
o: new MinKey() as any
o: new mongo.MinKey() as any
};

// Upper bound is adjusted for each batch
let upperBound: BucketDataKey = {
g: this.group_id,
b: bucketUpper as string,
o: new MaxKey() as any
o: new mongo.MaxKey() as any
};

while (true) {
Expand Down Expand Up @@ -287,7 +288,7 @@ export class MongoCompactor {
$gte: {
g: this.group_id,
b: bucket,
o: new MinKey() as any
o: new mongo.MinKey() as any
},
$lte: {
g: this.group_id,
Expand Down Expand Up @@ -349,7 +350,7 @@ export class MongoCompactor {
$gte: {
g: this.group_id,
b: bucket,
o: new MinKey() as any
o: new mongo.MinKey() as any
},
$lte: lastOpId!
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { mongo } from '@powersync/lib-service-mongodb';
import { storage } from '@powersync/service-core';
import { SqlSyncRules } from '@powersync/service-sync-rules';
import * as mongo from 'mongodb';
import { MongoPersistedSyncRules } from './MongoPersistedSyncRules.js';
import { MongoSyncRulesLock } from './MongoSyncRulesLock.js';
import { PowerSyncMongo } from './db.js';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { SqliteJsonRow, SqliteJsonValue, SqlSyncRules } from '@powersync/service-sync-rules';
import * as bson from 'bson';
import * as mongo from 'mongodb';

import * as lib_mongo from '@powersync/lib-service-mongodb';
import { mongo } from '@powersync/lib-service-mongodb';
import { DisposableObserver, logger } from '@powersync/lib-services-framework';
import { storage, utils } from '@powersync/service-core';
import { SqliteJsonRow, SqliteJsonValue, SqlSyncRules } from '@powersync/service-sync-rules';
import * as bson from 'bson';
import * as timers from 'timers/promises';
import { MongoBucketStorage } from '../MongoBucketStorage.js';
import { PowerSyncMongo } from './db.js';
Expand Down Expand Up @@ -498,7 +497,7 @@ export class MongoSyncBucketStorage
logger.info(`${this.slot_name} Done clearing data`);
return;
} catch (e: unknown) {
if (e instanceof mongo.MongoServerError && e.codeName == 'MaxTimeMSExpired') {
if (lib_mongo.isMongoServerError(e) && e.codeName == 'MaxTimeMSExpired') {
logger.info(
`${this.slot_name} Cleared batch of data in ${lib_mongo.db.MONGO_CLEAR_OPERATION_TIMEOUT_MS}ms, continuing...`
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { mongo } from '@powersync/lib-service-mongodb';
import { JSONBig } from '@powersync/service-jsonbig';
import { EvaluatedParameters, EvaluatedRow } from '@powersync/service-sync-rules';
import * as bson from 'bson';
import * as mongo from 'mongodb';

import { logger } from '@powersync/lib-services-framework';
import { storage, utils } from '@powersync/service-core';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as lib_mongo from '@powersync/lib-service-mongodb';
import { mongo } from '@powersync/lib-service-mongodb';
import { storage } from '@powersync/service-core';
import * as mongo from 'mongodb';

import { MongoStorageConfig } from '../../types/types.js';
import {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { storage, utils } from '@powersync/service-core';
import * as bson from 'bson';
import * as crypto from 'crypto';
import * as mongo from 'mongodb';
import * as uuid from 'uuid';

import { mongo } from '@powersync/lib-service-mongodb';
import { storage, utils } from '@powersync/service-core';

import { PowerSyncMongo } from './db.js';
import { BucketDataDocument } from './models.js';

Expand Down
1 change: 0 additions & 1 deletion modules/module-mongodb/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
"@powersync/service-sync-rules": "workspace:*",
"@powersync/service-types": "workspace:*",
"@powersync/lib-service-mongodb": "workspace:*",
"mongodb": "^6.11.0",
"bson": "^6.8.0",
"ts-codec": "^1.3.0",
"uuid": "^9.0.1"
Expand Down
7 changes: 4 additions & 3 deletions modules/module-mongodb/src/api/MongoRouteAPIAdapter.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import * as lib_mongo from '@powersync/lib-service-mongodb';
import { mongo } from '@powersync/lib-service-mongodb';
import { api, ParseSyncRulesOptions, SourceTable } from '@powersync/service-core';
import * as sync_rules from '@powersync/service-sync-rules';
import * as service_types from '@powersync/service-types';
import * as mongo from 'mongodb';

import { MongoManager } from '../replication/MongoManager.js';
import { constructAfterRecord, createCheckpoint } from '../replication/MongoRelation.js';
import { CHECKPOINTS_COLLECTION } from '../replication/replication-utils.js';
Expand Down Expand Up @@ -225,7 +226,7 @@ export class MongoRouteAPIAdapter implements api.RouteAPI {
try {
collections = await this.client.db(db.name).listCollections().toArray();
} catch (e) {
if (e instanceof mongo.MongoServerError && e.codeName == 'Unauthorized') {
if (lib_mongo.isMongoServerError(e) && e.codeName == 'Unauthorized') {
// Ignore databases we're not authorized to query
return null;
}
Expand Down Expand Up @@ -267,7 +268,7 @@ export class MongoRouteAPIAdapter implements api.RouteAPI {
});
}
} catch (e) {
if (e instanceof mongo.MongoServerError && e.codeName == 'Unauthorized') {
if (lib_mongo.isMongoServerError(e) && e.codeName == 'Unauthorized') {
// Ignore collections we're not authorized to query
continue;
}
Expand Down
6 changes: 3 additions & 3 deletions modules/module-mongodb/src/replication/ChangeStream.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { mongo } from '@powersync/lib-service-mongodb';
import { container, logger } from '@powersync/lib-services-framework';
import { Metrics, SaveOperationTag, SourceEntityDescriptor, SourceTable, storage } from '@powersync/service-core';
import { DatabaseInputRow, SqliteRow, SqlSyncRules, TablePattern } from '@powersync/service-sync-rules';
import * as mongo from 'mongodb';
import { PostImagesOption } from '../types/types.js';
import { escapeRegExp } from '../utils.js';
import { MongoManager } from './MongoManager.js';
import {
constructAfterRecord,
Expand All @@ -10,9 +12,7 @@ import {
getMongoRelation,
mongoLsnToTimestamp
} from './MongoRelation.js';
import { escapeRegExp } from '../utils.js';
import { CHECKPOINTS_COLLECTION } from './replication-utils.js';
import { PostImagesOption } from '../types/types.js';

export const ZERO_LSN = '0000000000000000';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { mongo } from '@powersync/lib-service-mongodb';
import { container } from '@powersync/lib-services-framework';
import { ChangeStreamInvalidatedError, ChangeStream } from './ChangeStream.js';

import { replication } from '@powersync/service-core';
import { ConnectionManagerFactory } from './ConnectionManagerFactory.js';

import * as mongo from 'mongodb';
import { ChangeStream, ChangeStreamInvalidatedError } from './ChangeStream.js';
import { ConnectionManagerFactory } from './ConnectionManagerFactory.js';

export interface ChangeStreamReplicationJobOptions extends replication.AbstractReplicationJobOptions {
connectionFactory: ConnectionManagerFactory;
Expand Down
3 changes: 2 additions & 1 deletion modules/module-mongodb/src/replication/MongoManager.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as mongo from 'mongodb';
import { mongo } from '@powersync/lib-service-mongodb';

import { NormalizedMongoConnectionConfig } from '../types/types.js';

export class MongoManager {
Expand Down
5 changes: 3 additions & 2 deletions modules/module-mongodb/src/replication/MongoRelation.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { mongo } from '@powersync/lib-service-mongodb';
import { storage } from '@powersync/service-core';
import { SqliteRow, SqliteValue, toSyncRulesRow } from '@powersync/service-sync-rules';
import * as mongo from 'mongodb';
import { JSONBig, JsonContainer } from '@powersync/service-jsonbig';
import { SqliteRow, SqliteValue } from '@powersync/service-sync-rules';

import { CHECKPOINTS_COLLECTION } from './replication-utils.js';

export function getMongoRelation(source: mongo.ChangeStreamNameSpace): storage.SourceEntityDescriptor {
Expand Down
11 changes: 6 additions & 5 deletions modules/module-mongodb/test/src/change_stream.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { test_utils } from '@powersync/service-core-tests';

import { PostImagesOption } from '@module/types/types.js';
import { storage } from '@powersync/service-core';
import * as crypto from 'crypto';
import * as mongo from 'mongodb';
import { setTimeout } from 'node:timers/promises';
import { describe, expect, test, vi } from 'vitest';

import { mongo } from '@powersync/lib-service-mongodb';
import { storage } from '@powersync/service-core';
import { test_utils } from '@powersync/service-core-tests';

import { PostImagesOption } from '@module/types/types.js';
import { ChangeStreamTestContext } from './change_stream_utils.js';
import { INITIALIZED_MONGO_STORAGE_FACTORY } from './util.js';

Expand Down
5 changes: 3 additions & 2 deletions modules/module-mongodb/test/src/change_stream_utils.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { mongo } from '@powersync/lib-service-mongodb';
import { ActiveCheckpoint, BucketStorageFactory, OpId, SyncRulesBucketStorage } from '@powersync/service-core';
import { test_utils } from '@powersync/service-core-tests';

import { ChangeStream, ChangeStreamOptions } from '@module/replication/ChangeStream.js';
import { MongoManager } from '@module/replication/MongoManager.js';
import { createCheckpoint } from '@module/replication/MongoRelation.js';
import { NormalizedMongoConnectionConfig } from '@module/types/types.js';
import { test_utils } from '@powersync/service-core-tests';
import * as mongo from 'mongodb';

import { TEST_CONNECTION_OPTIONS, clearTestDb } from './util.js';

export class ChangeStreamTestContext {
Expand Down
9 changes: 5 additions & 4 deletions modules/module-mongodb/test/src/mongo_test.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { mongo } from '@powersync/lib-service-mongodb';
import { SqliteRow, SqlSyncRules } from '@powersync/service-sync-rules';
import { describe, expect, test } from 'vitest';

import { MongoRouteAPIAdapter } from '@module/api/MongoRouteAPIAdapter.js';
import { ChangeStream } from '@module/replication/ChangeStream.js';
import { constructAfterRecord } from '@module/replication/MongoRelation.js';
import { SqliteRow, SqlSyncRules } from '@powersync/service-sync-rules';
import * as mongo from 'mongodb';
import { describe, expect, test } from 'vitest';
import { clearTestDb, connectMongoData, TEST_CONNECTION_OPTIONS } from './util.js';
import { PostImagesOption } from '@module/types/types.js';
import { clearTestDb, connectMongoData, TEST_CONNECTION_OPTIONS } from './util.js';

describe('mongo data types', () => {
async function setupTable(db: mongo.Db) {
Expand Down
6 changes: 4 additions & 2 deletions modules/module-mongodb/test/src/slow_tests.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { storage } from '@powersync/service-core';
import * as mongo from 'mongodb';
import { setTimeout } from 'node:timers/promises';
import { describe, expect, test } from 'vitest';

import { mongo } from '@powersync/lib-service-mongodb';
import { storage } from '@powersync/service-core';

import { ChangeStreamTestContext, setSnapshotHistorySeconds } from './change_stream_utils.js';
import { env } from './env.js';
import { INITIALIZED_MONGO_STORAGE_FACTORY } from './util.js';
Expand Down
6 changes: 3 additions & 3 deletions modules/module-mongodb/test/src/util.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as types from '@module/types/types.js';

import { mongo } from '@powersync/lib-service-mongodb';
import * as mongo_storage from '@powersync/service-module-mongodb-storage';
import * as mongo from 'mongodb';

import * as types from '@module/types/types.js';
import { env } from './env.js';

export const TEST_URI = env.MONGO_TEST_DATA_URL;
Expand Down
6 changes: 0 additions & 6 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading