var _ = require('lodash');
var _controller = require('./controller');
var _validator = require('./validator');
var _service = require('./service');
var _dto = require('./dto');
var _dao = require('./dao');
var _unitTest = require('./unit');
/**
* A SnoozeJS Entity Manager
* @constructor
* @param {object} module - The module the EntityManager will belong to
*
*/
var EntityManager = function(module) {
/**
* @access private
* @ignore
* SnoozeJS NPM Module
*/
var snooze = require('./snooze');
/**
* @access private
* @ignore
* SnoozeJS Module
*/
var _module = module;
/**
* @access private
* @ignore
* Managed Controllers
*/
var _controllers = [];
/**
* @access private
* @ignore
* Managed Validators
*/
var _validators = [];
/**
* @access private
* @ignore
* Managed Services
*/
var _services = [];
/**
* @access private
* @ignore
* Managed DTOs
*/
var _dtos = [];
/**
* @access private
* @ignore
* Managed DAOs
*/
var _daos = [];
/**
* @access private
* @ignore
* Managed Unit Tests
*/
var _units = [];
// Accessors
/**
* Checks if the entity exists in the supplied array
* @access private
* @ignore
* @param {array} arr - An array of entities
* @param {string} nm - The name of the entity
* @return {boolean}
*/
var entityExists = function(arr, nm) {
var ent = _.find(arr, function(entity) {
return entity.getName() === nm;
});
if(ent === undefined) {
return false;
}
return true;
};
/**
* Gets the entity from the supplied array
* @access private
* @ignore
* @param {array} arr - An array of entities
* @param {string} nm - The name of the entity
* @return {object} The entity searched for
*/
var getEntity = function(arr, nm) {
return _.find(arr, function(entity) {
return entity.getName() === nm;
});
};
/**
* Checks if the Service exists
* @param {string} nm - The name of the Service
* @return {boolean}
*/
var serviceExists = function(nm) {
return entityExists(_services, nm);
};
/**
* Checks if the DAO exists
* @param {string} nm - The name of the DAO
* @return {boolean}
*/
var daoExists = function(nm) {
return entityExists(_daos, nm);
};
/**
* Checks if the DTO exists
* @param {string} nm - The name of the DTO
* @return {boolean}
*/
var dtoExists = function(nm) {
return entityExists(_dtos, nm);
};
/**
* Checks if the Controller exists
* @param {string} nm - The name of the Controller
* @return {boolean}
*/
var controllerExists = function(nm) {
return entityExists(_controllers, nm);
};
/**
* Checks if the Validator exists
* @param {string} nm - The name of the Validator
* @return {boolean}
*/
var validatorExists = function(nm) {
return entityExists(_validators, nm);
};
/**
* Gets the Validator with the supplied name
* @param {string} nm - The name of the Validator
* @return {object} Validator
*/
var getValidator = function(nm) {
return getEntity(_validators, nm);
};
/**
* Gets the Controller with the supplied name
* @param {string} nm - The name of the Controller
* @return {object} Controller
*/
var getController = function(nm) {
return getEntity(_controllers, nm);
};
/**
* Gets the Service with the supplied name
* @param {string} nm - The name of the Service
* @return {object} Service
*/
var getService = function(nm) {
return getEntity(_services, nm);
};
/**
* Gets the DAO with the supplied name
* @param {string} nm - The name of the DAO
* @return {object} DAO
*/
var getDAO = function(nm) {
return getEntity(_daos, nm);
};
/**
* Gets the DTO with the supplied name
* @param {string} nm - The name of the DTO
* @return {object} DTO
*/
var getDTO = function(nm) {
return getEntity(_dtos, nm);
};
/**
* Gets the Controllers managed by this EntityManager
* @return {array} Array of Controllers
*/
var getControllers = function() {
return _controllers;
};
/**
* Gets the Services managed by this EntityManager
* @return {array} Array of Services
*/
var getServices = function() {
return _services;
};
/**
* Gets the Validators managed by this EntityManager
* @return {array} Array of Validators
*/
var getValidators = function() {
return _validators;
};
/**
* Gets the DTOs managed by this EntityManager
* @return {array} Array of DTOs
*/
var getDTOs = function() {
return _dtos;
};
/**
* Gets the DAOs managed by this EntityManager
* @return {array} Array of DAOs
*/
var getDAOs = function() {
return _daos;
};
/**
* Gets the Unit Tests managed by this EntityManager
* @return {array} Array of Unit Tests
*/
var getUnits = function() {
return _units;
};
// Modifiers
/**
* Creates a Controller and returns the Module this Entity
* Manager belongs to.
*
* @param {string} nm - The name of the Controller
* @param {function} func - The Injection Function to build this Controller on
* @return {object} The Module
*/
var controller = function(nm, func) {
removeController(nm);
var ctrl = _controller(nm, _module);
_controllers.push(ctrl);
ctrl._func = func;
return _module;
};
/**
* Creates a DAO and returns the Module this Entity
* Manager belongs to.
*
* @param {string} nm - The name of the DAO
* @param {function} func - The Injection Function to build this DAO on
* @return {object} The Module
*/
var dao = function(nm, func) {
removeDAO(nm);
var dao = _dao(nm + 'DAO', _module);
_daos.push(dao);
dao._func = func;
return _module;
};
/**
* Creates a DTO and returns the Module this Entity
* Manager belongs to.
*
* @param {string} nm - The name of the DTO
* @param {object} json - The DTO Properties
* @return {object} The Module
*/
var dto = function(nm, json) {
removeDTO(nm);
var dto = _dto(nm + 'DTO', _module);
dto.__json = json;
_dtos.push(dto);
return _module;
};
/**
* Creates a Service and returns the Module this Entity
* Manager belongs to.
*
* @param {string} nm - The name of the Service
* @param {function} func - The Injection Function to build this Service on
* @return {object} The Module
*/
var service = function(nm, func) {
removeService(nm);
var srv = _service(nm, _module);
_services.push(srv);
srv._func = func;
return _module;
};
/**
* Creates a Validator and returns the Module this Entity
* Manager belongs to.
*
* @param {string} nm - The name of the DAO
* @param {function} func - The Injection Function to build this Validator on
* @return {object} The Module
*/
var validator = function(nm, func) {
removeValidator(nm);
var vd = _validator(nm, _module);
_validators.push(vd);
vd._func = func;
return _module;
};
/**
* Creates a Unit Test and returns the Module this Entity
* Manager belongs to.
*
* @param {function} fn - The Injection Function to build this Unit Test on
* @return {object} The Module
*/
var unit = function(fn) {
var _unit = new _unitTest(_module);
_units.push(_unit);
_unit._func = fn;
return _module;
};
/**
* Removes the Entity from the supplied array
* @access private
* @ignore
* @param {array} arr - The array of entities
* @param {string} nm - The name of the Entity
*/
var removeEntity = function(arr, nm) {
var index = -1;
for(var i = 0; i < arr.length; i++) {
var entity = arr[i];
if(entity !== undefined) {
if(entity.getName() === nm) {
index = i;
break;
}
} else {
snooze.fatal(new Error('undefined entity comparing to ' + nm));
}
}
if(index !== -1) {
arr.splice(arr, index, 1);
}
};
/**
* Adds the Entity from the supplied array
* @access private
* @ignore
* @param {array} arr - The array of entities
* @param {object} item - The Entity
*/
var addEntity = function(arr, item) {
removeEntity(arr, item.getName());
arr.push(item);
};
/**
* Clears all entities from the entity arrays
* @access private
* @ignore
*/
var clearEntities = function() {
_services.splice(0);
_controllers.splice(0);
_validators.splice(0);
_dtos.splice(0);
_daos.splice(0);
};
/**
* Adds the Controller to this Entity Manager
* @param {object} ctrl - The Controller to Add
*/
var addController = function(ctrl) {
addEntity(_controllers, ctrl);
};
/**
* Adds the Service to this Entity Manager
* @param {object} srv - The Service to Add
*/
var addService = function(srv) {
addEntity(_services, srv);
};
/**
* Adds the Validator to this Entity Manager
* @param {object} vd - The Validator to Add
*/
var addValidator = function(vd) {
addEntity(_validators, vd);
};
/**
* Adds the DTO to this Entity Manager
* @param {object} dto - The DTO to Add
*/
var addDTO = function(dto) {
addEntity(_dtos, dto);
};
/**
* Adds the DAO to this Entity Manager
* @param {object} dao - The DAO to Add
*/
var addDAO = function(dao) {
addEntity(_dao, dao);
};
/**
* Removes the Controller from this Entity Manager
* @param {string} nm - The name of the Controller
*/
var removeController = function(nm) {
removeEntity(_controllers, nm);
};
/**
* Removes the Service from this Entity Manager
* @param {string} nm - The name of the Service
*/
var removeService = function(nm) {
removeEntity(_services, nm);
};
/**
* Removes the Validator from this Entity Manager
* @param {string} nm - The name of the Validator
*/
var removeValidator = function(nm) {
removeEntity(_validators, nm);
};
/**
* Removes the DTO from this Entity Manager
* @param {string} nm - The name of the DTO
*/
var removeDTO = function(nm) {
removeEntity(_dtos, nm);
};
/**
* Removes the DAO from this Entity Manager
* @param {string} nm - The name of the DAO
*/
var removeDAO = function(nm) {
removeEntity(_daos, nm);
};
/**
* Runs an Injection Function and returns it's output
* @param {function} _func - The Injection Function
* @return {mixed}
*/
var run = function(_func) {
var parameters = _module.getParams(_func);
var args = [];
for(var i = 0; i < parameters.length; i++) {
var parameter = parameters[i];
var inj = _module.getInjectable(parameter);
args.push(inj);
}
return _func.apply(null, args);
};
/**
* Compiles a Unit by running it's Injection Function and setting
* the returned function as the Unit's Test Function
*
* @param {object} unit - The Unit Test
*/
var compileUnit = function(unit) {
var test = run(unit._func);
unit.setTest(test);
}
/**
* Compiles a Controller by running it's Injection Function
* and adding the returned object to the Controller
*
* @param {object} ctrl - The Controller
*/
var compileController = function(ctrl) {
var methods = run(ctrl._func);
for(var key in methods) {
(function(key) {
if(typeof methods[key] === 'function') {
ctrl[key] = function() {
try {
return methods[key].apply(null, arguments);
} catch(e) {
snooze.fatal(e);
}
};
ctrl[key].toString = function() {
return methods[key]+'';
};
} else {
ctrl[key] = methods[key];
}
})(key);
// ctrl[key] = methods[key];
}
};
/**
* Compiles a Service by running it's Injection Function
* and adding the returned object to the Service
*
* @param {object} srv - The Service
*/
var compileService = function(srv) {
var methods = run(srv._func);
for(var key in methods) {
srv[key] = methods[key];
}
if(srv.$compile) {
srv.$compile();
}
};
/**
* Compiles a Validator by running it's Injection Function
* and adding the returned object to the Validator
*
* @param {object} vd - The Validator
*/
var compileValidator = function(vd) {
var func = run(vd._func);
vd.setTest(func.test);
vd.setErrors(func.errors);
};
/**
* Compiles a DTO by running it's Injection Function
* and defining the DTO from the returned JSON
*
* @param {object} dto - The DTO
*/
var compileDTO = function(dto) {
var json = dto.__json;
defineDTOFromJSON(dto, json);
};
/**
* Compiles a DAO by running it's Injection Function
* and settings the fields, and options of the DAO from the
* returned object. Additionally records DAO relationships
*
* @param {object} dao - The DAO
*/
var compileDAO = function(dao) {
var $conn = getService('$conn');
if($conn !== undefined) {
var parameters = _module.getParams(dao._func);
var args = [];
for(var i = 0; i < parameters.length; i++) {
var parameter = parameters[i];
var inj = _module.getInjectable(parameter, dao);
args.push(inj);
}
var res = dao._func.apply(null, args);
dao.setFields(res.fields);
dao.setOptions(res.options);
if(res._hasOne !== undefined) {
dao.setOneToOne(res._hasOne);
}
if(res._hasMany !== undefined) {
dao.setOneToMany(res._hasMany);
}
if(res._belongsTo !== undefined) {
dao.setBelongsTo(res._belongsTo);
}
var SeqDAO = $conn.$get().define(dao.getName().replace('DAO', ''), dao.getFields(), dao.getOptions);
dao.setSeqDAO(SeqDAO);
} else {
snooze.fatal(new snooze.exceptions.SequelizeNotFoundException());
}
};
/**
* Applies DAO relationships. This occurs after all
* DAOs have been compiled.
*
* @param {object} dao - The DAO
*/
var associateDAO = function(dao) {
var oneToOnes = dao.getOneToOne();
var oneToManys = dao.getOneToMany();
var belongs = dao.getBelongsTo();
var SeqDAO = dao.getSeqDAO();
for(var key in oneToOnes) {
var oneToOne = oneToOnes[key];
for(var i = 0; i < oneToOne.length; i++) {
var foreign = oneToOne[i];
var AssocDAO = getDAO(key + 'DAO');
if(foreign.through) {
var ThroughDAO = getDAO(foreign.through + 'DAO');
if(ThroughDAO !== undefined) {
foreign.through = ThroughDAO.getSeqDAO();
}
}
if(AssocDAO !== undefined) {
SeqDAO.hasOne(AssocDAO.getSeqDAO(), foreign);
} else {
snooze.fatal(new snooze.exceptions.DAOAssociationException(dao.getName(), key));
}
}
}
for(var key in oneToManys) {
var oneToMany = oneToManys[key];
for(var i = 0; i < oneToMany.length; i++) {
var foreign = oneToMany[i];
var AssocDAO = getDAO(key + 'DAO');
if(foreign.through) {
var ThroughDAO = getDAO(foreign.through + 'DAO');
if(ThroughDAO !== undefined) {
foreign.through = ThroughDAO.getSeqDAO();
}
}
if(AssocDAO !== undefined) {
SeqDAO.hasMany(AssocDAO.getSeqDAO(), foreign);
} else {
snooze.fatal(new snooze.exceptions.DAOAssociationException(dao.getName(), key));
}
}
}
for(var key in belongs) {
var bt = belongs[key];
for(var i = 0; i < bt.length; i++) {
var foreign = bt[i];
var AssocDAO = getDAO(key + 'DAO');
if(foreign.through) {
var ThroughDAO = getDAO(foreign.through + 'DAO');
if(ThroughDAO !== undefined) {
foreign.through = ThroughDAO.getSeqDAO();
}
}
if(AssocDAO !== undefined) {
SeqDAO.belongsTo(AssocDAO.getSeqDAO());
} else {
snooze.fatal(new snooze.exceptions.DAOAssociationException(dao.getName(), key));
}
}
}
};
/**
* Compiles all Entities for this EntityManager
*/
var compile = function() {
// Temp bugfix
// TODO: Seperate compiling and injecting
var _baseServices = ['$module', '$conn', 'seq'];
_.each(_services, function(srv) {
if(_.contains(_baseServices, srv.getName())) {
compileService(srv);
}
});
compileDAOs();
associateDAOs();
compileDTOs();
compileServices();
compileValidators();
compileControllers();
compileUnits();
};
/**
* Compiles all Units for this EntityManager
*/
var compileUnits = function() {
_.each(_units, function(unit) {
compileUnit(unit);
});
};
/**
* Compiles all Validators for this EntityManager
*/
var compileValidators = function() {
_.each(_validators, function(vd) {
compileValidator(vd);
});
};
/**
* Compiles all Services for this EntityManager
*/
var compileServices = function() {
_.each(_services, function(srv) {
compileService(srv);
});
};
/**
* Compiles all Controllers for this EntityManager
*/
var compileControllers = function() {
_.each(_controllers, function(ctrl) {
compileController(ctrl);
});
};
/**
* Compiles all DTOs for this EntityManager
*/
var compileDTOs = function() {
_.each(_dtos, function(dto) {
compileDTO(dto);
});
// Allows injecting DTOs into DTOs asynchronously
_.each(_dtos, function(dto) {
dto.completeDTOInjection();
});
};
/**
* Compiles all DAOs for this EntityManager
*/
var compileDAOs = function() {
_.each(_daos, function(dao) {
compileDAO(dao);
});
};
/**
* Associates all DAOs for this EntityManager
*/
var associateDAOs = function() {
_.each(_daos, function(dao) {
associateDAO(dao);
});
};
// Helpers
/**
* Defines a DTO from a DTO Property JSON Object
* @param {object} dto - The DTO to define
* @param {object} json - The DTO Property JSON
*/
var defineDTOFromJSON = function(dto, json) {
for(var key in json) {
if(key.substr(0, 2) !== '__') {
var type = json[key].type || null;
var def = json[key].default || null;
var description = json[key].description || null;
var example = json[key].example || null;
var required = json[key].required || false;
dto.addProperty(key, type, def, description, example, required);
}
}
var methods = json.__methods;
var newMethods = {};
for(var method in methods) {
var parameters = _module.getParams(methods[method]);
var args = [];
for(var i = 0; i < parameters.length; i++) {
var parameter = parameters[i];
var inj = _module.getInjectable(parameter, dto)
args.push(inj);
}
newMethods[method] = methods[method].apply(null, args);
}
var strict = json.__strict || false;
dto.isStrict(strict);
dto.setMethods(newMethods);
};
return {
compileControllers: compileControllers,
compileServices: compileServices,
compileValidators: compileValidators,
compileDTOs: compileDTOs,
compileDAOs: compileDAOs,
associateDAOs: associateDAOs,
controller: controller,
controllerExists: controllerExists,
getControllers: getControllers,
getController: getController,
compileController: compileController,
addController: addController,
service: service,
serviceExists: serviceExists,
getServices: getServices,
getService: getService,
compileService: compileService,
addService: addService,
validator: validator,
validatorExists: validatorExists,
getValidators: getValidators,
getValidator: getValidator,
compileValidator: compileValidator,
addValidator: addValidator,
dto: dto,
dtoExists: dtoExists,
getDTOs: getDTOs,
getDTO: getDTO,
compileDTO: compileDTO,
addDTO: addDTO,
dao: dao,
daoExists: daoExists,
getDAOs: getDAOs,
getDAO: getDAO,
compileDAO: compileDAO,
associateDAO: associateDAO,
addDAO: addDAO,
unit: unit,
getUnits: getUnits,
compileUnit: compileUnit,
defineDTOFromJSON: defineDTOFromJSON,
compile: compile,
clearEntities: clearEntities,
run: run
}
}
module.exports = EntityManager;