UNPKG

base-domain

Version:

simple module to help build Domain-Driven Design

292 lines (231 loc) 7.04 kB
var Base, BaseRepository, Entity, ResourceClientInterface, 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; Base = require('./base'); ResourceClientInterface = require('./resource-client-interface'); Entity = require('./entity'); /** Base repository class of DDD pattern. Responsible for perpetuation of models. BaseRepository has a client, which access to data resource (RDB, NoSQL, memory, etc...) the parent "Base" class just simply gives a @getFacade() method. @class BaseRepository @extends Base @module base-domain */ BaseRepository = (function(superClass) { extend(BaseRepository, superClass); /** model name to handle @property modelName @static @protected @type String */ BaseRepository.modelName = null; /** client accessing to data resource (RDB, NoSQL, memory, etc...) mock object is input by default. Extenders must set this property to achieve perpetuation @property client @abstract @protected @type ResourceClientInterface */ BaseRepository.prototype.client = new ResourceClientInterface(); /** constructor @constructor @return */ function BaseRepository() { var facade, modelName, useAnonymousFactory; modelName = this.constructor.modelName; facade = this.getFacade(); useAnonymousFactory = true; this.factory = facade.createFactory(modelName, useAnonymousFactory); } /** get model class this factory handles @method getModelClass @return {Class} */ BaseRepository.prototype.getModelClass = function() { var modelName; modelName = this.constructor.modelName; return this.getFacade().getModel(modelName); }; /** Update or insert a model instance @method save @public @param {Entity|Object} entity @param {ResourceClientInterface} [client=@client] @return {Promise(Entity)} entity (the same instance from input, if entity given,) */ BaseRepository.prototype.save = function(entity, client) { var data; if (!(entity instanceof Entity)) { entity = this.factory.createFromObject(entity); } if (client == null) { client = this.client; } data = entity.toPlainObject(); this.appendTimeStamp(data); return client.upsert(data).then((function(_this) { return function(obj) { var newEntity; newEntity = _this.factory.createFromObject(obj); return entity.inherit(newEntity); }; })(this)); }; /** get object by ID. @method get @public @param {any} id @param {ResourceClientInterface} [client=@client] @return {Promise(Entity)} entity */ BaseRepository.prototype.get = function(id, client) { if (client == null) { client = this.client; } return client.findById(id).then((function(_this) { return function(obj) { return _this.factory.createFromObject(obj); }; })(this)); }; /** alias for get() @method getById @public @param {any} id @param {ResourceClientInterface} [client=@client] @return {Promise(Entity)} entity */ BaseRepository.prototype.getById = function(id, client) { return this.get(id, client); }; /** Find all model instances that match params @method query @public @param {Object} [params] query parameters @param {ResourceClientInterface} [client=@client] @return {Promise(Array(Entity))} array of entities */ BaseRepository.prototype.query = function(params, client) { if (client == null) { client = this.client; } return client.find(params).then((function(_this) { return function(objs) { var obj; return (function() { var i, len, results; results = []; for (i = 0, len = objs.length; i < len; i++) { obj = objs[i]; results.push(this.factory.createFromObject(obj)); } return results; }).call(_this); }; })(this)); }; /** Find one model instance that matches params, Same as query, but limited to one result @method singleQuery @public @param {Object} [params] query parameters @param {ResourceClientInterface} [client=@client] @return {Promise(Entity)} entity */ BaseRepository.prototype.singleQuery = function(params, client) { if (client == null) { client = this.client; } return client.findOne(params).then((function(_this) { return function(obj) { return _this.factory.createFromObject(obj); }; })(this)); }; /** Destroy the given entity (which must have "id" value) @method delete @public @param {Entity} entity @param {ResourceClientInterface} [client=@client] @return {Promise(Boolean)} isDeleted */ BaseRepository.prototype["delete"] = function(entity, client) { if (client == null) { client = this.client; } return client.destroy(entity).then((function(_this) { return function() { return true; }; })(this)); }; /** Update set of attributes. @method update @public @param {any} id id of the entity to update @param {Object} data key-value pair to update (notice: this must not be instance of Entity) @param {ResourceClientInterface} [client=@client] @return {Promise(Entity)} updated entity */ BaseRepository.prototype.update = function(id, data, client) { var isUpdate; if (data instanceof Entity) { throw this.getFacade().error("update entity with BaseRepository#update() is not allowed.\nuse BaseRepository#save(entity) instead"); } if (client == null) { client = this.client; } this.appendTimeStamp(data, isUpdate = true); return client.updateAttributes(id, data).then((function(_this) { return function(obj) { return _this.factory.createFromObject(obj); }; })(this)); }; /** add createdAt, updatedAt to given data - createdAt will not be overriden if already set. - updatedAt will be overriden for each time @method appendTimeStamp @protected @param {Object} data @param {Boolean} isUpdate true when updating @return {Object} data */ BaseRepository.prototype.appendTimeStamp = function(data, isUpdate) { var Model, now, propCreatedAt, propUpdatedAt; if (isUpdate == null) { isUpdate = false; } Model = this.getModelClass(); propCreatedAt = Model.getPropInfo().createdAt; propUpdatedAt = Model.getPropInfo().updatedAt; now = new Date().toISOString(); if (propCreatedAt && !isUpdate) { if (data[propCreatedAt] == null) { data[propCreatedAt] = now; } } if (propUpdatedAt) { data[propUpdatedAt] = now; } return data; }; return BaseRepository; })(Base); module.exports = BaseRepository;