base-domain
Version:
simple module to help build Domain-Driven Design
341 lines (235 loc) • 7.22 kB
text/coffeescript
'use strict'
TypeInfo = require './type-info'
Base = require './base'
ModelProps = require './model-props'
Util = require '../util'
###*
Base model class of DDD pattern.
BaseModel
Base
base-domain
###
class BaseModel extends Base
: false
###*
key-value pair representing typeName - type
use for definition of for each extender
TYPES
Object
###
: TypeInfo.TYPES
###*
key-value pair representing property's name - type of the model
firstName : .STRING
lastName : .STRING
age : .NUMBER
registeredAt : .DATE
team : .MODEL 'team'
hobbies : .MODEL 'hobby-list'
info : .ANY
see type-info.coffee for full options.
properties
Object
###
: {}
###*
extend of Parent class
class Parent extends BaseModel
:
prop1: .STRING
class ChildModel extends ParentModel
:
prop2: .NUMBER
ChildModel.properties # prop1 and prop2
withParentProps
{Object}
###
: (properties = {}) ->
properties[k] ?= v for k, v of # === parent's properties
return properties
###*
enum
{Object([key: String => Number])}
###
: (prop) ->
# TODO Object.assign()
?[prop]?.numsByValue
###*
enum
{Object}
###
enum: (prop) ->
().getEnumDic(prop)
###*
getModelProps
{ModelProps}
###
getModelProps: ->
if ?
().getModelProps(.getName())
else
new ModelProps(.getName(), .properties, null)
###*
{any} obj
{RootInterface} root
###
constructor: (obj, root) ->
super(root)
obj if obj
###*
set value to prop
{BaseModel} this
###
set: (prop, value) ->
if typeof prop is 'object'
(k, v) for k, v of prop
return @
@[prop] = value
modelProps = ()
# 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)
(prop, value)
return @
###*
set enum value
setEnum
{String} prop
{String|Number} value
###
setEnum: (prop, value) ->
return if not value?
modelProps = ()
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
unset
{String} prop property name
{BaseModel} this
###
unset: (prop) ->
@[prop] = undefined
modelProps = ()
if modelProps.isEntity(prop)
subIdProp = modelProps.getIdPropByEntityProp(prop)
@[subIdProp] = undefined
return @
###*
inherit value of anotherModel
inherit
{BaseModel} anotherModel
{BaseModel} this
###
inherit: (anotherModel) ->
(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)
toPlainObject
{Object} plainObject
###
toPlainObject: ->
plainObject = {}
modelProps = ()
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
equals
{BaseModel} model
{Boolean}
###
equals: (model) ->
model? and is model.constructor
###*
clone the model as a plain object
plainClone
{Object}
###
plainClone: ->
plainObject = {}
modelProps = ()
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
clone
{BaseModel}
###
clone: ->
plainObject = ()
modelProps = ()
return ().createModel modelProps.modelName, plainObject
###*
include all relational models if not set
include
{Object} [options]
{Boolean} [options.recursive] recursively include models or not
{Boolean} [options.async=true] get async values
{Array(String)} [options.props] include only given props
{Promise(BaseModel)} self
###
include: (options = {}) ->
Includer = require './includer'
new Includer(@, options).include().then => @
###*
Check if all subentities are included.
included
{Boolean}
###
included: (recursive = false) ->
modelProps = ()
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