ottoman
Version:
Ottoman Couchbase ODM
321 lines • 11.7 kB
JavaScript
"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