eventric
Version:
Build JavaScript applications with Behaviour-driven Domain Design. Based on DDD, BDD, CQRS and EventSourcing.
127 lines (100 loc) • 4.08 kB
text/coffeescript
eventric = require 'eventric'
Aggregate = require 'eventric/src/context/aggregate'
class Repository
constructor: (params) ->
@_aggregateName = params.aggregateName
@_AggregateRoot = params.AggregateRoot
@_context = params.context
@_command = {}
@_aggregateInstances = {}
@_store = @_context.getDomainEventsStore()
findById: (aggregateId, callback = ->) =>
new Promise (resolve, reject) =>
@_findDomainEventsForAggregate aggregateId, (err, domainEvents) =>
if err
callback err, null
reject err
return
if not domainEvents.length
err = "No domainEvents for #{@_aggregateName} Aggregate with #{aggregateId} available"
eventric.log.error err
callback err, null
reject err
return
aggregate = new Aggregate @_context, @_aggregateName, @_AggregateRoot
aggregate.applyDomainEvents domainEvents
aggregate.id = aggregateId
commandId = @_command.id ? 'nocommand'
@_aggregateInstances[commandId] ?= {}
@_aggregateInstances[commandId][aggregateId] = aggregate
callback null, aggregate.root
resolve aggregate.root
_findDomainEventsForAggregate: (aggregateId, callback) ->
@_store.findDomainEventsByAggregateId aggregateId, (err, domainEvents) =>
return callback err, null if err
return callback null, [] if domainEvents.length == 0
callback null, domainEvents
create: =>
params = arguments
if typeof params[params.length-1] is 'function'
callback = params.pop()
new Promise (resolve, reject) =>
aggregate = new Aggregate @_context, @_aggregateName, @_AggregateRoot
aggregate.create params...
.then (aggregate) =>
commandId = @_command.id ? 'nocommand'
@_aggregateInstances[commandId] ?= {}
@_aggregateInstances[commandId][aggregate.id] = aggregate
callback? null, aggregate.id
resolve aggregate.id
save: (aggregateId, callback=->) =>
new Promise (resolve, reject) =>
commandId = @_command.id ? 'nocommand'
aggregate = @_aggregateInstances[commandId][aggregateId]
if not aggregate
err = "Tried to save unknown aggregate #{@_aggregateName}"
eventric.log.error err
err = new Error err
callback? err, null
reject err
return
domainEvents = aggregate.getDomainEvents()
if domainEvents.length < 1
err = "Tried to save 0 DomainEvents from Aggregate #{@_aggregateName}"
eventric.log.debug err, @_command
err = new Error err
callback? err, null
reject err
return
eventric.log.debug "Going to Save and Publish #{domainEvents.length} DomainEvents from Aggregate #{@_aggregateName}"
# TODO: this should be an transaction to guarantee consistency
eventric.eachSeries domainEvents, (domainEvent, next) =>
domainEvent.command = @_command
@_store.saveDomainEvent domainEvent, =>
eventric.log.debug "Saved DomainEvent", domainEvent
next null
, (err) =>
if err
callback err, null
reject err
else
if not @_context.isWaitingModeEnabled()
for domainEvent in domainEvents
eventric.log.debug "Publishing DomainEvent", domainEvent
@_context.getEventBus().publishDomainEvent domainEvent, ->
resolve aggregate.id
callback null, aggregate.id
else
eventric.eachSeries domainEvents, (domainEvent, next) =>
eventric.log.debug "Publishing DomainEvent in waiting mode", domainEvent
@_context.getEventBus().publishDomainEventAndWait domainEvent, next
, (err) =>
if err
callback err, null
reject err
else
resolve aggregate.id
callback null, aggregate.id
setCommand: (command) ->
@_command = command
module.exports = Repository