UNPKG

base-domain

Version:

simple module to help build Domain-Driven Design

297 lines (219 loc) 6.88 kB
require('es6-promise').polyfill() copy = require('copy-class').copy { camelize, requireFile } = require './util' getProto = Object.getPrototypeOf ? (obj) -> obj.__proto__ ###* Facade class of DDD pattern. - create instance of factories - create instance of repositories @class Facade @module base-domain ### class Facade ###* create instance of Facade @method createInstance @static @param {Object} [options] @return {Facade} ### @createInstance: (options= {}) -> Constructor = @ return new Constructor(options) ###* constructor @constructor @param {String} [options] @param {String} [options.dirname="."] path where domain definition files are included ### constructor: (options) -> @classes = {} @dirname = options.dirname ? '.' @init() # for base-domainify. keep it empty init: -> ###* load master tables @method loadMasterTables @return {Promise} ### loadMasterTables: (modelNames...) -> Promise.all (@getRepository(modelName).load?() for modelName in modelNames) ###* get a model class @method getModel @param {String} name @return {Class} ### getModel: (name) -> return @require(name) ###* get a factory class ISSUE: user will never know load failure @method getFactory @param {String} name @param {Boolean} [useAnonymousWhenFailed=false] @return {Function} ### getFactory: (name, useAnonymousWhenFailed = off) -> try return @require("#{name}-factory") catch e throw e if not useAnonymousWhenFailed AnonymousFactory = Facade.BaseFactory.getAnonymousClass(name) @addClass("#{name}-factory", AnonymousFactory, true) ###* get a repository class @method getRepository @param {String} name @return {Class} ### getRepository: (name) -> return @require("#{name}-repository") ###* create a factory instance @method createFactory @param {String} name @param {Boolean} [useAnonymousWhenFailed=false] @return {BaseFactory} ### createFactory: (name, useAnonymousWhenFailed = off) -> FactoryClass = @getFactory(name, useAnonymousWhenFailed) return new FactoryClass() ###* create a repository instance @method createRepository @param {String} name @param {Object} [options] @return {BaseRepository} ### createRepository: (name, options) -> @create("#{name}-repository", options) ###* read a file and returns class @method require @private @param {String} name @return {Function} ### require: (name) -> return @classes[name] if @classes[name]? file = "#{@dirname}/#{name}" klass = requireFile file @addClass name, klass ###* check existence of the class of the given name @method hasClass @param {String} name @return {Function} ### hasClass: (name) -> try @require(name) return true catch e return false ###* add copied class to facade. the class is acquired by @require(name) attaches getFacade() method (for both class and instance) @method addClass @private @param {String} name @param {Function} klass @param {Boolean} skipNameValidation validate class name is compatible with the name to register @return {Function} ### addClass: (name, klass, skipNameValidation = false) -> if skipNameValidation camelCasedName = camelize name else if klass.getName() isnt name throw @error """given class should be named '#{klass.getName()}', but '#{name}' given.""" camelCasedName = klass.name ParentClass = getProto(klass::).constructor if @constructor.isBaseClass ParentClass Class = copy(klass, camelCasedName) else CopiedParentClass = @require ParentClass.getName() Class = copy(klass, camelCasedName, CopiedParentClass) facade = @ Class.getFacade = -> facade Class::getFacade = -> facade @classes[name] = Class ###* read a file and returns the instance of the file's class @method create @private @param {String} name @param {Object} [options] @return {BaseFactory} ### create: (name, options) -> DomainClass = @require(name) return new DomainClass(options) ###* create instance of DomainError @method error @param {String} reason reason of the error @param {String} [message] @return {Error} ### error: (reason, message) -> DomainError = @constructor.DomainError return new DomainError(reason, message) ###* check if given object is instance of DomainError @method isDomainError @param {Error} e @return {Boolean} ### isDomainError: (e) -> DomainError = @constructor.DomainError return e instanceof DomainError ###* insert fixture data (Node.js only) @method insertFixtures @param {Object} [options] @param {String} [options.dataDir='./data'] directory to have fixture data files @param {String} [options.tsvDir='./tsv'] directory to have TSV files @param {Array(String)} [options.models=null] model names to insert. default: all models @return {Promise(Object)} dataPool inserted data ### insertFixtures: (options = {}) -> Fixture = require './fixture' fixture = new Fixture(@, options) fixture.insert(options.models).then -> return fixture.dataPool ###* check the given class is registered in facade @method isBaseClass @static @param {Function} klass @return {Boolean} ### @isBaseClass: (klass) -> (klass is @[klass.name]) or (klass is @DomainError) or (@[klass.name]?.toString() is klass.toString()) ###* registers the given class as a base class @method registerBaseClass @static @param {Function} klass ### @registerBaseClass: (klass) -> @[klass.name] = klass @Base : require './base' @BaseModel : require './base-model' @Entity : require './entity' @BaseList : require './base-list' @BaseDict : require './base-dict' @BaseFactory : require './base-factory' @ListFactory : require './list-factory' @DictFactory : require './dict-factory' @BaseRepository : require './base-repository' @MasterRepository : require './master-repository' @DomainError : require './domain-error' module.exports = Facade