base-domain
Version:
simple module to help build Domain-Driven Design
411 lines (327 loc) • 7.55 kB
JavaScript
'use strict';
var BaseDict, Collection,
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;
Collection = require('./collection');
/**
dictionary-structured data model
@class BaseDict
@extends Collection
@module base-domain
*/
BaseDict = (function(superClass) {
extend(BaseDict, superClass);
function BaseDict() {
return BaseDict.__super__.constructor.apply(this, arguments);
}
/**
get unique key from item
@method key
@static
@protected
*/
BaseDict.key = function(item) {
return item.id;
};
/**
the number of items
@property {Number} itemLength
@public
*/
Object.defineProperty(BaseDict.prototype, 'itemLength', {
get: function() {
if (!this.loaded()) {
return 0;
}
return Object.keys(this.items).length;
}
});
/**
items: dictionary of keys - models
@property {Object} items
*/
/**
@method initItems
@protected
*/
BaseDict.prototype.initItems = function() {
return this.items = {};
};
/**
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) {
if (!this.loaded()) {
return false;
}
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;
if (!this.loaded()) {
return false;
}
key = this.constructor.key(item);
sameKeyItem = this.get(key);
return sameKeyItem != null ? sameKeyItem.equals(item) : void 0;
};
/**
turn on/off the value
@method toggle
@param {BaseModel} item
*/
BaseDict.prototype.toggle = function(item) {
var key;
if (!this.loaded()) {
return this.add(item);
}
key = this.constructor.key(item);
if (this.has(key)) {
return this.remove(item);
} else {
return this.add(item);
}
};
/**
turn on/off the value and create a new model
@method toggle
@param {BaseModel} item
@return {BaseDict} newDict
*/
BaseDict.prototype.$toggle = function(item) {
var key;
if (!this.loaded()) {
throw this.error('NotLoaded');
}
key = this.constructor.key(item);
if (this.has(key)) {
return this.$remove(item);
} else {
return this.$add(item);
}
};
/**
return submodel of the given key
@method get
@public
@param {String|Number} key
@return {BaseModel}
*/
BaseDict.prototype.get = function(key) {
if (!this.loaded()) {
return void 0;
}
return this.items[key];
};
/**
return submodel of the given key
throw error when not found.
@method getItem
@public
@param {String|Number} key
@return {BaseModel}
*/
BaseDict.prototype.getItem = function(key) {
if (!this.has(key)) {
throw this.error('KeyNotFound');
}
return this.items[key];
};
/**
add item to @items
@method addItem
@protected
@param {BaseModel} item
*/
BaseDict.prototype.addItem = function(item) {
var key;
key = this.constructor.key(item);
return this.items[key] = item;
};
/**
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, idx, item, key, len;
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
if (!this.loaded()) {
return;
}
ItemClass = this.getItemModelClass();
for (i = 0, len = args.length; i < len; i++) {
arg = args[i];
if (arg instanceof ItemClass) {
key = this.constructor.key(arg);
} else {
key = arg;
}
item = this.items[key];
delete this.items[key];
if (item && this.ids) {
idx = this.ids.indexOf(item.id);
if (idx >= 0) {
this.ids.splice(idx, 1);
}
}
}
};
/**
remove submodel and create a new dict
both acceptable, keys and submodels
@method $remove
@public
@param {BaseModel|String|Number} item
@return {BaseDict} newDict
*/
BaseDict.prototype.$remove = function() {
var ItemClass, arg, args, i, key, len, newItems;
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
if (!this.loaded()) {
throw this.error('NotLoaded');
}
ItemClass = this.getItemModelClass();
newItems = this.toObject();
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 newItems[key];
}
return this.copyWith({
items: newItems
});
};
/**
replace item and return a new dict
@method $replace
@public
@param {BaseModel} item
@return {BaseDict} newDict
*/
BaseDict.prototype.$replace = function(item) {
var key, newItems;
newItems = this.toObject();
key = this.constructor.key(item);
if (key == null) {
throw new Error('InvalidItem');
}
if (!this.has(key)) {
throw new Error('KeyNotFound');
}
newItems[key] = item;
return this.copyWith({
items: newItems
});
};
/**
replace or add item and return a new dict
@method $append
@public
@param {BaseModel} item
@return {BaseDict} newDict
*/
BaseDict.prototype.$append = function(item) {
var key;
key = this.constructor.key(item);
if (key == null) {
throw new Error('InvalidItem');
}
if (this.has(key)) {
return this.$replace(item);
}
return this.$add(item);
};
/**
export models to Array
@method toArray
@public
*/
BaseDict.prototype.toArray = function() {
var item, key, ref, results;
if (!this.loaded()) {
return [];
}
ref = this.items;
results = [];
for (key in ref) {
item = ref[key];
results.push(item);
}
return results;
};
/**
get all keys
@method keys
@public
@return {Array}
*/
BaseDict.prototype.keys = function() {
var item, key, ref, results;
if (!this.loaded()) {
return [];
}
ref = this.items;
results = [];
for (key in ref) {
item = ref[key];
results.push(key);
}
return results;
};
/**
iterate key - item
@method keyValues
@public
@params {Function} fn 1st argument: key, 2nd argument: value
*/
BaseDict.prototype.keyValues = function(fn, _this) {
var item, key, ref;
if (_this == null) {
_this = this;
}
if (typeof fn !== 'function' || !this.loaded()) {
return;
}
ref = this.items;
for (key in ref) {
item = ref[key];
fn.call(_this, key, item);
}
};
/**
to key-value object
@method toObject
@public
*/
BaseDict.prototype.toObject = function() {
var k, obj, ref, v;
obj = {};
ref = this.items;
for (k in ref) {
v = ref[k];
obj[k] = v;
}
return obj;
};
return BaseDict;
})(Collection);
module.exports = BaseDict;