eventric
Version:
behavior-first application development
280 lines (199 loc) • 8.83 kB
text/coffeescript
AggregateRepository = require 'eventric/aggregate_repository'
domainEventService = require 'eventric/domain_event/domain_event_service'
class Context
constructor: () ->
EventBus = require 'eventric/event_bus'
Projection = require 'eventric/projection'
= require('eventric').getLogger()
= false
= false
# TODO: Consider removing this "DI" since queries can be executed by simply accessing the context
=
$query: => .apply @, arguments
= {}
= {}
= {}
= {}
= {}
= []
= {}
= null
= []
= new EventBus
= new Projection @
initialize: ->
startOfInitialization = new Date
.debug "eventric context \"#{@name}\" initializing"
.then =>
.then =>
endOfInitialization = new Date
durationOfInitialization = endOfInitialization - startOfInitialization
.debug "eventric context \"#{@name}\" initialized after #{durationOfInitialization}ms"
= true
_initializeStore: ->
# TODO: Test
eventric = require '../eventric'
storeDefinition = eventric.getStoreDefinition()
= new storeDefinition.Class
initializeStorePromise = .initialize @, storeDefinition.options
return initializeStorePromise
_initializeProjections: ->
initializeProjectionsPromise = Promise.resolve()
.forEach (projectionObject) =>
initializeProjectionsPromise = initializeProjectionsPromise.then =>
.initializeInstance projectionObject, {}
return initializeProjectionsPromise
defineDomainEvent: (domainEventName, DomainEventPayloadConstructor) ->
[domainEventName] = DomainEventPayloadConstructor
@
defineDomainEvents: (domainEventClassesObj) ->
for domainEventName, DomainEventPayloadConstructor of domainEventClassesObj
domainEventName, DomainEventPayloadConstructor
@
addCommandHandlers: (commandHandlers) ->
for commandHandlerName, commandFunction of commandHandlers
[commandHandlerName] = commandFunction
@
addQueryHandlers: (queryHandlers) ->
for queryHandlerName, queryFunction of queryHandlers
[queryHandlerName] = queryFunction
@
addAggregate: (aggregateName, AggregateClass) ->
[aggregateName] = AggregateClass
@
subscribeToAllDomainEvents: (handlerFn) ->
domainEventHandler = => handlerFn.apply , arguments
.subscribeToAllDomainEvents domainEventHandler
subscribeToDomainEvent: (domainEventName, handlerFn) ->
domainEventHandler = => handlerFn.apply , arguments
.subscribeToDomainEvent domainEventName, domainEventHandler
subscribeToDomainEvents: (domainEventHandlersObj) ->
domainEventName, handlerFn for domainEventName, handlerFn of domainEventHandlersObj
# TODO: Remove this when stream subscriptions are implemented
subscribeToDomainEventWithAggregateId: (domainEventName, aggregateId, handlerFn) ->
domainEventHandler = => handlerFn.apply , arguments
.subscribeToDomainEventWithAggregateId domainEventName, aggregateId, domainEventHandler
unsubscribeFromDomainEvent: (subscriberId) ->
.unsubscribe subscriberId
addProjection: (projectionObject) ->
.push projectionObject
@
destroyProjectionInstance: (projectionId) ->
.destroyInstance projectionId, @
getDomainEventPayloadConstructor: (domainEventName) ->
[domainEventName]
getDomainEventsStore: ->
getEventBus: ->
# TODO: Remove this when stream subscriptions are implemented
findDomainEventsByName: (findArguments...) ->
new Promise (resolve, reject) =>
.findDomainEventsByName findArguments..., (err, domainEvents) ->
return reject err if err
domainEvents = domainEventService.sortDomainEventsById domainEvents
resolve domainEvents
# TODO: Remove this when stream subscriptions are implemented
findDomainEventsByNameAndAggregateId: (findArguments...) ->
new Promise (resolve, reject) =>
.findDomainEventsByNameAndAggregateId findArguments..., (err, domainEvents) ->
return reject err if err
domainEvents = domainEventService.sortDomainEventsById domainEvents
resolve domainEvents
command: (commandName, params) ->
if
paramsWithHiddenPasswordValue = params
return Promise.reject new Error """
Context #{@name} was destroyed, cannot execute command #{commandName} with arguments
#{JSON.stringify(paramsWithHiddenPasswordValue)}
"""
executingCommand = new Promise (resolve, reject) =>
commandName
if not [commandName]
throw new Error "Given command #{commandName} not registered on context"
commandServicesToInject =
Promise.resolve()
.then =>
[commandName].apply commandServicesToInject, [params]
.then (result) =>
.debug 'Completed Command', commandName
resolve result
.catch (error) =>
paramsWithHiddenPasswordValue = params
commandErrorMessage = """
Command "#{commandName}" with arguments #{JSON.stringify(paramsWithHiddenPasswordValue)} of context "#{@name}"
rejects with an error
"""
if not error
reject new Error commandErrorMessage
return
error = error, commandErrorMessage
reject error
executingCommand
return executingCommand
_hidePasswordValue: (params) ->
if params.password
params.password = '******'
return params
_getCommandServicesToInject: ->
servicesToInject = {}
for diFnName, diFn of
servicesToInject[diFnName] = diFn
servicesToInject.$aggregate =
create: (aggregateName, aggregateParams...) =>
aggregateRepository = aggregateName
aggregateRepository.create aggregateParams...
load: (aggregateName, aggregateId) =>
aggregateRepository = aggregateName
aggregateRepository.load aggregateId
return servicesToInject
_extendError: (error, additionalMessage) ->
error.originalErrorMessage = error.message
error.message = "#{additionalMessage} - original error message: #{error.originalErrorMessage}"
return error
_getAggregateRepository: (aggregateName) =>
new AggregateRepository
aggregateName: aggregateName
AggregateClass: [aggregateName]
context: @
_addPendingPromise: (pendingPromise) ->
alwaysResolvingPromise = pendingPromise.catch ->
.push alwaysResolvingPromise
alwaysResolvingPromise.then =>
.splice .indexOf(alwaysResolvingPromise), 1
query: (queryName, params) ->
new Promise (resolve, reject) =>
.debug 'Got Query', queryName
queryName
if not [queryName]
reject new Error "Given query #{queryName} not registered on context"
return
Promise.resolve()
.then =>
[queryName].apply , [params]
.then (result) =>
.debug "Completed Query #{queryName} with Result #{result}"
resolve result
.catch (error) =>
paramsWithHiddenPasswordValue = params
queryErrorMessage = """
Query "#{queryName}" with arguments #{JSON.stringify(paramsWithHiddenPasswordValue)} of context "#{@name}"
rejects with an error
"""
if not error
reject new Error queryErrorMessage
return
error = error, queryErrorMessage
reject error
_verifyContextIsInitialized: (methodName) ->
if not
throw new Error "Context #{@name} not initialized yet, cannot execute #{methodName}"
destroy: ->
Promise.all
.then =>
.destroy()
.then =>
= true
module.exports = Context