UNPKG

ottoman

Version:
321 lines 11.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Schema = void 0; const types_1 = require("./types"); const errors_1 = require("./errors"); const global_plugin_handler_1 = require("../plugins/global-plugin-handler"); const helpers_1 = require("./helpers"); const hooks_1 = require("../utils/hooks"); const cast_strategy_1 = require("../utils/cast-strategy"); const fn_schema_1 = require("./helpers/fn-schema"); const addTimestamp = (obj, field, currentTime) => { if (obj[field]) { if (typeof obj[field] === 'function') { obj[field] = { type: obj[field] }; } obj[field].default = currentTime; } else { obj[field] = { type: Date, default: currentTime }; } }; class Schema { /** * @summary Creates an instance of Schema. * @name Schema * @class * @public * * @param obj Schema definition * @param options Settings to build schema * @param options.strict removes fields if they aren't defined in the schema * @param options.preHooks initialization of preHooks since Schema constructor * @param options.postHooks initialization of postHooks since Schema constructor * @returns Schema * * @example * ```ts * const schema = new Schema({ name: String, age: { type: Number, intVal: true, min: 18 } }); * ``` */ constructor(obj, options = { strict: true }) { this.statics = {}; this.methods = {}; this.preHooks = {}; this.postHooks = {}; this.index = {}; this.queries = {}; const preHooks = options === null || options === void 0 ? void 0 : options.preHooks; const postHooks = options === null || options === void 0 ? void 0 : options.postHooks; this.options = options; const strict = (options === null || options === void 0 ? void 0 : options.strict) === undefined ? true : options.strict; let timestamps = options.timestamps; if (timestamps === true) { timestamps = { createdAt: true, updatedAt: true }; } if (timestamps) { let createdAt = 'createdAt'; let updatedAt = 'updatedAt'; if (typeof timestamps === 'object') { const currentTime = timestamps.currentTime || function () { return new Date(); }; if (timestamps.createdAt || timestamps.currentTime) { createdAt = typeof timestamps.createdAt === 'string' ? timestamps.createdAt : createdAt; addTimestamp(obj, createdAt, currentTime); } if (timestamps.updatedAt || timestamps.currentTime) { updatedAt = typeof timestamps.updatedAt === 'string' ? timestamps.updatedAt : updatedAt; addTimestamp(obj, updatedAt, currentTime); this.pre(hooks_1.HOOKS.UPDATE, (doc) => { doc[updatedAt] = typeof currentTime === 'function' ? currentTime() : currentTime; return doc; }); } } } this.fields = (0, helpers_1.buildFields)(obj, strict); this.plugin(...(0, global_plugin_handler_1.getGlobalPlugins)()); if (preHooks !== undefined) { this._initPreHooks(hooks_1.HOOKS.VALIDATE, preHooks[hooks_1.HOOKS.VALIDATE]); this._initPreHooks(hooks_1.HOOKS.SAVE, preHooks[hooks_1.HOOKS.SAVE]); this._initPreHooks(hooks_1.HOOKS.UPDATE, preHooks[hooks_1.HOOKS.UPDATE]); this._initPreHooks(hooks_1.HOOKS.REMOVE, preHooks[hooks_1.HOOKS.REMOVE]); } if (postHooks !== undefined) { this._initPostHooks(hooks_1.HOOKS.VALIDATE, postHooks[hooks_1.HOOKS.VALIDATE]); this._initPostHooks(hooks_1.HOOKS.SAVE, postHooks[hooks_1.HOOKS.SAVE]); this._initPostHooks(hooks_1.HOOKS.UPDATE, postHooks[hooks_1.HOOKS.UPDATE]); this._initPostHooks(hooks_1.HOOKS.REMOVE, postHooks[hooks_1.HOOKS.REMOVE]); } } /** * Validate a model instance using the definition of the schema. * @method * @public * * @example * ```ts * const schema = new Schema({ name: String, age: { type: Number, intVal: true, min: 18 } }); * const result = schema.validate({name: 'John Doe', age: '34'}); * console.log(result) * ``` * > `{name: 'John Doe', age: 34}` */ validate(data, options = {}) { const _options = { strategy: cast_strategy_1.CAST_STRATEGY.THROW, strict: options.strict !== undefined ? options.strict : this.options.strict, }; return (0, helpers_1.validate)(data, this, _options); } /** * Cast a model instance using schema definition. * @method * @public * * @example * ```ts * const schema = new Schema({ name: String, age: {type: Number }}); * const result = schema.cast({ name: 'John Doe', age: '34' }); * console.log(result) * ``` * > `{ name: 'John Doe', age: 34 }` */ cast(data, options = {}) { options.strict = options.strict !== undefined ? options.strict : this.options.strict; return (0, cast_strategy_1.cast)(data, this, options); } /** * Applies default values defined on schema to an object instance. * @method * @public * @param obj * @example * ```ts * const schema = new Schema({ amount: { type: Number, default: 5 } }); * const result = schema.applyDefaultsToObject({}); * console.log(result) * ``` * > `{ amount: 5 }` */ applyDefaultsToObject(obj) { for (const key in this.fields) { const field = this.fields[key]; if (typeof obj[field.name] === 'undefined' && field instanceof types_1.CoreType) { if (field instanceof types_1.EmbedType) { const _val = {}; field.schema.applyDefaultsToObject(_val); if (Object.keys(_val).length > 0) { obj[field.name] = _val; } } else { const _val = field.buildDefault(); if (typeof _val !== 'undefined') { obj[field.name] = _val; } } } } return obj; } /** * Allows access to a specific field. * @example * ```ts * const schema = new Schema({ amount: { type: Number, default: 5 } }); * const field = schema.path('amount'); * console.log(field.typeName); * ``` * > Number */ path(path) { return this.fields[path]; } /** * Allows to apply plugins, to extend schema and model features. * @example * ```ts * const schema = new Schema({ amount: { type: Number, default: 5 } }); * schema.plugin((schema) => console.log(schema.path('amount').typeName)); * ``` * > Number */ plugin(...fns) { if (fns && Array.isArray(fns)) { for (const fn of fns) { fn(this); } } return this; } /** * Register a hook method. * Pre hooks are executed before the hooked method. * @example * ```ts * const schema = new Schema({ amount: { type: Number, default: 5} } ); * schema.pre(HOOKS.validate, (doc) => console.log(doc)); * ``` */ pre(hook, handler) { Schema.checkHook(hook); if (this.preHooks[hook] === undefined) { this.preHooks[hook] = []; } this.preHooks[hook].push(handler); return this; } /** * Register a hook function. * Post hooks are executed after the hooked method. * @example * ```ts * const schema = new Schema({ amount: { type: Number, default: 5} } ); * schema.post(HOOKS.validate, (doc) => console.log(doc)); * ``` */ post(hook, handler) { Schema.checkHook(hook); if (this.postHooks[hook] === undefined) { this.postHooks[hook] = []; } this.postHooks[hook].push(handler); return this; } static checkHook(hook) { if (!Object.values(hooks_1.HOOKS).includes(hook)) { throw new errors_1.BuildSchemaError(`The hook '${hook}' is not allowed`); } } _initPreHooks(hook, handlers) { if (handlers !== undefined) { if (typeof handlers === 'function') { handlers = [handlers]; } for (const i in handlers) { if (typeof handlers[i] === 'function') { this.pre(hook, handlers[i]); } } } } _initPostHooks(hook, handlers) { if (handlers !== undefined) { if (typeof handlers === 'function') { handlers = [handlers]; } for (const i in handlers) { if (typeof handlers[i] === 'function') { this.post(hook, handlers[i]); } } } } /** * Adds fields/schema type pairs to this schema. * @example * ```ts * const plane = new Schema({ name: String }); * const boeing = new Schema({ price: Number }); * boeing.add(plane); * * // You can add also add fields to this schema * boeing.add({ status: Boolean }); * ``` * @param obj Plain object to add, or another schema * @return Schema */ add(obj) { if (obj instanceof Schema) { this._addSchema(obj); } else if (typeof obj === 'object') { this._addObject(obj); } else { throw TypeError('Wrong type, must be Object or Schema'); } return this; } _addObject(obj) { var _a; const strict = ((_a = this.options) === null || _a === void 0 ? void 0 : _a.strict) || false; const objFields = (0, helpers_1.buildFields)(obj, strict); this.fields = Object.assign(Object.assign({}, this.fields), objFields); } _addSchema(obj) { this.fields = Object.assign(Object.assign({}, this.fields), obj.fields); this.queries = Object.assign(Object.assign({}, this.queries), obj.queries); this.index = Object.assign(Object.assign({}, this.index), obj.index); this.methods = Object.assign(Object.assign({}, this.methods), obj.methods); this.statics = Object.assign(Object.assign({}, this.statics), obj.statics); this.preHooks = (0, fn_schema_1.mergeHooks)(this.preHooks, obj.preHooks); this.postHooks = (0, fn_schema_1.mergeHooks)(this.postHooks, obj.postHooks); } } exports.Schema = Schema; Schema.FactoryTypes = { String: types_1.stringTypeFactory, Boolean: types_1.booleanTypeFactory, Number: types_1.numberTypeFactory, Date: types_1.dateTypeFactory, Array: types_1.arrayTypeFactory, Reference: types_1.referenceTypeFactory, Embed: types_1.embedTypeFactory, Mixed: types_1.mixedTypeFactory, }; Schema.Types = { String: types_1.StringType.prototype, Boolean: types_1.BooleanType.prototype, Number: types_1.NumberType.prototype, Date: types_1.DateType.prototype, Array: types_1.ArrayType.prototype, Reference: types_1.ReferenceType.prototype, Embed: types_1.EmbedType.prototype, Mixed: types_1.MixedType.prototype, }; Schema.validators = {}; //# sourceMappingURL=schema.js.map