base-domain
Version:
simple module to help build Domain-Driven Design
436 lines (347 loc) • 8.53 kB
JavaScript
var BaseDict, BaseModel,
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
hasProp = {}.hasOwnProperty,
slice = [].slice;
BaseModel = require('./base-model');
/**
dictionary-structured data model
@class BaseDict
@extends BaseModel
@module base-domain
*/
BaseDict = (function(superClass) {
extend(BaseDict, superClass);
/**
model name of the item
@property itemModelName
@static
@protected
@type String
*/
BaseDict.itemModelName = '';
/**
get unique key from item
@method key
@static
@protected
*/
BaseDict.key = function(item) {
return item.id;
};
/**
creates child class of BaseDict
@method getAnonymousClass
@params {String} itemModelName
@return {Function} child class of BaseDict
*/
BaseDict.getAnonymousClass = function(itemModelName) {
var AnonymousDict;
AnonymousDict = (function(superClass1) {
extend(AnonymousDict, superClass1);
function AnonymousDict() {
return AnonymousDict.__super__.constructor.apply(this, arguments);
}
AnonymousDict.itemModelName = itemModelName;
AnonymousDict.isAnonymous = true;
return AnonymousDict;
})(BaseDict);
return AnonymousDict;
};
/**
ids: get ids of items
@property ids
@type Array
@public
*/
Object.defineProperty(BaseDict.prototype, 'ids', {
get: function() {
var item, key;
if (!this.constructor.containsEntity()) {
return null;
}
return (function() {
var ref, results;
ref = this.items;
results = [];
for (key in ref) {
item = ref[key];
results.push(item.id);
}
return results;
}).call(this);
}
});
/**
items: dictionary of keys - models
@property items
@type Objects
*/
/**
loaded: is data loaded or not
@property loaded
@type Boolean
*/
/**
itemFactory: instance of factory which creates item models
@property itemFactory
@type BaseFactory
*/
/**
@constructor
*/
function BaseDict(props) {
var _itemFactory;
if (props == null) {
props = {};
}
_itemFactory = null;
Object.defineProperties(this, {
items: {
value: {},
enumerable: true
},
loaded: {
value: false,
writable: true
},
listeners: {
value: []
},
itemFactory: {
get: function() {
return _itemFactory != null ? _itemFactory : _itemFactory = this.getFacade().createFactory(this.constructor.itemModelName, true);
}
}
});
if (props.items) {
this.setItems(props.items);
}
if (props.ids) {
this.setIds(props.ids);
}
BaseDict.__super__.constructor.call(this, props);
}
/**
check if the model has submodel of the given key or not
@method has
@public
@param {String|Number} key
@return {Boolean}
*/
BaseDict.prototype.has = function(key) {
return this.items[key] != null;
};
/**
check if the model contains the given submodel or not
@method contains
@public
@param {BaseModel} item
@return {Boolean}
*/
BaseDict.prototype.contains = function(item) {
var key, sameKeyItem;
key = this.constructor.key(item);
sameKeyItem = this.get(key);
return item === sameKeyItem;
};
/**
return submodel of the given key
@method get
@public
@param {String|Number} key
@return {BaseModel}
*/
BaseDict.prototype.get = function(key) {
return this.items[key];
};
/**
add new submodel to item(s)
@method get
@public
@param {BaseModel} item
*/
BaseDict.prototype.add = function() {
var ItemClass, item, items, key, prevKey, results;
items = 1 <= arguments.length ? slice.call(arguments, 0) : [];
ItemClass = this.getFacade().getModel(this.constructor.itemModelName);
results = [];
for (prevKey in items) {
item = items[prevKey];
if (!(item instanceof ItemClass)) {
continue;
}
key = this.constructor.key(item);
results.push(this.items[key] = item);
}
return results;
};
/**
remove submodel from items
both acceptable, keys and submodels
@method remove
@public
@param {BaseModel|String|Number} item
*/
BaseDict.prototype.remove = function() {
var ItemClass, arg, args, i, key, len;
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
ItemClass = this.getFacade().getModel(this.constructor.itemModelName);
for (i = 0, len = args.length; i < len; i++) {
arg = args[i];
if (arg instanceof ItemClass) {
key = this.constructor.key(arg);
} else {
key = arg;
}
delete this.items[key];
}
};
/**
set ids.
@method setIds
@param {Array(String|Number)} ids
*/
BaseDict.prototype.setIds = function(ids) {
var ItemRepository, id, repo, subModels;
if (ids == null) {
ids = [];
}
if (!this.constructor.containsEntity()) {
return;
}
this.loaded = false;
ItemRepository = this.getFacade().getRepository(this.constructor.itemModelName);
repo = new ItemRepository();
if (ItemRepository.storeMasterTable && ItemRepository.loaded()) {
subModels = (function() {
var i, len, results;
results = [];
for (i = 0, len = ids.length; i < len; i++) {
id = ids[i];
results.push(repo.getByIdSync(id));
}
return results;
})();
this.setItems(subModels);
} else {
repo.query({
where: {
id: {
inq: ids
}
}
}).then((function(_this) {
return function(subModels) {
return _this.setItems(subModels);
};
})(this));
}
return this;
};
/**
set items from dic object
update to new key
@method setItems
@param {Object|Array} models
*/
BaseDict.prototype.setItems = function(models) {
var item, items, prevKey;
if (models == null) {
models = {};
}
items = (function() {
var results;
results = [];
for (prevKey in models) {
item = models[prevKey];
results.push(item);
}
return results;
})();
this.add.apply(this, items);
this.loaded = true;
this.emitLoaded();
return this;
};
/**
returns item is Entity
@method containsEntity
@static
@public
@return {Boolean}
*/
BaseDict.containsEntity = function() {
return this.getFacade().getModel(this.itemModelName).isEntity;
};
/**
export models to Array
@method toArray
@public
*/
BaseDict.prototype.toArray = function() {
var item, key, ref, results;
ref = this.items;
results = [];
for (key in ref) {
item = ref[key];
results.push(item);
}
return results;
};
/**
create plain dict.
if this dict contains entities, returns their ids
if this dict contains non-entity models, returns their plain objects
@method toPlainObject
@return {Object} plainObject
*/
BaseDict.prototype.toPlainObject = function() {
var item, key, plain, plainItems, ref;
plain = BaseDict.__super__.toPlainObject.call(this);
if (this.constructor.containsEntity()) {
plain.ids = this.ids;
delete plain.items;
} else {
plainItems = [];
ref = this.items;
for (key in ref) {
item = ref[key];
if (typeof item.toPlainObject === 'function') {
plainItems[key] = item.toPlainObject();
} else {
plainItems[key] = item;
}
}
plain.items = plainItems;
}
return plain;
};
/**
on addEventlisteners for 'loaded'
@method on
@public
*/
BaseDict.prototype.on = function(evtname, fn) {
if (evtname !== 'loaded') {
return;
}
if (this.loaded) {
process.nextTick(fn);
} else if (typeof fn === 'function') {
this.listeners.push(fn);
}
};
/**
tell listeners emit loaded
@method emitLoaded
@private
*/
BaseDict.prototype.emitLoaded = function() {
var fn;
while (fn = this.listeners.shift()) {
process.nextTick(fn);
}
};
return BaseDict;
})(BaseModel);
module.exports = BaseDict;