UNPKG

base-domain

Version:

simple module to help build Domain-Driven Design

341 lines (235 loc) 7.22 kB
'use strict' TypeInfo = require './type-info' Base = require './base' ModelProps = require './model-props' Util = require '../util' ###* Base model class of DDD pattern. @class BaseModel @extends Base @module base-domain ### class BaseModel extends Base @isEntity: false ###* key-value pair representing typeName - type use for definition of @properties for each extender @property TYPES @protected @final @static @type Object ### @TYPES: TypeInfo.TYPES ###* key-value pair representing property's name - type of the model firstName : @TYPES.STRING lastName : @TYPES.STRING age : @TYPES.NUMBER registeredAt : @TYPES.DATE team : @TYPES.MODEL 'team' hobbies : @TYPES.MODEL 'hobby-list' info : @TYPES.ANY see type-info.coffee for full options. @property properties @abstract @static @protected @type Object ### @properties: {} ###* extend @properties of Parent class @example class Parent extends BaseModel @properties: prop1: @TYPES.STRING class ChildModel extends ParentModel @properties: @withParentProps prop2: @TYPES.NUMBER ChildModel.properties # prop1 and prop2 @method withParentProps @protected @static @return {Object} ### @withParentProps: (properties = {}) -> properties[k] ?= v for k, v of @properties # @properties === parent's properties return properties ###* @method enum @public @return {Object([key: String => Number])} ### @enum: (prop) -> # TODO Object.assign() @properties?[prop]?.numsByValue ###* @method enum @public @return {Object} ### enum: (prop) -> @getModelProps().getEnumDic(prop) ###* @method getModelProps @private @return {ModelProps} ### getModelProps: -> if @root? @getFacade().getModelProps(@constructor.getName()) else new ModelProps(@constructor.getName(), @constructor.properties, null) ###* @constructor @params {any} obj @params {RootInterface} root ### constructor: (obj, root) -> super(root) @set obj if obj ###* set value to prop @return {BaseModel} this ### set: (prop, value) -> if typeof prop is 'object' @set(k, v) for k, v of prop return @ @[prop] = value modelProps = @getModelProps() # set entity prop if modelProps.isEntity(prop) subIdProp = modelProps.getIdPropByEntityProp(prop) @[subIdProp] = value?.id # set submodel id prop else if modelProps.isId(prop) and value? @[prop] = value submodelProp = modelProps.getEntityPropByIdProp(prop) # if new submodel id is set and old one exists, delete old one if @[submodelProp]? and @[prop] isnt @[submodelProp].id @[submodelProp] = undefined # set enum else if modelProps.isEnum(prop) @setEnum(prop, value) return @ ###* set enum value @method setEnum @private @param {String} prop @param {String|Number} value ### setEnum: (prop, value) -> return if not value? modelProps = @getModelProps() enums = modelProps.getEnumDic(prop) if typeof value is 'string' and enums[value]? return @[prop] = enums[value] else if typeof value is 'number' and modelProps.getEnumValues(prop)[value]? return @[prop] = value console.error(""" base-domain: Invalid value is passed to ENUM prop "#{prop}" in model "#{modelProps.modelName}". Value: "#{value}" The property was not set. """) ###* unset property @method unset @param {String} prop property name @return {BaseModel} this ### unset: (prop) -> @[prop] = undefined modelProps = @getModelProps() if modelProps.isEntity(prop) subIdProp = modelProps.getIdPropByEntityProp(prop) @[subIdProp] = undefined return @ ###* inherit value of anotherModel @method inherit @param {BaseModel} anotherModel @return {BaseModel} this ### inherit: (anotherModel) -> @set(k, v) for own k, v of anotherModel when v? return @ ###* create plain object without relational entities descendants of Entity are removed, but not descendants of BaseModel descendants of Entity in descendants of BaseModel are removed ( = recursive) @method toPlainObject @return {Object} plainObject ### toPlainObject: -> plainObject = {} modelProps = @getModelProps() for own prop, value of @ continue if modelProps.isEntity(prop) or modelProps.isOmitted(prop) if typeof value?.toPlainObject is 'function' plainObject[prop] = value.toPlainObject() else plainObject[prop] = value return plainObject ###* check equality @method equals @param {BaseModel} model @return {Boolean} ### equals: (model) -> model? and @constructor is model.constructor ###* clone the model as a plain object @method plainClone @public @return {Object} ### plainClone: -> plainObject = {} modelProps = @getModelProps() for own prop, value of @ if modelProps.isModel and value instanceof BaseModel plainObject[prop] = value.plainClone() else plainObject[prop] = Util.clone value return plainObject ###* create clone @method clone @public @return {BaseModel} ### clone: -> plainObject = @plainClone() modelProps = @getModelProps() return @getFacade().createModel modelProps.modelName, plainObject ###* include all relational models if not set @method include @param {Object} [options] @param {Boolean} [options.recursive] recursively include models or not @param {Boolean} [options.async=true] get async values @param {Array(String)} [options.props] include only given props @return {Promise(BaseModel)} self ### include: (options = {}) -> Includer = require './includer' new Includer(@, options).include().then => @ ###* Check if all subentities are included. @method included @return {Boolean} ### included: (recursive = false) -> modelProps = @getModelProps() for entityProp in modelProps.getEntityProps() subIdProp = modelProps.getIdPropByEntityProp(entityProp) return false if @[subIdProp]? and not @[entityProp]? return true if not recursive for modelProp in modelProps.models return false if @[modelProp]? and not @[modelProp].included() return true module.exports = BaseModel