ruby_event_store 0.30.0 → 1.3.1

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 (67) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +9 -1
  3. data/Makefile +15 -62
  4. data/lib/ruby_event_store/batch_enumerator.rb +15 -5
  5. data/lib/ruby_event_store/broker.rb +45 -0
  6. data/lib/ruby_event_store/client.rb +220 -130
  7. data/lib/ruby_event_store/composed_dispatcher.rb +24 -0
  8. data/lib/ruby_event_store/constants.rb +2 -0
  9. data/lib/ruby_event_store/correlated_commands.rb +42 -0
  10. data/lib/ruby_event_store/dispatcher.rb +20 -0
  11. data/lib/ruby_event_store/errors.rb +16 -16
  12. data/lib/ruby_event_store/event.rb +70 -14
  13. data/lib/ruby_event_store/expected_version.rb +2 -0
  14. data/lib/ruby_event_store/immediate_async_dispatcher.rb +17 -0
  15. data/lib/ruby_event_store/in_memory_repository.rb +45 -17
  16. data/lib/ruby_event_store/instrumented_dispatcher.rb +23 -0
  17. data/lib/ruby_event_store/instrumented_repository.rb +63 -0
  18. data/lib/ruby_event_store/link_by_metadata.rb +57 -0
  19. data/lib/ruby_event_store/mappers/default.rb +10 -26
  20. data/lib/ruby_event_store/mappers/encryption_key.rb +74 -0
  21. data/lib/ruby_event_store/mappers/encryption_mapper.rb +16 -0
  22. data/lib/ruby_event_store/mappers/forgotten_data.rb +30 -0
  23. data/lib/ruby_event_store/mappers/in_memory_encryption_key_repository.rb +34 -0
  24. data/lib/ruby_event_store/mappers/instrumented_mapper.rb +28 -0
  25. data/lib/ruby_event_store/mappers/json_mapper.rb +16 -0
  26. data/lib/ruby_event_store/mappers/null_mapper.rb +5 -8
  27. data/lib/ruby_event_store/mappers/pipeline.rb +31 -0
  28. data/lib/ruby_event_store/mappers/pipeline_mapper.rb +22 -0
  29. data/lib/ruby_event_store/mappers/protobuf.rb +13 -67
  30. data/lib/ruby_event_store/mappers/transformation/domain_event.rb +26 -0
  31. data/lib/ruby_event_store/mappers/transformation/encryption.rb +128 -0
  32. data/lib/ruby_event_store/mappers/transformation/event_class_remapper.rb +24 -0
  33. data/lib/ruby_event_store/mappers/transformation/item.rb +56 -0
  34. data/lib/ruby_event_store/mappers/transformation/proto_event.rb +17 -0
  35. data/lib/ruby_event_store/mappers/transformation/protobuf_encoder.rb +30 -0
  36. data/lib/ruby_event_store/mappers/transformation/protobuf_nested_struct_metadata.rb +30 -0
  37. data/lib/ruby_event_store/mappers/transformation/serialization.rb +34 -0
  38. data/lib/ruby_event_store/mappers/transformation/serialized_record.rb +27 -0
  39. data/lib/ruby_event_store/mappers/transformation/stringify_metadata_keys.rb +24 -0
  40. data/lib/ruby_event_store/mappers/transformation/symbolize_metadata_keys.rb +24 -0
  41. data/lib/ruby_event_store/metadata.rb +4 -2
  42. data/lib/ruby_event_store/projection.rb +34 -12
  43. data/lib/ruby_event_store/serialized_record.rb +3 -1
  44. data/lib/ruby_event_store/spec/broker_lint.rb +92 -0
  45. data/lib/ruby_event_store/spec/dispatcher_lint.rb +4 -36
  46. data/lib/ruby_event_store/spec/event_lint.rb +71 -0
  47. data/lib/ruby_event_store/spec/event_repository_lint.rb +1092 -962
  48. data/lib/ruby_event_store/spec/mapper_lint.rb +17 -0
  49. data/lib/ruby_event_store/spec/scheduler_lint.rb +9 -0
  50. data/lib/ruby_event_store/spec/subscriptions_lint.rb +111 -0
  51. data/lib/ruby_event_store/specification.rb +201 -56
  52. data/lib/ruby_event_store/specification_reader.rb +43 -0
  53. data/lib/ruby_event_store/specification_result.rb +212 -0
  54. data/lib/ruby_event_store/stream.rb +2 -0
  55. data/lib/ruby_event_store/subscriptions.rb +110 -0
  56. data/lib/ruby_event_store/transform_keys.rb +31 -0
  57. data/lib/ruby_event_store/version.rb +3 -1
  58. data/lib/ruby_event_store.rb +34 -4
  59. data/ruby_event_store.gemspec +1 -10
  60. metadata +47 -126
  61. data/exe/res-deprecated-read-api-migrator +0 -19
  62. data/lib/ruby_event_store/deprecated_read_api_rewriter.rb +0 -67
  63. data/lib/ruby_event_store/deprecated_read_api_runner.rb +0 -64
  64. data/lib/ruby_event_store/deprecations.rb +0 -7
  65. data/lib/ruby_event_store/pub_sub/broker.rb +0 -73
  66. data/lib/ruby_event_store/pub_sub/dispatcher.rb +0 -25
  67. data/lib/ruby_event_store/spec/event_broker_lint.rb +0 -211
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'date'
2
4
  require 'time'
3
5
  require 'forwardable'
@@ -43,9 +45,9 @@ module RubyEventStore
43
45
  private
44
46
 
45
47
  def allowed_types
46
- [String, Integer, Float, Date, Time, TrueClass, FalseClass, nil]
48
+ [String, Integer, Float, Date, Time, TrueClass, FalseClass, nil, Hash, Array]
47
49
  end
48
50
 
49
51
  private_constant :SAFE_HASH_METHODS
50
52
  end
51
- end
53
+ end
@@ -1,9 +1,22 @@
1
+ # frozen_string_literal: true
1
2
 
2
3
  module RubyEventStore
3
4
  class Projection
4
5
  private_class_method :new
5
6
 
6
7
  def self.from_stream(*streams)
8
+ first_of_streams = streams.first
9
+ if first_of_streams.respond_to?(:flatten)
10
+ warn <<~EOW
11
+ Passing array to .from_stream is not supported. This method expects undefined number
12
+ of positional arguments (splat) rather than an array.
13
+
14
+ Expected: .from_stream(#{first_of_streams.map(&:inspect).join(", ")})
15
+ Received: .from_stream(#{first_of_streams})
16
+ EOW
17
+ streams = first_of_streams
18
+ end
19
+
7
20
  raise(ArgumentError, "At least one stream must be given") if streams.empty?
8
21
  new(streams: streams)
9
22
  end
@@ -14,8 +27,8 @@ module RubyEventStore
14
27
 
15
28
  def initialize(streams: [])
16
29
  @streams = streams
17
- @handlers = Hash.new { ->(_, _) {} }
18
- @init = -> { Hash.new }
30
+ @handlers = {}
31
+ @init = -> { {} }
19
32
  end
20
33
 
21
34
  attr_reader :streams, :handlers
@@ -27,7 +40,7 @@ module RubyEventStore
27
40
 
28
41
  def when(events, handler)
29
42
  Array(events).each do |event|
30
- @handlers[event] = handler
43
+ handlers[event.to_s] = handler
31
44
  end
32
45
 
33
46
  self
@@ -42,14 +55,15 @@ module RubyEventStore
42
55
  end
43
56
 
44
57
  def call(event)
45
- handlers.fetch(event.class).(current_state, event)
58
+ handlers.fetch(event.event_type).(current_state, event)
46
59
  end
47
60
 
48
61
  def handled_events
49
62
  handlers.keys
50
63
  end
51
64
 
52
- def run(event_store, start: :head, count: PAGE_SIZE)
65
+ def run(event_store, start: nil, count: PAGE_SIZE)
66
+ return initial_state if handled_events.empty?
53
67
  if streams.any?
54
68
  reduce_from_streams(event_store, start, count)
55
69
  else
@@ -60,7 +74,7 @@ module RubyEventStore
60
74
  private
61
75
 
62
76
  def valid_starting_point?(start)
63
- return true if start === :head
77
+ return true unless start
64
78
  if streams.any?
65
79
  (start.instance_of?(Array) && start.size === streams.size)
66
80
  else
@@ -69,23 +83,31 @@ module RubyEventStore
69
83
  end
70
84
 
71
85
  def reduce_from_streams(event_store, start, count)
72
- raise ArgumentError.new('Start must be an array with event ids or :head') unless valid_starting_point?(start)
86
+ raise ArgumentError.new('Start must be an array with event ids') unless valid_starting_point?(start)
73
87
  streams.zip(start_events(start)).reduce(initial_state) do |state, (stream_name, start_event_id)|
74
- event_store.read.in_batches(count).stream(stream_name).from(start_event_id).each.reduce(state, &method(:transition))
88
+ read_scope(event_store, stream_name, count, start_event_id).reduce(state, &method(:transition))
75
89
  end
76
90
  end
77
91
 
78
92
  def reduce_from_all_streams(event_store, start, count)
79
- raise ArgumentError.new('Start must be valid event id or :head') unless valid_starting_point?(start)
80
- event_store.read.in_batches(count).from(start).each.reduce(initial_state, &method(:transition))
93
+ raise ArgumentError.new('Start must be valid event id') unless valid_starting_point?(start)
94
+ read_scope(event_store, nil, count, start).reduce(initial_state, &method(:transition))
95
+ end
96
+
97
+ def read_scope(event_store, stream, count, start)
98
+ scope = event_store.read.in_batches(count)
99
+ scope = scope.of_type(handled_events)
100
+ scope = scope.stream(stream) if stream
101
+ scope = scope.from(start) if start
102
+ scope
81
103
  end
82
104
 
83
105
  def start_events(start)
84
- start === :head ? Array.new(streams.size) { :head } : start
106
+ start ? start : Array.new
85
107
  end
86
108
 
87
109
  def transition(state, event)
88
- handlers[event.class].(state, event)
110
+ handlers.fetch(event.event_type).call(state, event)
89
111
  state
90
112
  end
91
113
  end
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RubyEventStore
2
4
  class SerializedRecord
3
5
  StringsRequired = Class.new(StandardError)
4
6
  def initialize(event_id:, data:, metadata:, event_type:)
5
- raise StringsRequired unless [event_id, data, metadata, event_type].all? { |v| v.instance_of?(String) }
7
+ raise StringsRequired unless [event_id, event_type].all? { |v| v.instance_of?(String) }
6
8
  @event_id = event_id
7
9
  @data = data
8
10
  @metadata = metadata
@@ -0,0 +1,92 @@
1
+ RSpec.shared_examples :broker do |broker_klass|
2
+ let(:event) { instance_double(::RubyEventStore::Event, event_type: 'EventType') }
3
+ let(:serialized_event) { instance_double(::RubyEventStore::SerializedRecord) }
4
+ let(:handler) { HandlerClass.new }
5
+ let(:subscriptions) { ::RubyEventStore::Subscriptions.new }
6
+ let(:dispatcher) { ::RubyEventStore::Dispatcher.new }
7
+ let(:broker) { broker_klass.new(subscriptions: subscriptions, dispatcher: dispatcher) }
8
+
9
+ specify "no dispatch when no subscriptions" do
10
+ expect(subscriptions).to receive(:all_for).with('EventType').and_return([])
11
+ expect(dispatcher).not_to receive(:call)
12
+ broker.call(event, serialized_event)
13
+ end
14
+
15
+ specify "calls subscription" do
16
+ expect(subscriptions).to receive(:all_for).with('EventType').and_return([handler])
17
+ expect(dispatcher).to receive(:call).with(handler, event, serialized_event)
18
+ broker.call(event, serialized_event)
19
+ end
20
+
21
+ specify "calls subscribed class" do
22
+ expect(subscriptions).to receive(:all_for).with('EventType').and_return([HandlerClass])
23
+ expect(dispatcher).to receive(:call).with(HandlerClass, event, serialized_event)
24
+ broker.call(event, serialized_event)
25
+ end
26
+
27
+ specify "calls all subscriptions" do
28
+ expect(subscriptions).to receive(:all_for).with('EventType').and_return([handler, HandlerClass])
29
+ expect(dispatcher).to receive(:call).with(handler, event, serialized_event)
30
+ expect(dispatcher).to receive(:call).with(HandlerClass, event, serialized_event)
31
+ broker.call(event, serialized_event)
32
+ end
33
+
34
+ specify 'raise error when no subscriber' do
35
+ expect { broker.add_subscription(nil, [])}.to raise_error(RubyEventStore::SubscriberNotExist, "subscriber must be first argument or block")
36
+ expect { broker.add_global_subscription(nil)}.to raise_error(RubyEventStore::SubscriberNotExist), "subscriber must be first argument or block"
37
+ expect { broker.add_thread_subscription(nil, []).call}.to raise_error(RubyEventStore::SubscriberNotExist), "subscriber must be first argument or block"
38
+ expect { broker.add_thread_global_subscription(nil).call}.to raise_error(RubyEventStore::SubscriberNotExist), "subscriber must be first argument or block"
39
+ end
40
+
41
+ specify 'raise error when wrong subscriber' do
42
+ allow(dispatcher).to receive(:verify).and_return(false)
43
+ expect do
44
+ broker.add_subscription(HandlerClass, [])
45
+ end.to raise_error(RubyEventStore::InvalidHandler, /Handler HandlerClass is invalid for dispatcher .*Dispatcher/)
46
+ expect do
47
+ broker.add_global_subscription(HandlerClass)
48
+ end.to raise_error(RubyEventStore::InvalidHandler, /is invalid for dispatcher/)
49
+ expect do
50
+ broker.add_thread_subscription(HandlerClass, [])
51
+ end.to raise_error(RubyEventStore::InvalidHandler, /is invalid for dispatcher/)
52
+ expect do
53
+ broker.add_thread_global_subscription(HandlerClass)
54
+ end.to raise_error(RubyEventStore::InvalidHandler, /is invalid for dispatcher/)
55
+ end
56
+
57
+ specify "verify and add - local subscriptions" do
58
+ expect(dispatcher).to receive(:verify).with(handler).and_return(true)
59
+ expect(subscriptions).to receive(:add_subscription).with(handler, ['EventType'])
60
+ broker.add_subscription(handler, ['EventType'])
61
+ end
62
+
63
+ specify "verify and add - global subscriptions" do
64
+ expect(dispatcher).to receive(:verify).with(handler).and_return(true)
65
+ expect(subscriptions).to receive(:add_global_subscription).with(handler)
66
+ broker.add_global_subscription(handler)
67
+ end
68
+
69
+ specify "verify and add - thread local subscriptions" do
70
+ expect(dispatcher).to receive(:verify).with(handler).and_return(true)
71
+ expect(subscriptions).to receive(:add_thread_subscription).with(handler, ['EventType'])
72
+ broker.add_thread_subscription(handler, ['EventType'])
73
+ end
74
+
75
+ specify "verify and add - thread global subscriptions" do
76
+ expect(dispatcher).to receive(:verify).with(handler).and_return(true)
77
+ expect(subscriptions).to receive(:add_thread_global_subscription).with(handler)
78
+ broker.add_thread_global_subscription(handler)
79
+ end
80
+
81
+ private
82
+
83
+ class HandlerClass
84
+ @@received = nil
85
+ def self.received
86
+ @@received
87
+ end
88
+ def call(event)
89
+ @@received = event
90
+ end
91
+ end
92
+ end
@@ -1,41 +1,9 @@
1
1
  RSpec.shared_examples :dispatcher do |dispatcher|
2
- specify "calls subscribed instance" do
3
- handler = HandlerClass.new
4
- event = instance_double(::RubyEventStore::Event)
5
-
6
- expect(handler).to receive(:call).with(event)
7
- dispatcher.(handler, event)
8
- end
9
-
10
- specify "calls subscribed class" do
11
- event = instance_double(::RubyEventStore::Event)
12
-
13
- expect(HandlerClass).to receive(:new).and_return( h = HandlerClass.new )
14
- expect(h).to receive(:call).with(event)
15
- dispatcher.(HandlerClass, event)
2
+ specify "#call" do
3
+ expect(dispatcher).to respond_to(:call).with(3).arguments
16
4
  end
17
5
 
18
- specify "allows callable classes and instances" do
19
- expect do
20
- dispatcher.verify(HandlerClass)
21
- end.not_to raise_error
22
- expect do
23
- dispatcher.verify(HandlerClass.new)
24
- end.not_to raise_error
25
- expect do
26
- dispatcher.verify(Proc.new{ "yo" })
27
- end.not_to raise_error
28
- end
29
-
30
- private
31
-
32
- class HandlerClass
33
- @@received = nil
34
- def self.received
35
- @@received
36
- end
37
- def call(event)
38
- @@received = event
39
- end
6
+ specify "#verify" do
7
+ expect(dispatcher).to respond_to(:verify).with(1).argument
40
8
  end
41
9
  end
@@ -0,0 +1,71 @@
1
+ RSpec.shared_examples :event do |event_class, data, metadata|
2
+ it 'allows initialization' do
3
+ expect {
4
+ event_class.new(event_id: Object.new, data: data || Object.new, metadata: metadata || {})
5
+ }.not_to raise_error
6
+ end
7
+
8
+ it 'provides event_id as string' do
9
+ event = event_class.new
10
+ expect(event.event_id).to be_an_instance_of(String)
11
+ expect(event.event_id).not_to eq ''
12
+ expect(event.event_id).not_to eq nil
13
+ end
14
+
15
+ it 'provides message_id as string' do
16
+ event = event_class.new
17
+ expect(event.message_id).to be_an_instance_of(String)
18
+ end
19
+
20
+ it 'message_id is the same as event_id' do
21
+ event = event_class.new
22
+ expect(event.event_id).to eq event.message_id
23
+ end
24
+
25
+ it 'exposes given event_id to string' do
26
+ event = event_class.new(event_id: 1234567890)
27
+ expect(event.event_id).to eq '1234567890'
28
+ end
29
+
30
+ it 'provides event type as string' do
31
+ event = event_class.new
32
+ expect(event.event_type).to be_an_instance_of(String)
33
+ expect(event.event_type).not_to eq ''
34
+ expect(event.event_type).not_to eq nil
35
+ end
36
+
37
+ it "provides data" do
38
+ event = event_class.new
39
+ expect(event).to respond_to(:data).with(0).arguments
40
+ end
41
+
42
+ it "metadata allows to read keys" do
43
+ event = event_class.new
44
+ expect(event.metadata).to respond_to(:[]).with(1).arguments
45
+ end
46
+
47
+ it "metadata allows to set keys value" do
48
+ event = event_class.new
49
+ expect(event.metadata).to respond_to(:[]=).with(2).argument
50
+ end
51
+
52
+ it "metadata allows to fetch keys" do
53
+ event = event_class.new
54
+ expect(event.metadata).to respond_to(:fetch).with(1).argument
55
+ end
56
+
57
+ it "metadata allows to check existence of keys" do
58
+ event = event_class.new
59
+ expect(event.metadata).to respond_to(:has_key?).with(1).argument
60
+ end
61
+
62
+ it "metadata allows to iterate through keys" do
63
+ event = event_class.new
64
+ expect(event.metadata).to respond_to(:each_with_object).with(1).argument
65
+ end
66
+
67
+ it "metadata must convert to hash" do
68
+ event = event_class.new
69
+ expect(event.metadata).to respond_to(:to_h).with(0).argument
70
+ end
71
+ end