eventric
Version:
behavior-first application development
1,495 lines (1,247 loc) • 59.3 kB
JavaScript
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define([], factory);
else if(typeof exports === 'object')
exports["eventric"] = factory();
else
root["eventric"] = factory();
})(this, function() {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ return installedModules[moduleId].exports;
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ exports: {},
/******/ id: moduleId,
/******/ loaded: false
/******/ };
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/ // Flag the module as loaded
/******/ module.loaded = true;
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/ // Load entry module and return exports
/******/ return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ function(module, exports, __webpack_require__) {
module.exports = __webpack_require__(1);
/***/ },
/* 1 */
/***/ function(module, exports, __webpack_require__) {
var Context, Eventric, Projection, Remote, remoteContextHash, uuidGenerator,
bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
Context = __webpack_require__(2);
Remote = __webpack_require__(19);
Projection = __webpack_require__(17);
uuidGenerator = __webpack_require__(10);
remoteContextHash = {};
Eventric = (function() {
function Eventric() {
this._handleRemoteRPCRequest = bind(this._handleRemoteRPCRequest, this);
var GlobalContext, InmemoryStore, inmemoryRemote;
this._logger = __webpack_require__(22);
GlobalContext = __webpack_require__(24);
inmemoryRemote = __webpack_require__(21);
InmemoryStore = __webpack_require__(26);
this._contexts = {};
this._params = {};
this._domainEventHandlers = {};
this._domainEventHandlersAll = [];
this._storeDefinition = null;
this._remoteEndpoints = [];
this._globalProjections = [];
this._globalContext = new GlobalContext;
this.addRemoteEndpoint(inmemoryRemote.endpoint);
this.setStore(InmemoryStore, {});
}
Eventric.prototype.setLogger = function(logger) {
return this._logger = logger;
};
Eventric.prototype.getLogger = function() {
return this._logger;
};
Eventric.prototype.setLogLevel = function(logLevel) {
return this._logger.setLogLevel(logLevel);
};
Eventric.prototype.setStore = function(StoreClass, storeOptions) {
if (storeOptions == null) {
storeOptions = {};
}
return this._storeDefinition = {
Class: StoreClass,
options: storeOptions
};
};
Eventric.prototype.getStoreDefinition = function() {
return this._storeDefinition;
};
Eventric.prototype.context = function(name) {
var context;
if (!name) {
throw new Error('Contexts must have a name');
}
context = new Context(name);
context.subscribeToAllDomainEvents((function(_this) {
return function(domainEvent) {
return _this._delegateDomainEventToRemoteEndpoints(domainEvent);
};
})(this));
this._contexts[name] = context;
return context;
};
Eventric.prototype.initializeGlobalProjections = function() {
var initializeGlobalProjectionsPromise, startOfInitialization;
if (!this._projectionService) {
this._projectionService = new Projection(this._globalContext);
}
startOfInitialization = new Date;
this._logger.debug('eventric global projections initializing');
initializeGlobalProjectionsPromise = Promise.resolve();
this._globalProjections.forEach((function(_this) {
return function(globalProjection) {
return initializeGlobalProjectionsPromise = initializeGlobalProjectionsPromise.then(function() {
return _this._projectionService.initializeInstance(globalProjection, {});
});
};
})(this));
initializeGlobalProjectionsPromise.then((function(_this) {
return function() {
var durationOfInitialization, endOfInitialization;
endOfInitialization = new Date;
durationOfInitialization = endOfInitialization - startOfInitialization;
return _this._logger.debug("eventric global projections initialized after " + durationOfInitialization + "ms");
};
})(this));
return initializeGlobalProjectionsPromise;
};
Eventric.prototype.addGlobalProjection = function(projectionObject) {
return this._globalProjections.push(projectionObject);
};
Eventric.prototype.getRegisteredContextNames = function() {
return Object.keys(this._contexts);
};
Eventric.prototype.setDefaultRemoteClient = function(remoteClient) {
return this._defaultRemoteClient = remoteClient;
};
Eventric.prototype.remoteContext = function(contextName) {
var remote;
if (!contextName) {
throw new Error('Missing context name');
}
if (remoteContextHash[contextName]) {
return remoteContextHash[contextName];
}
remote = remoteContextHash[contextName] = new Remote(contextName);
if (this._defaultRemoteClient) {
remote.setClient(this._defaultRemoteClient);
}
return remote;
};
Eventric.prototype.addRemoteEndpoint = function(remoteEndpoint) {
this._remoteEndpoints.push(remoteEndpoint);
return remoteEndpoint.setRPCHandler(this._handleRemoteRPCRequest);
};
Eventric.prototype.generateUuid = function() {
return uuidGenerator.generateUuid();
};
Eventric.prototype._handleRemoteRPCRequest = function(request, callback) {
var context, error;
context = this._contexts[request.contextName];
if (!context) {
error = new Error("Tried to handle Remote RPC with not registered context " + request.contextName);
this._logger.error(error, '\n', error.stack);
callback(error, null);
return;
}
if (Remote.ALLOWED_RPC_OPERATIONS.indexOf(request.functionName) === -1) {
error = new Error("RPC operation '" + request.functionName + "' not allowed");
this._logger.error(error, '\n', error.stack);
callback(error, null);
return;
}
if (!(request.functionName in context)) {
error = new Error("Remote RPC function " + request.functionName + " not found on Context " + request.contextName);
this._logger.error(error, '\n', error.stack);
callback(error, null);
return;
}
return context[request.functionName].apply(context, request.args).then(function(result) {
return callback(null, result);
})["catch"](function(error) {
return callback(error);
});
};
Eventric.prototype._delegateDomainEventToRemoteEndpoints = function(domainEvent) {
return Promise.all(this._remoteEndpoints.map(function(remoteEndpoint) {
var publishPromise;
publishPromise = Promise.resolve().then(function() {
return remoteEndpoint.publish(domainEvent.context, domainEvent.name, domainEvent);
});
if (domainEvent.aggregate) {
publishPromise = publishPromise.then(function() {
return remoteEndpoint.publish(domainEvent.context, domainEvent.name, domainEvent.aggregate.id, domainEvent);
});
}
return publishPromise;
}));
};
return Eventric;
})();
module.exports = new Eventric;
/***/ },
/* 2 */
/***/ function(module, exports, __webpack_require__) {
module.exports = __webpack_require__(3);
/***/ },
/* 3 */
/***/ function(module, exports, __webpack_require__) {
var AggregateRepository, Context, domainEventService,
bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
slice = [].slice;
AggregateRepository = __webpack_require__(4);
domainEventService = __webpack_require__(12);
Context = (function() {
function Context(name) {
var EventBus, Projection;
this.name = name;
this._getAggregateRepository = bind(this._getAggregateRepository, this);
EventBus = __webpack_require__(14);
Projection = __webpack_require__(17);
this._logger = __webpack_require__(13).getLogger();
this._isInitialized = false;
this._isDestroyed = false;
this._di = {
$query: (function(_this) {
return function() {
return _this.query.apply(_this, arguments);
};
})(this)
};
this._aggregateClasses = {};
this._commandHandlers = {};
this._queryHandlers = {};
this._domainEventPayloadConstructors = {};
this._domainEventHandlers = {};
this._projectionObjects = [];
this._repositoryInstances = {};
this._storeInstance = null;
this._pendingPromises = [];
this._eventBus = new EventBus;
this._projectionService = new Projection(this);
}
Context.prototype.initialize = function() {
var startOfInitialization;
startOfInitialization = new Date;
this._logger.debug("eventric context \"" + this.name + "\" initializing");
return this._initializeStore().then((function(_this) {
return function() {
return _this._initializeProjections();
};
})(this)).then((function(_this) {
return function() {
var durationOfInitialization, endOfInitialization;
endOfInitialization = new Date;
durationOfInitialization = endOfInitialization - startOfInitialization;
_this._logger.debug("eventric context \"" + _this.name + "\" initialized after " + durationOfInitialization + "ms");
return _this._isInitialized = true;
};
})(this));
};
Context.prototype._initializeStore = function() {
var eventric, initializeStorePromise, storeDefinition;
eventric = __webpack_require__(1);
storeDefinition = eventric.getStoreDefinition();
this._storeInstance = new storeDefinition.Class;
initializeStorePromise = this._storeInstance.initialize(this, storeDefinition.options);
return initializeStorePromise;
};
Context.prototype._initializeProjections = function() {
var initializeProjectionsPromise;
initializeProjectionsPromise = Promise.resolve();
this._projectionObjects.forEach((function(_this) {
return function(projectionObject) {
return initializeProjectionsPromise = initializeProjectionsPromise.then(function() {
return _this._projectionService.initializeInstance(projectionObject, {});
});
};
})(this));
return initializeProjectionsPromise;
};
Context.prototype.defineDomainEvent = function(domainEventName, DomainEventPayloadConstructor) {
this._domainEventPayloadConstructors[domainEventName] = DomainEventPayloadConstructor;
return this;
};
Context.prototype.defineDomainEvents = function(domainEventClassesObj) {
var DomainEventPayloadConstructor, domainEventName;
for (domainEventName in domainEventClassesObj) {
DomainEventPayloadConstructor = domainEventClassesObj[domainEventName];
this.defineDomainEvent(domainEventName, DomainEventPayloadConstructor);
}
return this;
};
Context.prototype.addCommandHandlers = function(commandHandlers) {
var commandFunction, commandHandlerName;
for (commandHandlerName in commandHandlers) {
commandFunction = commandHandlers[commandHandlerName];
this._commandHandlers[commandHandlerName] = commandFunction;
}
return this;
};
Context.prototype.addQueryHandlers = function(queryHandlers) {
var queryFunction, queryHandlerName;
for (queryHandlerName in queryHandlers) {
queryFunction = queryHandlers[queryHandlerName];
this._queryHandlers[queryHandlerName] = queryFunction;
}
return this;
};
Context.prototype.addAggregate = function(aggregateName, AggregateClass) {
this._aggregateClasses[aggregateName] = AggregateClass;
return this;
};
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.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.unsubscribeFromDomainEvent = function(subscriberId) {
return this._eventBus.unsubscribe(subscriberId);
};
Context.prototype.addProjection = function(projectionObject) {
this._projectionObjects.push(projectionObject);
return this;
};
Context.prototype.destroyProjectionInstance = function(projectionId) {
return this._projectionService.destroyInstance(projectionId, this);
};
Context.prototype.getDomainEventPayloadConstructor = function(domainEventName) {
return this._domainEventPayloadConstructors[domainEventName];
};
Context.prototype.getDomainEventsStore = function() {
return this._storeInstance;
};
Context.prototype.getEventBus = function() {
return this._eventBus;
};
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, domainEvents) {
if (err) {
return reject(err);
}
domainEvents = domainEventService.sortDomainEventsById(domainEvents);
return resolve(domainEvents);
}]));
};
})(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, domainEvents) {
if (err) {
return reject(err);
}
domainEvents = domainEventService.sortDomainEventsById(domainEvents);
return resolve(domainEvents);
}]));
};
})(this));
};
Context.prototype.command = function(commandName, params) {
var executingCommand, paramsWithHiddenPasswordValue;
if (this._isDestroyed) {
paramsWithHiddenPasswordValue = this._hidePasswordValue(params);
return Promise.reject(new Error("Context " + this.name + " was destroyed, cannot execute command " + commandName + " with arguments\n" + (JSON.stringify(paramsWithHiddenPasswordValue))));
}
executingCommand = new Promise((function(_this) {
return function(resolve, reject) {
var commandServicesToInject;
_this._verifyContextIsInitialized(commandName);
if (!_this._commandHandlers[commandName]) {
throw new Error("Given command " + commandName + " not registered on context");
}
commandServicesToInject = _this._getCommandServicesToInject();
return Promise.resolve().then(function() {
return _this._commandHandlers[commandName].apply(commandServicesToInject, [params]);
}).then(function(result) {
_this._logger.debug('Completed Command', commandName);
return resolve(result);
})["catch"](function(error) {
var commandErrorMessage;
paramsWithHiddenPasswordValue = _this._hidePasswordValue(params);
commandErrorMessage = "Command \"" + commandName + "\" with arguments " + (JSON.stringify(paramsWithHiddenPasswordValue)) + " of context \"" + _this.name + "\"\nrejects with an error";
if (!error) {
reject(new Error(commandErrorMessage));
return;
}
error = _this._extendError(error, commandErrorMessage);
return reject(error);
});
};
})(this));
this._addPendingPromise(executingCommand);
return executingCommand;
};
Context.prototype._hidePasswordValue = function(params) {
if (params.password) {
params.password = '******';
}
return params;
};
Context.prototype._getCommandServicesToInject = function() {
var diFn, diFnName, ref, servicesToInject;
servicesToInject = {};
ref = this._di;
for (diFnName in ref) {
diFn = ref[diFnName];
servicesToInject[diFnName] = diFn;
}
servicesToInject.$aggregate = {
create: (function(_this) {
return function() {
var aggregateName, aggregateParams, aggregateRepository;
aggregateName = arguments[0], aggregateParams = 2 <= arguments.length ? slice.call(arguments, 1) : [];
aggregateRepository = _this._getAggregateRepository(aggregateName);
return aggregateRepository.create.apply(aggregateRepository, aggregateParams);
};
})(this),
load: (function(_this) {
return function(aggregateName, aggregateId) {
var aggregateRepository;
aggregateRepository = _this._getAggregateRepository(aggregateName);
return aggregateRepository.load(aggregateId);
};
})(this)
};
return servicesToInject;
};
Context.prototype._extendError = function(error, additionalMessage) {
error.originalErrorMessage = error.message;
error.message = additionalMessage + " - original error message: " + error.originalErrorMessage;
return error;
};
Context.prototype._getAggregateRepository = function(aggregateName) {
return new AggregateRepository({
aggregateName: aggregateName,
AggregateClass: this._aggregateClasses[aggregateName],
context: this
});
};
Context.prototype._addPendingPromise = function(pendingPromise) {
var alwaysResolvingPromise;
alwaysResolvingPromise = pendingPromise["catch"](function() {});
this._pendingPromises.push(alwaysResolvingPromise);
return alwaysResolvingPromise.then((function(_this) {
return function() {
return _this._pendingPromises.splice(_this._pendingPromises.indexOf(alwaysResolvingPromise), 1);
};
})(this));
};
Context.prototype.query = function(queryName, params) {
return new Promise((function(_this) {
return function(resolve, reject) {
_this._logger.debug('Got Query', queryName);
_this._verifyContextIsInitialized(queryName);
if (!_this._queryHandlers[queryName]) {
reject(new Error("Given query " + queryName + " not registered on context"));
return;
}
return Promise.resolve().then(function() {
return _this._queryHandlers[queryName].apply(_this._di, [params]);
}).then(function(result) {
_this._logger.debug("Completed Query " + queryName + " with Result " + result);
return resolve(result);
})["catch"](function(error) {
var paramsWithHiddenPasswordValue, queryErrorMessage;
paramsWithHiddenPasswordValue = _this._hidePasswordValue(params);
queryErrorMessage = "Query \"" + queryName + "\" with arguments " + (JSON.stringify(paramsWithHiddenPasswordValue)) + " of context \"" + _this.name + "\"\nrejects with an error";
if (!error) {
reject(new Error(queryErrorMessage));
return;
}
error = _this._extendError(error, queryErrorMessage);
return reject(error);
});
};
})(this));
};
Context.prototype._verifyContextIsInitialized = function(methodName) {
if (!this._isInitialized) {
throw new Error("Context " + this.name + " not initialized yet, cannot execute " + methodName);
}
};
Context.prototype.destroy = function() {
return Promise.all(this._pendingPromises).then((function(_this) {
return function() {
return _this._eventBus.destroy();
};
})(this)).then((function(_this) {
return function() {
return _this._isDestroyed = true;
};
})(this));
};
return Context;
})();
module.exports = Context;
/***/ },
/* 4 */
/***/ function(module, exports, __webpack_require__) {
module.exports = __webpack_require__(5);
/***/ },
/* 5 */
/***/ function(module, exports, __webpack_require__) {
var Aggregate, AggregateRepository, domainEventService, uuidGenerator,
bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
Aggregate = __webpack_require__(6);
uuidGenerator = __webpack_require__(10);
domainEventService = __webpack_require__(12);
AggregateRepository = (function() {
function AggregateRepository(params) {
this.save = bind(this.save, this);
this.create = bind(this.create, this);
this.load = bind(this.load, this);
this._logger = __webpack_require__(13).getLogger();
this._aggregateName = params.aggregateName;
this._AggregateClass = params.AggregateClass;
this._context = params.context;
this._store = this._context.getDomainEventsStore();
}
AggregateRepository.prototype.load = function(aggregateId) {
return new Promise((function(_this) {
return function(resolve, reject) {
return _this._store.findDomainEventsByAggregateId(aggregateId, function(error, domainEvents) {
var aggregate, aggregateDeletedEvent, domainEvent, i;
if (error) {
reject(error);
return;
}
if (!(domainEvents != null ? domainEvents.length : void 0)) {
reject(new Error("No domainEvents for aggregate of type " + _this._aggregateName + " with " + aggregateId + " available"));
return;
}
domainEvents = domainEventService.sortDomainEventsById(domainEvents);
aggregateDeletedEvent = null;
for (i = domainEvents.length - 1; i >= 0; i += -1) {
domainEvent = domainEvents[i];
if (domainEvent.name.indexOf(_this._aggregateName + "Deleted") > -1) {
aggregateDeletedEvent = domainEvent;
break;
}
}
if (aggregateDeletedEvent != null) {
reject(new Error("Aggregate of type " + _this._aggregateName + " with id " + aggregateId + " is marked as deleted because of domain event " + aggregateDeletedEvent.name + " with domain event id " + aggregateDeletedEvent.id));
return;
}
aggregate = new Aggregate(_this._context, _this._aggregateName, _this._AggregateClass);
aggregate.setId(aggregateId);
aggregate.applyDomainEvents(domainEvents);
_this._installSaveFunctionOnAggregateInstance(aggregate);
return resolve(aggregate.instance);
});
};
})(this));
};
AggregateRepository.prototype.create = function(params, id) {
if (id == null) {
id = null;
}
return Promise.resolve().then((function(_this) {
return function() {
var aggregate;
aggregate = new Aggregate(_this._context, _this._aggregateName, _this._AggregateClass);
if (typeof aggregate.instance.create !== 'function') {
throw new Error('No create function on aggregate');
}
if (id != null) {
aggregate.setId(id);
} else {
aggregate.setId(uuidGenerator.generateUuid());
}
_this._installSaveFunctionOnAggregateInstance(aggregate);
return Promise.resolve(aggregate.instance.create(params)).then(function() {
return aggregate.instance;
});
};
})(this));
};
AggregateRepository.prototype._installSaveFunctionOnAggregateInstance = function(aggregate) {
return aggregate.instance.$save = (function(_this) {
return function() {
return _this.save(aggregate);
};
})(this);
};
AggregateRepository.prototype.save = function(aggregate) {
return Promise.resolve().then((function(_this) {
return function() {
var domainEvents, saveDomainEventQueue, savedDomainEvents;
if (!aggregate) {
throw new Error("Tried to save unknown aggregate " + _this._aggregateName);
}
domainEvents = aggregate.getNewDomainEvents();
if (!(domainEvents != null ? domainEvents.length : void 0)) {
throw new Error("No new domain events to save for aggregate of type " + _this._aggregateName + " with id " + aggregate.id);
}
_this._logger.debug("Going to Save and Publish " + domainEvents.length + " DomainEvents from Aggregate " + _this._aggregateName);
saveDomainEventQueue = Promise.resolve();
savedDomainEvents = [];
domainEvents.forEach(function(domainEvent) {
return saveDomainEventQueue = saveDomainEventQueue.then(function() {
return _this._store.saveDomainEvent(domainEvent).then(function(domainEvent) {
return savedDomainEvents.push(domainEvent);
});
});
});
return saveDomainEventQueue.then(function() {
savedDomainEvents.forEach(function(domainEvent) {
return _this._context.getEventBus().publishDomainEvent(domainEvent)["catch"](function(error) {
return _this._logger.error(error, '\n', error.stack);
});
});
return aggregate.id;
});
};
})(this));
};
return AggregateRepository;
})();
module.exports = AggregateRepository;
/***/ },
/* 6 */
/***/ function(module, exports, __webpack_require__) {
module.exports = __webpack_require__(7);
/***/ },
/* 7 */
/***/ function(module, exports, __webpack_require__) {
var Aggregate, DomainEvent,
bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
DomainEvent = __webpack_require__(8);
Aggregate = (function() {
function Aggregate(_context, _name, AggregateClass) {
this._context = _context;
this._name = _name;
this.emitDomainEvent = bind(this.emitDomainEvent, this);
this._newDomainEvents = [];
this.instance = new AggregateClass;
this.instance.$emitDomainEvent = this.emitDomainEvent;
}
Aggregate.prototype.setId = function(id) {
this.id = id;
return this.instance.$id = this.id;
};
Aggregate.prototype.emitDomainEvent = function(domainEventName, domainEventPayload) {
var aggregate, domainEvent;
aggregate = {
id: this.id,
name: this._name
};
domainEvent = this._createDomainEvent(domainEventName, domainEventPayload, aggregate);
this._newDomainEvents.push(domainEvent);
return this._handleDomainEvent(domainEventName, domainEvent);
};
Aggregate.prototype._createDomainEvent = function(domainEventName, domainEventConstructorParams, aggregate) {
var DomainEventPayloadConstructor, payload;
DomainEventPayloadConstructor = this._context.getDomainEventPayloadConstructor(domainEventName);
if (!DomainEventPayloadConstructor) {
throw new Error("Tried to create domain event '" + domainEventName + "' which is not defined");
}
payload = {};
DomainEventPayloadConstructor.apply(payload, [domainEventConstructorParams]);
return new DomainEvent({
name: domainEventName,
aggregate: aggregate,
context: this._context.name,
payload: payload
});
};
Aggregate.prototype._handleDomainEvent = function(domainEventName, domainEvent) {
if (this.instance["handle" + domainEventName]) {
return this.instance["handle" + domainEventName](domainEvent);
}
};
Aggregate.prototype.getNewDomainEvents = function() {
return this._newDomainEvents;
};
Aggregate.prototype.applyDomainEvents = function(domainEvents) {
var domainEvent, i, len, results;
results = [];
for (i = 0, len = domainEvents.length; i < len; i++) {
domainEvent = domainEvents[i];
results.push(this._applyDomainEvent(domainEvent));
}
return results;
};
Aggregate.prototype._applyDomainEvent = function(domainEvent) {
return this._handleDomainEvent(domainEvent.name, domainEvent);
};
return Aggregate;
})();
module.exports = Aggregate;
/***/ },
/* 8 */
/***/ function(module, exports, __webpack_require__) {
module.exports = __webpack_require__(9);
/***/ },
/* 9 */
/***/ function(module, exports) {
var DomainEvent;
DomainEvent = (function() {
function DomainEvent(params) {
this.id = params.id;
this.name = params.name;
this.payload = params.payload;
this.aggregate = params.aggregate;
this.context = params.context;
this.timestamp = new Date().getTime();
}
return DomainEvent;
})();
module.exports = DomainEvent;
/***/ },
/* 10 */
/***/ function(module, exports, __webpack_require__) {
module.exports = __webpack_require__(11);
/***/ },
/* 11 */
/***/ function(module, exports) {
var UuidGenerator;
UuidGenerator = (function() {
function UuidGenerator() {}
UuidGenerator.prototype._uuidTemplate = 'xxxxxxxx-xxxx-4xxx-vxxx-xxxxxxxxxxxx';
UuidGenerator.prototype.generateUuid = function() {
var uuid;
uuid = this._uuidTemplate.replace(/[xv]/g, function(characterToReplace) {
var randomNumber, variant;
randomNumber = Math.floor(Math.random() * 16);
if (characterToReplace === 'x') {
return randomNumber.toString(16);
} else {
variant = randomNumber & 0x3 | 0x8;
return variant.toString(16);
}
});
return uuid;
};
return UuidGenerator;
})();
module.exports = new UuidGenerator;
/***/ },
/* 12 */
/***/ function(module, exports) {
var DomainEventService;
DomainEventService = (function() {
function DomainEventService() {}
DomainEventService.prototype.sortDomainEventsById = function(domainEvents) {
return domainEvents.sort(function(firstDomainEvent, secondDomainEvent) {
return firstDomainEvent.id - secondDomainEvent.id;
});
};
return DomainEventService;
})();
module.exports = new DomainEventService;
/***/ },
/* 13 */
/***/ function(module, exports, __webpack_require__) {
module.exports = __webpack_require__(1);
/***/ },
/* 14 */
/***/ function(module, exports, __webpack_require__) {
module.exports = __webpack_require__(15);
/***/ },
/* 15 */
/***/ function(module, exports, __webpack_require__) {
var EventBus, Subscriber;
Subscriber = __webpack_require__(16);
EventBus = (function() {
function EventBus() {
this._subscribers = [];
this._subscriberId = 0;
this._eventPublishQueue = Promise.resolve();
this._isDestroyed = false;
}
EventBus.prototype.subscribeToAllDomainEvents = function(subscriberFunction) {
return this._subscribe('*', subscriberFunction);
};
EventBus.prototype.subscribeToDomainEvent = function(eventName, subscriberFunction) {
return this._subscribe(eventName, subscriberFunction);
};
EventBus.prototype.subscribeToDomainEventWithAggregateId = function(eventName, aggregateId, subscriberFunction) {
return this._subscribe(eventName + "/" + aggregateId, subscriberFunction);
};
EventBus.prototype._subscribe = function(eventName, subscriberFunction) {
return new Promise((function(_this) {
return function(resolve) {
var subscriber;
subscriber = new Subscriber({
eventName: eventName,
subscriberFunction: subscriberFunction,
subscriberId: _this._getNextSubscriberId()
});
_this._subscribers.push(subscriber);
return resolve(subscriber.subscriberId);
};
})(this));
};
EventBus.prototype._getNextSubscriberId = function() {
return this._subscriberId++;
};
EventBus.prototype.publishDomainEvent = function(domainEvent) {
return new Promise((function(_this) {
return function(resolve, reject) {
var publishOperation;
_this._verifyPublishIsPossible(domainEvent);
publishOperation = function() {
return _this._notifySubscribers(domainEvent).then(resolve)["catch"](reject);
};
return _this._enqueueEventPublishing(publishOperation);
};
})(this));
};
EventBus.prototype._verifyPublishIsPossible = function(domainEvent) {
var errorMessage, ref;
if (this._isDestroyed) {
errorMessage = "Event Bus was destroyed, cannot publish " + domainEvent.name + "\nwith payload " + (JSON.stringify(domainEvent.payload));
if ((ref = domainEvent.aggregate) != null ? ref.id : void 0) {
errorMessage += " and aggregate id " + domainEvent.aggregate.id;
}
throw new Error(errorMessage);
}
};
EventBus.prototype._notifySubscribers = function(domainEvent) {
return Promise.resolve().then((function(_this) {
return function() {
var subscribers;
subscribers = _this._getSubscribersForDomainEvent(domainEvent);
return Promise.all(subscribers.map(function(subscriber) {
return subscriber.subscriberFunction(domainEvent);
}));
};
})(this));
};
EventBus.prototype._getSubscribersForDomainEvent = function(domainEvent) {
var ref, subscribers;
subscribers = this._subscribers.filter(function(subscriber) {
return subscriber.eventName === '*';
});
subscribers = subscribers.concat(this._subscribers.filter(function(subscriber) {
return subscriber.eventName === domainEvent.name;
}));
if ((ref = domainEvent.aggregate) != null ? ref.id : void 0) {
subscribers = subscribers.concat(this._subscribers.filter(function(subscriber) {
return subscriber.eventName === (domainEvent.name + "/" + domainEvent.aggregate.id);
}));
}
return subscribers;
};
EventBus.prototype._enqueueEventPublishing = function(publishOperation) {
return this._eventPublishQueue = this._eventPublishQueue.then(publishOperation);
};
EventBus.prototype.unsubscribe = function(subscriberId) {
return Promise.resolve().then((function(_this) {
return function() {
return _this._subscribers = _this._subscribers.filter(function(subscriber) {
return subscriber.subscriberId !== subscriberId;
});
};
})(this));
};
EventBus.prototype.destroy = function() {
return this._waitForEventPublishQueue().then((function(_this) {
return function() {
return _this._isDestroyed = true;
};
})(this));
};
EventBus.prototype._waitForEventPublishQueue = function() {
var currentEventPublishQueue;
currentEventPublishQueue = this._eventPublishQueue;
return currentEventPublishQueue.then((function(_this) {
return function() {
if (_this._eventPublishQueue !== currentEventPublishQueue) {
return _this._waitForEventPublishQueue();
}
};
})(this));
};
return EventBus;
})();
module.exports = EventBus;
/***/ },
/* 16 */
/***/ function(module, exports) {
var Subscriber;
Subscriber = (function() {
function Subscriber(arg) {
this.eventName = arg.eventName, this.subscriberFunction = arg.subscriberFunction, this.subscriberId = arg.subscriberId;
}
return Subscriber;
})();
module.exports = Subscriber;
/***/ },
/* 17 */
/***/ function(module, exports, __webpack_require__) {
module.exports = __webpack_require__(18);
/***/ },
/* 18 */
/***/ function(module, exports, __webpack_require__) {
var ProjectionService, uuidGenerator;
uuidGenerator = __webpack_require__(10);
ProjectionService = (function() {
function ProjectionService(_context) {
this._context = _context;
this._logger = __webpack_require__(13).getLogger();
this._handlerFunctions = {};
this._projectionInstances = {};
}
ProjectionService.prototype.initializeInstance = function(projectionInstance, params) {
var aggregateId, diFn, diName, eventNames, projectionId, ref;
if (this._context._di) {
ref = this._context._di;
for (diName in ref) {
diFn = ref[diName];
projectionInstance[diName] = diFn;
}
}
projectionId = uuidGenerator.generateUuid();
aggregateId = null;
projectionInstance.$subscribeHandlersWithAggregateId = function(_aggregateId) {
if (!_aggregateId) {
throw new Error('Missing aggregate id');
}
return aggregateId = _aggregateId;
};
eventNames = null;
return this._callInitializeOnProjection(projectionInstance, params).then((function(_this) {
return function() {
return _this._parseEventNamesFromProjection(projectionInstance);
};
})(this)).then((function(_this) {
return function(_eventNames) {
eventNames = _eventNames;
return _this._applyDomainEventsFromStoreToProjection(projectionInstance, eventNames, aggregateId);
};
})(this)).then((function(_this) {
return function() {
return _this._subscribeProjectionToDomainEvents(projectionId, projectionInstance, eventNames, aggregateId);
};
})(this)).then((function(_this) {
return function() {
return _this._projectionInstances[projectionId] = projectionInstance;
};
})(this)).then(function() {
return projectionInstance.isInitialized = true;
}).then(function() {
return projectionId;
});
};
ProjectionService.prototype._callInitializeOnProjection = function(projection, params) {
return new Promise(function(resolve) {
if (!projection.initialize) {
return resolve(projection);
}
return projection.initialize(params, function() {
return resolve(projection);
});
});
};
ProjectionService.prototype._parseEventNamesFromProjection = function(projection) {
return new Promise(function(resolve) {
var eventName, eventNames, key, value;
eventNames = [];
for (key in projection) {
value = projection[key];
if ((key.indexOf('handle')) === 0 && (typeof value === 'function')) {
eventName = key.replace(/^handle/, '');
eventNames.push(eventName);
}
}
return resolve(eventNames);
});
};
ProjectionService.prototype._applyDomainEventsFromStoreToProjection = function(projection, eventNames, aggregateId) {
var findEvents;
if (aggregateId) {
findEvents = this._context.findDomainEventsByNameAndAggregateId(eventNames, aggregateId);
} else {
findEvents = this._context.findDomainEventsByName(eventNames);
}
return findEvents.then((function(_this) {
return function(domainEvents) {
var applyDomainEventsToProjectionPromise;
if (!domainEvents || domainEvents.length === 0) {
return;
}
applyDomainEventsToProjectionPromise = Promise.resolve();
domainEvents.forEach(function(domainEvent) {
return applyDomainEventsToProjectionPromise = applyDomainEventsToProjectionPromise.then(function() {
return _this._applyDomainEventToProjection(domainEvent, projection);
});
});
return applyDomainEventsToProjectionPromise;
};
})(this));
};
ProjectionService.prototype._subscribeProjectionToDomainEvents = function(projectionId, projection, eventNames, aggregateId) {
var domainEventHandler, subscribeProjectionToDomainEventsPromise;
domainEventHandler = (function(_this) {
return function(domainEvent) {
return _this._applyDomainEventToProjection(domainEvent, projection);
};
})(this);
this._handlerFunctions[projectionId] = [];
subscribeProjectionToDomainEventsPromise = Promise.resolve();
eventNames.forEach((function(_this) {
return function(eventName) {
return subscribeProjectionToDomainEventsPromise = subscribeProjectionToDomainEventsPromise.then(function() {
if (aggregateId) {
return _this._context.subscribeToDomainEventWithAggregateId(eventName, aggregateId, domainEventHandler);
} else {
return _this._context.subscribeToDomainEvent(eventName, domainEventHandler);
}
}).then(function(subscriberId) {
return _this._handlerFunctions[projectionId].push(subscriberId);
});
};
})(this));
return subscribeProjectionToDomainEventsPromise;
};
ProjectionService.prototype._applyDomainEventToProjection = function(domainEvent, projection) {
return Promise.resolve().then((function(_this) {
return function() {
if (!projection["handle" + domainEvent.name]) {
_this._logger.warn("ProjectionService: handle" + domainEvent.name + " not defined");
}
return projection["handle" + domainEvent.name](domainEvent);
};
})(this));
};
ProjectionService.prototype.getInstance = function(projectionId) {
return this._projectionInstances[projectionId];
};
ProjectionService.prototype.destroyInstance = function(projectionId) {
var i, len, ref, subscriberId, unsubscribePromises;
if (!projectionId) {
return Promise.reject(new Error('Missing projection id'));
}
if (!this._handlerFunctions[projectionId]) {
return Promise.reject(new Error("Projection with id \"" + projectionId + "\" is not initialized"));
}
unsubscribePromises = [];
ref = this._handlerFunctions[projectionId];
for (i = 0, len = ref.length; i < len; i++) {
subscriberId = ref[i];
unsubscribePromises.push(this._context.unsubscribeFromDomainEvent(subscriberId));
}
delete this._handlerFunctions[projectionId];
delete this._projectionInstances[projectionId];
return Promise.all(unsubscribePromises);
};
return ProjectionService;
})();
module.exports = ProjectionService;
/***/ },
/* 19 */
/***/ function(module, exports, __webpack_require__) {
module.exports = __webpack_require__(20);
/***/ },
/* 20 */
/***/ function(module, exports, __webpack_require__) {
var Remote;
Remote = (function() {
Remote.ALLOWED_RPC_OPERATIONS = ['command', 'query', 'findDomainEventsByName', 'findDomainEventsByNameAndAggregateId'];
function Remote(_contextName) {
var Projection, inmemoryRemote;
this._contextName = _contextName;
Projection = __webpack_require__(17);
inmemoryRemote = __webpack_require__(21);
this._params = {};
this._handlerFunctions = {};
this._projectionService = new Projection(this);
this.setClient(inmemoryRemote.client);
this._exposeRpcOperationsAsMemberFunctions();
}
Remote.prototype._exposeRpcOperationsAsMemberFunctions = function() {
return Remote.ALLOWED_RPC_OPERATIONS.forEach((function(_this) {
return function(rpcOperation) {
return _this[rpcOperation] = function() {
return _this._rpc(rpcOperation, arguments);
};
};
})(this));
};
Remote.prototype.subscribeToAllDomainEvents = function(handlerFn) {
return this._client.subscribe(this._contextName, handlerFn);
};
Remote.prototype.subscribeToDomainEvent = function(domainEventName, handlerFn) {
return this._client.subscribe(this._contextName, domainEventName, handlerFn);
};
Remote.prototype.subscribeToDomainEventWithAggregateId = function(domainEventName, aggregateId, handlerFn) {
return this._client.subscribe(this._contextName, domainEventName, aggregateId, handlerFn);
};
Remote.prototype.unsubscribeFromDomainEvent = function(subscriberId) {
return this._client.unsubscribe(subscriberId);
};
Remote.prototype._rpc = function(functionName, args) {
return this._client.rpc({
contextName: this._contextName,
functionName: functionName,
args: Array.prototype.slice.call(args)
});
};
Remote.prototype.setClient = function(client) {
this._client = client;
return this;
};
Remote.prototype.initializeProjection = function(projectionObject, params) {
return this._projectionService.initializeInstance(projectionObject, params);
};
Remote.prototype.destroyProjectionInstance = function(projectionId) {
return this._projectionService.destroyInstance(projectionId, this);
};
return Remote;
})();
module.exports = Remote;
/***/ },
/* 21 */
/***/ function(module, exports, __webpack_require__) {
(function webpackUniversalModuleDefinition(root, factory) {
if(true)
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define(factory);
else if(typeof exports === 'object')
exports["eventric-remote-inmemory"] = factory();
else
root["eventric-remote-inmemory"] = factory();
})(this, function() {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ return installedModules[moduleId].exports;
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ exports: {},
/******/ id: moduleId,
/******/ loaded: false
/******/ };
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/ // Flag the module as loaded
/******/ module.loaded = true;
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/ // Load entry module and return exports
/******/ return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ function(module, exports, __webpack_require__) {
module.exports = {
endpoint: __webpack_require__(1),
client: __webpack_require__(3)
};
/***/ },
/* 1 */
/***/ function(module, exports, __webpack_require__) {
var InMemoryRemoteEndpoint, pubSub,
slice = [].slice;
pubSub = __webpack_require__(2);
InMemoryRemoteEndpoint = (function() {
function InMemoryRemoteEndpoint() {}
InMemoryRemoteEndpoint.prototype.setRPCHandler = function(handleRPCRequest) {
this.handleRPCRequest = handleRPCRequest;
};
InMemoryRemoteEndpoint.prototype.publish = function() {
var aggregateId, arg, contextName, domainEventName, fullEventName, i, payload;
contextName = arguments[0], arg = 3 <= arguments.length ? slice.call(arguments, 1, i = arguments.length - 1) : (i = 1, []), payload = arguments[i++];
domainEventName = arg[0], aggregateId = arg[1];
fullEventName = pubSub.getFullEventName(contextName, domainEventName, aggregateId);
return pubSub.publish(fullEventName, payload);
};
return InMemoryRemoteEndpoint;
})();
module.exports = new InMemoryRemoteEndpoint;
/***/ },
/* 2 */
/***/ function(module, exports) {
var PubSub,
slice = [].slice;
PubSub = (function() {
function PubSub() {
this._subscribers = [];
this._subscriberId = 0;
}
PubSub.prototype.subscribe = function(eventName, subscriberFunction) {
return new Promise((function(_this) {
return function(resolve) {
var subscrib