UNPKG

blow-data

Version:
173 lines (144 loc) 4.8 kB
'use strict'; import * as Joi from 'joi'; import {pluralize} from 'inflection'; import {isUndefined} from 'util'; import {ModelPropertyMetadata} from './ModelPropertyMetadata'; import {ModelRelationMetadata} from './ModelRelationMetadata'; import { IBaseModelConstructor, IModelMetadataOptions, IModelMetadata, IModelPropertyMetadata, IModelRelationMetadata, IPersistedModelConstructor, IModelPropertyMetadataOptions, IModelRelationMetadataOptions } from './interfaces'; const DEFAULT_CONNECTION_NAME = 'default'; const ASYNC_VALIDATORS = ['custom']; export class ModelMetadata implements IModelMetadata { protected _name: string; protected _pluralName: string; protected _autoId: boolean; protected _connectionName: string; protected _properties: Map<string, IModelPropertyMetadata>; protected _relations: Map<string, IModelRelationMetadata>; protected _model: IBaseModelConstructor; protected _raw: any; constructor(options: IModelMetadataOptions, properties?: {[key: string]: IModelPropertyMetadataOptions}, relations?: {[key: string]: IModelRelationMetadataOptions}) { this._raw = { options, properties, relations } this._name = options.name; this._pluralName = isUndefined(options.pluralName) ? pluralize(options.name) : options.pluralName; this._autoId = isUndefined(options.autoId) ? true : options.autoId; this._properties = new Map(); this._relations = new Map(); this._connectionName = isUndefined(options.connection) ? DEFAULT_CONNECTION_NAME : options.connection; } get name(): string { return this._name; } get pluralName(): string { return this._pluralName; } get autoId(): boolean { return this._autoId; } get properties(): IterableIterator<IModelPropertyMetadata> { return this._properties.values(); } get relations(): IterableIterator<IModelRelationMetadata> { return this._relations.values(); } get connectionName(): string { return this._connectionName; } get idProperty(): IModelPropertyMetadata { for(const property of this.properties) { if(property.id) { return property; } } } get validationSchema(): {[key: string]: any} { const schema = {}; for(const property of this.properties) { schema[property.name] = Joi; for(const validation of property.validations) { if(ASYNC_VALIDATORS.indexOf(validation[0]) === -1 && schema[property.name][validation[0]]) { schema[property.name] = schema[property.name][validation[0]](validation[1]); } } } return schema; } get asyncValidationSchema(): {[key: string]: any} { const schema = {}; for(const property of this.properties) { schema[property.name] = []; for(const validation of property.validations) { if(ASYNC_VALIDATORS.indexOf(validation[0]) !== -1) { schema[property.name].push(validation[1]); } } } return schema; } defineProperty(options: IModelPropertyMetadataOptions): void { if(options.id) { this._autoId = false; } const property = new ModelPropertyMetadata(options); this._properties.set(options.name, property); if(this._model) { property.apply(this._model); } } buildPropertyId(name: string, type: any): void { if(this.autoId && !this.idProperty) { this.defineProperty({ name: name, type: type, id: true }); } } getProperty(name: string): IModelPropertyMetadata { return this._properties.get(name); } hasProperty(name: string): boolean { return this._properties.has(name); } isAllowedProperty(name: string): boolean { return this.hasProperty(name); } defineRelation(options: IModelRelationMetadataOptions): void { const relation = new ModelRelationMetadata(options); this._relations.set(relation.name, relation); if(this._model) { relation.apply(<IPersistedModelConstructor>this._model); } } apply(model): void { if(!isUndefined(this._raw.properties)) { Object.keys(this._raw.properties).forEach(propertyName => { this.defineProperty(Object.assign({name: propertyName}, this._raw.properties[propertyName])); }); } if(!isUndefined(this._raw.relations)) { Object.keys(this._raw.relations).forEach(relationName => { this.defineRelation(Object.assign({name: relationName}, this._raw.relations[relationName])); }); } this._model = model; for(const property of this.properties) { property.apply(model); } for(const relation of this.relations) { relation.apply(model); } } }