File: src/lib/base-model.coffee
TypeInfo = require './type-info'
PropInfo = require './prop-info'
Base = require './base'
Includer = require './includer'
###*
Base model class of DDD pattern.
the parent "Base" class just simply gives a @getFacade() method.
@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_LIST 'hobby'
info : @TYPES.ANY
see type-info.coffee for full options.
@property properties
@abstract
@static
@protected
@type Object
###
@properties: {}
###*
get an instance of PropInfo, which summarizes properties of this class
@method getPropInfo
@public
@return {PropInfo}
###
@_pi: null
@getPropInfo: ->
@_pi ?= new PropInfo @properties, @getFacade()
###*
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: (props = {}) ->
props[k] ?= v for k, v of @properties # @properties === parent's properties
return props
###*
get list of properties which contains entity
@method getEntityProps
@public
@static
@return {Array}
###
@getEntityProps: ->
@getPropInfo().entityProps
###*
get list of properties which contains relational model
@method getModelProps
@public
@static
@param {Object} [options]
@param {Boolean} [options.includeList] include props of BaseList
@return {Array}
###
@getModelProps: (options = {}) ->
propInfo = @getPropInfo()
ret = propInfo.modelProps.slice()
ret.concat propInfo.listProps if options.includeList
return ret
###*
@constructor
###
constructor: (obj) ->
@set obj if obj
getTypeInfo: (prop) ->
@constructor.getPropInfo().dic[prop]
isEntityProp: (prop) ->
@constructor.getPropInfo().isEntityProp prop
###*
set value to prop
@return {BaseModel} this
###
set: (prop, value) ->
if typeof prop is 'object'
@set(k, v) for k, v of prop
return @
typeInfo = @getTypeInfo prop
if typeInfo?.model and @isEntityProp prop
@setEntityProp(prop, value)
else
@setNonEntityProp(prop, value)
return @
###*
set model prop
@return {BaseModel} this
###
setNonEntityProp: (prop, value) ->
@[prop] = value
###*
set related model(s)
@method setEntityProp
@param {String} prop property name of the related model
@param {Entity|Array<Entity>} submodel
@return {BaseModel} this
###
setEntityProp: (prop, submodel) ->
typeInfo = @getTypeInfo prop
modelName = typeInfo.model
@[prop] = submodel
idPropName = typeInfo.idPropName
@[idPropName] = submodel?.id
return @
###*
unset related model(s)
@param {String} prop property name of the related models
@return {BaseModel} this
@method unsetEntityProp
###
unsetEntityProp: (prop) ->
typeInfo = @getTypeInfo(prop)
@[prop] = undefined
@[typeInfo.idPropName] = undefined
return @
###*
inherit value of anotherModel
@method inherit
@param {BaseModel} anotherModel
@return {BaseModel} this
###
inherit: (anotherModel) ->
for own k, v of anotherModel
if v?
@[k] = 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: ->
facade = @getFacade()
plainObject = {}
for own prop, value of @
# remove entities
if @isEntityProp prop
continue
typeInfo = @getTypeInfo prop
continue if typeInfo?.tmp
# set non-model properties
if not typeInfo?.model?
plainObject[prop] = value
continue
# plainize submodels, lists
if typeof value?.toPlainObject is 'function'
plainObject[prop] = value.toPlainObject()
else
plainObject[prop] = value
return plainObject
###*
include all relational models if not set
@method include
@param {Object} [options]
@param {Boolean} [options.recursive] recursively include models or not
@return {Promise(BaseModel)} self
###
include: (options = {}) ->
new Includer(@).include(recursive: options.recursive)
module.exports = BaseModel