"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var src_exports = {}; __export(src_exports, { ModelManager: () => ModelManager, ModelUtils: () => ModelUtils, MongooseUtils: () => MongooseUtils_default }); module.exports = __toCommonJS(src_exports); // src/ModelManager.ts var import_lodash = __toESM(require("lodash"), 1); var import_glob = require("glob"); var import_error_manager_helper2 = require("error-manager-helper"); // src/MongooseUtils.ts var import_mongoose = __toESM(require("mongoose"), 1); var import_error_manager_helper = require("error-manager-helper"); var MongooseUtils = class _MongooseUtils { /** * ๐Ÿšซ Private constructor to ensure singleton pattern for each database instance. * * @private * @param {string} dbName - Name of the MongoDB database. */ constructor(dbName) { this.dbName = dbName; this.connectionString = process.env.MONGODB_CONNECTION_STRING; } // ๐Ÿ—‚๏ธ Map to store instances of MongooseUtils for different databases static instances = /* @__PURE__ */ new Map(); // โšก MongoDB connection object, initialized as null conn = null; // ๐Ÿ”— Connection string for MongoDB connectionString; /** * ๐Ÿ”‘ Retrieves the singleton instance of `MongooseUtils` for a specific database. * * @static * @param {string} dbName - Name of the database to connect. * @returns {MongooseUtils} The instance managing the connection to the database. */ static getInstance(dbName) { if (!_MongooseUtils.instances.has(dbName)) { _MongooseUtils.instances.set(dbName, new _MongooseUtils(dbName)); } return _MongooseUtils.instances.get(dbName); } /** * ๐Ÿ› ๏ธ Creates a new Mongoose schema for a model. * * @static * @template IMongooseSchema - Interface representing the Mongoose schema. * @param {mongoose.SchemaDefinition} schema - The schema definition for the model. * @param {mongoose.SchemaOptions} options - Schema options such as timestamps or collection name. * @returns {mongoose.Schema} The constructed Mongoose schema. * * @see https://mongoosejs.com/docs/guide.html#options for options. */ static createSchema(schema, options) { const mongooseSchema = new import_mongoose.default.Schema(schema, options); return mongooseSchema; } /** * ๐Ÿš€ Initializes a connection to MongoDB for the current database. * * If the connection fails, it throws an error wrapped in `BaseError`. * * @private * @throws {BaseError} If the MongoDB connection fails. * @returns {Promise} Resolves when connection is successfully established. */ async init() { console.log("[ModelManager] - Attempting to connect to MongoDB..."); this.updateConnectionString(); try { this.conn = await import_mongoose.default.createConnection(this.connectionString).asPromise(); } catch (e) { throw new import_error_manager_helper.BaseError( "[ModelManager] - Error while initializing connection with MongoDB", e ); } } /** * ๐Ÿ”„ Updates the connection string with the current database name. * * Modifies the `pathname` of the connection URL to ensure the correct database is targeted. * * @private * @returns {void} The connection string is updated in place. */ updateConnectionString() { const urlObj = new URL(this.connectionString); urlObj.pathname = `/${this.dbName}`; this.connectionString = urlObj.toString(); } /** * ๐Ÿ›ก๏ธ Retrieves the MongoDB connection, initializing it if not already connected. * * Ensures that the database connection is established and returns it. * * @returns {Promise} The established MongoDB connection. */ async getConnection() { if (!this.conn) { await this.init(); } return this.conn; } /** * ๐Ÿ“Š Creates a Mongoose model for a specific schema and collection. * * This method connects to the database, defines a schema, and initializes a model. * * @template IMongooseSchema - Interface representing the schema definition. * @param {mongoose.SchemaDefinition} schema - The schema to define the model. * @param {string} modelName - The name of the model and corresponding MongoDB collection. * @returns {Promise>} The initialized Mongoose model. */ async createModel(schema, modelName) { const mongooseSchema = _MongooseUtils.createSchema(schema, { collection: modelName }); const conn = await this.getConnection(); const model = conn.model(modelName, mongooseSchema, modelName); return model; } }; var MongooseUtils_default = MongooseUtils; // src/ModelManager.ts var ModelManager = class _ModelManager { // ๐Ÿ”’ Static instance for Singleton pattern // eslint-disable-next-line no-use-before-define static instance; /** ๐Ÿ“‹ Array storing all loaded Mongoose models. */ models = []; /** * ๐Ÿ”’ Private constructor to enforce singleton pattern. * Use `getInstance` to access the ModelManager. */ constructor() { } /** * ๐Ÿš€ Retrieves the singleton instance of the ModelManager. * Initializes the instance on the first call. * @static * @returns {Promise} The singleton instance. */ static async getInstance() { if (!this.instance) { this.instance = new _ModelManager(); await this.instance.init(); } return this.instance; } /** * โš™๏ธ Initializes the ModelManager by loading all models dynamically. * @private * @returns {Promise} Resolves when all models are loaded. */ async init() { if (import_lodash.default.isEmpty(this.models)) { const expression = `${process.cwd()}/**/*.model.mjs`; this.models = await this.globModels(expression); } } /** * ๐Ÿ” Finds model files using a glob pattern and dynamically imports them. * @private * @param {string} expression - Glob pattern to find model files. * @returns {Promise[]>} Resolves to an array of loaded models. */ async globModels(expression) { const modelPaths = await (0, import_glob.glob)(expression); const modelDetails = []; for (const path of modelPaths) { console.log("[ModelManager] - Importing Model:", path); const modelCoreDetail = await import( /* webpackIgnore: true */ path ); const { modelName, dbName, schema } = modelCoreDetail; const Model = await this.createModel({ modelName, schema, dbName }); console.log("[ModelManager] - Loaded Model:", modelName); modelDetails.push({ modelName, Model, dbName, schema }); } return modelDetails; } /** * โž• Adds a new Mongoose model to the collection. * Throws an error if the model name already exists. * @private * @template IMongooseSchema - The schema type. * @param {IModel} modelDetails - Details of the model. * @throws {ValidationError} If the model already exists. */ pushModel(modelDetails) { const existingModel = this.models.find((model) => model.modelName === modelDetails.modelName); if (existingModel) { throw new import_error_manager_helper2.ValidationError( `Model '${modelDetails.modelName}' already exists.`, { modelDetails, existingModel } ); } this.models.push(modelDetails); } /** * ๐Ÿงพ Returns all loaded Mongoose models. * @public * @returns {IModel[]} Array of loaded models. */ getModels() { return this.models; } /** * ๐Ÿ” Retrieves a Mongoose model by its name. * Throws an error if the model is not found. * @public * @param {string} name - The model name. * @returns {IModel} The Mongoose model or throws an error. * @throws {ResourceNotFoundError} If the model is not found. */ getModel(name) { const modelDetails = this.models.find((model) => model.modelName === name); if (!modelDetails) { throw new import_error_manager_helper2.ResourceNotFoundError(`[Model Manager] - Model '${name}' not found.`, { name }); } return modelDetails; } /** * ๐Ÿ—๏ธ Creates a new Mongoose model. * @public * @template IMongooseSchema - The schema type. * @param {IModelCore} modelDetails - Object containing details for creating the model. * @param {string} modelDetails.modelName - The name of the model being created. * This will be used as the identifier within the application and MongoDB collection. * @param {mongoose.Schema} modelDetails.schema - The Mongoose schema defining the structure * and validation rules for the model. It dictates how documents in the collection will be structured. * @param {string} modelDetails.dbName - The name of the database where the model will be stored. * This is essential for multi-tenant applications or cases where multiple databases are managed. * @returns {Promise>} The created Mongoose model. * */ async createModel({ modelName, schema, dbName }) { const mongooseUtils = MongooseUtils_default.getInstance(dbName); const Model = await mongooseUtils.createModel(schema, modelName); await Model.createIndexes(); this.pushModel({ modelName, Model, dbName, schema }); return Model; } }; // src/ModelUtils.ts var import_mongodb_memory_server = require("mongodb-memory-server"); var import_mongoose2 = __toESM(require("mongoose"), 1); var ModelUtils = class { /** * Creates an in-memory Mongoose model, connecting it to an in-memory MongoDB instance. * This is particularly useful for unit/integration testing without needing * to spin up a real MongoDB server. * * @static * @template IMongooseSchema - The TypeScript type representing the Mongoose schema. * @param {IModelCore} modelCoreDetails - The core model details including schema and model name. * @returns {Promise>} - Promise resolving to an in-memory model with its connection. */ static async createMemoryModel(modelCoreDetails) { const { dbName, schema, modelName } = modelCoreDetails; const mongooseSchema = MongooseUtils_default.createSchema(schema, { collection: modelName }); const mongoServer = await import_mongodb_memory_server.MongoMemoryServer.create({ instance: { dbName } }); const conn = await import_mongoose2.default.createConnection(mongoServer.getUri(), { dbName }).asPromise(); const Model = conn.model(modelName, mongooseSchema, modelName); const mongoUri = mongoServer.getUri(); const memoryModel = { Model, mongoServer, conn, mongoUri }; return memoryModel; } }; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { ModelManager, ModelUtils, MongooseUtils }); //# sourceMappingURL=index.cjs.map