@notross/mongo-singleton
Version:
A lightweight, zero-fuss way to get a single shared MongoDB connection across your Node.js codebase.
151 lines • 5.23 kB
JavaScript
import { MongoClient, ServerApiVersion } from 'mongodb';
import { buildConnectionString, Logger } from './utils';
const mongodbConfig = {
serverApi: {
version: ServerApiVersion.v1,
strict: true,
deprecationErrors: true,
},
};
const logger = new Logger();
/**
* MongoSingleton
*
* Manages a single, shared MongoDB connection for the application.
* Subsequent calls to `.connect()` return the same connection.
*
* Like me, it's single and looking for a connection. 💔
*/
export default class MongoSingleton {
/**
* @param connectionProps - Either a full ConnectionProps object, a SparseConnectionProps object, or a raw MongoDB URI string.
* @param database - The name of the database to operate on.
*/
constructor(connectionProps, database) {
this.client = null;
this.database = null;
this.status = 'Disconnected';
this.error = null;
this.initializeLogging(connectionProps);
this.databaseName = database;
if (typeof connectionProps === 'string') {
this.uri = connectionProps;
}
else {
this.uri = connectionProps.uri ||
buildConnectionString(connectionProps);
}
}
initializeLogging(props) {
var _a, _b;
const logging = typeof props === 'object'
? (_a = props.logging) !== null && _a !== void 0 ? _a : true
: true;
logger.toggleLogging(logging);
const levels = typeof props === 'object'
? (_b = props.logLevels) !== null && _b !== void 0 ? _b : undefined
: undefined;
logger.setLevels(levels);
}
initializeClient() {
if (this.client) {
return this.client;
}
const client = new MongoClient(this.uri, mongodbConfig);
return client;
}
initializeDatabase(client) {
this.database = client.db(this.databaseName);
return this.database;
}
getDb(client) {
return this.database || this.initializeDatabase(client);
}
/**
* Establishes a connection to MongoDB if not already connected.
* If already connected, returns the existing client and database.
*
* @returns Promise resolving to the connected MongoClient and Db.
* @example
* const { client, database } = await mongoClient.connect();
*/
async connect() {
if (this.client) {
return {
client: this.client,
database: this.getDb(this.client),
};
}
this.client = this.initializeClient();
await this.client.connect().then((client) => this.initializeDatabase(client));
this.client.on('connectionReady', () => {
this.status = 'MongoDB connection is ready';
logger.log(this.status);
});
this.client.on('close', () => {
this.status = 'MongoDB connection closed';
logger.log(this.status);
});
this.client.on('error', (err) => {
this.status = 'MongoDB connection error';
this.error = err;
logger.error(this.status, err);
});
this.client.on('reconnect', () => {
this.status = 'MongoDB reconnected';
logger.log(this.status);
});
this.client.on('reconnectFailed', () => {
this.status = 'MongoDB reconnection failed';
logger.error(this.status);
});
this.client.on('timeout', () => {
this.status = 'MongoDB connection timed out';
logger.error(this.status);
});
this.client.on('serverHeartbeatFailed', (err) => {
this.status = 'MongoDB server heartbeat failed:';
this.error = err;
logger.error(this.status, this.error);
});
this.client.on('serverHeartbeatSucceeded', () => {
this.status = 'MongoDB server heartbeat succeeded';
logger.log(this.status);
});
this.client.on('serverClosed', () => {
this.status = 'MongoDB server closed';
logger.log(this.status);
});
this.client.on('serverOpening', () => {
this.status = 'MongoDB server opening';
logger.log(this.status);
});
return {
client: this.client,
database: this.getDb(this.client),
};
}
/**
* Gracefully closes the MongoDB connection and resets internal state.
* If no client exists, logs a warning instead.
*/
async disconnect() {
if (this.client) {
await this.client.close().then(() => {
this.client = null;
this.database = null;
this.status = 'Disconnected from MongoDB';
logger.log(this.status);
}).catch((err) => {
this.status = 'Error disconnecting from MongoDB';
this.error = err;
logger.error(this.status, err);
});
}
else {
this.status = 'No MongoDB client to disconnect';
logger.warn(this.status);
}
}
}
//# sourceMappingURL=client.js.map