synapse-core 0.5.4 → 0.5.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. data/lib/synapse/command/async_command_bus.rb +3 -5
  2. data/lib/synapse/common.rb +0 -1
  3. data/lib/synapse/configuration/component/command_bus/async_command_bus.rb +3 -2
  4. data/lib/synapse/configuration/component/{mixin → shared}/thread_pool.rb +10 -8
  5. data/lib/synapse/configuration/dependent.rb +2 -2
  6. data/lib/synapse/configuration/ext.rb +58 -29
  7. data/lib/synapse/configuration.rb +1 -1
  8. data/lib/synapse/domain/aggregate_root.rb +43 -19
  9. data/lib/synapse/domain/errors.rb +9 -0
  10. data/lib/synapse/domain/event_container.rb +3 -3
  11. data/lib/synapse/domain/message.rb +2 -2
  12. data/lib/synapse/domain/message_builder.rb +2 -2
  13. data/lib/synapse/domain/simple_stream.rb +39 -0
  14. data/lib/synapse/domain/stream.rb +2 -41
  15. data/lib/synapse/domain.rb +3 -0
  16. data/lib/synapse/event_sourcing/aggregate_root.rb +102 -2
  17. data/lib/synapse/event_sourcing/caching.rb +1 -1
  18. data/lib/synapse/event_sourcing/entity.rb +2 -2
  19. data/lib/synapse/event_sourcing/member.rb +3 -13
  20. data/lib/synapse/event_sourcing/repository.rb +9 -2
  21. data/lib/synapse/event_sourcing/snapshot/taker.rb +2 -2
  22. data/lib/synapse/mapping/mapping.rb +2 -2
  23. data/lib/synapse/process_manager/simple_process_manager.rb +1 -0
  24. data/lib/synapse/rails/injection_helper.rb +23 -0
  25. data/lib/synapse/railtie.rb +17 -0
  26. data/lib/synapse/repository/lock_manager.rb +3 -3
  27. data/lib/synapse/uow/listener.rb +2 -2
  28. data/lib/synapse/uow/listener_collection.rb +7 -51
  29. data/lib/synapse/version.rb +1 -1
  30. data/lib/synapse-core.rb +1 -0
  31. data/lib/synapse.rb +3 -0
  32. data/test/command/async_command_bus_test.rb +8 -11
  33. data/test/configuration/component/command_bus/async_command_bus_test.rb +7 -6
  34. data/test/configuration/component/serialization/serializer_test.rb +2 -2
  35. data/test/configuration/fixtures/dependent.rb +1 -1
  36. data/test/rails/injection_helper_test.rb +27 -0
  37. data/test/serialization/converter/ox_test.rb +2 -2
  38. data/test/serialization/serializer/oj_test.rb +1 -1
  39. data/test/serialization/serializer/ox_test.rb +1 -1
  40. data/test/test_helper.rb +8 -9
  41. data/test/uow/uow_test.rb +2 -2
  42. metadata +221 -222
  43. data/lib/synapse/common/concurrency/executor.rb +0 -13
  44. data/test/support/countdown_latch.rb +0 -18
@@ -1,5 +1,3 @@
1
- require 'thread/pool'
2
-
3
1
  module Synapse
4
2
  module Command
5
3
  # Command bus that uses a thread pool to asynchronously execute commands, invoking the given
@@ -7,8 +5,8 @@ module Synapse
7
5
  #
8
6
  # @todo Look into non-blocking circular buffers or LMAX Disruptor
9
7
  class AsynchronousCommandBus < SimpleCommandBus
10
- # Pool of dispatching threads backed by a queue
11
- # @return [Thread::Pool]
8
+ # Pool of worker threads that dispatch commands from a queue
9
+ # @return [Contender::Pool::ThreadPoolExecutor]
12
10
  attr_accessor :thread_pool
13
11
 
14
12
  # @api public
@@ -16,7 +14,7 @@ module Synapse
16
14
  # @param [CommandCallback] callback
17
15
  # @return [undefined]
18
16
  def dispatch_with_callback(command, callback)
19
- @thread_pool.process do
17
+ @thread_pool.execute do
20
18
  super command, callback
21
19
  end
22
20
  end
@@ -3,7 +3,6 @@ require 'synapse/common/identifier'
3
3
  require 'synapse/common/message'
4
4
  require 'synapse/common/message_builder'
5
5
 
6
- require 'synapse/common/concurrency/executor'
7
6
  require 'synapse/common/concurrency/identifier_lock'
8
7
  require 'synapse/common/concurrency/public_lock'
9
8
 
@@ -3,13 +3,14 @@ module Synapse
3
3
  # Definition builder used to build an asynchronous command bus
4
4
  #
5
5
  # @see SimpleCommandBusDefinitionBuilder For additional options
6
+ # @see Contender::Pool::ThreadPoolExecutor For pool options
6
7
  #
7
8
  # @example The minimum possible effort to build an asynchronous command bus
8
9
  # async_command_bus
9
10
  #
10
11
  # @example Create an asynchronous command bus with a custom thread count
11
12
  # async_command_bus do
12
- # use_threads 8, 12
13
+ # use_pool_options size: 2
13
14
  # end
14
15
  class AsynchronousCommandBusDefinitionBuilder < SimpleCommandBusDefinitionBuilder
15
16
  include ThreadPoolDefinitionBuilder
@@ -19,7 +20,7 @@ module Synapse
19
20
  # @return [undefined]
20
21
  def populate_defaults
21
22
  super
22
- use_threads 4
23
+ use_pool_options size: 4
23
24
  end
24
25
 
25
26
  # @param [UnitOfWorkFactory] unit_factory
@@ -1,25 +1,27 @@
1
1
  module Synapse
2
2
  module Configuration
3
3
  # Mixin for a definition builder that creates a service that is backed by a thread pool
4
+ # @see Contender::Pool::ThreadPoolExecutor For pool options
4
5
  module ThreadPoolDefinitionBuilder
5
6
  extend ActiveSupport::Concern
6
7
 
7
- # Sets the upper and lower limits of the size of the thread pool
8
+ # Sets the options for the thread pool
8
9
  #
9
- # @param [Integer] min_threads
10
- # @param [Integer] max_threads
10
+ # @param [Hash] pool_options
11
11
  # @return [undefined]
12
- def use_threads(min_threads, max_threads = nil)
13
- @min_threads = min_threads
14
- @max_threads = max_threads
12
+ def use_pool_options(pool_options)
13
+ @pool_options = pool_options
15
14
  end
16
15
 
17
16
  protected
18
17
 
19
18
  # Creates a thread pool with the configured options
20
- # @return [Thread::Pool]
19
+ # @return [Contender::Pool::ThreadPoolExecutor]
21
20
  def create_thread_pool
22
- Thread.pool @min_threads, @max_threads
21
+ pool = Contender::Pool::ThreadPoolExecutor.new @pool_options
22
+ pool.start
23
+
24
+ pool
23
25
  end
24
26
  end # ThreadPoolDefinitionBuilder
25
27
  end # Configuration
@@ -1,6 +1,6 @@
1
1
  module Synapse
2
2
  module Configuration
3
- # Mixin for an object defines its dependencies so that they can be auto-injected by the
3
+ # Mixin for an object defines its dependencies so that they can be auto-injected by the
4
4
  # service container after it has been instantiated
5
5
  #
6
6
  # Note that this only supports setter injection
@@ -20,7 +20,7 @@ module Synapse
20
20
  def depends_on(service, *args)
21
21
  options = args.extract_options!
22
22
 
23
- attribute = options[:attribute] || service
23
+ attribute = options[:as] || service
24
24
  attr_accessor attribute
25
25
 
26
26
  self.dependencies[service] = attribute
@@ -1,35 +1,64 @@
1
1
  module Synapse
2
- # @return [Configuration::Container]
3
- mattr_accessor :container
2
+ class << self
3
+ # @return [Configuration::Container]
4
+ attr_accessor :container
4
5
 
5
- # @return [Configuration::ContainerBuilder]
6
- mattr_accessor :container_builder
6
+ # @return [Configuration::ContainerBuilder]
7
+ attr_accessor :container_builder
7
8
 
8
- # Initializes the service container and the container builder
9
- #
10
- # The given block is executed in the container of the container builder. Factory blocks are
11
- # always deferred until the service is needed to build another service or is manually
12
- # requested from the container.
13
- #
14
- # This method can be called multiple times without losing the state of the container.
15
- #
16
- # @example
17
- # Synapse.build do
18
- # definition :account_projection do
19
- # tag :event_listener, :projection
20
- # use_factory do
21
- # Bank::Projections::AccountProjection.new
22
- # end
23
- # end
24
- # end
25
- #
26
- # @see Configuration::ContainerBuilder#build_with
27
- # @param [Proc] block
28
- # @return [undefined]
29
- def self.build(&block)
30
- self.container ||= Configuration::Container.new
31
- self.container_builder ||= Configuration::ContainerBuilder.new self.container
9
+ # Initializes the service container and the container builder
10
+ #
11
+ # The given block is executed in the container of the container builder. Factory blocks are
12
+ # always deferred until the service is needed to build another service or is manually
13
+ # requested from the container.
14
+ #
15
+ # This method can be called multiple times without losing the state of the container.
16
+ #
17
+ # @example
18
+ # Synapse.build do
19
+ # definition :account_projection do
20
+ # tag :event_listener, :projection
21
+ # use_factory do
22
+ # Bank::Projections::AccountProjection.new
23
+ # end
24
+ # end
25
+ # end
26
+ #
27
+ # @see Configuration::ContainerBuilder#build_with
28
+ # @param [Proc] block
29
+ # @return [undefined]
30
+ def build(&block)
31
+ self.container ||= Configuration::Container.new
32
+ self.container_builder ||= Configuration::ContainerBuilder.new self.container
32
33
 
33
- self.container_builder.build_with(&block)
34
+ self.container_builder.build_with(&block)
35
+ end
36
+
37
+ # Initializes the service container and the container builder and applies simple defaults for
38
+ # getting started with a single node setup
39
+ #
40
+ # @example
41
+ # Synapse.build_with_defaults do
42
+ # # Setup things like command handlers, event listeners and repositories
43
+ # end
44
+ #
45
+ # @see Configuration::ContainerBuilder#build_with
46
+ # @param [Proc] block
47
+ # @return [undefined]
48
+ def build_with_defaults(&block)
49
+ build do
50
+ converter_factory
51
+ serializer
52
+ upcaster_chain
53
+
54
+ unit_factory
55
+ simple_command_bus
56
+ gateway
57
+
58
+ simple_event_bus
59
+ end
60
+
61
+ build &block
62
+ end
34
63
  end
35
64
  end
@@ -5,7 +5,7 @@ require 'synapse/configuration/definition_builder'
5
5
  require 'synapse/configuration/dependent'
6
6
  require 'synapse/configuration/ext'
7
7
 
8
- require 'synapse/configuration/component/mixin/thread_pool'
8
+ require 'synapse/configuration/component/shared/thread_pool'
9
9
  require 'synapse/configuration/component/command_bus'
10
10
  require 'synapse/configuration/component/event_bus'
11
11
  # Has to be loaded before event sourcing
@@ -1,6 +1,22 @@
1
1
  module Synapse
2
2
  module Domain
3
- # Mixin module for a basic aggregate root
3
+ # Mixin module for a basic aggregate root that is not event-sourced
4
+ #
5
+ # The persistence mechanism is left up to the aggregate root that uses this mixin. Any sort of
6
+ # ORM can be used to persist aggregates.
7
+ #
8
+ # If optimistic locking is used, the ORM must increment the version field before saving.
9
+ #
10
+ # class Order
11
+ # include Synapse::Domain::AggregateRoot
12
+ # include MongoMapper::Document
13
+ #
14
+ # key :version, Integer
15
+ #
16
+ # before_save { self.version += 1 }
17
+ # end
18
+ #
19
+ # @see Repository::SimpleRepository
4
20
  module AggregateRoot
5
21
  # @return [Boolean] True if this aggregate has been marked for deletion
6
22
  attr_reader :deleted
@@ -14,6 +30,8 @@ module Synapse
14
30
  attr_reader :version
15
31
 
16
32
  # Marks this aggregate as committed by a repository
33
+ #
34
+ # @api public
17
35
  # @return [undefined]
18
36
  def mark_committed
19
37
  if @event_container
@@ -23,6 +41,8 @@ module Synapse
23
41
  end
24
42
 
25
43
  # Returns the number of uncommitted events published by this aggregate
44
+ #
45
+ # @api public
26
46
  # @return [Integer]
27
47
  def uncommitted_event_count
28
48
  unless @event_container
@@ -33,6 +53,8 @@ module Synapse
33
53
  end
34
54
 
35
55
  # Returns a domain event strema containing any uncommitted events published by this aggregate
56
+ #
57
+ # @api public
36
58
  # @return [DomainEventStream]
37
59
  def uncommitted_events
38
60
  unless @event_container
@@ -47,7 +69,8 @@ module Synapse
47
69
  # If an event registration listener is added after events have already been registered, it
48
70
  # will still get a change to process the uncommitted events in this aggregate.
49
71
  #
50
- # @param [#call] listener
72
+ # @api public
73
+ # @param [Proc] listener
51
74
  # @return [undefined]
52
75
  def add_registration_listener(&listener)
53
76
  event_container.add_registration_listener listener
@@ -57,10 +80,13 @@ module Synapse
57
80
 
58
81
  # Publishes a domain event with the given payload and optional metadata
59
82
  #
83
+ # Before any events are published, the aggregate identifier must be set.
84
+ #
60
85
  # @api public
86
+ # @raise [AggregateIdentifierNotInitializedError] If identifier not set
61
87
  # @param [Object] payload Payload of the message; the actual event object
62
88
  # @param [Hash] metadata Metadata associated with the event
63
- # @return [DomainEventMessage] The event that will be committed
89
+ # @return [DomainEventMessage] The event that will be published
64
90
  def publish_event(payload, metadata = nil)
65
91
  event_container.register_event payload, metadata
66
92
  end
@@ -73,18 +99,9 @@ module Synapse
73
99
  @deleted = true
74
100
  end
75
101
 
76
- # Initializes the event container with the given sequence number
77
- #
78
- # @param [Integer] last_sequence_number
79
- # The sequence number of the last committed event for this aggregate
80
- #
81
- # @return [undefined]
82
- def initialize_event_container(last_sequence_number)
83
- event_container.initialize_sequence_number last_sequence_number
84
- @last_sequence_number = last_sequence_number >= 0 ? last_sequence_number : nil
85
- end
86
-
87
102
  # Returns the sequence number of the last committed event
103
+ #
104
+ # @api public
88
105
  # @return [Integer]
89
106
  def last_committed_sequence_number
90
107
  unless @event_container
@@ -96,6 +113,16 @@ module Synapse
96
113
 
97
114
  private
98
115
 
116
+ # Initializes the event container with the given sequence number
117
+ #
118
+ # @param [Integer] last_sequence_number
119
+ # The sequence number of the last committed event for this aggregate
120
+ # @return [undefined]
121
+ def initialize_event_container(last_sequence_number)
122
+ event_container.initialize_sequence_number last_sequence_number
123
+ @last_sequence_number = last_sequence_number >= 0 ? last_sequence_number : nil
124
+ end
125
+
99
126
  # Initializes the uncommitted event container for this aggregate, if not already
100
127
  #
101
128
  # @raise [AggregateIdentifierNotInitializedError] If identifier not set
@@ -112,9 +139,6 @@ module Synapse
112
139
 
113
140
  @event_container
114
141
  end
115
- end
116
-
117
- # Raised when an event is published but the aggregate identifier is not set
118
- class AggregateIdentifierNotInitializedError < NonTransientError; end
119
- end
142
+ end # AggregateRoot
143
+ end # Domain
120
144
  end
@@ -0,0 +1,9 @@
1
+ module Synapse
2
+ module Domain
3
+ # Raised when an event is published but the aggregate identifier is not set
4
+ class AggregateIdentifierNotInitializedError < NonTransientError; end
5
+
6
+ # Raised when the end of a domain event stream has been reached
7
+ class EndOfStreamError < NonTransientError; end
8
+ end
9
+ end
@@ -56,7 +56,7 @@ module Synapse
56
56
  # If the listener is added after events have already registered with the container, it will
57
57
  # be called with a backlog of events to process.
58
58
  #
59
- # @param [#call] listener
59
+ # @param [Proc] listener
60
60
  # @return [undefined]
61
61
  def add_registration_listener(listener)
62
62
  @listeners.push listener
@@ -122,6 +122,6 @@ module Synapse
122
122
  def next_sequence_number
123
123
  last_sequence_number ? last_sequence_number.next : 0
124
124
  end
125
- end
126
- end
125
+ end # EventContainer
126
+ end # Domain
127
127
  end
@@ -53,6 +53,6 @@ module Synapse
53
53
  builder.aggregate_id = @aggregate_id
54
54
  builder.sequence_number = @sequence_number
55
55
  end
56
- end
57
- end
56
+ end # DomainEventMessage
57
+ end # Domain
58
58
  end
@@ -20,6 +20,6 @@ module Synapse
20
20
  def build
21
21
  DomainEventMessage.new @id, @metadata, @payload, @timestamp, @aggregate_id, @sequence_number
22
22
  end
23
- end
24
- end
23
+ end # DomainEventMessageBuilder
24
+ end # Domain
25
25
  end
@@ -0,0 +1,39 @@
1
+ module Synapse
2
+ module Domain
3
+ # Implementation of a domain event stream that holds a stream of events in memory
4
+ class SimpleDomainEventStream < DomainEventStream
5
+ def initialize(*events)
6
+ @events = events.flatten
7
+ @next_index = 0
8
+ end
9
+
10
+ # Returns true if the end of the stream has been reached
11
+ # @return [Boolean]
12
+ def end?
13
+ @next_index >= @events.size
14
+ end
15
+
16
+ # Returns the next event in the stream and moves the stream's pointer forward
17
+ #
18
+ # @raise [EndOfStreamError] If the end of the stream has been reached
19
+ # @return [DomainEventMessage]
20
+ def next_event
21
+ assert_valid
22
+
23
+ event = @events.at @next_index
24
+ @next_index += 1
25
+
26
+ event
27
+ end
28
+
29
+ # Returns the next event in the stream without moving the stream's pointer forward
30
+ #
31
+ # @raise [EndOfStreamError] If the end of the stream has been reached
32
+ # @return [DomainEventMessage]
33
+ def peek
34
+ assert_valid
35
+ @events.at @next_index
36
+ end
37
+ end # SimpleDomainEventStream
38
+ end # Domain
39
+ end
@@ -64,45 +64,6 @@ module Synapse
64
64
  raise EndOfStreamError
65
65
  end
66
66
  end
67
- end
68
-
69
- # Raised when the end of a domain event stream has been reached
70
- class EndOfStreamError < NonTransientError; end
71
-
72
- # Implementation of a domain event stream that holds a stream of events in memory
73
- class SimpleDomainEventStream < DomainEventStream
74
- def initialize(*events)
75
- @events = events.flatten
76
- @next_index = 0
77
- end
78
-
79
- # Returns true if the end of the stream has been reached
80
- # @return [Boolean]
81
- def end?
82
- @next_index >= @events.size
83
- end
84
-
85
- # Returns the next event in the stream and moves the stream's pointer forward
86
- #
87
- # @raise [EndOfStreamError] If the end of the stream has been reached
88
- # @return [DomainEventMessage]
89
- def next_event
90
- assert_valid
91
-
92
- event = @events.at @next_index
93
- @next_index += 1
94
-
95
- event
96
- end
97
-
98
- # Returns the next event in the stream without moving the stream's pointer forward
99
- #
100
- # @raise [EndOfStreamError] If the end of the stream has been reached
101
- # @return [DomainEventMessage]
102
- def peek
103
- assert_valid
104
- @events.at @next_index
105
- end
106
- end
107
- end
67
+ end # DomainEventStream
68
+ end # Domain
108
69
  end
@@ -1,5 +1,8 @@
1
+ require 'synapse/domain/errors'
2
+
1
3
  require 'synapse/domain/aggregate_root'
2
4
  require 'synapse/domain/event_container'
3
5
  require 'synapse/domain/message'
4
6
  require 'synapse/domain/message_builder'
5
7
  require 'synapse/domain/stream'
8
+ require 'synapse/domain/simple_stream'
@@ -1,6 +1,106 @@
1
1
  module Synapse
2
2
  module EventSourcing
3
3
  # Mixin for the root entity of an aggregate that is initialized from a historical event stream
4
+ #
5
+ # = Handling events
6
+ #
7
+ # For ease of use, the event mapping DSL is included in event-sourced aggregates. This includes
8
+ # both the aggregate root and any entities that are a member of the aggregate.
9
+ #
10
+ # This mapping DSL can be used to map handlers for events that have been applied to the
11
+ # aggregate
12
+ #
13
+ # class Order
14
+ # include Synapse::EventSourcing::AggregateRoot
15
+ #
16
+ # def add_item(sku, quantity, unit_price)
17
+ # # Do business logic validation here
18
+ # apply(new ItemsAddedToOrder(id, sku, quantity, unit_price))
19
+ # end
20
+ #
21
+ # map_event ItemsAddedToOrder do |event|
22
+ # @value = @value + (event.quantity * event.unit_price)
23
+ # @line_items.add(OrderLineItem.new(sku, quantity, unit_price))
24
+ # end
25
+ # end
26
+ #
27
+ # Events applied to the aggregate root are cascaded down to any child entities of the aggregate
28
+ # root. Events applied to a child entity are actually applied to the aggregate root's event
29
+ # container, and are then cascaded down to the child entities.
30
+ #
31
+ # = Initialization
32
+ #
33
+ # An aggregate can be initialized in three ways:
34
+ #
35
+ # - Created by the caller using new, usually to create a new aggregate
36
+ # - Allocated, then initialized from an event stream
37
+ # - Deserialized from a snapshot
38
+ #
39
+ # Because of the different ways the aggregate can be created, it is necessary to separate out
40
+ # the logic needed to create data structures required by the aggregate to function.
41
+ #
42
+ # Ruby does not support method overloading, so there is a hook provided to do any logic
43
+ # necessary to instantiate the aggregate, such as creating collections.
44
+ #
45
+ # class Order
46
+ # include Synapse::EventSourcing::AggregateRoot
47
+ #
48
+ # def initialize(id, max_value)
49
+ # pre_initialize
50
+ # apply(OrderCreated.new(id, max_value))
51
+ # end
52
+ #
53
+ # protected
54
+ #
55
+ # def pre_initialize
56
+ # @line_items = Set.new
57
+ # end
58
+ # end
59
+ #
60
+ # Instead of using the pre-initialization hook, you can also do lazy initialization.
61
+ #
62
+ # class Order
63
+ # include Synapse::EventSourcing::AggregateRoot
64
+ #
65
+ # def line_items
66
+ # @line_items ||= Set.new
67
+ # end
68
+ # end
69
+ #
70
+ # = Snapshots
71
+ #
72
+ # When the event stream for an aggregate becomes large, it can put a drain on the application
73
+ # to have to load the entire stream of an aggregate just to perform a single operation upon
74
+ # it.
75
+ #
76
+ # To solve this issue, Synapse supports snapshotting aggregates. The built-in way to snapshot
77
+ # is simply to serialize the aggregate root, since it contains entire state of the aggregate.
78
+ #
79
+ # When using a marshalling serializer, like the built-in Ruby marshaller or ones like Oj and
80
+ # Ox, no work needs to be done to prepare the aggregate for serialization. However, when using
81
+ # the attribute serializer, you have to treat snapshots as mementos.
82
+ #
83
+ # class Order
84
+ # include Synapse::EventSourcing::AggregateRoot
85
+ #
86
+ # def attributes
87
+ # line_items = @line_items.map { |li| li.attributes }
88
+ # { id: @id, value: @value }
89
+ # end
90
+ #
91
+ # # Note that this is called after #allocate
92
+ # def attributes=(attributes)
93
+ # @id = attributes[:id]
94
+ # @value = attributes[:value]
95
+ # # Yeah, it's pretty ugly to support this
96
+ # @line_items = attributes[:line_items].map do |line_item|
97
+ # OrderLineItem.allocate.tap { |li| li.attributes = line_item }
98
+ # end
99
+ # end
100
+ # end
101
+ #
102
+ # It would be nice to have something like XStream to make serialization easier, but as far as
103
+ # I can tell, there's nothing even close to it for Ruby.
4
104
  module AggregateRoot
5
105
  extend ActiveSupport::Concern
6
106
  include Domain::AggregateRoot
@@ -119,6 +219,6 @@ module Synapse
119
219
  entity.handle_aggregate_event event
120
220
  end
121
221
  end
122
- end
123
- end
222
+ end # AggregateRoot
223
+ end # EventSourcing
124
224
  end
@@ -28,7 +28,7 @@ module Synapse
28
28
  if aggregate.nil?
29
29
  aggregate = super aggregate_id, expected_version
30
30
  elsif aggregate.deleted?
31
- raise AggregateDeletedError
31
+ raise AggregateDeletedError.new type_identifier, aggregate_id
32
32
  end
33
33
 
34
34
  register_listener CacheClearingUnitOfWorkListener.new aggregate_id, @cache
@@ -59,6 +59,6 @@ module Synapse
59
59
 
60
60
  @aggregate_root.handle_member_event payload, metadata
61
61
  end
62
- end
63
- end
62
+ end # Entity
63
+ end # EventSourcing
64
64
  end
@@ -2,17 +2,16 @@ module Synapse
2
2
  module EventSourcing
3
3
  # Base mixin for a member of an aggregate which has its state mutated by events that are
4
4
  # applied to the aggregate
5
+ #
6
+ # @see AggregateRoot
7
+ # @see Entity
5
8
  module Member
6
9
  extend ActiveSupport::Concern
7
10
 
8
11
  included do
9
- # @return [Mapper::Mapping]
10
- class_attribute :command_mapper
11
-
12
12
  # @return [Mapper::Mapping]
13
13
  class_attribute :event_mapper
14
14
 
15
- self.command_mapper = Mapping::Mapper.new false
16
15
  self.event_mapper = Mapping::Mapper.new true
17
16
  end
18
17
 
@@ -33,15 +32,6 @@ module Synapse
33
32
  @child_entities ||= Set.new
34
33
  end
35
34
 
36
- # @see Mapper#map
37
- # @param [Class] type
38
- # @param [Object...] args
39
- # @param [Proc] block
40
- # @return [undefined]
41
- def map_command(type, *args, &block)
42
- commnad_mapper.map type, *args, &block
43
- end
44
-
45
35
  # @see Mapper#map
46
36
  # @param [Class] type
47
37
  # @param [Object...] args