synapse-core 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (155) hide show
  1. data/lib/synapse.rb +351 -0
  2. data/lib/synapse/command/command_bus.rb +45 -0
  3. data/lib/synapse/command/command_callback.rb +18 -0
  4. data/lib/synapse/command/command_filter.rb +17 -0
  5. data/lib/synapse/command/command_handler.rb +13 -0
  6. data/lib/synapse/command/dispatch_interceptor.rb +16 -0
  7. data/lib/synapse/command/duplication.rb +43 -0
  8. data/lib/synapse/command/errors.rb +27 -0
  9. data/lib/synapse/command/filters/validation.rb +32 -0
  10. data/lib/synapse/command/gateway.rb +34 -0
  11. data/lib/synapse/command/interceptor_chain.rb +31 -0
  12. data/lib/synapse/command/interceptors/serialization.rb +35 -0
  13. data/lib/synapse/command/message.rb +19 -0
  14. data/lib/synapse/command/rollback_policy.rb +22 -0
  15. data/lib/synapse/command/simple_command_bus.rb +138 -0
  16. data/lib/synapse/command/wiring.rb +47 -0
  17. data/lib/synapse/domain/aggregate_root.rb +121 -0
  18. data/lib/synapse/domain/event_container.rb +127 -0
  19. data/lib/synapse/domain/message.rb +82 -0
  20. data/lib/synapse/domain/message_builder.rb +34 -0
  21. data/lib/synapse/domain/stream.rb +108 -0
  22. data/lib/synapse/duplication.rb +60 -0
  23. data/lib/synapse/errors.rb +13 -0
  24. data/lib/synapse/event_bus/event_bus.rb +40 -0
  25. data/lib/synapse/event_bus/event_listener.rb +16 -0
  26. data/lib/synapse/event_bus/event_listener_proxy.rb +12 -0
  27. data/lib/synapse/event_bus/simple_event_bus.rb +69 -0
  28. data/lib/synapse/event_bus/wiring.rb +23 -0
  29. data/lib/synapse/event_sourcing/aggregate_factory.rb +69 -0
  30. data/lib/synapse/event_sourcing/aggregate_root.rb +104 -0
  31. data/lib/synapse/event_sourcing/conflict_resolver.rb +80 -0
  32. data/lib/synapse/event_sourcing/entity.rb +64 -0
  33. data/lib/synapse/event_sourcing/member.rb +72 -0
  34. data/lib/synapse/event_sourcing/repository.rb +119 -0
  35. data/lib/synapse/event_sourcing/snapshot/count_stream.rb +86 -0
  36. data/lib/synapse/event_sourcing/snapshot/count_trigger.rb +91 -0
  37. data/lib/synapse/event_sourcing/snapshot/taker.rb +73 -0
  38. data/lib/synapse/event_sourcing/storage_listener.rb +34 -0
  39. data/lib/synapse/event_sourcing/stream_decorator.rb +25 -0
  40. data/lib/synapse/event_store/errors.rb +16 -0
  41. data/lib/synapse/event_store/event_store.rb +43 -0
  42. data/lib/synapse/event_store/in_memory.rb +59 -0
  43. data/lib/synapse/event_store/mongo/cursor_event_stream.rb +63 -0
  44. data/lib/synapse/event_store/mongo/event_store.rb +86 -0
  45. data/lib/synapse/event_store/mongo/per_commit_strategy.rb +253 -0
  46. data/lib/synapse/event_store/mongo/per_event_strategy.rb +143 -0
  47. data/lib/synapse/event_store/mongo/storage_strategy.rb +113 -0
  48. data/lib/synapse/event_store/mongo/template.rb +73 -0
  49. data/lib/synapse/identifier.rb +23 -0
  50. data/lib/synapse/message.rb +101 -0
  51. data/lib/synapse/message_builder.rb +38 -0
  52. data/lib/synapse/process_manager/correlation.rb +32 -0
  53. data/lib/synapse/process_manager/correlation_resolver.rb +14 -0
  54. data/lib/synapse/process_manager/correlation_set.rb +58 -0
  55. data/lib/synapse/process_manager/process.rb +71 -0
  56. data/lib/synapse/repository/errors.rb +26 -0
  57. data/lib/synapse/repository/lock_manager.rb +40 -0
  58. data/lib/synapse/repository/locking.rb +97 -0
  59. data/lib/synapse/repository/pessimistic_lock_manager.rb +61 -0
  60. data/lib/synapse/repository/repository.rb +109 -0
  61. data/lib/synapse/serialization/converter.rb +39 -0
  62. data/lib/synapse/serialization/converter/chain.rb +45 -0
  63. data/lib/synapse/serialization/converter/factory.rb +68 -0
  64. data/lib/synapse/serialization/converter/identity.rb +29 -0
  65. data/lib/synapse/serialization/converter/json.rb +31 -0
  66. data/lib/synapse/serialization/converter/ox.rb +31 -0
  67. data/lib/synapse/serialization/errors.rb +12 -0
  68. data/lib/synapse/serialization/lazy_object.rb +61 -0
  69. data/lib/synapse/serialization/message/data.rb +25 -0
  70. data/lib/synapse/serialization/message/metadata.rb +13 -0
  71. data/lib/synapse/serialization/message/serialization_aware.rb +17 -0
  72. data/lib/synapse/serialization/message/serialization_aware_message.rb +66 -0
  73. data/lib/synapse/serialization/message/serialized_message.rb +201 -0
  74. data/lib/synapse/serialization/message/serialized_message_builder.rb +64 -0
  75. data/lib/synapse/serialization/message/serialized_object_cache.rb +50 -0
  76. data/lib/synapse/serialization/message/serializer.rb +47 -0
  77. data/lib/synapse/serialization/revision_resolver.rb +30 -0
  78. data/lib/synapse/serialization/serialized_object.rb +37 -0
  79. data/lib/synapse/serialization/serialized_type.rb +31 -0
  80. data/lib/synapse/serialization/serializer.rb +98 -0
  81. data/lib/synapse/serialization/serializer/marshal.rb +32 -0
  82. data/lib/synapse/serialization/serializer/oj.rb +34 -0
  83. data/lib/synapse/serialization/serializer/ox.rb +31 -0
  84. data/lib/synapse/uow/factory.rb +28 -0
  85. data/lib/synapse/uow/listener.rb +79 -0
  86. data/lib/synapse/uow/listener_collection.rb +93 -0
  87. data/lib/synapse/uow/nesting.rb +262 -0
  88. data/lib/synapse/uow/provider.rb +71 -0
  89. data/lib/synapse/uow/storage_listener.rb +14 -0
  90. data/lib/synapse/uow/transaction_manager.rb +27 -0
  91. data/lib/synapse/uow/uow.rb +178 -0
  92. data/lib/synapse/upcasting/chain.rb +78 -0
  93. data/lib/synapse/upcasting/context.rb +58 -0
  94. data/lib/synapse/upcasting/data.rb +30 -0
  95. data/lib/synapse/upcasting/single_upcaster.rb +57 -0
  96. data/lib/synapse/upcasting/upcaster.rb +55 -0
  97. data/lib/synapse/version.rb +3 -0
  98. data/lib/synapse/wiring/message_wiring.rb +41 -0
  99. data/lib/synapse/wiring/wire.rb +55 -0
  100. data/lib/synapse/wiring/wire_registry.rb +61 -0
  101. data/test/command/duplication_test.rb +54 -0
  102. data/test/command/gateway_test.rb +25 -0
  103. data/test/command/interceptor_chain_test.rb +26 -0
  104. data/test/command/serialization_test.rb +37 -0
  105. data/test/command/simple_command_bus_test.rb +141 -0
  106. data/test/command/validation_test.rb +42 -0
  107. data/test/command/wiring_test.rb +73 -0
  108. data/test/domain/aggregate_root_test.rb +57 -0
  109. data/test/domain/fixtures.rb +31 -0
  110. data/test/domain/message_test.rb +61 -0
  111. data/test/domain/stream_test.rb +35 -0
  112. data/test/duplication_test.rb +40 -0
  113. data/test/event_bus/wiring_test.rb +46 -0
  114. data/test/event_sourcing/aggregate_factory_test.rb +28 -0
  115. data/test/event_sourcing/aggregate_root_test.rb +76 -0
  116. data/test/event_sourcing/entity_test.rb +34 -0
  117. data/test/event_sourcing/fixtures.rb +85 -0
  118. data/test/event_sourcing/repository_test.rb +102 -0
  119. data/test/event_sourcing/snapshot/aggregate_taker_test.rb +39 -0
  120. data/test/event_sourcing/snapshot/deferred_taker_test.rb +19 -0
  121. data/test/event_sourcing/snapshot/integration_test.rb +65 -0
  122. data/test/event_sourcing/storage_listener_test.rb +77 -0
  123. data/test/event_store/in_memory_test.rb +47 -0
  124. data/test/process_manager/correlation_set_test.rb +49 -0
  125. data/test/process_manager/correlation_test.rb +24 -0
  126. data/test/process_manager/process_test.rb +52 -0
  127. data/test/repository/locking_test.rb +101 -0
  128. data/test/serialization/converter/factory_test.rb +33 -0
  129. data/test/serialization/converter/identity_test.rb +17 -0
  130. data/test/serialization/converter/json_test.rb +31 -0
  131. data/test/serialization/converter/ox_test.rb +40 -0
  132. data/test/serialization/fixtures.rb +17 -0
  133. data/test/serialization/lazy_object_test.rb +32 -0
  134. data/test/serialization/message/metadata_test.rb +19 -0
  135. data/test/serialization/message/serialization_aware_message_test.rb +88 -0
  136. data/test/serialization/message/serialized_message_builder_test.rb +41 -0
  137. data/test/serialization/message/serialized_message_test.rb +140 -0
  138. data/test/serialization/message/serializer_test.rb +50 -0
  139. data/test/serialization/revision_resolver_test.rb +12 -0
  140. data/test/serialization/serialized_object_test.rb +36 -0
  141. data/test/serialization/serialized_type_test.rb +27 -0
  142. data/test/serialization/serializer/marshal_test.rb +22 -0
  143. data/test/serialization/serializer/oj_test.rb +24 -0
  144. data/test/serialization/serializer/ox_test.rb +36 -0
  145. data/test/serialization/serializer_test.rb +20 -0
  146. data/test/test_helper.rb +19 -0
  147. data/test/uow/factory_test.rb +23 -0
  148. data/test/uow/outer_commit_listener_test.rb +50 -0
  149. data/test/uow/provider_test.rb +70 -0
  150. data/test/uow/uow_test.rb +337 -0
  151. data/test/upcasting/chain_test.rb +29 -0
  152. data/test/upcasting/fixtures.rb +66 -0
  153. data/test/wiring/wire_registry_test.rb +60 -0
  154. data/test/wiring/wire_test.rb +51 -0
  155. metadata +263 -0
@@ -0,0 +1,43 @@
1
+ module Synapse
2
+ module EventStore
3
+ # Represents a mechanism for reading and appending streams of domain events
4
+ # @abstract
5
+ class EventStore
6
+ # Fetches an event stream for the aggregate identified by the given type identifier and
7
+ # the given aggregate identifier. This stream can be used to rebuild the state of the
8
+ # aggregate.
9
+ #
10
+ # Implementations may omit or replace events (for example, with snapshot events) from the
11
+ # stream for performance purposes.
12
+ #
13
+ # @abstract
14
+ # @raise [EventStoreError] If an error occurs while reading the stream from the store
15
+ # @param [String] type_identifier Type descriptor of the aggregate to retrieve
16
+ # @param [Object] aggregate_id
17
+ # @return [DomainEventStream]
18
+ def read_events(type_identifier, aggregate_id); end
19
+
20
+ # Appends the domain events in the given stream to the event store
21
+ #
22
+ # @abstract
23
+ # @raise [EventStoreError] If an error occurs while appending the stream to the store
24
+ # @param [String] type_identifier Type descriptor of the aggregate to append to
25
+ # @param [DomainEventStream] stream
26
+ # @return [undefined]
27
+ def append_events(type_identifier, stream); end
28
+ end
29
+
30
+ # Represents an event store with the capability to manage aggregate snapshots
31
+ # @abstract
32
+ class SnapshotEventStore < EventStore
33
+ # Appends the given snapshot event to the event store
34
+ #
35
+ # @abstract
36
+ # @raise [EventStoreError] If an error occurs while appending the event to the store
37
+ # @param [String] type_identifier Type descriptor of the aggregate to append to
38
+ # @param [DomainEventMessage] snapshot_event
39
+ # @return [undefined]
40
+ def append_snapshot_event(type_identifier, snapshot_event); end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,59 @@
1
+ module Synapse
2
+ module EventStore
3
+ # Implementation of an event store that stores events in memory; for testing purposes and
4
+ # not thread safe
5
+ class InMemoryEventStore < EventStore
6
+ def initialize
7
+ @streams = Hash.new
8
+ end
9
+
10
+ # Clears all streams from this event store
11
+ def clear
12
+ @streams.clear
13
+ end
14
+
15
+ # @raise [StreamNotFoundError] If the stream for the given aggregate identifier is empty
16
+ # @param [String] type_identifier Type descriptor of the aggregate to retrieve
17
+ # @param [Object] aggregate_id
18
+ # @return [DomainEventStream]
19
+ def read_events(type_identifier, aggregate_id)
20
+ events = events_for aggregate_id
21
+
22
+ if events.empty?
23
+ raise StreamNotFoundError.new type_identifier, aggregate_id
24
+ end
25
+
26
+ Domain::SimpleDomainEventStream.new events
27
+ end
28
+
29
+ # Appends any events in the given stream to the end of the aggregate's stream
30
+ #
31
+ # @param [String] type_identifier Type descriptor of the aggregate to append to
32
+ # @param [DomainEventStream] stream
33
+ # @return [undefined]
34
+ def append_events(type_identifier, stream)
35
+ if stream.end?
36
+ return
37
+ end
38
+
39
+ events = events_for stream.peek.aggregate_id
40
+
41
+ until stream.end?
42
+ events.push stream.next_event
43
+ end
44
+ end
45
+
46
+ # Creates and/or retrieves an array of events for the given aggregate identifier
47
+ #
48
+ # @param [Object] aggregate_id
49
+ # @return [Array<DomainEventMessage>]
50
+ def events_for(aggregate_id)
51
+ if @streams.has_key? aggregate_id
52
+ return @streams.fetch aggregate_id
53
+ end
54
+
55
+ @streams.store aggregate_id, Array.new
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,63 @@
1
+ module Synapse
2
+ module EventStore
3
+ module Mongo
4
+ # TODO Document me
5
+ class CursorDomainEventStream < Domain::DomainEventStream
6
+ # @param [StorageStrategy] storage_strategy
7
+ # @param [Mongo::Cursor] cursor
8
+ # @param [Array] last_snapshot_commit
9
+ # @param [Object] aggregate_id
10
+ # @return [undefined]
11
+ def initialize(storage_strategy, cursor, last_snapshot_commit, aggregate_id)
12
+ @storage_strategy = storage_strategy
13
+ @cursor = cursor
14
+ @aggregate_id = aggregate_id
15
+
16
+ if last_snapshot_commit
17
+ # Current batch is an enumerator
18
+ @current_batch = last_snapshot_commit.each
19
+ else
20
+ @current_batch = [].each
21
+ end
22
+
23
+ initialize_next_event
24
+ end
25
+
26
+ # @return [Boolean]
27
+ def end?
28
+ @next.nil?
29
+ end
30
+
31
+ # @return [DomainEventMessage]
32
+ def next_event
33
+ current = @next
34
+ initialize_next_event
35
+ current
36
+ end
37
+
38
+ # @return [DomainEventMessage]
39
+ def peek
40
+ @next
41
+ end
42
+
43
+ private
44
+
45
+ # @return [undefined]
46
+ def initialize_next_event
47
+ begin
48
+ @next = @current_batch.next
49
+ rescue StopIteration
50
+ if @cursor.has_next?
51
+ document = @cursor.next
52
+ @current_batch = @storage_strategy.extract_events(document, @aggregate_id).each
53
+
54
+ retry
55
+ else
56
+ @next = nil
57
+ end
58
+ end
59
+ end
60
+ end # CursorDomainEventStream
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,86 @@
1
+ module Synapse
2
+ module EventStore
3
+ module Mongo
4
+ # Implementation of an event store backed by a Mongo database
5
+ class MongoEventStore < SnapshotEventStore
6
+ # @param [MongoTemplate] template
7
+ # @param [StorageStrategy] storage_strategy
8
+ # @return [undefined]
9
+ def initialize(template, storage_strategy)
10
+ @storage_strategy = storage_strategy
11
+ @template = template
12
+ end
13
+
14
+ # @return [undefined]
15
+ def ensure_indexes
16
+ @storage_strategy.ensure_indexes
17
+ end
18
+
19
+ # @raise [EventStoreError] If an error occurs while reading the stream from the store
20
+ # @param [String] type_identifier Type descriptor of the aggregate to retrieve
21
+ # @param [Object] aggregate_id
22
+ # @return [DomainEventStream]
23
+ def read_events(type_identifier, aggregate_id)
24
+ first_sequence_number = -1
25
+
26
+ last_snapshot_commit = load_last_snapshot type_identifier, aggregate_id
27
+ if last_snapshot_commit and last_snapshot_commit.size > 0
28
+ first_sequence_number = last_snapshot_commit[0].sequence_number
29
+ end
30
+
31
+ cursor = @storage_strategy.fetch_events type_identifier, aggregate_id, first_sequence_number
32
+
33
+ unless last_snapshot_commit or cursor.has_next?
34
+ raise StreamNotFoundError.new type_identifier, aggregate_id
35
+ end
36
+
37
+ CursorDomainEventStream.new @storage_strategy, cursor, last_snapshot_commit, aggregate_id
38
+ end
39
+
40
+ # @raise [EventStoreError] If an error occurs while appending the stream to the store
41
+ # @param [String] type_identifier Type descriptor of the aggregate to append to
42
+ # @param [DomainEventStream] stream
43
+ # @return [undefined]
44
+ def append_events(type_identifier, stream)
45
+ events = stream.to_a
46
+ documents = @storage_strategy.create_documents type_identifier, events
47
+
48
+ begin
49
+ @template.event_collection.insert documents
50
+ rescue Mongo::OperationFailure => ex
51
+ if e.error_code == 11000
52
+ raise Repository::ConcurrencyException,
53
+ 'Event for this aggregate and sequence number already present'
54
+ end
55
+
56
+ raise ex
57
+ end
58
+ end
59
+
60
+ # @raise [EventStoreError] If an error occurs while appending the event to the store
61
+ # @param [String] type_identifier Type descriptor of the aggregate to append to
62
+ # @param [DomainEventMessage] snapshot_event
63
+ # @return [undefined]
64
+ def append_snapshot_event(type_identifier, snapshot_event)
65
+ documents = @storage_strategy.create_documents type_identifier, [snapshot_event]
66
+ @template.snapshot_collection.insert documents
67
+ end
68
+
69
+ private
70
+
71
+ # @param [String] type_identifier Type descriptor of the aggregate to retrieve
72
+ # @param [Object] aggregate_id
73
+ def load_last_snapshot(type_identifier, aggregate_id)
74
+ cursor = @storage_strategy.fetch_last_snapshot type_identifier, aggregate_id
75
+
76
+ unless cursor.has_next?
77
+ return
78
+ end
79
+
80
+ first = cursor.next_document
81
+ @storage_strategy.extract_events first, aggregate_id
82
+ end
83
+ end # MongoEventStore
84
+ end # Mongo
85
+ end # EventStore
86
+ end # Synapse
@@ -0,0 +1,253 @@
1
+ module Synapse
2
+ module EventStore
3
+ module Mongo
4
+ # Storage strategy that stores all events in a commit operation in a single document
5
+ #
6
+ # Since Mongo doesn't support transactions, this can be used as a substitute to guarantee
7
+ # atomic storage of events. The only downside is that it may be harder to query events
8
+ # from the event store.
9
+ #
10
+ # Performance also seems to be better using this strategy
11
+ class DocumentPerCommitStrategy < StorageStrategy
12
+ # @param [String] type_identifier Type identifier for the aggregate
13
+ # @param [Array] events Domain events to be committed
14
+ # @return [Array]
15
+ def create_documents(type_identifier, events)
16
+ document = CommitDocument.new
17
+ document.from_events(type_identifier, events, @serializer).to_hash
18
+ end
19
+
20
+ # @param [Hash] hash
21
+ # @param [Object] aggregate_id
22
+ # @return [Array]
23
+ def extract_events(hash, aggregate_id)
24
+ document = CommitDocument.new
25
+ document.from_hash(hash).to_events(aggregate_id, @serializer, @upcaster_chain)
26
+ end
27
+
28
+ # Mongo document that represents a commit containing one or more events
29
+ class CommitDocument
30
+ # @return [Object]
31
+ attr_reader :aggregate_id
32
+
33
+ # @param [String] type_identifier
34
+ # @param [Array] events
35
+ # @param [Serializer] serializer
36
+ # @return [CommitDocument]
37
+ def from_events(type_identifier, events, serializer)
38
+ first_event = events.first
39
+ last_event = events.last
40
+
41
+ @aggregate_type = type_identifier
42
+ @aggregate_id = first_event.aggregate_id.to_s
43
+ @first_sequence_number = first_event.sequence_number
44
+ @last_sequence_number = last_event.sequence_number
45
+ @first_timestamp = first_event.timestamp
46
+ @last_timestamp = last_event.timestamp
47
+
48
+ @events = Array.new
49
+ events.each do |event|
50
+ event_document = EventDocument.new
51
+ event_document.from_event event, serializer
52
+
53
+ @events.push event_document
54
+ end
55
+
56
+ self
57
+ end
58
+
59
+ # @param [Hash] hash
60
+ # @return [CommitDocument]
61
+ def from_hash(hash)
62
+ hash.symbolize_keys!
63
+
64
+ @aggregate_id = hash.fetch :aggregate_id
65
+ @aggregate_type = hash.fetch :aggregate_type
66
+ @first_sequence_number = hash.fetch :first_sequence_number
67
+ @last_sequence_number = hash.fetch :last_sequence_number
68
+ @first_timestamp = hash.fetch :first_timestamp
69
+ @last_timestamp = hash.fetch :last_timestamp
70
+
71
+ @events = Array.new
72
+
73
+ event_hashes = hash.fetch :events
74
+ event_hashes.each do |event_hash|
75
+ event_document = EventDocument.new
76
+ event_document.from_hash event_hash
77
+
78
+ @events.push event_document
79
+ end
80
+
81
+ self
82
+ end
83
+
84
+ # @return [Hash]
85
+ def to_hash
86
+ events = Array.new
87
+ @events.each do |event|
88
+ events.push event.to_hash
89
+ end
90
+
91
+ { aggregate_id: @aggregate_id,
92
+ aggregate_type: @aggregate_type,
93
+ # Allows us to use the same query to filter events as DocumentPerEvent
94
+ sequence_number: @first_sequence_number,
95
+ first_sequence_number: @first_sequence_number,
96
+ last_sequence_number: @last_sequence_number,
97
+ # Allows us to use the same query to filter events as DocumentPerEvent
98
+ timestamp: @first_timestamp,
99
+ first_timestamp: @first_timestamp,
100
+ last_timestamp: @last_timestamp,
101
+ events: events }
102
+ end
103
+
104
+ # @param [Object] aggregate_id The actual aggregate identifier used to query the evnet store
105
+ # @param [Serializer] serializer
106
+ # @param [UpcasterChain] upcaster_chain
107
+ # @return [Array]
108
+ def to_events(aggregate_id, serializer, upcaster_chain)
109
+ events = Array.new
110
+
111
+ @events.each do |event_document|
112
+ event_data = DocumentDomainEventData.new aggregate_id, event_document
113
+ context = Upcasting::SerializedDomainEventUpcastingContext.new event_data, aggregate_id, serializer
114
+
115
+ upcast_objects = upcaster_chain.upcast event_document.payload, context
116
+ upcast_objects.each do |upcast_object|
117
+ upcast_data = Upcasting::UpcastSerializedDomainEventData.new event_data, aggregate_id, upcast_object
118
+
119
+ builder = Serialization::SerializedDomainEventMessageBuilder.new
120
+
121
+ # Prevent duplicate serialization of metadata if it was accessed during upcasting
122
+ metadata = context.serialized_metadata
123
+ if metadata.deserialized?
124
+ builder.metadata = Serialization::DeserializedObject.new metadata.deserialized
125
+ end
126
+
127
+ builder.from_data upcast_data, serializer
128
+
129
+ events.push builder.build
130
+ end
131
+ end
132
+
133
+ events
134
+ end
135
+ end # CommitDocument
136
+
137
+ # Mongo document that represents a single event as part of a commit document
138
+ class EventDocument
139
+ # @return [String]
140
+ attr_reader :id
141
+
142
+ # @return [Time]
143
+ attr_reader :timestamp
144
+
145
+ # @return [Integer]
146
+ attr_reader :sequence_number
147
+
148
+ # @return [SerializedObject]
149
+ def metadata
150
+ Serialization::SerializedMetadata.new @metadata, @metadata.class
151
+ end
152
+
153
+ # @return [SerializedObject]
154
+ def payload
155
+ Serialization::SerializedObject.new @payload, @payload.class,
156
+ Serialization::SerializedType.new(@payload_type, @payload_revision)
157
+ end
158
+
159
+ # @param [EventMessage] event
160
+ # @param [Serializer] serializer
161
+ # @return [EventDocument]
162
+ def from_event(event, serializer)
163
+ serialization_target = String
164
+ if serializer.can_serialize_to? Hash
165
+ serialization_target = Hash
166
+ end
167
+
168
+ serialized_metadata = serializer.serialize_metadata event, serialization_target
169
+ serialized_payload = serializer.serialize_payload event, serialization_target
170
+
171
+ @id = event.id
172
+ @metadata = serialized_metadata.content
173
+ @payload = serialized_payload.content
174
+ @payload_type = serialized_payload.type.name
175
+ @payload_revision = serialized_payload.type.revision
176
+ @timestamp = event.timestamp
177
+ @sequence_number = event.sequence_number
178
+
179
+ self
180
+ end
181
+
182
+ # @param [Hash] hash
183
+ # @return [EventDocument]
184
+ def from_hash(hash)
185
+ hash.symbolize_keys!
186
+
187
+ @id = hash.fetch :id
188
+ @metadata = hash.fetch :metadata
189
+ @payload = hash.fetch :payload
190
+ @payload_type = hash.fetch :payload_type
191
+ @payload_revision = hash.fetch :payload_revision
192
+ @timestamp = hash.fetch :timestamp
193
+ @sequence_number = hash.fetch :sequence_number
194
+
195
+ self
196
+ end
197
+
198
+ # @return [Hash]
199
+ def to_hash
200
+ { id: @id,
201
+ metadata: @metadata,
202
+ payload: @payload,
203
+ payload_type: @payload_type,
204
+ payload_revision: @payload_revision,
205
+ timestamp: @timestamp,
206
+ sequence_number: @sequence_number }
207
+ end
208
+ end # EventDocument
209
+
210
+ # Serialized domain event data from an event document
211
+ class DocumentDomainEventData < Serialization::SerializedDomainEventData
212
+ # @param [Object] aggregate_id
213
+ # @param [EventDocument] event_document
214
+ # @return [undefined]
215
+ def initialize(aggregate_id, event_document)
216
+ @aggregate_id = aggregate_id
217
+ @event_document = event_document
218
+ end
219
+
220
+ # @return [String]
221
+ def id
222
+ @event_document.id
223
+ end
224
+
225
+ # @return [SerializedObject]
226
+ def metadata
227
+ @event_document.metadata
228
+ end
229
+
230
+ # @return [SerializedObject]
231
+ def payload
232
+ @event_document.payload
233
+ end
234
+
235
+ # @return [Time]
236
+ def timestamp
237
+ @event_document.timestamp
238
+ end
239
+
240
+ # @return [Object]
241
+ def aggregate_id
242
+ @aggregate_id
243
+ end
244
+
245
+ # @return [Integer]
246
+ def sequence_number
247
+ @event_document.sequence_number
248
+ end
249
+ end # DocumentDomainEventData
250
+ end # DocumentPerCommitStrategy
251
+ end # Mongo
252
+ end # EventStore
253
+ end # Synapse