UNPKG

eventric

Version:

behavior-first application development

144 lines (106 loc) 4.87 kB
logger = require 'eventric/logger' uidGenerator = require 'eventric/uid_generator' class Projection constructor: (@_context) -> @_handlerFunctions = {} @_projectionInstances = {} @_domainEventsApplied = {} initializeInstance: (projectionName, Projection, params) -> if typeof Projection is 'function' projection = new Projection else projection = Projection if @_context._di for diName, diFn of @_context._di projection[diName] = diFn projectionId = uidGenerator.generateUid() aggregateId = null projection.$subscribeHandlersWithAggregateId = (_aggregateId) -> aggregateId = _aggregateId eventNames = null @_callInitializeOnProjection projectionName, projection, params .then => @_parseEventNamesFromProjection projection .then (_eventNames) => eventNames = _eventNames @_applyDomainEventsFromStoreToProjection projectionId, projection, eventNames, aggregateId .then => @_subscribeProjectionToDomainEvents projectionId, projectionName, projection, eventNames, aggregateId .then => @_projectionInstances[projectionId] = projection .then -> projection.isInitialized = true .then -> projectionId _callInitializeOnProjection: (projectionName, projection, params) -> new Promise (resolve, reject) => if not projection.initialize logger.debug "[#{@_context.name}] No initialize function on Projection #{projectionName} given, skipping" return resolve projection logger.debug "[#{@_context.name}] Calling initialize on Projection #{projectionName}" projection.initialize params, => logger.debug "[#{@_context.name}] Finished initialize call on Projection #{projectionName}" resolve projection _parseEventNamesFromProjection: (projection) -> new Promise (resolve, reject) -> eventNames = [] for key, value of projection if (key.indexOf 'handle') is 0 and (typeof value is 'function') eventName = key.replace /^handle/, '' eventNames.push eventName resolve eventNames _applyDomainEventsFromStoreToProjection: (projectionId, projection, eventNames, aggregateId) -> @_domainEventsApplied[projectionId] = {} if aggregateId findEvents = @_context.findDomainEventsByNameAndAggregateId eventNames, aggregateId else findEvents = @_context.findDomainEventsByName eventNames findEvents .then (domainEvents) => if not domainEvents or domainEvents.length is 0 return applyDomainEventsToProjectionPromise = Promise.resolve() domainEvents.forEach (domainEvent) => applyDomainEventsToProjectionPromise = applyDomainEventsToProjectionPromise.then => @_applyDomainEventToProjection domainEvent, projection .then => @_domainEventsApplied[projectionId][domainEvent.id] = true return applyDomainEventsToProjectionPromise _subscribeProjectionToDomainEvents: (projectionId, projectionName, projection, eventNames, aggregateId) -> domainEventHandler = (domainEvent) => if @_domainEventsApplied[projectionId][domainEvent.id] return @_applyDomainEventToProjection domainEvent, projection .then => @_domainEventsApplied[projectionId][domainEvent.id] = true return subscribeProjectionToDomainEventsPromise = Promise.resolve() eventNames.forEach (eventName) => subscribeProjectionToDomainEventsPromise = subscribeProjectionToDomainEventsPromise.then => if aggregateId @_context.subscribeToDomainEventWithAggregateId eventName, aggregateId, domainEventHandler else @_context.subscribeToDomainEvent eventName, domainEventHandler .then (subscriberId) => @_handlerFunctions[projectionId] ?= [] @_handlerFunctions[projectionId].push subscriberId return subscribeProjectionToDomainEventsPromise _applyDomainEventToProjection: (domainEvent, projection) => Promise.resolve() .then => if !projection["handle#{domainEvent.name}"] logger.debug "Tried to apply DomainEvent '#{domainEvent.name}' to Projection without a matching handle method" return return projection["handle#{domainEvent.name}"] domainEvent getInstance: (projectionId) -> @_projectionInstances[projectionId] destroyInstance: (projectionId) -> if not @_handlerFunctions[projectionId] return Promise.reject new Error 'Missing attribute projectionId' unsubscribePromises = [] for subscriberId in @_handlerFunctions[projectionId] unsubscribePromises.push @_context.unsubscribeFromDomainEvent subscriberId delete @_handlerFunctions[projectionId] delete @_projectionInstances[projectionId] Promise.all unsubscribePromises module.exports = Projection