synapse-core 0.1.2 → 0.2.0

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 (57) hide show
  1. data/lib/synapse/auditing/audit_logger.rb +28 -0
  2. data/lib/synapse/auditing/data_provider.rb +42 -0
  3. data/lib/synapse/auditing/dispatch_interceptor.rb +29 -0
  4. data/lib/synapse/auditing/unit_listener.rb +53 -0
  5. data/lib/synapse/auditing.rb +4 -0
  6. data/lib/synapse/command.rb +34 -0
  7. data/lib/synapse/{duplication.rb → common/duplication.rb} +0 -0
  8. data/lib/synapse/{errors.rb → common/errors.rb} +0 -0
  9. data/lib/synapse/{identifier.rb → common/identifier.rb} +2 -1
  10. data/lib/synapse/{message.rb → common/message.rb} +0 -0
  11. data/lib/synapse/{message_builder.rb → common/message_builder.rb} +0 -0
  12. data/lib/synapse/domain.rb +5 -0
  13. data/lib/synapse/event_bus.rb +5 -0
  14. data/lib/synapse/event_sourcing/conflict_resolver.rb +4 -6
  15. data/lib/synapse/event_sourcing/member.rb +11 -2
  16. data/lib/synapse/event_sourcing/snapshot/taker.rb +0 -18
  17. data/lib/synapse/event_sourcing.rb +13 -0
  18. data/lib/synapse/event_store/mongo/cursor_event_stream.rb +3 -3
  19. data/lib/synapse/event_store/mongo.rb +8 -0
  20. data/lib/synapse/event_store.rb +11 -0
  21. data/lib/synapse/partitioning/amqp/amqp_queue_reader.rb +50 -0
  22. data/lib/synapse/partitioning/amqp/amqp_queue_writer.rb +31 -0
  23. data/lib/synapse/partitioning/amqp/key_resolver.rb +26 -0
  24. data/lib/synapse/partitioning/amqp.rb +3 -0
  25. data/lib/synapse/partitioning/memory_queue_reader.rb +31 -0
  26. data/lib/synapse/partitioning/memory_queue_writer.rb +19 -0
  27. data/lib/synapse/partitioning/message_receipt.rb +25 -0
  28. data/lib/synapse/partitioning/packing/json_packer.rb +93 -0
  29. data/lib/synapse/partitioning/packing/json_unpacker.rb +83 -0
  30. data/lib/synapse/partitioning/packing.rb +27 -0
  31. data/lib/synapse/partitioning/queue_reader.rb +32 -0
  32. data/lib/synapse/partitioning/queue_writer.rb +17 -0
  33. data/lib/synapse/partitioning.rb +20 -0
  34. data/lib/synapse/process_manager.rb +4 -0
  35. data/lib/synapse/repository/locking.rb +3 -8
  36. data/lib/synapse/repository.rb +7 -0
  37. data/lib/synapse/serialization/converter/bson.rb +28 -0
  38. data/lib/synapse/serialization/serializer/attribute.rb +48 -0
  39. data/lib/synapse/serialization/serializer.rb +1 -1
  40. data/lib/synapse/serialization.rb +46 -0
  41. data/lib/synapse/uow/factory.rb +5 -5
  42. data/lib/synapse/uow/uow.rb +13 -13
  43. data/lib/synapse/uow.rb +8 -0
  44. data/lib/synapse/upcasting/chain.rb +1 -1
  45. data/lib/synapse/upcasting.rb +5 -0
  46. data/lib/synapse/version.rb +1 -1
  47. data/lib/synapse/wiring.rb +3 -0
  48. data/lib/synapse.rb +26 -338
  49. data/test/auditing/data_provider_test.rb +30 -0
  50. data/test/auditing/dispatch_interceptor_test.rb +25 -0
  51. data/test/auditing/unit_listener_test.rb +70 -0
  52. data/test/partitioning/memory_test.rb +34 -0
  53. data/test/partitioning/packing/json_test.rb +61 -0
  54. data/test/test_ext.rb +14 -0
  55. data/test/test_helper.rb +4 -0
  56. metadata +45 -24
  57. data/test/event_sourcing/snapshot/deferred_taker_test.rb +0 -19
@@ -0,0 +1,28 @@
1
+ module Synapse
2
+ module Auditing
3
+ # Represents a mechanism for auditing commands and the events produced by their execution
4
+ # @abstract
5
+ class AuditLogger
6
+ # Called when a command execution was finished successfully
7
+ #
8
+ # @abstract
9
+ # @param [CommandMessage] command
10
+ # @param [Object] return_value
11
+ # @param [Array<EventMessage>] events
12
+ # @return [undefined]
13
+ def on_success(command, return_value, events); end
14
+
15
+ # Called when a command execution results in an exception being raised
16
+ #
17
+ # The list of events may not be empty; in this case, some events could have been published
18
+ # to the event bus and/or appended to the event store.
19
+ #
20
+ # @abstract
21
+ # @param [CommandMessage] command
22
+ # @param [Exception] exception
23
+ # @param [Array<EventMessage>] events
24
+ # @return [undefined]
25
+ def on_failure(command, exception, events); end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,42 @@
1
+ module Synapse
2
+ module Auditing
3
+ # Provides relevant information to events for auditing purposes
4
+ # @abstract
5
+ class AuditDataProvider
6
+ # Returns auditing information for the given command
7
+ #
8
+ # @abstract
9
+ # @param [CommandMessage] command
10
+ # @return [Hash]
11
+ def provide_data_for(command); end
12
+ end
13
+
14
+ # Implementation of an audit provider that simply audits a command's metadata
15
+ class CommandMetadataProvider < AuditDataProvider
16
+ # @param [CommandMessage] command
17
+ # @return [Hash]
18
+ def provide_data_for(command)
19
+ command.metadata
20
+ end
21
+ end
22
+
23
+ # Implementation of an audit provider that attaches a command's identifier to each event
24
+ # produced as a result of the execution of that command
25
+ class CorrelationDataProvider < AuditDataProvider
26
+ # The default key to use when correlating events with commands
27
+ DEFAULT_KEY = :command_id
28
+
29
+ # @param [Symbol] correlation_key
30
+ # @return [undefined]
31
+ def initialize(correlation_key = DEFAULT_KEY)
32
+ @correlation_key = correlation_key
33
+ end
34
+
35
+ # @param [CommandMessage] command
36
+ # @return [Hash]
37
+ def provide_data_for(command)
38
+ Hash[@correlation_key, command.id]
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,29 @@
1
+ module Synapse
2
+ module Auditing
3
+ class AuditingDispatchInterceptor < Command::DispatchInterceptor
4
+ # @return [Array<AuditDataProvider>]
5
+ attr_accessor :data_providers
6
+
7
+ # @return [Array<AuditLogger>]
8
+ attr_accessor :loggers
9
+
10
+ def initialize
11
+ @data_providers = Array.new
12
+ @loggers = Array.new
13
+ end
14
+
15
+ # @param [CommandMessage] command
16
+ # @param [UnitOfWork] unit The current unit of work for this command dispatch
17
+ # @param [InterceptorChain] chain
18
+ # @return [Object] The result of the execution of the command
19
+ def intercept(command, unit, chain)
20
+ audit_listener = AuditingUnitOfWorkListener.new command, @data_providers, @loggers
21
+ unit.register_listener audit_listener
22
+
23
+ chain.proceed(command).tap do |result|
24
+ audit_listener.return_value = result
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,53 @@
1
+ module Synapse
2
+ module Auditing
3
+ class AuditingUnitOfWorkListener < UnitOfWork::UnitOfWorkListener
4
+ # @return [Array<EventMessage>]
5
+ attr_reader :recorded_events
6
+
7
+ # @return [Object]
8
+ attr_accessor :return_value
9
+
10
+ # @param [CommandMessage] command
11
+ # @param [Array<AuditDataProvider>] data_providers
12
+ # @param [Array<AuditLogger>] loggers
13
+ # @return [undefined]
14
+ def initialize(command, data_providers, loggers)
15
+ @command = command
16
+ @data_providers = data_providers
17
+ @loggers = loggers
18
+ @recorded_events = Array.new
19
+ end
20
+
21
+ # @param [UnitOfWork] unit
22
+ # @param [EventMessage] event
23
+ # @return [EventMessage]
24
+ def on_event_registered(unit, event)
25
+ audit_data = Hash.new
26
+ @data_providers.each do |provider|
27
+ audit_data.merge! provider.provide_data_for @command
28
+ end
29
+
30
+ event.and_metadata(audit_data).tap do |e|
31
+ @recorded_events.push e
32
+ end
33
+ end
34
+
35
+ # @param [UnitOfWork] unit
36
+ # @return [undefined]
37
+ def after_commit(unit)
38
+ @loggers.each do |logger|
39
+ logger.on_success @command, @return_value, @recorded_events
40
+ end
41
+ end
42
+
43
+ # @param [UnitOfWork] unit
44
+ # @param [Error] cause
45
+ # @return [undefined]
46
+ def on_rollback(unit, cause = nil)
47
+ @loggers.each do |logger|
48
+ logger.on_success @command, cause, @recorded_events
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,4 @@
1
+ require 'synapse/auditing/audit_logger'
2
+ require 'synapse/auditing/data_provider'
3
+ require 'synapse/auditing/dispatch_interceptor'
4
+ require 'synapse/auditing/unit_listener'
@@ -0,0 +1,34 @@
1
+ module Synapse
2
+ module Command
3
+ extend ActiveSupport::Autoload
4
+
5
+ # Optional filters and interceptors
6
+ autoload_at 'synapse/command/duplication' do
7
+ autoload :DuplicationFilter
8
+ autoload :DuplicationCleanupInterceptor
9
+ end
10
+
11
+ autoload_at 'synapse/command/filters/validation' do
12
+ autoload :ActiveModelValidationFilter
13
+ autoload :ActiveModelValidationError
14
+ end
15
+
16
+ autoload_at 'synapse/command/interceptors/serialization' do
17
+ autoload :SerializationOptimizingInterceptor
18
+ autoload :SerializationOptimizingListener
19
+ end
20
+ end
21
+ end
22
+
23
+ require 'synapse/command/command_bus'
24
+ require 'synapse/command/command_callback'
25
+ require 'synapse/command/command_filter'
26
+ require 'synapse/command/command_handler'
27
+ require 'synapse/command/dispatch_interceptor'
28
+ require 'synapse/command/errors'
29
+ require 'synapse/command/gateway'
30
+ require 'synapse/command/interceptor_chain'
31
+ require 'synapse/command/message'
32
+ require 'synapse/command/rollback_policy'
33
+ require 'synapse/command/simple_command_bus'
34
+ require 'synapse/command/wiring'
File without changes
@@ -19,5 +19,6 @@ module Synapse
19
19
  end
20
20
  end
21
21
 
22
- ActiveSupport.run_load_hooks :identifier_factory, IdentifierFactory
22
+ # Setup the default identifier factory
23
+ IdentifierFactory.instance = GuidIdentifierFactory.new
23
24
  end
File without changes
@@ -0,0 +1,5 @@
1
+ require 'synapse/domain/aggregate_root'
2
+ require 'synapse/domain/event_container'
3
+ require 'synapse/domain/message'
4
+ require 'synapse/domain/message_builder'
5
+ require 'synapse/domain/stream'
@@ -0,0 +1,5 @@
1
+ require 'synapse/event_bus/event_bus'
2
+ require 'synapse/event_bus/event_listener'
3
+ require 'synapse/event_bus/event_listener_proxy'
4
+ require 'synapse/event_bus/simple_event_bus'
5
+ require 'synapse/event_bus/wiring'
@@ -64,13 +64,11 @@ module Synapse
64
64
 
65
65
  # @return [DomainEventMessage]
66
66
  def next_event
67
- event = @delegate.next_event
68
-
69
- if @expected_version and event.sequence_number > @expected_version
70
- @unseen_events.push event
67
+ @delegate.next_event.tap do |event|
68
+ if @expected_version and event.sequence_number > @expected_version
69
+ @unseen_events.push event
70
+ end
71
71
  end
72
-
73
- event
74
72
  end
75
73
 
76
74
  # Delegators for domain event stream
@@ -4,6 +4,11 @@ module Synapse
4
4
  # applied to the aggregate
5
5
  module Member
6
6
  extend ActiveSupport::Concern
7
+ include Wiring::MessageWiring
8
+
9
+ included do
10
+ self.wire_registry = Wiring::WireRegistry.new true
11
+ end
7
12
 
8
13
  module ClassMethods
9
14
  # Registers an instance variable as a child entity
@@ -53,10 +58,14 @@ module Synapse
53
58
  # If the event is relative to this member, its parameters will be used to change
54
59
  # the state of this member
55
60
  #
56
- # @abstract
57
61
  # @param [EventMessage] event
58
62
  # @return [undefined]
59
- def handle_event(event); end
63
+ def handle_event(event)
64
+ wire = self.wire_registry.wire_for event.payload_type
65
+ if wire
66
+ invoke_wire event, wire
67
+ end
68
+ end
60
69
 
61
70
  private
62
71
 
@@ -17,24 +17,6 @@ module Synapse
17
17
  def schedule_snapshot(type_identifier, aggregate_id); end
18
18
  end
19
19
 
20
- # Snapshot taker that uses EventMachine to defer scheduling of snapshots
21
- class DeferredSnapshotTaker < SnapshotTaker
22
- # @param [SnapshotTaker] delegate
23
- # @return [undefined]
24
- def initialize(delegate)
25
- @delegate = delegate
26
- end
27
-
28
- # @param [String] type_identifier
29
- # @param [Object] aggregate_id
30
- # @return [undefined]
31
- def schedule_snapshot(type_identifier, aggregate_id)
32
- EventMachine.defer do
33
- @delegate.schedule_snapshot type_identifier, aggregate_id
34
- end
35
- end
36
- end
37
-
38
20
  # Snapshot taker that uses the actual aggregate and its state to create a snapshot event
39
21
  class AggregateSnapshotTaker < SnapshotTaker
40
22
  # @param [SnapshotEventStore] event_store
@@ -0,0 +1,13 @@
1
+ require 'synapse/event_sourcing/aggregate_factory'
2
+ require 'synapse/event_sourcing/conflict_resolver'
3
+ require 'synapse/event_sourcing/repository'
4
+ require 'synapse/event_sourcing/storage_listener'
5
+ require 'synapse/event_sourcing/stream_decorator'
6
+
7
+ require 'synapse/event_sourcing/member'
8
+ require 'synapse/event_sourcing/aggregate_root'
9
+ require 'synapse/event_sourcing/entity'
10
+
11
+ require 'synapse/event_sourcing/snapshot/count_stream'
12
+ require 'synapse/event_sourcing/snapshot/count_trigger'
13
+ require 'synapse/event_sourcing/snapshot/taker'
@@ -30,9 +30,9 @@ module Synapse
30
30
 
31
31
  # @return [DomainEventMessage]
32
32
  def next_event
33
- current = @next
34
- initialize_next_event
35
- current
33
+ @next.tap do
34
+ initialize_next_event
35
+ end
36
36
  end
37
37
 
38
38
  # @return [DomainEventMessage]
@@ -0,0 +1,8 @@
1
+ require 'synapse/event_store/mongo/cursor_event_stream'
2
+ require 'synapse/event_store/mongo/event_store'
3
+
4
+ require 'synapse/event_store/mongo/storage_strategy'
5
+ require 'synapse/event_store/mongo/per_commit_strategy'
6
+ require 'synapse/event_store/mongo/per_event_strategy'
7
+
8
+ require 'synapse/event_store/mongo/template'
@@ -0,0 +1,11 @@
1
+ module Synapse
2
+ module EventStore
3
+ extend ActiveSupport::Autoload
4
+
5
+ autoload :InMemoryEventStore, 'synapse/event_store/in_memory'
6
+ autoload :Mongo
7
+ end
8
+ end
9
+
10
+ require 'synapse/event_store/errors'
11
+ require 'synapse/event_store/event_store'
@@ -0,0 +1,50 @@
1
+ module Synapse
2
+ module Partitioning
3
+ module AMQP
4
+ # Implementation of a queue reader that subscribes to an AMQP queue
5
+ class AMQPQueueReader < QueueReader
6
+ # The behavior when a message is not acknowledged by a message handler
7
+ #
8
+ # When a message is explicitly rejected, this usually indicates that there was an
9
+ # error while processing the message. When the message is rejected, it can either be
10
+ # put back on the queue so that it can be retried later, or it can be routed as a dead
11
+ # letter if using RabbitMQ.
12
+ #
13
+ # @see http://www.rabbitmq.com/dlx.html
14
+ # @return [Boolean] Default value is true
15
+ attr_accessor :requeue_on_nack
16
+
17
+ # @param [AMQP::Queue] queue
18
+ # @param [AMQP::Channel] channel
19
+ # @param [MessageUnpacker] unpacker
20
+ # @return [undefined]
21
+ def initialize(queue, channel, unpacker)
22
+ @queue = queue
23
+ @channel = channel
24
+ @requeue_on_nack = true
25
+ end
26
+
27
+ # @yield [MessageReceipt] Receipt of the message taken off the queue
28
+ # @return [undefined]
29
+ def subscribe(&handler)
30
+ @queue.subscribe do |headers, packed|
31
+ receipt = MessageReceipt.new headers.delivery_tag, packed, @queue.name
32
+ handler.call receipt
33
+ end
34
+ end
35
+
36
+ # @param [MessageReceipt] receipt
37
+ # @return [undefined]
38
+ def ack_message(receipt)
39
+ @channel.acknowledge receipt.tag
40
+ end
41
+
42
+ # @param [MessageReceipt] receipt
43
+ # @return [undefined]
44
+ def nack_message(receipt)
45
+ @channel.reject receipt.tag, @requeue_on_nack
46
+ end
47
+ end # AMQPQueueReader
48
+ end # AMQP
49
+ end # Partitioning
50
+ end # Synapse
@@ -0,0 +1,31 @@
1
+ module Synapse
2
+ module Partitioning
3
+ module AMQP
4
+ # Implementation of a queue writer that publishes packed messages to an AMQP exchange
5
+ class AMQPQueueWriter < QueueWriter
6
+ # @return [Hash] Additional options that will be used when publishing messages
7
+ attr_accessor :publish_options
8
+
9
+ # @param [AMQP::Exchange] exchange
10
+ # @param [RoutingKeyResolver] key_resolver
11
+ # @return [undefined]
12
+ def initialize(exchange, key_resolver)
13
+ @exchange = exchange
14
+ @key_resolver = key_resolver
15
+ @publish_options = Hash.new
16
+ end
17
+
18
+ # @param [Object] packed
19
+ # @param [Message] unpacked
20
+ # @return [undefined]
21
+ def put_message(packed, unpacked)
22
+ publish_options = {
23
+ routing_key: @key_resolver.resolve_key(unpacked)
24
+ }
25
+
26
+ @exchange.publish(packed, @publish_options.merge(publish_options))
27
+ end
28
+ end # AMQPQueueWriter
29
+ end # AMQP
30
+ end # Partitioning
31
+ end # Synapse
@@ -0,0 +1,26 @@
1
+ module Synapse
2
+ module Partitioning
3
+ module AMQP
4
+ # Represents a mechanism for determining the routing key to use when publishing a message
5
+ class RoutingKeyResolver
6
+ # Returns the routing key to use when publishing the given message
7
+ #
8
+ # @param [Message] message
9
+ # @return [String]
10
+ def resolve_key(message); end
11
+ end
12
+
13
+ # Implementation of a routing key resolver that uses the message payload's module name
14
+ class ModuleRoutingKeyResolver
15
+ # @param [Message] message
16
+ # @return [String]
17
+ def resolve_key(message)
18
+ type = message.payload_type.to_s
19
+ type.deconstantize.underscore.tap do |key|
20
+ key.tr! '/', '.'
21
+ end
22
+ end
23
+ end
24
+ end # AMQP
25
+ end # Partitioning
26
+ end # Synapse
@@ -0,0 +1,3 @@
1
+ require 'synapse/partitioning/amqp/amqp_queue_reader'
2
+ require 'synapse/partitioning/amqp/amqp_queue_writer'
3
+ require 'synapse/partitioning/amqp/key_resolver'
@@ -0,0 +1,31 @@
1
+ module Synapse
2
+ module Partitioning
3
+ # Queue reader that dequeues messages from an in-memory Ruby queue
4
+ class MemoryQueueReader < QueueReader
5
+ # @param [Queue] queue
6
+ # @param [String] name Name of the queue being read from
7
+ # @return [undefined]
8
+ def initialize(queue, name)
9
+ @queue = queue
10
+ @name = name
11
+ end
12
+
13
+ # @yield [MessageReceipt] Receipt of the message taken off the queue
14
+ # @return [undefined]
15
+ def subscribe(&handler)
16
+ loop do
17
+ packed = @queue.pop
18
+
19
+ receipt = MessageReceipt.new 0, packed, @name
20
+ handler.call receipt
21
+ end
22
+ end
23
+
24
+ # @param [MessageReceipt] receipt
25
+ # @return [undefined]
26
+ def nack_message(receipt)
27
+ @queue.push receipt.packed
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,19 @@
1
+ module Synapse
2
+ module Partitioning
3
+ # Queue writer that pushes message into an in-memory Ruby queue
4
+ class MemoryQueueWriter < QueueWriter
5
+ # @param [Queue] queue
6
+ # @return [undefined]
7
+ def initialize(queue)
8
+ @queue = queue
9
+ end
10
+
11
+ # @param [Object] packed
12
+ # @param [Message] unpacked
13
+ # @return [undefined]
14
+ def put_message(packed, unpacked)
15
+ @queue.push packed
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,25 @@
1
+ module Synapse
2
+ module Partitioning
3
+ # Receipt used to track messages taken off of a queue
4
+ class MessageReceipt
5
+ # @return [Object] The transport mechanism's record of the message
6
+ attr_reader :tag
7
+
8
+ # @return [Object] The packed message from the transport
9
+ attr_reader :packed
10
+
11
+ # @return [String] The name of the queue the message was read from
12
+ attr_reader :queue_name
13
+
14
+ # @param [Object] tag
15
+ # @param [Object] packed
16
+ # @param [String] queue_name
17
+ # @return [undefined]
18
+ def initialize(tag, packed, queue_name)
19
+ @tag = tag
20
+ @packed = packed
21
+ @queue_name = queue_name
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,93 @@
1
+ module Synapse
2
+ module Partitioning
3
+ # Implementation of a message packer that serializes the metadata and payload of any
4
+ # message and then serializes the entire message so it can go onto the wire.
5
+ class JsonMessagePacker < MessagePacker
6
+ # @param [Serializer] serializer
7
+ # @return [undefined]
8
+ def initialize(serializer)
9
+ @serializer = serializer
10
+
11
+ @serialization_target = String
12
+ # Ideally, we want to serialize the metadata and payload to hashes so that we don't
13
+ # duplicate serialization while serializing the message as a whole to a string
14
+ if serializer.can_serialize_to? Hash
15
+ @serialization_target = Hash
16
+ end
17
+ end
18
+
19
+ # @param [Message] unpacked
20
+ # @return [String]
21
+ def pack_message(unpacked)
22
+ message_type = type_for unpacked
23
+
24
+ metadata = @serializer.serialize unpacked.metadata, @serialization_target
25
+ payload = @serializer.serialize unpacked.payload, @serialization_target
26
+
27
+ packed = {
28
+ message_type: message_type,
29
+ id: unpacked.id,
30
+ metadata: metadata.content,
31
+ payload: payload.content,
32
+ payload_type: payload.type.name,
33
+ payload_revision: payload.type.revision
34
+ }
35
+
36
+ if [:event, :domain_event].include? message_type
37
+ pack_event unpacked, packed
38
+ end
39
+
40
+ if :domain_event == message_type
41
+ pack_domain_event unpacked, packed
42
+ end
43
+
44
+ JSON.dump packed
45
+ end
46
+
47
+ private
48
+
49
+ # Packs additional attributes specific to event messages
50
+ #
51
+ # @param [EventMessage] unpacked
52
+ # @param [Hash] packed
53
+ # @return [undefined]
54
+ def pack_event(unpacked, packed)
55
+ additional = {
56
+ timestamp: unpacked.timestamp.to_i
57
+ }
58
+ packed.merge! additional
59
+ end
60
+
61
+ # Packs additional attributes specific to domain event messages
62
+ #
63
+ # @param [DomainEventMessage] unpacked
64
+ # @param [Hash] packed
65
+ # @return [undefined]
66
+ def pack_domain_event(unpacked, packed)
67
+ additional = {
68
+ aggregate_id: unpacked.aggregate_id.to_s,
69
+ sequence_number: unpacked.sequence_number
70
+ }
71
+ packed.merge! additional
72
+ end
73
+
74
+ # Returns the packed type for the given message
75
+ #
76
+ # @raise [ArgumentError] If the given message isn't supported by this packer
77
+ # @param [Message] unpacked
78
+ # @return [Symbol]
79
+ def type_for(unpacked)
80
+ case unpacked
81
+ when Command::CommandMessage
82
+ :command
83
+ when Domain::DomainEventMessage
84
+ :domain_event
85
+ when Domain::EventMessage
86
+ :event
87
+ else
88
+ raise ArgumentError, 'Unknown message type'
89
+ end
90
+ end
91
+ end # JsonMessagePacker
92
+ end # Partitioning
93
+ end # Synapse