eventric
Version:
behavior-first application development
520 lines (477 loc) • 18.3 kB
JavaScript
var Context,
__bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
__slice = [].slice;
Context = (function() {
function Context(name, _eventric) {
this.name = name;
this._eventric = _eventric;
this.clearProjectionStore = __bind(this.clearProjectionStore, this);
this.getProjectionStore = __bind(this.getProjectionStore, this);
this._getAggregateRepository = __bind(this._getAggregateRepository, this);
this.publishDomainEvent = __bind(this.publishDomainEvent, this);
this.emitDomainEvent = __bind(this.emitDomainEvent, this);
this._initialized = false;
this._params = this._eventric.get();
this._di = {};
this._aggregateRootClasses = {};
this._commandHandlers = {};
this._queryHandlers = {};
this._domainEventClasses = {};
this._domainEventHandlers = {};
this._projectionClasses = {};
this._domainEventStreamClasses = {};
this._domainEventStreamInstances = {};
this._repositoryInstances = {};
this._storeClasses = {};
this._storeInstances = {};
this._eventBus = new this._eventric.EventBus(this._eventric);
this.projectionService = new this._eventric.Projection(this._eventric);
this.log = this._eventric.log;
}
Context.prototype.set = function(key, value) {
this._params[key] = value;
return this;
};
Context.prototype.get = function(key) {
return this._params[key];
};
Context.prototype.emitDomainEvent = function(domainEventName, domainEventPayload) {
var DomainEventClass, domainEvent;
DomainEventClass = this.getDomainEvent(domainEventName);
if (!DomainEventClass) {
throw new Error("Tried to emitDomainEvent '" + domainEventName + "' which is not defined");
}
domainEvent = this._createDomainEvent(domainEventName, DomainEventClass, domainEventPayload);
return this.saveAndPublishDomainEvent(domainEvent).then((function(_this) {
return function() {
return _this._eventric.log.debug("Created and Handled DomainEvent in Context", domainEvent);
};
})(this));
};
Context.prototype.publishDomainEvent = function(domainEvent) {
return this._eventBus.publishDomainEvent(domainEvent);
};
Context.prototype._createDomainEvent = function(domainEventName, DomainEventClass, domainEventPayload) {
return new this._eventric.DomainEvent({
id: this._eventric.generateUid(),
name: domainEventName,
context: this.name,
payload: new DomainEventClass(domainEventPayload)
});
};
Context.prototype.addStore = function(storeName, StoreClass, storeOptions) {
if (storeOptions == null) {
storeOptions = {};
}
this._storeClasses[storeName] = {
Class: StoreClass,
options: storeOptions
};
return this;
};
Context.prototype.defineDomainEvent = function(domainEventName, DomainEventClass) {
this._domainEventClasses[domainEventName] = DomainEventClass;
return this;
};
Context.prototype.defineDomainEvents = function(domainEventClassesObj) {
var DomainEventClass, domainEventName;
for (domainEventName in domainEventClassesObj) {
DomainEventClass = domainEventClassesObj[domainEventName];
this.defineDomainEvent(domainEventName, DomainEventClass);
}
return this;
};
Context.prototype.addCommandHandler = function(commandHandlerName, commandHandlerFn) {
this._commandHandlers[commandHandlerName] = commandHandlerFn;
return this;
};
Context.prototype._getAggregateRepository = function(aggregateName, command) {
var AggregateRoot, repositoriesCache, repository;
if (!repositoriesCache) {
repositoriesCache = {};
}
if (!repositoriesCache[aggregateName]) {
AggregateRoot = this._aggregateRootClasses[aggregateName];
repository = new this._eventric.Repository({
aggregateName: aggregateName,
AggregateRoot: AggregateRoot,
context: this,
eventric: this._eventric
});
repositoriesCache[aggregateName] = repository;
}
repositoriesCache[aggregateName].setCommand(command);
return repositoriesCache[aggregateName];
};
Context.prototype.addCommandHandlers = function(commandObj) {
var commandFunction, commandHandlerName;
for (commandHandlerName in commandObj) {
commandFunction = commandObj[commandHandlerName];
this.addCommandHandler(commandHandlerName, commandFunction);
}
return this;
};
Context.prototype.addQueryHandler = function(queryHandlerName, queryHandlerFn) {
this._queryHandlers[queryHandlerName] = queryHandlerFn;
return this;
};
Context.prototype.addQueryHandlers = function(queryObj) {
var queryFunction, queryHandlerName;
for (queryHandlerName in queryObj) {
queryFunction = queryObj[queryHandlerName];
this.addQueryHandler(queryHandlerName, queryFunction);
}
return this;
};
Context.prototype.addAggregate = function(aggregateName, AggregateRootClass) {
this._aggregateRootClasses[aggregateName] = AggregateRootClass;
return this;
};
Context.prototype.addAggregates = function(aggregatesObj) {
var AggregateRootClass, aggregateName;
for (aggregateName in aggregatesObj) {
AggregateRootClass = aggregatesObj[aggregateName];
this.addAggregate(aggregateName, AggregateRootClass);
}
return this;
};
Context.prototype.subscribeToDomainEvent = function(domainEventName, handlerFn) {
var domainEventHandler;
domainEventHandler = (function(_this) {
return function() {
return handlerFn.apply(_this._di, arguments);
};
})(this);
return this._eventBus.subscribeToDomainEvent(domainEventName, domainEventHandler);
};
Context.prototype.subscribeToDomainEvents = function(domainEventHandlersObj) {
var domainEventName, handlerFn, _results;
_results = [];
for (domainEventName in domainEventHandlersObj) {
handlerFn = domainEventHandlersObj[domainEventName];
_results.push(this.subscribeToDomainEvent(domainEventName, handlerFn));
}
return _results;
};
Context.prototype.subscribeToDomainEventWithAggregateId = function(domainEventName, aggregateId, handlerFn) {
var domainEventHandler;
domainEventHandler = (function(_this) {
return function() {
return handlerFn.apply(_this._di, arguments);
};
})(this);
return this._eventBus.subscribeToDomainEventWithAggregateId(domainEventName, aggregateId, domainEventHandler);
};
Context.prototype.subscribeToAllDomainEvents = function(handlerFn) {
var domainEventHandler;
domainEventHandler = (function(_this) {
return function() {
return handlerFn.apply(_this._di, arguments);
};
})(this);
return this._eventBus.subscribeToAllDomainEvents(domainEventHandler);
};
Context.prototype.addProjection = function(projectionName, ProjectionClass) {
this._projectionClasses[projectionName] = ProjectionClass;
return this;
};
Context.prototype.addProjections = function(viewsObj) {
var ProjectionClass, projectionName;
for (projectionName in viewsObj) {
ProjectionClass = viewsObj[projectionName];
this.addProjection(projectionName, ProjectionClass);
}
return this;
};
Context.prototype.getProjectionInstance = function(projectionId) {
return this.projectionService.getInstance(projectionId);
};
Context.prototype.destroyProjectionInstance = function(projectionId) {
return this.projectionService.destroyInstance(projectionId, this);
};
Context.prototype.initializeProjectionInstance = function(projectionName, params) {
var err;
if (!this._projectionClasses[projectionName]) {
err = "Given projection " + projectionName + " not registered on context";
this._eventric.log.error(err);
err = new Error(err);
return err;
}
return this.projectionService.initializeInstance(projectionName, this._projectionClasses[projectionName], params, this);
};
Context.prototype.initialize = function() {
return new Promise((function(_this) {
return function(resolve, reject) {
_this.log.debug("[" + _this.name + "] Initializing");
_this.log.debug("[" + _this.name + "] Initializing Store");
return _this._initializeStores().then(function() {
_this.log.debug("[" + _this.name + "] Finished initializing Store");
return _this._di = {
$query: function() {
return _this.query.apply(_this, arguments);
},
$projectionStore: function() {
return _this.getProjectionStore.apply(_this, arguments);
},
$emitDomainEvent: function() {
return _this.emitDomainEvent.apply(_this, arguments);
}
};
}).then(function() {
_this.log.debug("[" + _this.name + "] Initializing Projections");
return _this._initializeProjections();
}).then(function() {
_this.log.debug("[" + _this.name + "] Finished initializing Projections");
_this.log.debug("[" + _this.name + "] Finished initializing");
_this._initialized = true;
return resolve();
})["catch"](function(err) {
return reject(err);
});
};
})(this));
};
Context.prototype._initializeStores = function() {
return new Promise((function(_this) {
return function(resolve, reject) {
var store, storeName, stores, _ref;
stores = [];
_ref = _this._eventric.defaults(_this._storeClasses, _this._eventric.getStores());
for (storeName in _ref) {
store = _ref[storeName];
stores.push({
name: storeName,
Class: store.Class,
options: store.options
});
}
return _this._eventric.eachSeries(stores, function(store, next) {
_this.log.debug("[" + _this.name + "] Initializing Store " + store.name);
_this._storeInstances[store.name] = new store.Class;
return _this._storeInstances[store.name].initialize(_this, store.options).then(function() {
_this.log.debug("[" + _this.name + "] Finished initializing Store " + store.name);
return next();
})["catch"](function(err) {
return next(err);
});
}, function(err) {
if (err) {
return reject(err);
}
return resolve();
});
};
})(this));
};
Context.prototype._initializeProjections = function() {
return new Promise((function(_this) {
return function(resolve, reject) {
var ProjectionClass, projectionName, projections, _ref;
projections = [];
_ref = _this._projectionClasses;
for (projectionName in _ref) {
ProjectionClass = _ref[projectionName];
projections.push({
name: projectionName,
"class": ProjectionClass
});
}
return _this._eventric.eachSeries(projections, function(projection, next) {
var eventNames;
eventNames = null;
_this.log.debug("[" + _this.name + "] Initializing Projection " + projection.name);
return _this.projectionService.initializeInstance(projection.name, projection["class"], {}, _this).then(function(projectionId) {
_this.log.debug("[" + _this.name + "] Finished initializing Projection " + projection.name);
return next();
})["catch"](function(err) {
return reject(err);
});
}, function(err) {
if (err) {
return reject(err);
}
return resolve();
});
};
})(this));
};
Context.prototype.getProjection = function(projectionId) {
return this.projectionService.getInstance(projectionId);
};
Context.prototype.getDomainEvent = function(domainEventName) {
return this._domainEventClasses[domainEventName];
};
Context.prototype.getDomainEventsStore = function() {
var storeName;
storeName = this.get('default domain events store');
return this._storeInstances[storeName];
};
Context.prototype.saveAndPublishDomainEvent = function(domainEvent) {
return new Promise((function(_this) {
return function(resolve, reject) {
return _this.getDomainEventsStore().saveDomainEvent(domainEvent).then(function() {
return _this.publishDomainEvent(domainEvent);
}).then(function(err) {
if (err) {
return reject(err);
}
return resolve(domainEvent);
});
};
})(this));
};
Context.prototype.findDomainEventsByName = function() {
var findArguments;
findArguments = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
return new Promise((function(_this) {
return function(resolve, reject) {
var _ref;
return (_ref = _this.getDomainEventsStore()).findDomainEventsByName.apply(_ref, __slice.call(findArguments).concat([function(err, events) {
if (err) {
return reject(err);
}
return resolve(events);
}]));
};
})(this));
};
Context.prototype.findDomainEventsByNameAndAggregateId = function() {
var findArguments;
findArguments = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
return new Promise((function(_this) {
return function(resolve, reject) {
var _ref;
return (_ref = _this.getDomainEventsStore()).findDomainEventsByNameAndAggregateId.apply(_ref, __slice.call(findArguments).concat([function(err, events) {
if (err) {
return reject(err);
}
return resolve(events);
}]));
};
})(this));
};
Context.prototype.getProjectionStore = function(storeName, projectionName) {
return new Promise((function(_this) {
return function(resolve, reject) {
var err;
if (!_this._storeInstances[storeName]) {
err = "Requested Store with name " + storeName + " not found";
_this.log.error(err);
return reject(err);
}
return _this._storeInstances[storeName].getProjectionStore(projectionName).then(function(projectionStore) {
return resolve(projectionStore);
})["catch"](function(err) {
return reject(err);
});
};
})(this));
};
Context.prototype.clearProjectionStore = function(storeName, projectionName) {
return new Promise((function(_this) {
return function(resolve, reject) {
var err;
if (!_this._storeInstances[storeName]) {
err = "Requested Store with name " + storeName + " not found";
_this.log.error(err);
return reject(err);
}
return _this._storeInstances[storeName].clearProjectionStore(projectionName).then(function() {
return resolve();
})["catch"](function(err) {
return reject(err);
});
};
})(this));
};
Context.prototype.getEventBus = function() {
return this._eventBus;
};
Context.prototype.command = function(name, params) {
return new Promise((function(_this) {
return function(resolve, reject) {
var command, commandHandlerFn, diFn, diFnName, err, executeCommand, _di, _ref;
command = {
id: _this._eventric.generateUid(),
name: name,
params: params
};
_this.log.debug('Got Command', command);
if (!_this._initialized) {
err = 'Context not initialized yet';
_this.log.error(err);
err = new Error(err);
return reject(err);
}
if (!_this._commandHandlers[name]) {
err = "Given command " + name + " not registered on context";
_this.log.error(err);
err = new Error(err);
return reject(err);
}
_di = {};
_ref = _this._di;
for (diFnName in _ref) {
diFn = _ref[diFnName];
_di[diFnName] = diFn;
}
_di.$aggregate = {
create: function() {
var aggregateName, aggregateParams, repository;
aggregateName = arguments[0], aggregateParams = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
repository = _this._getAggregateRepository(aggregateName, command);
return repository.create.apply(repository, aggregateParams);
},
load: function(aggregateName, aggregateId) {
var repository;
repository = _this._getAggregateRepository(aggregateName, command);
return repository.findById(aggregateId);
}
};
executeCommand = null;
commandHandlerFn = _this._commandHandlers[name];
executeCommand = commandHandlerFn.apply(_di, [params]);
return Promise.all([executeCommand]).then(function(_arg) {
var result;
result = _arg[0];
_this.log.debug('Completed Command', name);
return resolve(result);
})["catch"](function(error) {
return reject(error);
});
};
})(this));
};
Context.prototype.query = function(name, params) {
return new Promise((function(_this) {
return function(resolve, reject) {
var err, executeQuery;
_this.log.debug('Got Query', name);
if (!_this._initialized) {
err = 'Context not initialized yet';
_this.log.error(err);
err = new Error(err);
reject(err);
return;
}
if (!_this._queryHandlers[name]) {
err = "Given query " + name + " not registered on context";
_this.log.error(err);
err = new Error(err);
return reject(err);
}
executeQuery = _this._queryHandlers[name].apply(_this._di, [params]);
return Promise.all([executeQuery]).then(function(_arg) {
var result;
result = _arg[0];
_this.log.debug("Completed Query " + name + " with Result " + result);
return resolve(result);
})["catch"](function(err) {
return reject(err);
});
};
})(this));
};
return Context;
})();
module.exports = Context;