ruby_event_store 0.30.0 → 0.31.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4df1be4d7e983bb77d1c069496cdca690f72d593a0c0d83f9d3d7519d63ed115
4
- data.tar.gz: 0d156019cb436a9fb262b680e3e46d007d7c64ec46f1186bae82c5e4344b03c8
3
+ metadata.gz: 7bc6504270eee043e23b424f0aa08bb484d857629f28bda3332f1a7ba68afcef
4
+ data.tar.gz: 1088258a8ac91e24006ef5f9b12422a12bfaed0b00e264047b84fecafd060966
5
5
  SHA512:
6
- metadata.gz: 490e25c72237a78d241df447ad97d55f2d245d40ea4d3b7665b5c699e5273d3b8257f06d2a0a3a1d8d3bc0940158819f433d72b47460620a5c4ed756fad5d646
7
- data.tar.gz: 4355818327a762070c48a8121728c9914b74881187f028c8dc8c440d46c9b51556621b5fb697cdbbd97fc93c3eaff03cafa69fefa6d84f6655023cb053336ae4
6
+ metadata.gz: d0ed208c9c47f2fdac29afa6206ae5d0d4eaeb3095abc416ed77239ab05d9b3b203181dd6cb88e3ad87e1c85c919785b56ecea1532c1e2fefb75e2c6d630531d
7
+ data.tar.gz: c4d92331c73f56c91ad6016407031e2407874589b0421d8cc9b0472d7f5bdbcac8b2e11579e00f8b7ae05f43ac554b8d92d892e7e12b78d88899c10ed6eb3b36
data/Makefile CHANGED
@@ -15,7 +15,12 @@ IGNORE = RubyEventStore.const_missing \
15
15
  RubyEventStore::Client\#read_events_forward \
16
16
  RubyEventStore::Client\#read_events_backward \
17
17
  RubyEventStore::DeprecatedReadAPIRunner* \
18
- RubyEventStore::DeprecatedReadAPIRewriter*
18
+ RubyEventStore::DeprecatedReadAPIRewriter* \
19
+ RubyEventStore::Client\#publish_event \
20
+ RubyEventStore::Client\#publish_events \
21
+ RubyEventStore::Client\#link_to_stream \
22
+ RubyEventStore::Client\#append_to_stream \
23
+
19
24
  SUBJECT ?= RubyEventStore*
20
25
 
21
26
  install: ## Install gem dependencies
@@ -1,4 +1,5 @@
1
1
  require 'ruby_event_store/pub_sub/dispatcher'
2
+ require 'ruby_event_store/pub_sub/subscriptions'
2
3
  require 'ruby_event_store/pub_sub/broker'
3
4
  require 'ruby_event_store/in_memory_repository'
4
5
  require 'ruby_event_store/projection'
@@ -16,4 +17,8 @@ require 'ruby_event_store/mappers/default'
16
17
  require 'ruby_event_store/mappers/protobuf'
17
18
  require 'ruby_event_store/mappers/null_mapper'
18
19
  require 'ruby_event_store/batch_enumerator'
20
+ require 'ruby_event_store/correlated_commands'
21
+ require 'ruby_event_store/link_by_metadata'
22
+ require 'ruby_event_store/async_proxy_strategy'
23
+ require 'ruby_event_store/async_dispatcher'
19
24
  require 'ruby_event_store/version'
@@ -0,0 +1,20 @@
1
+ module RubyEventStore
2
+ class AsyncDispatcher < PubSub::Dispatcher
3
+ def initialize(proxy_strategy: AsyncProxyStrategy::Inline.new, scheduler:)
4
+ @async_proxy_strategy = proxy_strategy
5
+ @scheduler = scheduler
6
+ end
7
+
8
+ def call(subscriber, _, serialized_event)
9
+ if @scheduler.async_handler?(subscriber)
10
+ @async_proxy_strategy.call(->{ @scheduler.call(subscriber, serialized_event) })
11
+ else
12
+ super
13
+ end
14
+ end
15
+
16
+ def verify(subscriber)
17
+ super unless @scheduler.async_handler?(subscriber)
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,9 @@
1
+ module RubyEventStore
2
+ module AsyncProxyStrategy
3
+ class Inline
4
+ def call(schedule_proc)
5
+ schedule_proc.call
6
+ end
7
+ end
8
+ end
9
+ end
@@ -1,49 +1,118 @@
1
+ require 'concurrent'
2
+
1
3
  module RubyEventStore
2
4
  class Client
5
+
3
6
  def initialize(repository:,
4
7
  mapper: Mappers::Default.new,
5
- event_broker: PubSub::Broker.new,
8
+ subscriptions: PubSub::Subscriptions.new,
9
+ dispatcher: PubSub::Dispatcher.new,
6
10
  page_size: PAGE_SIZE,
7
- metadata_proc: nil,
8
11
  clock: ->{ Time.now.utc })
9
12
  @repository = repository
10
13
  @mapper = mapper
11
- @event_broker = event_broker
14
+ @broker = PubSub::Broker.new(subscriptions: subscriptions, dispatcher: dispatcher)
12
15
  @page_size = page_size
13
- warn "`RubyEventStore::Client#metadata_proc` has been deprecated. Use `RubyEventStore::Client#with_metadata` instead." if metadata_proc
14
- @metadata_proc = metadata_proc
15
16
  @clock = clock
17
+ @metadata = Concurrent::ThreadLocalVar.new
16
18
  end
17
19
 
18
- def publish_events(events, stream_name: GLOBAL_STREAM, expected_version: :any)
19
- append_to_stream(events, stream_name: stream_name, expected_version: expected_version)
20
- events.each do |ev|
21
- event_broker.notify_subscribers(ev)
20
+
21
+ # Persists events and notifies subscribed handlers about them
22
+ #
23
+ # @param events [Array<Event, Proto>, Event, Proto] event(s)
24
+ # @param stream_name [String] name of the stream for persisting events.
25
+ # @param expected_version [:any, :auto, :none, Integer] controls optimistic locking strategy. {http://railseventstore.org/docs/expected_version/ Read more}
26
+ # @return [:ok]
27
+ def publish(events, stream_name: GLOBAL_STREAM, expected_version: :any)
28
+ enriched_events = enrich_events_metadata(events)
29
+ serialized_events = serialize_events(enriched_events)
30
+ append_to_stream_serialized_events(serialized_events, stream_name: stream_name, expected_version: expected_version)
31
+ enriched_events.zip(serialized_events) do |event, serialized_event|
32
+ with_metadata(
33
+ correlation_id: event.metadata[:correlation_id] || event.event_id,
34
+ causation_id: event.event_id,
35
+ ) do
36
+ broker.(event, serialized_event)
37
+ end
22
38
  end
23
39
  :ok
24
40
  end
25
41
 
42
+ # @deprecated Use {#publish} instead
43
+ def publish_events(events, stream_name: GLOBAL_STREAM, expected_version: :any)
44
+ warn <<~EOW
45
+ RubyEventStore::Client#publish_events has been deprecated.
46
+
47
+ Use RubyEventStore::Client#publish instead
48
+ EOW
49
+ publish(events, stream_name: stream_name, expected_version: expected_version)
50
+ end
51
+
52
+ # @deprecated Use {#publish} instead
26
53
  def publish_event(event, stream_name: GLOBAL_STREAM, expected_version: :any)
27
- publish_events([event], stream_name: stream_name, expected_version: expected_version)
54
+ warn <<~EOW
55
+ RubyEventStore::Client#publish_event has been deprecated.
56
+
57
+ Use RubyEventStore::Client#publish instead
58
+ EOW
59
+ publish(event, stream_name: stream_name, expected_version: expected_version)
28
60
  end
29
61
 
62
+ # @deprecated Use {#append} instead
30
63
  def append_to_stream(events, stream_name: GLOBAL_STREAM, expected_version: :any)
31
- events = normalize_to_array(events)
32
- events.each{|event| enrich_event_metadata(event) }
33
- repository.append_to_stream(serialized_events(events), Stream.new(stream_name), ExpectedVersion.new(expected_version))
64
+ warn <<~EOW
65
+ RubyEventStore::Client#append_to_stream has been deprecated.
66
+
67
+ Use RubyEventStore::Client#append instead
68
+ EOW
69
+ append(events, stream_name: stream_name, expected_version: expected_version)
70
+ end
71
+
72
+ # Persists new event(s) without notifying any subscribed handlers
73
+ #
74
+ # @param (see #publish)
75
+ # @return [:ok]
76
+ def append(events, stream_name: GLOBAL_STREAM, expected_version: :any)
77
+ serialized_events = serialize_events(enrich_events_metadata(events))
78
+ append_to_stream_serialized_events(serialized_events, stream_name: stream_name, expected_version: expected_version)
34
79
  :ok
35
80
  end
36
81
 
37
- def link_to_stream(event_ids, stream_name:, expected_version: :any)
82
+ # Links already persisted event(s) to a different stream.
83
+ # Does not notify any subscribed handlers.
84
+ #
85
+ # @param event_ids [String, Array<String>] ids of events
86
+ # @param stream_name (see #publish)
87
+ # @param expected_version (see #publish)
88
+ # @return [self]
89
+ def link(event_ids, stream_name:, expected_version: :any)
38
90
  repository.link_to_stream(event_ids, Stream.new(stream_name), ExpectedVersion.new(expected_version))
39
91
  self
40
92
  end
41
93
 
94
+ # @deprecated Use {#link} instead
95
+ def link_to_stream(event_ids, stream_name:, expected_version: :any)
96
+ warn <<~EOW
97
+ RubyEventStore::Client#link_to_stream has been deprecated.
98
+
99
+ Use RubyEventStore::Client#link instead
100
+ EOW
101
+ link(event_ids, stream_name: stream_name, expected_version: expected_version)
102
+ end
103
+
104
+ # Deletes a stream.
105
+ # All events from the stream remain intact but they are no
106
+ # longer linked to the stream.
107
+ #
108
+ # @param stream_name [String] name of the stream to be cleared.
109
+ # @return [:ok]
42
110
  def delete_stream(stream_name)
43
111
  repository.delete_stream(Stream.new(stream_name))
44
112
  :ok
45
113
  end
46
114
 
115
+ # @deprecated Use {#read} instead. {https://github.com/RailsEventStore/rails_event_store/releases/tag/v0.30.0 More info}
47
116
  def read_events_forward(stream_name, start: :head, count: page_size)
48
117
  warn <<~EOW
49
118
  RubyEventStore::Client#read_events_forward has been deprecated.
@@ -54,6 +123,7 @@ module RubyEventStore
54
123
  read.stream(stream_name).limit(count).from(start).each.to_a
55
124
  end
56
125
 
126
+ # @deprecated Use {#read} instead. {https://github.com/RailsEventStore/rails_event_store/releases/tag/v0.30.0 More info}
57
127
  def read_events_backward(stream_name, start: :head, count: page_size)
58
128
  warn <<~EOW
59
129
  RubyEventStore::Client#read_events_backward has been deprecated.
@@ -64,6 +134,7 @@ module RubyEventStore
64
134
  read.stream(stream_name).limit(count).from(start).backward.each.to_a
65
135
  end
66
136
 
137
+ # @deprecated Use {#read} instead. {https://github.com/RailsEventStore/rails_event_store/releases/tag/v0.30.0 More info}
67
138
  def read_stream_events_forward(stream_name)
68
139
  warn <<~EOW
69
140
  RubyEventStore::Client#read_stream_events_forward has been deprecated.
@@ -74,6 +145,7 @@ module RubyEventStore
74
145
  read.stream(stream_name).each.to_a
75
146
  end
76
147
 
148
+ # @deprecated Use {#read} instead. {https://github.com/RailsEventStore/rails_event_store/releases/tag/v0.30.0 More info}
77
149
  def read_stream_events_backward(stream_name)
78
150
  warn <<~EOW
79
151
  RubyEventStore::Client#read_stream_events_backward has been deprecated.
@@ -84,6 +156,7 @@ module RubyEventStore
84
156
  read.stream(stream_name).backward.each.to_a
85
157
  end
86
158
 
159
+ # @deprecated Use {#read} instead. {https://github.com/RailsEventStore/rails_event_store/releases/tag/v0.30.0 More info}
87
160
  def read_all_streams_forward(start: :head, count: page_size)
88
161
  warn <<~EOW
89
162
  RubyEventStore::Client#read_all_streams_forward has been deprecated.
@@ -94,6 +167,7 @@ module RubyEventStore
94
167
  read.limit(count).from(start).each.to_a
95
168
  end
96
169
 
170
+ # @deprecated Use {#read} instead. {https://github.com/RailsEventStore/rails_event_store/releases/tag/v0.30.0 More info}
97
171
  def read_all_streams_backward(start: :head, count: page_size)
98
172
  warn <<~EOW
99
173
  RubyEventStore::Client#read_all_streams_backward has been deprecated.
@@ -104,70 +178,125 @@ module RubyEventStore
104
178
  read.limit(count).from(start).backward.each.to_a
105
179
  end
106
180
 
181
+ # Returns a single, persisted event based on its ID.
182
+ #
183
+ # @param event_id [String] event id
184
+ # @return [Event, Proto]
107
185
  def read_event(event_id)
108
186
  deserialize_event(repository.read_event(event_id))
109
187
  end
110
188
 
189
+ # Starts building a query specification for reading events.
190
+ # {http://railseventstore.org/docs/read/ More info.}
191
+ #
192
+ # @return [Specification]
111
193
  def read
112
194
  Specification.new(repository, mapper)
113
195
  end
114
196
 
115
- # subscribe(subscriber, to:)
116
- # subscribe(to:, &subscriber)
197
+ # Subscribes a handler (subscriber) that will be invoked for published events of provided type.
198
+ #
199
+ # @overload subscribe(subscriber, to:)
200
+ # @param to [Array<Class>] types of events to subscribe
201
+ # @param subscriber [Object, Class] handler
202
+ # @return [Proc] - unsubscribe proc. Call to unsubscribe.
203
+ # @raise [ArgumentError, SubscriberNotExist]
204
+ # @overload subscribe(to:, &subscriber)
205
+ # @param to [Array<Class>] types of events to subscribe
206
+ # @param subscriber [Proc] handler
207
+ # @return [Proc] - unsubscribe proc. Call to unsubscribe.
208
+ # @raise [ArgumentError, SubscriberNotExist]
117
209
  def subscribe(subscriber = nil, to:, &proc)
118
210
  raise ArgumentError, "subscriber must be first argument or block, cannot be both" if subscriber && proc
119
- raise SubscriberNotExist, "subscriber must be first argument or block" unless subscriber || proc
120
211
  subscriber ||= proc
121
- event_broker.add_subscriber(subscriber, to)
212
+ broker.add_subscription(subscriber, to)
122
213
  end
123
214
 
124
- # subscribe_to_all_events(subscriber)
125
- # subscribe_to_all_events(&subscriber)
215
+ # Subscribes a handler (subscriber) that will be invoked for all published events
216
+ #
217
+ # @overload subscribe_to_all_events(subscriber)
218
+ # @param subscriber [Object, Class] handler
219
+ # @return [Proc] - unsubscribe proc. Call to unsubscribe.
220
+ # @raise [ArgumentError, SubscriberNotExist]
221
+ # @overload subscribe_to_all_events(&subscriber)
222
+ # @param subscriber [Proc] handler
223
+ # @return [Proc] - unsubscribe proc. Call to unsubscribe.
224
+ # @raise [ArgumentError, SubscriberNotExist]
126
225
  def subscribe_to_all_events(subscriber = nil, &proc)
127
226
  raise ArgumentError, "subscriber must be first argument or block, cannot be both" if subscriber && proc
128
- raise SubscriberNotExist, "subscriber must be first argument or block" unless subscriber || proc
129
- event_broker.add_global_subscriber(subscriber || proc)
227
+ broker.add_global_subscription(subscriber || proc)
130
228
  end
131
229
 
230
+ # Builder object for collecting temporary handlers (subscribers)
231
+ # which are active only during the invocation of the provided
232
+ # block of code.
132
233
  class Within
133
- def initialize(block, event_broker)
234
+ def initialize(block, broker)
134
235
  @block = block
135
- @event_broker = event_broker
236
+ @broker = broker
136
237
  @global_subscribers = []
137
238
  @subscribers = Hash.new {[]}
138
239
  end
139
240
 
241
+ # Subscribes temporary handlers that
242
+ # will be called for all published events.
243
+ # The subscription is active only during the invocation
244
+ # of the block of code provided to {Client#within}.
245
+ # {http://railseventstore.org/docs/subscribe/#temporary-subscriptions Read more.}
246
+ #
247
+ # @param handlers [Object, Class] handlers passed as objects or classes
248
+ # @param handler2 [Proc] handler passed as proc
249
+ # @return [self]
140
250
  def subscribe_to_all_events(*handlers, &handler2)
141
251
  handlers << handler2 if handler2
142
252
  @global_subscribers += handlers
143
253
  self
144
254
  end
145
255
 
256
+ # Subscribes temporary handlers that
257
+ # will be called for published events of provided type.
258
+ # The subscription is active only during the invocation
259
+ # of the block of code provided to {Client#within}.
260
+ # {http://railseventstore.org/docs/subscribe/#temporary-subscriptions Read more.}
261
+ #
262
+ # @overload subscribe(handler, to:)
263
+ # @param handler [Object, Class] handler passed as objects or classes
264
+ # @param to [Array<Class>] types of events to subscribe
265
+ # @return [self]
266
+ # @overload subscribe(to:, &handler)
267
+ # @param to [Array<Class>] types of events to subscribe
268
+ # @param handler [Proc] handler passed as proc
269
+ # @return [self]
146
270
  def subscribe(handler=nil, to:, &handler2)
147
271
  raise ArgumentError if handler && handler2
148
272
  @subscribers[handler || handler2] += normalize_to_array(to)
149
273
  self
150
274
  end
151
275
 
276
+ # Invokes the block of code provided to {Client#within}
277
+ # and then unsubscribes temporary handlers.
278
+ # {http://railseventstore.org/docs/subscribe/#temporary-subscriptions Read more.}
279
+ #
280
+ # @return [Object] value returned by the invoked block of code
152
281
  def call
153
282
  unsubs = add_thread_global_subscribers
154
283
  unsubs += add_thread_subscribers
155
284
  @block.call
156
285
  ensure
157
- unsubs.each(&:call)
286
+ unsubs.each(&:call) if unsubs
158
287
  end
159
288
 
160
289
  private
161
290
 
162
291
  def add_thread_subscribers
163
- @subscribers.map do |handler, types|
164
- @event_broker.add_thread_subscriber(handler, types)
292
+ @subscribers.map do |subscriber, types|
293
+ @broker.add_thread_subscription(subscriber, types)
165
294
  end
166
295
  end
167
296
 
168
297
  def add_thread_global_subscribers
169
- @global_subscribers.map do |s|
170
- @event_broker.add_thread_global_subscriber(s)
298
+ @global_subscribers.map do |subscriber|
299
+ @broker.add_thread_global_subscription(subscriber)
171
300
  end
172
301
  end
173
302
 
@@ -176,22 +305,52 @@ module RubyEventStore
176
305
  end
177
306
  end
178
307
 
308
+ # Use for starting temporary subscriptions.
309
+ # {http://railseventstore.org/docs/subscribe/#temporary-subscriptions Read more}
310
+ #
311
+ # @param block [Proc] block of code during which the temporary subscriptions will be active
312
+ # @return [Within] builder object which collects temporary subscriptions
179
313
  def within(&block)
180
314
  raise ArgumentError if block.nil?
181
- Within.new(block, event_broker)
315
+ Within.new(block, broker)
182
316
  end
183
317
 
318
+ # Set additional metadata for all events published within the provided block
319
+ # {http://railseventstore.org/docs/request_metadata#passing-your-own-metadata-using-with_metadata-method Read more}
320
+ #
321
+ # @param metadata [Hash] metadata to set for events
322
+ # @param block [Proc] block of code during which the metadata will be added
323
+ # @return [Object] last value returned by the provided block
184
324
  def with_metadata(metadata, &block)
185
325
  previous_metadata = metadata()
186
- self.metadata = (previous_metadata || {}).merge(metadata)
326
+ self.metadata = previous_metadata.merge(metadata)
187
327
  block.call if block_given?
188
328
  ensure
189
329
  self.metadata = previous_metadata
190
330
  end
191
331
 
332
+ # Deserialize event which was serialized for async event handlers
333
+ # {http://railseventstore.org/docs/subscribe/#async-handlers Read more}
334
+ #
335
+ # @return [Event, Proto] deserialized event
336
+ def deserialize(event_type:, event_id:, data:, metadata:)
337
+ mapper.serialized_record_to_event(SerializedRecord.new(event_type: event_type, event_id: event_id, data: data, metadata: metadata))
338
+ end
339
+
340
+ # Read additional metadata which will be added for published events
341
+ # {http://railseventstore.org/docs/request_metadata#passing-your-own-metadata-using-with_metadata-method Read more}
342
+ #
343
+ # @return [Hash]
344
+ def metadata
345
+ @metadata.value || EMPTY_HASH
346
+ end
347
+
348
+ EMPTY_HASH = {}.freeze
349
+ private_constant :EMPTY_HASH
350
+
192
351
  private
193
352
 
194
- def serialized_events(events)
353
+ def serialize_events(events)
195
354
  events.map do |ev|
196
355
  mapper.event_to_serialized_record(ev)
197
356
  end
@@ -205,27 +364,27 @@ module RubyEventStore
205
364
  return *events
206
365
  end
207
366
 
367
+ def enrich_events_metadata(events)
368
+ events = normalize_to_array(events)
369
+ events.each{|event| enrich_event_metadata(event) }
370
+ events
371
+ end
372
+
208
373
  def enrich_event_metadata(event)
209
- if metadata_proc
210
- md = metadata_proc.call || {}
211
- md.each{|k,v| event.metadata[k]=(v) }
212
- end
213
- if metadata
214
- metadata.each { |key, value| event.metadata[key] = value }
215
- end
374
+ metadata.each { |key, value| event.metadata[key] ||= value }
216
375
  event.metadata[:timestamp] ||= clock.call
217
376
  end
218
377
 
219
- attr_reader :repository, :mapper, :event_broker, :clock, :metadata_proc, :page_size
378
+ def append_to_stream_serialized_events(serialized_events, stream_name:, expected_version:)
379
+ repository.append_to_stream(serialized_events, Stream.new(stream_name), ExpectedVersion.new(expected_version))
380
+ end
220
381
 
221
382
  protected
222
383
 
223
- def metadata
224
- Thread.current["ruby_event_store_#{hash}"]
225
- end
226
-
227
384
  def metadata=(value)
228
- Thread.current["ruby_event_store_#{hash}"] = value
385
+ @metadata.value = value
229
386
  end
387
+
388
+ attr_reader :repository, :mapper, :broker, :clock, :page_size
230
389
  end
231
390
  end