@arpinum/ddd
Version:
DDD framework CQRS and ES friendly
69 lines (59 loc) • 1.88 kB
JavaScript
;
const _ = require('lodash');
const t = require('tcomb');
const co = require('co');
const {try: asyncTry} = require('@arpinum/promise');
const {EventStoreContract} = require('../types');
const {executePromiseInBatch} = require('../tools').stream;
const {Logger, LoggerContract} = require('@arpinum/log');
const Creation = t.interface({
eventStore: EventStoreContract,
isEmpty: t.Function,
handlers: t.Object,
options: t.maybe(t.interface({
log: t.maybe(LoggerContract)
}))
});
class ProjectionUpdater {
constructor(creation) {
let {eventStore, isEmpty, handlers, options} = Creation(creation);
this._eventStore = eventStore;
this._isEmpty = isEmpty;
this._handlers = handlers;
this._options = Object.assign({}, {log: new Logger({fileName: __filename}), options});
}
build() {
let self = this;
return co(function *() {
if (yield self._isEmpty()) {
return buildFromEvents();
}
return Promise.resolve();
});
function buildFromEvents() {
return co(function *() {
self._options.log.debug('Projection build started');
let stream = self._eventStore.eventsFromTypes(eventTypes());
yield executePromiseInBatch(stream, event => self._handleEvent(event));
self._options.log.debug('Projection build done');
});
}
function eventTypes() {
return _.keys(self._handlers);
}
}
registerToBus(eventBus) {
_.forEach(this._handlers, (handler, type) => {
eventBus.register(type, event => this._handleEvent(event));
});
}
_handleEvent(event) {
let self = this;
return asyncTry(() => self._handlers[event.type](event))
.catch(rejection => {
self._options.log.error(`Update failed on event ${event.id}`, rejection);
throw rejection;
});
}
}
module.exports = ProjectionUpdater;