UNPKG

papr

Version:

MongoDB TypeScript-aware Models

175 lines (174 loc) 6.55 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __exportStar = (this && this.__exportStar) || function(m, exports) { for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Types = exports.types = exports.schema = void 0; const model_1 = require("./model"); const schema_1 = __importDefault(require("./schema")); exports.schema = schema_1.default; const types_1 = __importDefault(require("./types")); exports.types = types_1.default; exports.Types = types_1.default; class Papr { /** * Returns a new instance of `Papr`. * * It may be called with some options for before and after [hooks](api/hooks.md) and a maximum execution time for queries. * * @name Papr * * @param [options] {ModelOptions} * @param [options.hooks] {Hooks} * @param [options.maxTime] {number} * * @example * const papr = new Papr(); * * const paprWithOptions = new Papr({ * hooks: { * after: [afterHook], * before: [beforeHook] * }, * maxTime: 1000 * }); */ constructor(options) { // eslint-disable-next-line @typescript-eslint/no-explicit-any this.models = new Map(); // eslint-disable-next-line @typescript-eslint/no-explicit-any this.schemas = new Map(); this.options = options; } /** * Initialize existing and future registered models with a mongo db instance. * * @param db {mongodb.Db} * * @example * import { MongoClient } from 'mongodb'; * * const connection = await MongoClient.connect('mongodb://localhost:27017'); * * papr.initialize(connection.db('test')); */ initialize(db) { if (this.db) { return; } this.db = db; // If we have models defined before initializing a database, we build them now for (const [collectionName, collectionSchema] of this.schemas.entries()) { const model = this.models.get(collectionName); if (model && !model.collection) { (0, model_1.build)(collectionSchema, model, this.db.collection(collectionName), this.options); } } } /** * Builds a model instance and associates its collection name and schema. * * @param collectionName {string} * @param collectionSchema {TSchema} * * @returns {Model<TSchema, TOptions>} * * @example * const User = papr.model('users', userSchema); */ model(collectionName, collectionSchema) { const model = (0, model_1.abstract)(collectionSchema); if (this.db) { (0, model_1.build)(collectionSchema, model, this.db.collection(collectionName), this.options); } this.models.set(collectionName, model); this.schemas.set(collectionName, collectionSchema); return model; } /** * Updates the validation schema and validation options on the MongoDB collection used by a model. * * It uses the [`createCollection`](https://docs.mongodb.com/manual/reference/method/db.createCollection/) * method for new collections, and the [`collMod`](https://docs.mongodb.com/manual/reference/command/collMod/#dbcmd.collMod) * command for existing collections. * * @param model {Model<TSchema, TOptions>} * * @returns {Promise<void>} * * @example * await papr.updateSchema(User); */ async updateSchema(model) { if (!this.db) { throw new Error('The DB is not connected'); } if (!model.collection) { throw new Error('The model collection is not initialized'); } const { collectionName } = model.collection; const { // @ts-expect-error We're defining the defaults in the JSON Schema object, but TS sees these as `any` $defaults, // @ts-expect-error We're defining these timestamp options in the JSON Schema object, but TS sees these as `any` $timestamps, // @ts-expect-error We're defining these validation options in the JSON Schema object, but TS sees these as `any` $validationAction: validationAction, // @ts-expect-error We're defining these validation options in the JSON Schema object, but TS sees these as `any` $validationLevel: validationLevel, ...schema } = model.schema; const options = { // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment validationAction, // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment validationLevel, validator: { $jsonSchema: schema, }, }; const collections = await this.db.collections(); const exists = collections.find((item) => item.collectionName === collectionName); if (exists) { await this.db.command({ collMod: collectionName, ...options, }); return; } await this.db.createCollection(collectionName, options); } /** * Updates the validation schemas and validation options on all the MongoDB collections registered by models. * * @returns {Promise<void>} * * @example * await papr.updateSchemas(); */ async updateSchemas() { if (!this.db) { throw new Error('The DB is not connected'); } // prettier-ignore await Promise.all([...this.models.values()].map(model => this.updateSchema(model))); } } exports.default = Papr; __exportStar(require("./hooks"), exports); __exportStar(require("./model"), exports); __exportStar(require("./mongodbTypes"), exports); __exportStar(require("./schema"), exports); __exportStar(require("./utils"), exports);