synapse-core 0.4.0 → 0.5.1

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 (163) hide show
  1. data/lib/synapse/command/async_command_bus.rb +41 -0
  2. data/lib/synapse/command/command_callback.rb +49 -2
  3. data/lib/synapse/command/command_handler.rb +2 -0
  4. data/lib/synapse/command/filters/validation.rb +2 -2
  5. data/lib/synapse/command/gateway/interval_retry_scheduler.rb +75 -0
  6. data/lib/synapse/command/gateway/retry_scheduler.rb +26 -0
  7. data/lib/synapse/command/gateway/retrying_callback.rb +46 -0
  8. data/lib/synapse/command/gateway.rb +56 -11
  9. data/lib/synapse/command/interceptor_chain.rb +2 -2
  10. data/lib/synapse/command/interceptors/serialization.rb +2 -2
  11. data/lib/synapse/command/message.rb +16 -0
  12. data/lib/synapse/command/simple_command_bus.rb +6 -2
  13. data/lib/synapse/command/wiring.rb +3 -3
  14. data/lib/synapse/command.rb +7 -1
  15. data/lib/synapse/common/concurrency/identifier_lock.rb +2 -17
  16. data/lib/synapse/common/concurrency/public_lock.rb +8 -9
  17. data/lib/synapse/common/errors.rb +1 -1
  18. data/lib/synapse/common/message.rb +2 -6
  19. data/lib/synapse/common.rb +9 -0
  20. data/lib/synapse/configuration/component/command_bus/async_command_bus.rb +41 -0
  21. data/lib/synapse/configuration/component/command_bus/gateway.rb +38 -0
  22. data/lib/synapse/configuration/component/command_bus/simple_command_bus.rb +81 -0
  23. data/lib/synapse/configuration/component/command_bus.rb +35 -0
  24. data/lib/synapse/configuration/component/event_bus/simple_event_bus.rb +41 -0
  25. data/lib/synapse/configuration/component/event_bus.rb +15 -0
  26. data/lib/synapse/configuration/component/event_sourcing/repository.rb +62 -0
  27. data/lib/synapse/configuration/component/event_sourcing.rb +15 -0
  28. data/lib/synapse/configuration/component/repository/locking_repository.rb +85 -0
  29. data/lib/synapse/configuration/component/repository/simple_repository.rb +31 -0
  30. data/lib/synapse/configuration/component/repository.rb +15 -0
  31. data/lib/synapse/configuration/component/serialization/converter_factory.rb +50 -0
  32. data/lib/synapse/configuration/component/serialization/serializer.rb +90 -0
  33. data/lib/synapse/configuration/component/serialization.rb +25 -0
  34. data/lib/synapse/configuration/component/uow/unit_factory.rb +51 -0
  35. data/lib/synapse/configuration/component/uow.rb +22 -0
  36. data/lib/synapse/configuration/component/upcasting/upcaster_chain.rb +61 -0
  37. data/lib/synapse/configuration/component/upcasting.rb +15 -0
  38. data/lib/synapse/configuration/container.rb +80 -0
  39. data/lib/synapse/configuration/container_builder.rb +108 -0
  40. data/lib/synapse/configuration/definition.rb +31 -0
  41. data/lib/synapse/configuration/definition_builder.rb +138 -0
  42. data/lib/synapse/configuration/dependent.rb +31 -0
  43. data/lib/synapse/configuration/ext.rb +35 -0
  44. data/lib/synapse/configuration.rb +32 -0
  45. data/lib/synapse/domain/aggregate_root.rb +25 -26
  46. data/lib/synapse/domain/event_container.rb +5 -5
  47. data/lib/synapse/domain/message.rb +16 -0
  48. data/lib/synapse/event_bus/event_listener.rb +2 -0
  49. data/lib/synapse/event_bus/event_publisher.rb +19 -0
  50. data/lib/synapse/event_bus/simple_event_bus.rb +21 -30
  51. data/lib/synapse/event_bus/wiring.rb +5 -4
  52. data/lib/synapse/event_bus.rb +1 -1
  53. data/lib/synapse/event_sourcing/aggregate_root.rb +6 -4
  54. data/lib/synapse/process_manager/container_resource_injector.rb +18 -0
  55. data/lib/synapse/process_manager/pessimistic_lock_manager.rb +1 -1
  56. data/lib/synapse/process_manager/process.rb +4 -0
  57. data/lib/synapse/process_manager/process_factory.rb +3 -3
  58. data/lib/synapse/process_manager/repository/in_memory.rb +1 -1
  59. data/lib/synapse/process_manager/wiring/process.rb +6 -6
  60. data/lib/synapse/process_manager/wiring/process_manager.rb +8 -8
  61. data/lib/synapse/process_manager.rb +2 -0
  62. data/lib/synapse/repository/locking.rb +5 -3
  63. data/lib/synapse/repository/optimistic_lock_manager.rb +2 -7
  64. data/lib/synapse/repository/pessimistic_lock_manager.rb +3 -3
  65. data/lib/synapse/repository/repository.rb +2 -2
  66. data/lib/synapse/repository/simple_repository.rb +69 -0
  67. data/lib/synapse/repository.rb +1 -0
  68. data/lib/synapse/serialization/converter/chain.rb +2 -2
  69. data/lib/synapse/serialization/converter_factory.rb +2 -2
  70. data/lib/synapse/serialization/lazy_object.rb +2 -2
  71. data/lib/synapse/serialization/message/serialization_aware_message.rb +3 -3
  72. data/lib/synapse/serialization/message/serialized_message.rb +6 -10
  73. data/lib/synapse/serialization/message/serialized_message_builder.rb +4 -4
  74. data/lib/synapse/serialization/message/serialized_object_cache.rb +2 -2
  75. data/lib/synapse/serialization/message/serializer.rb +2 -2
  76. data/lib/synapse/serialization/revision_resolver.rb +3 -3
  77. data/lib/synapse/serialization/serialized_object.rb +2 -2
  78. data/lib/synapse/serialization/serialized_type.rb +2 -2
  79. data/lib/synapse/serialization/serializer/attribute.rb +2 -2
  80. data/lib/synapse/serialization/serializer/marshal.rb +2 -2
  81. data/lib/synapse/serialization/serializer/oj.rb +2 -2
  82. data/lib/synapse/serialization/serializer/ox.rb +2 -2
  83. data/lib/synapse/serialization/serializer.rb +2 -2
  84. data/lib/synapse/uow/factory.rb +2 -2
  85. data/lib/synapse/uow/listener_collection.rb +2 -2
  86. data/lib/synapse/uow/nesting.rb +9 -2
  87. data/lib/synapse/uow/provider.rb +2 -2
  88. data/lib/synapse/uow/uow.rb +8 -2
  89. data/lib/synapse/upcasting/{chain.rb → upcaster_chain.rb} +0 -0
  90. data/lib/synapse/upcasting.rb +1 -1
  91. data/lib/synapse/version.rb +1 -1
  92. data/lib/synapse/wiring/message_wiring.rb +31 -0
  93. data/lib/synapse.rb +2 -14
  94. data/test/auditing/data_provider_test.rb +2 -2
  95. data/test/auditing/dispatch_interceptor_test.rb +1 -1
  96. data/test/auditing/unit_listener_test.rb +3 -3
  97. data/test/command/async_command_bus_test.rb +49 -0
  98. data/test/command/duplication_test.rb +2 -2
  99. data/test/command/gateway/interval_retry_scheduler_test.rb +42 -0
  100. data/test/command/gateway/retrying_callback_test.rb +57 -0
  101. data/test/command/gateway_test.rb +41 -7
  102. data/test/command/interceptor_chain_test.rb +1 -1
  103. data/test/command/message_test.rb +17 -0
  104. data/test/command/serialization_test.rb +2 -2
  105. data/test/command/simple_command_bus_test.rb +7 -7
  106. data/test/command/validation_test.rb +3 -3
  107. data/test/command/wiring_test.rb +3 -3
  108. data/test/common/concurrency/identifier_lock_test.rb +2 -13
  109. data/test/common/concurrency/public_lock_test.rb +6 -6
  110. data/test/{duplication_test.rb → common/duplication_test.rb} +3 -3
  111. data/test/configuration/component/command_bus/async_command_bus_test.rb +36 -0
  112. data/test/configuration/component/command_bus/simple_command_bus_test.rb +57 -0
  113. data/test/configuration/component/event_bus/simple_event_bus_test.rb +58 -0
  114. data/test/configuration/component/serialization/converter_factory_test.rb +48 -0
  115. data/test/configuration/component/serialization/serializer_test.rb +78 -0
  116. data/test/configuration/component/uow/unit_factory_test.rb +46 -0
  117. data/test/configuration/container_builder_test.rb +47 -0
  118. data/test/configuration/container_test.rb +88 -0
  119. data/test/configuration/definition_builder_test.rb +126 -0
  120. data/test/configuration/definition_test.rb +41 -0
  121. data/test/configuration/dependent_test.rb +30 -0
  122. data/test/configuration/ext_test.rb +19 -0
  123. data/test/configuration/fixtures/dependent.rb +10 -0
  124. data/test/domain/aggregate_root_test.rb +5 -5
  125. data/test/domain/message_test.rb +15 -3
  126. data/test/domain/stream_test.rb +2 -2
  127. data/test/event_bus/publisher_test.rb +29 -0
  128. data/test/event_bus/wiring_test.rb +1 -1
  129. data/test/event_sourcing/aggregate_factory_test.rb +12 -6
  130. data/test/event_sourcing/aggregate_root_test.rb +4 -4
  131. data/test/event_sourcing/entity_test.rb +10 -9
  132. data/test/event_sourcing/repository_test.rb +6 -6
  133. data/test/event_sourcing/storage_listener_test.rb +8 -4
  134. data/test/event_store/in_memory_test.rb +3 -3
  135. data/test/process_manager/container_resource_injector_test.rb +19 -0
  136. data/test/process_manager/correlation_set_test.rb +2 -2
  137. data/test/process_manager/correlation_test.rb +2 -2
  138. data/test/process_manager/in_memory_test.rb +3 -3
  139. data/test/process_manager/process_factory_test.rb +2 -2
  140. data/test/process_manager/process_test.rb +3 -3
  141. data/test/process_manager/simple_process_manager_test.rb +5 -5
  142. data/test/process_manager/wiring/process_manager_test.rb +4 -4
  143. data/test/process_manager/wiring/process_test.rb +2 -2
  144. data/test/repository/locking_test.rb +4 -4
  145. data/test/repository/optimistic_test.rb +2 -2
  146. data/test/repository/pessimistic_test.rb +1 -1
  147. data/test/repository/simple_repository_test.rb +79 -0
  148. data/test/support/countdown_latch.rb +18 -0
  149. data/test/test_helper.rb +6 -3
  150. data/test/upcasting/data_test.rb +31 -0
  151. metadata +84 -25
  152. data/lib/synapse/event_bus/event_listener_proxy.rb +0 -12
  153. data/lib/synapse/partitioning/memory_queue_reader.rb +0 -31
  154. data/lib/synapse/partitioning/memory_queue_writer.rb +0 -19
  155. data/lib/synapse/partitioning/message_receipt.rb +0 -25
  156. data/lib/synapse/partitioning/packing/json_packer.rb +0 -93
  157. data/lib/synapse/partitioning/packing/json_unpacker.rb +0 -83
  158. data/lib/synapse/partitioning/packing.rb +0 -27
  159. data/lib/synapse/partitioning/queue_reader.rb +0 -32
  160. data/lib/synapse/partitioning/queue_writer.rb +0 -17
  161. data/lib/synapse/partitioning.rb +0 -18
  162. data/test/partitioning/memory_test.rb +0 -34
  163. data/test/partitioning/packing/json_test.rb +0 -62
@@ -0,0 +1,19 @@
1
+ module Synapse
2
+ module EventBus
3
+ # Mixin for an object that wishes to easily be able to publish events to an event bus
4
+ module EventPublisher
5
+ # @return [EventBus]
6
+ attr_accessor :event_bus
7
+
8
+ protected
9
+
10
+ # Publishes the given event object or event message to the configured event bus
11
+ #
12
+ # @param [Object] event
13
+ # @return [undefined]
14
+ def publish_event(event)
15
+ @event_bus.publish(Domain::EventMessage.as_message(event))
16
+ end
17
+ end # EventPublisher
18
+ end # EventBus
19
+ end
@@ -8,62 +8,53 @@ module Synapse
8
8
  @logger = Logging.logger[self.class]
9
9
  end
10
10
 
11
+ # @api public
11
12
  # @param [EventMessage...] events
12
13
  # @return [undefined]
13
14
  def publish(*events)
14
- if @listeners.empty?
15
- return
16
- end
15
+ return if @listeners.empty?
17
16
 
18
17
  events.flatten!
19
18
  events.each do |event|
20
19
  @listeners.each do |listener|
21
- if @logger.debug?
22
- listener_type = actual_type listener
23
- @logger.debug 'Dispatching event [%s] to listener [%s]' %
24
- [event.payload_type, listener_type]
25
- end
20
+ @logger.debug 'Dispatching event [%s] to listener [%s]' %
21
+ [event.payload_type, listener.class]
26
22
 
27
23
  listener.notify event
28
24
  end
29
25
  end
30
26
  end
31
27
 
28
+ # Returns true if the given listener is subscribed to this event bus
29
+ #
30
+ # @api public
31
+ # @param [EventListener] listener
32
+ # @return [Boolean]
33
+ def subscribed?(listener)
34
+ @listeners.include? listener
35
+ end
36
+
37
+ # @api public
32
38
  # @param [EventListener] listener
33
39
  # @return [undefined]
34
40
  def subscribe(listener)
35
- listener_type = actual_type listener
36
-
37
41
  if @listeners.add? listener
38
- @logger.debug 'Event listener [%s] subscribed' % listener_type
42
+ @logger.debug 'Event listener [%s] subscribed' % listener.class
39
43
  else
40
- @logger.info 'Event listener [%s] not added, was already subscribed' % listener_type
44
+ @logger.info 'Event listener [%s] not added, was already subscribed' % listener.class
41
45
  end
42
46
  end
43
47
 
48
+ # @api public
44
49
  # @param [EventListener] listener
45
50
  # @return [undefined]
46
51
  def unsubscribe(listener)
47
- listener_type = actual_type listener
48
-
49
52
  if @listeners.delete? listener
50
- @logger.debug 'Event listener [%s] unsubscribed' % listener_type
51
- else
52
- @logger.info 'Event listener [%s] not removed, was not subscribed' % listener_type
53
- end
54
- end
55
-
56
- private
57
-
58
- # @param [EventListener] listener
59
- # @return [Class]
60
- def actual_type(listener)
61
- if listener.respond_to? :proxied_type
62
- listener.proxied_type
53
+ @logger.debug 'Event listener [%s] unsubscribed' % listener.class
63
54
  else
64
- listener.class
55
+ @logger.info 'Event listener [%s] not removed, was not subscribed' % listener.class
65
56
  end
66
57
  end
67
- end
68
- end
58
+ end # SimpleEventBus
59
+ end # EventBus
69
60
  end
@@ -9,10 +9,11 @@ module Synapse
9
9
  # @param [EventMessage] event
10
10
  # @return [undefined]
11
11
  def notify(event)
12
- wire = self.wire_registry.wire_for event.payload_type
13
- if wire
14
- invoke_wire event, wire
15
- end
12
+ wire = wire_registry.wire_for event.payload_type
13
+
14
+ return unless wire
15
+
16
+ invoke_wire event, wire
16
17
  end
17
18
  end
18
19
  end
@@ -1,5 +1,5 @@
1
1
  require 'synapse/event_bus/event_bus'
2
2
  require 'synapse/event_bus/event_listener'
3
- require 'synapse/event_bus/event_listener_proxy'
3
+ require 'synapse/event_bus/event_publisher'
4
4
  require 'synapse/event_bus/simple_event_bus'
5
5
  require 'synapse/event_bus/wiring'
@@ -67,6 +67,7 @@ module Synapse
67
67
  # Creates an event with the given metadata and payload, publishes it using the event
68
68
  # container, and finally handles it locally and recursively down the aggregate.
69
69
  #
70
+ # @api public
70
71
  # @param [Object] payload
71
72
  # @param [Hash] metadata
72
73
  # @return [undefined]
@@ -76,10 +77,10 @@ module Synapse
76
77
  handle_recursively event
77
78
  else
78
79
  # This is a workaround for aggregates that set the aggregate identifier in an event handler
79
- event = Domain::DomainEventMessage.build do |b|
80
- b.metadata = metadata
81
- b.payload = payload
82
- b.sequence_number = 0
80
+ event = Domain::DomainEventMessage.build do |builder|
81
+ builder.metadata = metadata
82
+ builder.payload = payload
83
+ builder.sequence_number = 0
83
84
  end
84
85
 
85
86
  handle_recursively event
@@ -89,6 +90,7 @@ module Synapse
89
90
 
90
91
  # Handles the event locally and then cascades to any registered child entities
91
92
  #
93
+ # @api private
92
94
  # @param [DomainEventMessage] event
93
95
  # @return [undefined]
94
96
  def handle_recursively(event)
@@ -0,0 +1,18 @@
1
+ module Synapse
2
+ module ProcessManager
3
+ # Resource injector that uses the service container and dependency DSL to inject resources
4
+ class ContainerResourceInjector < ResourceInjector
5
+ # @param [Configuration::Container] container
6
+ # @return [undefined]
7
+ def initialize(container)
8
+ @container = container
9
+ end
10
+
11
+ # @param [Process] process
12
+ # @return [undefined]
13
+ def inject_resources(process)
14
+ @container.inject_into process
15
+ end
16
+ end # ContainerResourceInjector
17
+ end # ProcessManager
18
+ end
@@ -1,6 +1,6 @@
1
1
  module Synapse
2
2
  module ProcessManager
3
- # Lock manager that does pessimistic locking for processes
3
+ # Lock manager that blocks until a lock can be obtained for a process
4
4
  class PessimisticLockManager
5
5
  def initialize
6
6
  @lock = IdentifierLock.new
@@ -6,6 +6,8 @@ module Synapse
6
6
  # "maintain the state of the sequence and determine the next processing step based on
7
7
  # intermediate results" (Hohpe 279). Processes are also called sagas in some CQRS frameworks.
8
8
  #
9
+ # Consider using the implementation of a process that uses message wiring.
10
+ #
9
11
  # @abstract
10
12
  class Process
11
13
  # @return [String] The unique identifier of this process
@@ -47,6 +49,7 @@ module Synapse
47
49
 
48
50
  # Correlates this process instance with the given key and value
49
51
  #
52
+ # @api public
50
53
  # @param [Symbol] key
51
54
  # @param [String] value
52
55
  # @return [undefined]
@@ -56,6 +59,7 @@ module Synapse
56
59
 
57
60
  # Dissociates this process instance from the given key and value
58
61
  #
62
+ # @api public
59
63
  # @param [Symbol] key
60
64
  # @param [String] value
61
65
  # @return [undefined]
@@ -19,7 +19,7 @@ module Synapse
19
19
  # @param [Class] process_type
20
20
  # @return [Boolean]
21
21
  def supports(process_type); end
22
- end
22
+ end # ProcessFactory
23
23
 
24
24
  # Generic implementation of a process factory that supports any process implementations that
25
25
  # have a no-argument constructor
@@ -47,6 +47,6 @@ module Synapse
47
47
  ctor = process_type.instance_method :initialize
48
48
  ctor.arity <= 0
49
49
  end
50
- end
51
- end
50
+ end # GenericProcessFactory
51
+ end # ProcessManager
52
52
  end
@@ -59,5 +59,5 @@ module Synapse
59
59
  @managed_processes.count
60
60
  end
61
61
  end # InMemoryProcessRepository
62
- end
62
+ end # ProcessManager
63
63
  end
@@ -15,13 +15,13 @@ module Synapse
15
15
  def handle(event)
16
16
  return unless @active
17
17
 
18
- wire = self.wire_registry.wire_for event.payload_type
18
+ wire = wire_registry.wire_for event.payload_type
19
19
 
20
- if wire
21
- invoke_wire event, wire
22
- finish if wire.options[:finish]
23
- end
20
+ return unless wire
21
+
22
+ invoke_wire event, wire
23
+ finish if wire.options[:finish]
24
24
  end
25
25
  end # WiringProcess
26
- end
26
+ end # ProcessManager
27
27
  end
@@ -1,7 +1,7 @@
1
1
  module Synapse
2
2
  module ProcessManager
3
3
  # Process manager that is aware of processes that use the wiring DSL
4
- # @see [WiringProcess]
4
+ # @see WiringProcess
5
5
  class WiringProcessManager < ProcessManager
6
6
  # @raise [ArgumentError] If a process type is given that doesn't support the wiring DSL
7
7
  # @param [ProcessRepository] repository
@@ -44,11 +44,11 @@ module Synapse
44
44
  def extract_correlation(process_type, event)
45
45
  wire = process_type.wire_registry.wire_for event.payload_type
46
46
 
47
- if wire
48
- correlation_key = wire.options[:correlate]
49
- if correlation_key
50
- correlation_value event.payload, correlation_key
51
- end
47
+ return unless wire
48
+
49
+ correlation_key = wire.options[:correlate]
50
+ if correlation_key
51
+ correlation_value event.payload, correlation_key
52
52
  end
53
53
  end
54
54
 
@@ -67,6 +67,6 @@ module Synapse
67
67
  Correlation.new correlation_key, value
68
68
  end
69
69
  end
70
- end
71
- end
70
+ end # WiringProcessManager
71
+ end # ProcessManager
72
72
  end
@@ -8,6 +8,8 @@ require 'synapse/process_manager/process_factory'
8
8
  require 'synapse/process_manager/process_manager'
9
9
  require 'synapse/process_manager/process_repository'
10
10
  require 'synapse/process_manager/resource_injector'
11
+ # Must be loaded after the resource injector
12
+ require 'synapse/process_manager/container_resource_injector'
11
13
  require 'synapse/process_manager/simple_process_manager'
12
14
 
13
15
  require 'synapse/process_manager/wiring/process'
@@ -13,6 +13,7 @@ module Synapse
13
13
  @logger = Logging.logger[self.class]
14
14
  end
15
15
 
16
+ # @api public
16
17
  # @raise [AggregateNotFoundError]
17
18
  # If the aggregate with the given identifier could not be found
18
19
  # @raise [ConflictingModificationError]
@@ -37,6 +38,7 @@ module Synapse
37
38
  end
38
39
  end
39
40
 
41
+ # @api public
40
42
  # @raise [ArgumentError] If the version of the aggregate is not null
41
43
  # @param [AggregateRoot] aggregate
42
44
  # @return [undefined]
@@ -69,7 +71,7 @@ module Synapse
69
71
  # @param [Integer] expected_version
70
72
  # @return [AggregateRoot]
71
73
  def perform_load(aggregate_id, expected_version); end
72
- end
74
+ end # LockingRepository
73
75
 
74
76
  # Unit of work listener that releases the lock on an aggregate when the unit of work
75
77
  # is cleaning up
@@ -87,6 +89,6 @@ module Synapse
87
89
  def on_cleanup(unit)
88
90
  @lock_manager.release_lock @aggregate_id
89
91
  end
90
- end
91
- end
92
+ end # LockCleaningUnitOfWorkListener
93
+ end # Repository
92
94
  end
@@ -65,7 +65,7 @@ module Synapse
65
65
  end
66
66
  end
67
67
  end
68
- end
68
+ end # OptimisticLockManager
69
69
 
70
70
  # Lock that keeps track of an aggregate's version
71
71
  # @api private
@@ -88,12 +88,7 @@ module Synapse
88
88
  def validate(aggregate)
89
89
  last_committed = aggregate.version
90
90
  if @version.nil? or @version.eql? last_committed
91
- if last_committed.nil?
92
- last_committed = 0
93
- end
94
-
95
- @version = last_committed + aggregate.uncommitted_event_count
96
-
91
+ @version = (last_committed or 0) + aggregate.uncommitted_event_count
97
92
  true
98
93
  else
99
94
  false
@@ -1,6 +1,6 @@
1
1
  module Synapse
2
2
  module Repository
3
- # Rough implementation of a pessimistic lock manager using local locks
3
+ # Implementation of a lock manager that blocks until a lock can be obtained
4
4
  class PessimisticLockManager < LockManager
5
5
  def initialize
6
6
  @aggregates = IdentifierLock.new
@@ -23,6 +23,6 @@ module Synapse
23
23
  def release_lock(aggregate_id)
24
24
  @aggregates.release_lock aggregate_id
25
25
  end
26
- end
27
- end
26
+ end # PessimisticLockManager
27
+ end # Repository
28
28
  end
@@ -104,6 +104,6 @@ module Synapse
104
104
  def current_unit
105
105
  @unit_provider.current
106
106
  end
107
- end
108
- end
107
+ end # Repository
108
+ end # Repository
109
109
  end
@@ -0,0 +1,69 @@
1
+ module Synapse
2
+ module Repository
3
+ # Simple repository that works with all sorts of different object mappers, including:
4
+ #
5
+ # - ActiveRecord
6
+ # - DataMapper
7
+ # - Mongoid
8
+ # - MongoMapper
9
+ #
10
+ # The only requirement of the model is that it properly increment the version field upon save
11
+ class SimpleRepository < LockingRepository
12
+ # @param [LockManager] lock_manager
13
+ # @param [Class] aggregate_type
14
+ # @return [undefined]
15
+ def initialize(lock_manager, aggregate_type)
16
+ super lock_manager
17
+
18
+ @aggregate_type = aggregate_type
19
+ @storage_listener = SimpleStorageListener.new
20
+ end
21
+
22
+ protected
23
+
24
+ # @raise [AggregateNotFoundError]
25
+ # If the aggregate with the given identifier could not be found
26
+ # @raise [ConflictingModificationError]
27
+ # If the expected version doesn't match the aggregate's actual version
28
+ # @param [Object] aggregate_id
29
+ # @param [Integer] expected_version
30
+ # @return [AggregateRoot]
31
+ def perform_load(aggregate_id, expected_version)
32
+ # Most ORMs that I can think of use #find like this -- no need for orm_adapter or anything
33
+ # crazy like that
34
+ aggregate = @aggregate_type.find aggregate_id
35
+ aggregate.tap do
36
+ unless aggregate
37
+ raise AggregateNotFoundError
38
+ end
39
+
40
+ assert_version_expected aggregate, expected_version
41
+ end
42
+ end
43
+
44
+ # @return [Class]
45
+ def aggregate_type
46
+ @aggregate_type
47
+ end
48
+
49
+ # @return [StorageListener]
50
+ def storage_listener
51
+ @storage_listener
52
+ end
53
+ end # SimpleRepository
54
+
55
+ # Storage listener that simply calls #save on the aggregate, unless it has been marked for
56
+ # deletion. In that case, then the #destroy method is called instead.
57
+ class SimpleStorageListener < UnitOfWork::StorageListener
58
+ # @param [AggregateRoot] aggregate
59
+ # @return [undefined]
60
+ def store(aggregate)
61
+ if aggregate.deleted?
62
+ aggregate.destroy
63
+ else
64
+ aggregate.save
65
+ end
66
+ end
67
+ end # SimpleStorageListener
68
+ end # Repository
69
+ end
@@ -6,3 +6,4 @@ require 'synapse/repository/pessimistic_lock_manager'
6
6
 
7
7
  require 'synapse/repository/repository'
8
8
  require 'synapse/repository/locking'
9
+ require 'synapse/repository/simple_repository'
@@ -40,6 +40,6 @@ module Synapse
40
40
  end
41
41
  intermediate
42
42
  end
43
- end
44
- end
43
+ end # ConverterChain
44
+ end # Serialization
45
45
  end
@@ -63,6 +63,6 @@ module Synapse
63
63
  converter.source_type == source_type && converter.target_type == target_type
64
64
  end
65
65
  end
66
- end
67
- end
66
+ end # ConverterFactory
67
+ end # Serialization
68
68
  end
@@ -56,6 +56,6 @@ module Synapse
56
56
  def deserialized?
57
57
  true
58
58
  end
59
- end
60
- end
59
+ end # LazyObject
60
+ end # Serialization
61
61
  end
@@ -55,12 +55,12 @@ module Synapse
55
55
 
56
56
  # Delegators for message attribute readers
57
57
  def_delegators :@message, :id, :metadata, :payload, :payload_type, :timestamp
58
- end
58
+ end # SerializationAwareEventMessage
59
59
 
60
60
  # Decorator for a domain event message that adds serialization awareness
61
61
  class SerializationAwareDomainEventMessage < SerializationAwareEventMessage
62
62
  # Delegators for domain event specific attribute readers
63
63
  def_delegators :@message, :aggregate_id, :sequence_number
64
- end
65
- end
64
+ end # SerializationAwareDomainEventMessage
65
+ end # Serialization
66
66
  end
@@ -44,9 +44,7 @@ module Synapse
44
44
  # @param [Hash] additional_metadata
45
45
  # @return [SerializedMessage]
46
46
  def and_metadata(additional_metadata)
47
- if additional_metadata.empty?
48
- return self
49
- end
47
+ return self if additional_metadata.empty?
50
48
 
51
49
  self.class.build do |builder|
52
50
  build_duplicate builder, metadata.merge(additional_metadata)
@@ -59,9 +57,7 @@ module Synapse
59
57
  # @param [Hash] replacement_metadata
60
58
  # @return [SerializedMessage]
61
59
  def with_metadata(replacement_metadata)
62
- if @serialized_metadata.deserialized == replacement_metadata
63
- return self
64
- end
60
+ return self if @serialized_metadata.deserialized == replacement_metadata
65
61
 
66
62
  self.class.build do |builder|
67
63
  build_duplicate builder, replacement_metadata
@@ -126,7 +122,7 @@ module Synapse
126
122
  serializer.serialize object.deserialized, expected_type
127
123
  end
128
124
  end
129
- end
125
+ end # SerializedMessage
130
126
 
131
127
  # Serialized representation of an event message
132
128
  class SerializedEventMessage < SerializedMessage
@@ -157,7 +153,7 @@ module Synapse
157
153
  super
158
154
  builder.timestamp = @timestamp
159
155
  end
160
- end
156
+ end # SerializedEventMessage
161
157
 
162
158
  # Serialized representation of a domain event message
163
159
  class SerializedDomainEventMessage < SerializedEventMessage
@@ -196,6 +192,6 @@ module Synapse
196
192
  builder.aggregate_id = @aggregate_id
197
193
  builder.sequence_number = @sequence_number
198
194
  end
199
- end
200
- end
195
+ end # SerializedDomainEventMessage
196
+ end # Serialization
201
197
  end
@@ -22,7 +22,7 @@ module Synapse
22
22
  def build
23
23
  SerializedMessage.new @id, @metadata, @payload
24
24
  end
25
- end
25
+ end # SerializedMessageBuilder
26
26
 
27
27
  # Message builder capable of producing SerializedEventMessage instances
28
28
  class SerializedEventMessageBuilder < SerializedMessageBuilder
@@ -33,7 +33,7 @@ module Synapse
33
33
  def build
34
34
  SerializedEventMessage.new @id, @metadata, @payload, @timestamp
35
35
  end
36
- end
36
+ end # SerializedEventMessageBuilder
37
37
 
38
38
  # Message builder capable of producing SerializedDomainEventMessage instances
39
39
  class SerializedDomainEventMessageBuilder < SerializedEventMessageBuilder
@@ -59,6 +59,6 @@ module Synapse
59
59
  def build
60
60
  SerializedDomainEventMessage.new @id, @metadata, @payload, @timestamp, @aggregate_id, @sequence_number
61
61
  end
62
- end
63
- end
62
+ end # SerializedDomainEventMessageBuilder
63
+ end # Serialization
64
64
  end
@@ -45,6 +45,6 @@ module Synapse
45
45
  end
46
46
  end
47
47
  end
48
- end
49
- end
48
+ end # SerializedObjectCache
49
+ end # Serialization
50
50
  end
@@ -42,6 +42,6 @@ module Synapse
42
42
  # Delegators for regular serializer methods
43
43
  def_delegators :@serializer, :converter_factory, :serialize, :deserialize,
44
44
  :can_serialize_to?, :class_for, :type_for
45
- end
46
- end
45
+ end # MessageSerializer
46
+ end # Serialization
47
47
  end
@@ -9,7 +9,7 @@ module Synapse
9
9
  # @param [Class] payload_type
10
10
  # @return [String] The revision of the given payload type
11
11
  def revision_of(payload_type); end
12
- end
12
+ end # RevisionResolver
13
13
 
14
14
  # Implementation of a revision resolver that returns a fixed value. This could be an
15
15
  # application version number, for example
@@ -25,6 +25,6 @@ module Synapse
25
25
  def revision_of(payload_type)
26
26
  @revision.to_s
27
27
  end
28
- end
29
- end
28
+ end # FixedRevisionResolver
29
+ end # Serialization
30
30
  end
@@ -32,6 +32,6 @@ module Synapse
32
32
  def hash
33
33
  @content.hash ^ @content_type.hash ^ @type.hash
34
34
  end
35
- end
36
- end
35
+ end # SerializedObject
36
+ end # Serialization
37
37
  end
@@ -26,6 +26,6 @@ module Synapse
26
26
  def hash
27
27
  @name.hash ^ @revision.hash
28
28
  end
29
- end
30
- end
29
+ end # SerializedType
30
+ end # Serialization
31
31
  end
@@ -43,6 +43,6 @@ module Synapse
43
43
  def native_content_type
44
44
  Hash
45
45
  end
46
- end
47
- end
46
+ end # AttributeSerializer
47
+ end # Serialization
48
48
  end
@@ -27,6 +27,6 @@ module Synapse
27
27
  def native_content_type
28
28
  String
29
29
  end
30
- end
31
- end
30
+ end # MarshalSerializer
31
+ end # Serialization
32
32
  end