synapse-core 0.4.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
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