framework for Domain-Driven Design in JavaScript (or CoffeeScript, recommended.)
$ npm install -g base-domain
base-domain helps easier practice of Domain-Driven Design.
- list models in the domain of your concern (by your own way)
- define models with base-domain
- define their factories with base-domain
- define their repositories with base-domain
- define services with base-domain if needed
- Base
- Facade
- BaseModel
- BaseFactory
- BaseRepository
- Entity
- ValueObject
- BaseList
- BaseDict
- Base is an origin of all classes
- Base has Facade
- Base does not have any other properties or methods
- Facade is the gate of all classes
- Facade knows all classes
- Facade is module-exported in base-domain: require('base-domain') returns Facade class
- BaseModel is a base class of model
- essential methods for model are defined
- BaseModel is a child of Base
- BaseFactory is a base class of factory
- BaseFactory creates specific BaseModel instance
- BaseFactory is a child of Base
- BaseRepository is a base class of repository
- BaseRepository connects to database, filesystem or other external data resources (settings needed).
- BaseRepository saves specific BaseModel to data resources
- BaseRepository read BaseModels from data resources
- BaseRepository base BaseFactory (to generate BaseModel from data resources)
- ValueObject is child of BaseModel
- instance of ValueObject does not have id
- ValueObject.isEntity is false
- that's all of ValueObject
- Entity is child of BaseModel
- instance of Entity has id
- Entity.isEntity is true
- BaseList is child of ValueObject
- BaseList has many BaseModels as items
- BaseList#items is array of specific BaseModel
- BaseDict is child of ValueObject
- BaseDict has many BaseModels as items
- BaseDict#items is dictionary of key => specific BaseModel
- BaseDict.key is function to get key from item
MODEL_NAME='foo-bar'
DIR_NAME='.'
$ base-domain $MODEL_NAME $DIR_NAME
- ./foo-bar.coffee
- ./foo-bar-factory.coffee
- ./foo-bar-repository.coffee
are generated.
- foo-bar.coffee defines and exports class FooBar extends Entity
- foo-bar-factory.coffee defines and exports class FooBarFactory extends BaseFactory
- foo-bar-repository.coffee defines and exports class FooBarRepository extends BaseRepository
model is classified into "Entity" and "ValueObject"
Entity is model with id, ValueObject is model without id.
# {domain-dir}/hospital.coffee
class Hospital extends require('base-domain').Entity
# property types
@properties:
name : @TYPES.STRING
address : @TYPES.STRING
beds : @TYPES.NUMBER
registeredAt : @TYPES.DATE
isValidated : @TYPES.BOOLEAN
doctors : @TYPES.MODEL_LIST 'doctor'
flags : @TYPES.MODEL_DICT 'flag'
doctorIdx : @TYPES.TMP 'NUMBER'
module.exports = Hospital
there are two kinds of @TYPES.XXX
- @TYPES.XXX is object
- @TYPES.XXX is function
when @TYPES.XXX is object, you can just set props as follows
@properties:
somePropName: @TYPES.XXX
mark | property type | meaning |
---|---|---|
x | @TYPES.ANY | prop accepts any type |
x | @TYPES.STRING | prop is string |
x | @TYPES.NUMBER | prop is number |
x | @TYPES.DATE | prop is date |
x | @TYPES.BOOLEAN | prop is boolean |
x | @TYPES.ARRAY | prop is array |
x | @TYPES.OBJECT | prop is object |
x | @TYPES.BUFFER | prop is buffer |
x | @TYPES.GEOPOINT | prop is geopoint |
o | @TYPES.CREATED_AT | prop is date, automatically inserted when first saved |
o | @TYPES.UPDATED_AT | prop is date, automatically inserted each time saved |
o | @TYPES.TMP | prop is not saved |
these are object-typed types. Currently, types with marked "x" are just provides the name of the type.
base-domain does not validate
the prop's type.
when @TYPES.XXX is function, you must set type with arguments like
@properties:
somePropName: @TYPES.XXX 'arg1', 'arg2'
property type | meaning | arg1 | arg2 |
---|---|---|---|
@TYPES.MODEL | prop is BaseModel | model name | id prop name (if model is Entity) |
@TYPES.MODEL_LIST | prop is BaseList | item model name | model name (model name of BaseList) |
@TYPES.MODEL_DICT | prop is BaseDict | item model name | model name (model name of BaseDict) |
@TYPES.TMP | prop is not saved | type |
# {domain-dir}/hospital-factory.coffee
class HospitalFactory extends require('base-domain').BaseFactory
@modelName: 'hospital'
module.exports = HospitalFactory
# {domain-dir}/hospital-repository.coffee
class HospitalRepository extends require('base-domain').BaseRepository
@modelName: 'hospital'
module.exports = HospitalRepository
domain = require('base-domain').createInstance
dirname: '/path/to/domain-dir'
Hospital = domain.getModel('hospital')
hospitalFactory = domain.createFactory('hospital')
hospitalRepository = domain.createRepository('hospital')
hosp = hospitalFactory.createFromObject(name: 'Suzuki Clinic')
hospitalRepository.query(where: name: 'CureApp Hp.').then (hospitals)->
console.log hospitals
# {domain-dir}/hospital-list.coffee
class HospitalList extends require('base-domain').BaseList
@itemModelName: 'hospital'
module.exports = HospitalList
# {domain-dir}/hospital-dict.coffee
class HospitalDict extends require('base-domain').BaseDict
@itemModelName: 'hospital'
@key: (item) -> item.id
module.exports = HospitalDict
browserify is a tool for packing a js project into one file for web browsers
to enable base-domain's requiring system in browsers, use 'base-domain/ify' transformer.
browserify -t [ base-domain/ify --dirname /path/to/domain/dir ] <entry-file>