ruby_event_store 0.30.0 → 0.31.0

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