refactor to typescript

This commit is contained in:
Leonardo Venturini
2024-10-29 08:44:25 -04:00
parent 84c0cca7db
commit ca8219b1ca
3 changed files with 131 additions and 86 deletions

View File

@@ -100,7 +100,7 @@ Package.onUse(function (api) {
"server"
);
api.addFiles("local_collection_driver.js", ["client", "server"]);
api.addFiles("remote_collection_driver.js", "server");
api.addFiles("remote_collection_driver.ts", "server");
api.addFiles("collection.js", ["client", "server"]);
api.addFiles("connection_options.js", "server");
api.addAssets("mongo.d.ts", "server");

View File

@@ -1,85 +0,0 @@
import once from 'lodash.once';
import {
ASYNC_COLLECTION_METHODS,
getAsyncMethodName,
CLIENT_ONLY_METHODS
} from "meteor/minimongo/constants";
import { MongoConnection } from './mongo_connection';
MongoInternals.RemoteCollectionDriver = function (mongo_url, options) {
this.mongo = new MongoConnection(mongo_url, options);
};
const REMOTE_COLLECTION_METHODS = [
'createCappedCollectionAsync',
'dropIndexAsync',
'ensureIndexAsync',
'createIndexAsync',
'countDocuments',
'dropCollectionAsync',
'estimatedDocumentCount',
'find',
'findOneAsync',
'insertAsync',
'rawCollection',
'removeAsync',
'updateAsync',
'upsertAsync',
];
Object.assign(MongoInternals.RemoteCollectionDriver.prototype, {
open: function (name) {
var self = this;
var ret = {};
REMOTE_COLLECTION_METHODS.forEach(function (m) {
ret[m] = self.mongo[m].bind(self.mongo, name);
if (!ASYNC_COLLECTION_METHODS.includes(m)) return;
const asyncMethodName = getAsyncMethodName(m);
ret[asyncMethodName] = function (...args) {
return ret[m](...args);
};
});
CLIENT_ONLY_METHODS.forEach(function (m) {
ret[m] = function (...args) {
throw new Error(
`${m} is not available on the server. Please use ${getAsyncMethodName(
m
)}() instead.`
);
};
});
return ret;
},
});
// Create the singleton RemoteCollectionDriver only on demand, so we
// only require Mongo configuration if it's actually used (eg, not if
// you're only trying to receive data from a remote DDP server.)
MongoInternals.defaultRemoteCollectionDriver = once(function () {
var connectionOptions = {};
var mongoUrl = process.env.MONGO_URL;
if (process.env.MONGO_OPLOG_URL) {
connectionOptions.oplogUrl = process.env.MONGO_OPLOG_URL;
}
if (! mongoUrl)
throw new Error("MONGO_URL must be set in environment");
const driver = new MongoInternals.RemoteCollectionDriver(mongoUrl, connectionOptions);
// As many deployment tools, including Meteor Up, send requests to the app in
// order to confirm that the deployment finished successfully, it's required
// to know about a database connection problem before the app starts. Doing so
// in a `Meteor.startup` is fine, as the `WebApp` handles requests only after
// all are finished.
Meteor.startup(async () => {
await driver.mongo.client.connect();
});
return driver;
});

View File

@@ -0,0 +1,130 @@
import once from 'lodash.once';
import {
ASYNC_COLLECTION_METHODS,
getAsyncMethodName,
CLIENT_ONLY_METHODS
} from "meteor/minimongo/constants";
import { MongoConnection } from './mongo_connection';
// Define interfaces and types
interface IConnectionOptions {
oplogUrl?: string;
[key: string]: unknown; // Changed from 'any' to 'unknown' for better type safety
}
interface IMongoInternals {
RemoteCollectionDriver: typeof RemoteCollectionDriver;
defaultRemoteCollectionDriver: () => RemoteCollectionDriver;
}
// More specific typing for collection methods
type MongoMethodFunction = (...args: unknown[]) => unknown;
interface ICollectionMethods {
[key: string]: MongoMethodFunction;
}
// Type for MongoConnection
interface IMongoClient {
connect: () => Promise<void>;
}
interface IMongoConnection {
client: IMongoClient;
[key: string]: MongoMethodFunction | IMongoClient;
}
declare global {
namespace NodeJS {
interface ProcessEnv {
MONGO_URL: string;
MONGO_OPLOG_URL?: string;
}
}
const MongoInternals: IMongoInternals;
const Meteor: {
startup: (callback: () => Promise<void>) => void;
};
}
class RemoteCollectionDriver {
private readonly mongo: MongoConnection;
private static readonly REMOTE_COLLECTION_METHODS = [
'createCappedCollectionAsync',
'dropIndexAsync',
'ensureIndexAsync',
'createIndexAsync',
'countDocuments',
'dropCollectionAsync',
'estimatedDocumentCount',
'find',
'findOneAsync',
'insertAsync',
'rawCollection',
'removeAsync',
'updateAsync',
'upsertAsync',
] as const;
constructor(mongoUrl: string, options: IConnectionOptions) {
this.mongo = new MongoConnection(mongoUrl, options);
}
public open(name: string): ICollectionMethods {
const ret: ICollectionMethods = {};
// Handle remote collection methods
RemoteCollectionDriver.REMOTE_COLLECTION_METHODS.forEach((method) => {
// Type assertion needed because we know these methods exist on MongoConnection
const mongoMethod = this.mongo[method] as MongoMethodFunction;
ret[method] = mongoMethod.bind(this.mongo, name);
if (!ASYNC_COLLECTION_METHODS.includes(method)) return;
const asyncMethodName = getAsyncMethodName(method);
ret[asyncMethodName] = (...args: unknown[]) => ret[method](...args);
});
// Handle client-only methods
CLIENT_ONLY_METHODS.forEach((method) => {
ret[method] = (...args: unknown[]): never => {
throw new Error(
`${method} is not available on the server. Please use ${getAsyncMethodName(
method
)}() instead.`
);
};
});
return ret;
}
}
// Assign the class to MongoInternals
MongoInternals.RemoteCollectionDriver = RemoteCollectionDriver;
// Create the singleton RemoteCollectionDriver only on demand
MongoInternals.defaultRemoteCollectionDriver = once((): RemoteCollectionDriver => {
const connectionOptions: IConnectionOptions = {};
const mongoUrl = process.env.MONGO_URL;
if (!mongoUrl) {
throw new Error("MONGO_URL must be set in environment");
}
if (process.env.MONGO_OPLOG_URL) {
connectionOptions.oplogUrl = process.env.MONGO_OPLOG_URL;
}
const driver = new RemoteCollectionDriver(mongoUrl, connectionOptions);
// Initialize database connection on startup
Meteor.startup(async (): Promise<void> => {
await driver.mongo.client.connect();
});
return driver;
});
export { RemoteCollectionDriver, IConnectionOptions, ICollectionMethods };