UNPKG

@notross/mongo-singleton

Version:

A lightweight, zero-fuss way to get a single shared MongoDB connection across your Node.js codebase.

180 lines 6.1 kB
import * as mongodb from 'mongodb'; import { logger } from '@notross/node-client-logger'; import { defaultConfig } from './config'; import { buildConnectionString } from './utils'; /** * 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 class MongoSingleton { /** * @param connection - 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(props) { this.config = defaultConfig; this.databaseName = ''; this.uri = 'mongodb://localhost:27017'; this.client = null; this.database = null; this.status = 'Disconnected'; this.error = null; if (props) { this.setup(props); } this.setConfig(props === null || props === void 0 ? void 0 : props.config); this.collection = this.getCollection.bind(this); this.configure = this.setConfig.bind(this); this.connectedDb = this.getDb.bind(this); this.db = this._getDb.bind(this); this.init = this.setup.bind(this); } setup({ config, connection, database } = { connection: 'mongodb://localhost:27017', database: '', }) { this.initializeLogging(connection); this.databaseName = database; if (typeof connection === 'string') { this.uri = connection; } else { this.uri = connection.uri || buildConnectionString(connection); } if (config) { this.setConfig(config); } this.initializeClient(); } setConfig(config = defaultConfig) { this.config = config; } 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; } this.client = new mongodb.MongoClient(this.uri, this.config); return this.client; } initializeDatabase() { const client = this.client; this.database = client.db(this.databaseName); return this.database; } _getDb() { return this.database || this.initializeDatabase(); } /** * 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(), }; } const client = this.initializeClient(); await client.connect().then(() => this.initializeDatabase()); client.on('connectionReady', () => { this.status = 'MongoDB connection is ready'; logger.log(this.status); }); client.on('close', () => { this.status = 'MongoDB connection closed'; logger.log(this.status); }); client.on('error', (err) => { this.status = 'MongoDB connection error'; this.error = err; logger.error(this.status, err); }); client.on('reconnect', () => { this.status = 'MongoDB reconnected'; logger.log(this.status); }); client.on('reconnectFailed', () => { this.status = 'MongoDB reconnection failed'; logger.error(this.status); }); client.on('timeout', () => { this.status = 'MongoDB connection timed out'; logger.error(this.status); }); client.on('serverHeartbeatFailed', (err) => { this.status = 'MongoDB server heartbeat failed:'; this.error = err; logger.error(this.status, this.error); }); client.on('serverHeartbeatSucceeded', () => { this.status = 'MongoDB server heartbeat succeeded'; logger.log(this.status); }); client.on('serverClosed', () => { this.status = 'MongoDB server closed'; logger.log(this.status); }); client.on('serverOpening', () => { this.status = 'MongoDB server opening'; logger.log(this.status); }); return { client: client, database: this._getDb(), }; } /** * 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); } } async getDb() { const { database } = await this.connect(); return database; } getCollection(name) { const database = this._getDb(); return database.collection(name); } } //# sourceMappingURL=mongo-singleton.js.map