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.
- checksums.yaml +4 -4
- data/Gemfile +9 -1
- data/Makefile +15 -62
- data/lib/ruby_event_store/batch_enumerator.rb +15 -5
- data/lib/ruby_event_store/broker.rb +45 -0
- data/lib/ruby_event_store/client.rb +220 -130
- data/lib/ruby_event_store/composed_dispatcher.rb +24 -0
- data/lib/ruby_event_store/constants.rb +2 -0
- data/lib/ruby_event_store/correlated_commands.rb +42 -0
- data/lib/ruby_event_store/dispatcher.rb +20 -0
- data/lib/ruby_event_store/errors.rb +16 -16
- data/lib/ruby_event_store/event.rb +70 -14
- data/lib/ruby_event_store/expected_version.rb +2 -0
- data/lib/ruby_event_store/immediate_async_dispatcher.rb +17 -0
- data/lib/ruby_event_store/in_memory_repository.rb +45 -17
- data/lib/ruby_event_store/instrumented_dispatcher.rb +23 -0
- data/lib/ruby_event_store/instrumented_repository.rb +63 -0
- data/lib/ruby_event_store/link_by_metadata.rb +57 -0
- data/lib/ruby_event_store/mappers/default.rb +10 -26
- data/lib/ruby_event_store/mappers/encryption_key.rb +74 -0
- data/lib/ruby_event_store/mappers/encryption_mapper.rb +16 -0
- data/lib/ruby_event_store/mappers/forgotten_data.rb +30 -0
- data/lib/ruby_event_store/mappers/in_memory_encryption_key_repository.rb +34 -0
- data/lib/ruby_event_store/mappers/instrumented_mapper.rb +28 -0
- data/lib/ruby_event_store/mappers/json_mapper.rb +16 -0
- data/lib/ruby_event_store/mappers/null_mapper.rb +5 -8
- data/lib/ruby_event_store/mappers/pipeline.rb +31 -0
- data/lib/ruby_event_store/mappers/pipeline_mapper.rb +22 -0
- data/lib/ruby_event_store/mappers/protobuf.rb +13 -67
- data/lib/ruby_event_store/mappers/transformation/domain_event.rb +26 -0
- data/lib/ruby_event_store/mappers/transformation/encryption.rb +128 -0
- data/lib/ruby_event_store/mappers/transformation/event_class_remapper.rb +24 -0
- data/lib/ruby_event_store/mappers/transformation/item.rb +56 -0
- data/lib/ruby_event_store/mappers/transformation/proto_event.rb +17 -0
- data/lib/ruby_event_store/mappers/transformation/protobuf_encoder.rb +30 -0
- data/lib/ruby_event_store/mappers/transformation/protobuf_nested_struct_metadata.rb +30 -0
- data/lib/ruby_event_store/mappers/transformation/serialization.rb +34 -0
- data/lib/ruby_event_store/mappers/transformation/serialized_record.rb +27 -0
- data/lib/ruby_event_store/mappers/transformation/stringify_metadata_keys.rb +24 -0
- data/lib/ruby_event_store/mappers/transformation/symbolize_metadata_keys.rb +24 -0
- data/lib/ruby_event_store/metadata.rb +4 -2
- data/lib/ruby_event_store/projection.rb +34 -12
- data/lib/ruby_event_store/serialized_record.rb +3 -1
- data/lib/ruby_event_store/spec/broker_lint.rb +92 -0
- data/lib/ruby_event_store/spec/dispatcher_lint.rb +4 -36
- data/lib/ruby_event_store/spec/event_lint.rb +71 -0
- data/lib/ruby_event_store/spec/event_repository_lint.rb +1092 -962
- data/lib/ruby_event_store/spec/mapper_lint.rb +17 -0
- data/lib/ruby_event_store/spec/scheduler_lint.rb +9 -0
- data/lib/ruby_event_store/spec/subscriptions_lint.rb +111 -0
- data/lib/ruby_event_store/specification.rb +201 -56
- data/lib/ruby_event_store/specification_reader.rb +43 -0
- data/lib/ruby_event_store/specification_result.rb +212 -0
- data/lib/ruby_event_store/stream.rb +2 -0
- data/lib/ruby_event_store/subscriptions.rb +110 -0
- data/lib/ruby_event_store/transform_keys.rb +31 -0
- data/lib/ruby_event_store/version.rb +3 -1
- data/lib/ruby_event_store.rb +34 -4
- data/ruby_event_store.gemspec +1 -10
- metadata +47 -126
- data/exe/res-deprecated-read-api-migrator +0 -19
- data/lib/ruby_event_store/deprecated_read_api_rewriter.rb +0 -67
- data/lib/ruby_event_store/deprecated_read_api_runner.rb +0 -64
- data/lib/ruby_event_store/deprecations.rb +0 -7
- data/lib/ruby_event_store/pub_sub/broker.rb +0 -73
- data/lib/ruby_event_store/pub_sub/dispatcher.rb +0 -25
- 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 =
|
18
|
-
@init = -> {
|
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
|
-
|
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.
|
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:
|
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
|
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
|
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
|
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
|
80
|
-
event_store
|
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
|
106
|
+
start ? start : Array.new
|
85
107
|
end
|
86
108
|
|
87
109
|
def transition(state, event)
|
88
|
-
handlers
|
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,
|
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 "
|
3
|
-
|
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 "
|
19
|
-
expect
|
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
|