UNPKG

base-domain

Version:

simple module to help build Domain-Driven Design

399 lines (284 loc) 7.7 kB
'use strict' ValueObject = require './value-object' EntityPool = require '../entity-pool' BaseModel = require './base-model' ###* collection model of one model @class Collection @extends ValueObject @module base-domain ### class Collection extends ValueObject ###* model name of the item @property itemModelName @static @protected @type String ### @itemModelName: null ###* the number of items (or ids when @isItemEntity is true) @property {Number} length @public ### Object.defineProperty @::, 'length', get: -> if @isItemEntity return @ids.length else return @itemLength ###* items (submodel collection) @property {Object} items @abstract ### ###* @constructor @params {any} props @params {RootInterface} root ### constructor: (props = {}, root) -> @setRoot(root) if not @constructor.itemModelName? throw @error 'base-domain:itemModelNameRequired', "@itemModelName is not set, in class #{@constructor.name}" _itemFactory = null isItemEntity = @getFacade().getModel(@constructor.itemModelName).isEntity Object.defineProperties @, ###* item factory Created only one time. Be careful that @root is not changed even the collection's root is changed. @property {FactoryInterface} itemFactory ### itemFactory: get: -> _itemFactory ?= require('./general-factory').create(@constructor.itemModelName, @root) isItemEntity: value: isItemEntity, writable: false @clear() if props.ids? and props.items { ids } = props delete props.ids super(props, root) props.ids = ids else super(props, root) ###* Get the copy of ids @return {Array(String)} ids ### getIds: -> return undefined if not @isItemEntity return @ids?.slice() ###* set value to prop @return {BaseModel} this ### set: (k, v) -> switch k when 'items' @setItems v when 'ids' @setIds v else super return @ ###* add new submodel to item(s) @method add @public @param {BaseModel|Object} ...items ### add: (items...) -> @addItems(items) ###* @method addItems @param {Object|Array(BaseModel|Object)} items @protected ### addItems: (items = []) -> @initItems() if not @loaded() factory = @itemFactory for key, item of items @addItem(factory.createFromObject item) if @isItemEntity @ids = (item.id for item in @toArray()) ###* add item to @items @method addItem @protected @abstract @param {BaseModel} item ### addItem: (item) -> ###* clear and set ids. @method setIds @param {Array(String|Number)} ids @chainable ### setIds: (ids = []) -> return if not @isItemEntity return if not Array.isArray ids @clear() @ids = ids ###* clear and add items @method setItems @param {Object|Array(BaseModel|Object)} items ### setItems: (items = []) -> @clear() @addItems(items) return @ ###* removes all items and ids @method clear ### clear: -> delete @items if @isItemEntity @ids = [] ###* export items to Array @method toArray @public @abstract @return {Array} ### toArray: -> ###* Execute given function for each item @method forEach @public @param {Function} fn @param {Object} _this ### forEach: (fn, _this) -> @map(fn, _this) return ###* Execute given function for each item returns an array of the result @method map @public @param {Function} fn @param {Object} _this @return {Array} ### map: (fn, _this) -> _this ?= @ return [] if typeof fn isnt 'function' (fn.call(_this, item) for item in @toArray()) ###* Filter items with given function @method filter @public @param {Function} fn @param {Object} _this @return {Array} ### filter: (fn, _this) -> _this ?= @ return @toArray() if typeof fn isnt 'function' @toArray().filter(fn, _this) ###* Returns if some items match the condition in given function @method some @public @param {Function} fn @param {Object} _this @return {Boolean} ### some: (fn, _this) -> _this ?= @ return false if typeof fn isnt 'function' @toArray().some(fn, _this) ###* Returns if every items match the condition in given function @method every @public @param {Function} fn @param {Object} _this @return {Boolean} ### every: (fn, _this) -> _this ?= @ return false if typeof fn isnt 'function' @toArray().every(fn, _this) initItems: -> ###* 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 = {}) -> options.entityPool ?= new EntityPool superResult = super(options) if not @isItemEntity @includeVOItems(options, superResult) else @includeEntityItems(options, superResult) includeVOItems: (options, superResult) -> return superResult if not options.recursive Promise.all([ superResult Promise.all @map (item) -> item.include(options) ]).then => @ includeEntityItems: (options, superResult) -> EntityCollectionIncluder = require './entity-collection-includer' Promise.all([ superResult new EntityCollectionIncluder(@, options).include() ]).then => @ ###* create plain object. if this dict contains entities, returns their ids if this dict contains non-entity models, returns their plain objects @method toPlainObject @return {Object} plainObject ### toPlainObject: -> plain = super() if @isItemEntity plain.ids = @ids.slice() delete plain.items else if @loaded() plainItems = for key, item of @items if typeof item.toPlainObject is 'function' item.toPlainObject() else item plain.items = plainItems return plain ###* clone the model as a plain object @method clone @return {BaseModel} ### plainClone: -> plain = super() if @loaded() plain.items = for key, item of @items if item instanceof BaseModel item.plainClone() else item return plain ###* @method loaded @public @return {Boolean} ### loaded: -> @items? ###* get item model @method getItemModelClass @return {Function} ### getItemModelClass: -> @getFacade().getModel(@constructor.itemModelName) module.exports = Collection