synapse-core 0.5.4 → 0.5.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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