ruby_event_store 0.25.2 → 0.26.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 +5 -5
- data/Makefile +2 -1
- data/lib/ruby_event_store/client.rb +87 -14
- data/lib/ruby_event_store/in_memory_repository.rb +11 -8
- data/lib/ruby_event_store/pub_sub/broker.rb +25 -1
- data/lib/ruby_event_store/spec/event_broker_lint.rb +67 -2
- data/lib/ruby_event_store/version.rb +1 -1
- data/ruby_event_store.gemspec +1 -0
- metadata +17 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a57244de5351622091fa442885288c1775dc5ad0
|
4
|
+
data.tar.gz: 2280e2361f7c8466484caa459822c28e213d1b4d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d64e4f0c8d49aa4161df43acddd7e16ff16ea9c7e193826a3817224035b27f9953ec943da86126b8cb94f9e41ac3fd5d4ab29d8058038d19be3a0c4fd8e94523
|
7
|
+
data.tar.gz: e3cc5306c6ae098ed5d3544000a1a1aa87ae672a9c9a66510e64141ad813ae8b28123b8b24cf69125e0393c446a17aca7c077a5c4098849405e02607379d7c33
|
data/Makefile
CHANGED
@@ -5,6 +5,7 @@ IGNORE = RubyEventStore.const_missing \
|
|
5
5
|
RubyEventStore::InMemoryRepository\#append_with_synchronize \
|
6
6
|
RubyEventStore::InMemoryRepository\#normalize_to_array \
|
7
7
|
RubyEventStore::Client\#normalize_to_array \
|
8
|
+
RubyEventStore::Client::Within\#normalize_to_array \
|
8
9
|
RubyEventStore::SerializedRecord \
|
9
10
|
RubyEventStore::Projection\#read_events_from_stream \
|
10
11
|
RubyEventStore::Projection\#read_events_from_all_streams
|
@@ -20,7 +21,7 @@ test: ## Run unit tests
|
|
20
21
|
|
21
22
|
mutate: test ## Run mutation tests
|
22
23
|
@echo "Running mutation tests"
|
23
|
-
@bundle exec mutant --include lib \
|
24
|
+
@MUTATING=true bundle exec mutant --include lib \
|
24
25
|
$(addprefix --require ,$(REQUIRE)) \
|
25
26
|
$(addprefix --ignore-subject ,$(IGNORE)) \
|
26
27
|
--use rspec "$(SUBJECT)"
|
@@ -82,18 +82,99 @@ module RubyEventStore
|
|
82
82
|
@repository.get_all_streams
|
83
83
|
end
|
84
84
|
|
85
|
-
|
86
|
-
|
87
|
-
|
85
|
+
|
86
|
+
DEPRECATED_WITHIN = "subscribe(subscriber, event_types, &task) has been deprecated. Use within(&task).subscribe(subscriber, to: event_types).call instead"
|
87
|
+
DEPRECATED_TO = "subscribe(subscriber, event_types) has been deprecated. Use subscribe(subscriber, to: event_types) instead"
|
88
|
+
# OLD:
|
89
|
+
# subscribe(subscriber, event_types, &within)
|
90
|
+
# subscribe(subscriber, event_types)
|
91
|
+
# NEW:
|
92
|
+
# subscribe(subscriber, to:)
|
93
|
+
# subscribe(to:, &subscriber)
|
94
|
+
def subscribe(subscriber = nil, event_types = nil, to: nil, &proc)
|
95
|
+
if to
|
96
|
+
raise ArgumentError, "subscriber must be first argument or block, cannot be both" if subscriber && proc
|
97
|
+
raise SubscriberNotExist, "subscriber must be first argument or block" unless subscriber || proc
|
98
|
+
raise ArgumentError, "list of event types must be second argument or named argument to: , it cannot be both" if event_types
|
99
|
+
subscriber ||= proc
|
100
|
+
@event_broker.add_subscriber(subscriber, to)
|
101
|
+
else
|
102
|
+
if proc
|
103
|
+
warn(DEPRECATED_WITHIN)
|
104
|
+
within(&proc).subscribe(subscriber, to: event_types).call
|
105
|
+
-> {}
|
106
|
+
else
|
107
|
+
warn(DEPRECATED_TO)
|
108
|
+
subscribe(subscriber, to: event_types)
|
109
|
+
end
|
88
110
|
end
|
89
111
|
end
|
90
112
|
|
91
|
-
|
92
|
-
|
93
|
-
|
113
|
+
DEPRECATED_ALL_WITHIN = "subscribe_to_all_events(subscriber, &task) has been deprecated. Use within(&task).subscribe_to_all_events(subscriber).call instead."
|
114
|
+
# OLD:
|
115
|
+
# subscribe_to_all_events(subscriber, &within)
|
116
|
+
# subscribe_to_all_events(subscriber)
|
117
|
+
# NEW:
|
118
|
+
# subscribe_to_all_events(subscriber)
|
119
|
+
# subscribe_to_all_events(&subscriber)
|
120
|
+
def subscribe_to_all_events(subscriber = nil, &proc)
|
121
|
+
if subscriber
|
122
|
+
if proc
|
123
|
+
warn(DEPRECATED_ALL_WITHIN)
|
124
|
+
within(&proc).subscribe_to_all_events(subscriber).call
|
125
|
+
-> {}
|
126
|
+
else
|
127
|
+
@event_broker.add_global_subscriber(subscriber)
|
128
|
+
end
|
129
|
+
else
|
130
|
+
@event_broker.add_global_subscriber(proc)
|
94
131
|
end
|
95
132
|
end
|
96
133
|
|
134
|
+
class Within
|
135
|
+
def initialize(block, event_broker)
|
136
|
+
@block = block
|
137
|
+
@event_broker = event_broker
|
138
|
+
@global_subscribers = []
|
139
|
+
@subscribers = Hash.new {[]}
|
140
|
+
end
|
141
|
+
|
142
|
+
def subscribe_to_all_events(*handlers, &handler2)
|
143
|
+
handlers << handler2 if handler2
|
144
|
+
@global_subscribers += handlers
|
145
|
+
self
|
146
|
+
end
|
147
|
+
|
148
|
+
def subscribe(handler=nil, to:, &handler2)
|
149
|
+
raise ArgumentError if handler && handler2
|
150
|
+
@subscribers[handler || handler2] += normalize_to_array(to)
|
151
|
+
self
|
152
|
+
end
|
153
|
+
|
154
|
+
def call
|
155
|
+
unsubs = @global_subscribers.map do |s|
|
156
|
+
@event_broker.add_thread_global_subscriber(s)
|
157
|
+
end
|
158
|
+
unsubs += @subscribers.map do |handler, types|
|
159
|
+
@event_broker.add_thread_subscriber(handler, types)
|
160
|
+
end
|
161
|
+
@block.call
|
162
|
+
ensure
|
163
|
+
unsubs.each(&:call)
|
164
|
+
end
|
165
|
+
|
166
|
+
private
|
167
|
+
|
168
|
+
def normalize_to_array(objs)
|
169
|
+
return *objs
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
def within(&block)
|
174
|
+
raise ArgumentError if block.nil?
|
175
|
+
Within.new(block, @event_broker)
|
176
|
+
end
|
177
|
+
|
97
178
|
private
|
98
179
|
|
99
180
|
def normalize_to_array(events)
|
@@ -108,14 +189,6 @@ module RubyEventStore
|
|
108
189
|
# event.class.new(event_id: event.event_id, metadata: metadata, data: event.data)
|
109
190
|
end
|
110
191
|
|
111
|
-
def handle_subscribe(unsub, &proc)
|
112
|
-
begin
|
113
|
-
proc.call
|
114
|
-
ensure
|
115
|
-
unsub.()
|
116
|
-
end if proc
|
117
|
-
end
|
118
|
-
|
119
192
|
class Page
|
120
193
|
def initialize(repository, start, count)
|
121
194
|
if start.instance_of?(Symbol)
|
@@ -73,21 +73,20 @@ module RubyEventStore
|
|
73
73
|
def add_to_stream(events, expected_version, stream_name, include_global)
|
74
74
|
raise InvalidExpectedVersion if !expected_version.equal?(:any) && stream_name.eql?(GLOBAL_STREAM)
|
75
75
|
events = normalize_to_array(events)
|
76
|
-
stream = read_stream_events_forward(stream_name)
|
77
76
|
expected_version = case expected_version
|
78
77
|
when :none
|
79
78
|
-1
|
80
|
-
when :auto
|
81
|
-
|
82
|
-
when Integer
|
79
|
+
when :auto
|
80
|
+
read_stream_events_forward(stream_name).size - 1
|
81
|
+
when Integer, :any
|
83
82
|
expected_version
|
84
83
|
else
|
85
84
|
raise InvalidExpectedVersion
|
86
85
|
end
|
87
|
-
append_with_synchronize(events, expected_version,
|
86
|
+
append_with_synchronize(events, expected_version, stream_name, include_global)
|
88
87
|
end
|
89
88
|
|
90
|
-
def append_with_synchronize(events, expected_version,
|
89
|
+
def append_with_synchronize(events, expected_version, stream_name, include_global)
|
91
90
|
# expected_version :auto assumes external lock is used
|
92
91
|
# which makes reading stream before writing safe.
|
93
92
|
#
|
@@ -97,11 +96,15 @@ module RubyEventStore
|
|
97
96
|
# not for the whole read+write algorithm.
|
98
97
|
Thread.pass
|
99
98
|
@mutex.synchronize do
|
100
|
-
|
99
|
+
if expected_version == :any
|
100
|
+
expected_version = read_stream_events_forward(stream_name).size - 1
|
101
|
+
end
|
102
|
+
append(events, expected_version, stream_name, include_global)
|
101
103
|
end
|
102
104
|
end
|
103
105
|
|
104
|
-
def append(events, expected_version,
|
106
|
+
def append(events, expected_version, stream_name, include_global)
|
107
|
+
stream = read_stream_events_forward(stream_name)
|
105
108
|
raise WrongExpectedEventVersion unless (stream.size - 1).equal?(expected_version)
|
106
109
|
events.each do |event|
|
107
110
|
raise EventDuplicatedInStream if stream.any?{|ev| ev.event_id.eql?(event.event_id) }
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'concurrent'
|
2
|
+
|
1
3
|
module RubyEventStore
|
2
4
|
module PubSub
|
3
5
|
class Broker
|
@@ -6,6 +8,12 @@ module RubyEventStore
|
|
6
8
|
def initialize(dispatcher: DEFAULT_DISPATCHER)
|
7
9
|
@subscribers = Hash.new {|hsh, key| hsh[key] = [] }
|
8
10
|
@global_subscribers = []
|
11
|
+
|
12
|
+
@thread_global_subscribers = Concurrent::ThreadLocalVar.new([])
|
13
|
+
@thread_subscribers = Concurrent::ThreadLocalVar.new do
|
14
|
+
Hash.new {|hsh, key| hsh[key] = [] }
|
15
|
+
end
|
16
|
+
|
9
17
|
@dispatcher = dispatcher
|
10
18
|
end
|
11
19
|
|
@@ -21,6 +29,19 @@ module RubyEventStore
|
|
21
29
|
->() { @global_subscribers.delete(subscriber) }
|
22
30
|
end
|
23
31
|
|
32
|
+
def add_thread_global_subscriber(subscriber)
|
33
|
+
verify_subscriber(subscriber)
|
34
|
+
@thread_global_subscribers.value += [subscriber]
|
35
|
+
|
36
|
+
->() { @thread_global_subscribers.value -= [subscriber] }
|
37
|
+
end
|
38
|
+
|
39
|
+
def add_thread_subscriber(subscriber, event_types)
|
40
|
+
verify_subscriber(subscriber)
|
41
|
+
event_types.each{ |type| @thread_subscribers.value[type.name] << subscriber }
|
42
|
+
->() {event_types.each{ |type| @thread_subscribers.value.fetch(type.name).delete(subscriber) } }
|
43
|
+
end
|
44
|
+
|
24
45
|
def notify_subscribers(event)
|
25
46
|
all_subscribers_for(event.class).each do |subscriber|
|
26
47
|
@dispatcher.call(subscriber, event)
|
@@ -40,7 +61,10 @@ module RubyEventStore
|
|
40
61
|
end
|
41
62
|
|
42
63
|
def all_subscribers_for(event_type)
|
43
|
-
@subscribers[event_type.name] +
|
64
|
+
@subscribers[event_type.name] +
|
65
|
+
@global_subscribers +
|
66
|
+
@thread_global_subscribers.value +
|
67
|
+
@thread_subscribers.value[event_type.name]
|
44
68
|
end
|
45
69
|
end
|
46
70
|
end
|
@@ -35,10 +35,12 @@ RSpec.shared_examples :event_broker do |broker_class|
|
|
35
35
|
|
36
36
|
it 'raise error when no subscriber' do
|
37
37
|
expect { broker.add_subscriber(nil, [])}.to raise_error(RubyEventStore::SubscriberNotExist)
|
38
|
+
expect { broker.add_thread_subscriber(nil, [])}.to raise_error(RubyEventStore::SubscriberNotExist)
|
38
39
|
expect { broker.add_global_subscriber(nil)}.to raise_error(RubyEventStore::SubscriberNotExist)
|
40
|
+
expect { broker.add_thread_global_subscriber(nil)}.to raise_error(RubyEventStore::SubscriberNotExist)
|
39
41
|
end
|
40
42
|
|
41
|
-
it '
|
43
|
+
it 'notifies subscribed handlers' do
|
42
44
|
handler = TestHandler.new
|
43
45
|
another_handler = TestHandler.new
|
44
46
|
global_handler = TestHandler.new
|
@@ -60,6 +62,28 @@ RSpec.shared_examples :event_broker do |broker_class|
|
|
60
62
|
expect(global_handler.events).to eq([event1,event2,event3])
|
61
63
|
end
|
62
64
|
|
65
|
+
it 'notifies subscribed thread handlers' do
|
66
|
+
handler = TestHandler.new
|
67
|
+
another_handler = TestHandler.new
|
68
|
+
global_handler = TestHandler.new
|
69
|
+
|
70
|
+
broker.add_thread_subscriber(handler, [Test1DomainEvent, Test3DomainEvent])
|
71
|
+
broker.add_thread_subscriber(another_handler, [Test2DomainEvent])
|
72
|
+
broker.add_thread_global_subscriber(global_handler)
|
73
|
+
|
74
|
+
event1 = Test1DomainEvent.new
|
75
|
+
event2 = Test2DomainEvent.new
|
76
|
+
event3 = Test3DomainEvent.new
|
77
|
+
|
78
|
+
[event1, event2, event3].each do |ev|
|
79
|
+
broker.notify_subscribers(ev)
|
80
|
+
end
|
81
|
+
|
82
|
+
expect(handler.events).to eq([event1,event3])
|
83
|
+
expect(another_handler.events).to eq([event2])
|
84
|
+
expect(global_handler.events).to eq([event1,event2,event3])
|
85
|
+
end
|
86
|
+
|
63
87
|
it 'raises error when no valid method on handler' do
|
64
88
|
subscriber = InvalidTestHandler.new
|
65
89
|
expect do
|
@@ -74,13 +98,27 @@ RSpec.shared_examples :event_broker do |broker_class|
|
|
74
98
|
end.to raise_error(RubyEventStore::InvalidHandler)
|
75
99
|
end
|
76
100
|
|
101
|
+
it 'raises error when no valid method on thread handler' do
|
102
|
+
subscriber = InvalidTestHandler.new
|
103
|
+
expect do
|
104
|
+
broker.add_thread_subscriber(subscriber, [Test1DomainEvent])
|
105
|
+
end.to raise_error(RubyEventStore::InvalidHandler)
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'raises error when no valid method on global thread handler' do
|
109
|
+
subscriber = InvalidTestHandler.new
|
110
|
+
expect do
|
111
|
+
broker.add_thread_global_subscriber(subscriber)
|
112
|
+
end.to raise_error(RubyEventStore::InvalidHandler)
|
113
|
+
end
|
114
|
+
|
77
115
|
it 'returns lambda as an output of global subscribe methods' do
|
78
116
|
handler = TestHandler.new
|
79
117
|
result = broker.add_global_subscriber(handler)
|
80
118
|
expect(result).to respond_to(:call)
|
81
119
|
end
|
82
120
|
|
83
|
-
it '
|
121
|
+
it 'returns lambda as an output of subscribe methods' do
|
84
122
|
handler = TestHandler.new
|
85
123
|
result = broker.add_subscriber(handler, [Test1DomainEvent, Test2DomainEvent])
|
86
124
|
expect(result).to respond_to(:call)
|
@@ -112,6 +150,32 @@ RSpec.shared_examples :event_broker do |broker_class|
|
|
112
150
|
expect(handler.events).to eq([event1])
|
113
151
|
end
|
114
152
|
|
153
|
+
it 'revokes thread global subscription' do
|
154
|
+
handler = TestHandler.new
|
155
|
+
event1 = Test1DomainEvent.new
|
156
|
+
event2 = Test2DomainEvent.new
|
157
|
+
|
158
|
+
revoke = broker.add_thread_global_subscriber(handler)
|
159
|
+
broker.notify_subscribers(event1)
|
160
|
+
expect(handler.events).to eq([event1])
|
161
|
+
revoke.()
|
162
|
+
broker.notify_subscribers(event2)
|
163
|
+
expect(handler.events).to eq([event1])
|
164
|
+
end
|
165
|
+
|
166
|
+
it 'revokes thread subscription' do
|
167
|
+
handler = TestHandler.new
|
168
|
+
event1 = Test1DomainEvent.new
|
169
|
+
event2 = Test2DomainEvent.new
|
170
|
+
|
171
|
+
revoke = broker.add_thread_subscriber(handler, [Test1DomainEvent, Test2DomainEvent])
|
172
|
+
broker.notify_subscribers(event1)
|
173
|
+
expect(handler.events).to eq([event1])
|
174
|
+
revoke.()
|
175
|
+
broker.notify_subscribers(event2)
|
176
|
+
expect(handler.events).to eq([event1])
|
177
|
+
end
|
178
|
+
|
115
179
|
it 'allows to provide a custom dispatcher' do
|
116
180
|
dispatcher = TestDispatcher.new
|
117
181
|
handler = TestHandler.new
|
@@ -123,6 +187,7 @@ RSpec.shared_examples :event_broker do |broker_class|
|
|
123
187
|
end
|
124
188
|
|
125
189
|
private
|
190
|
+
|
126
191
|
class HandlerClass
|
127
192
|
@@received = nil
|
128
193
|
def self.received
|
data/ruby_event_store.gemspec
CHANGED
@@ -21,6 +21,7 @@ Gem::Specification.new do |spec|
|
|
21
21
|
|
22
22
|
|
23
23
|
spec.add_dependency 'activesupport'
|
24
|
+
spec.add_dependency 'concurrent-ruby', '~> 1.0'
|
24
25
|
spec.add_development_dependency 'bundler', '~> 1.15'
|
25
26
|
spec.add_development_dependency 'rake', '~> 10.0'
|
26
27
|
spec.add_development_dependency 'rspec', '~> 3.6'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby_event_store
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.26.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Arkency
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-03-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: concurrent-ruby
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.0'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: bundler
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -129,7 +143,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
129
143
|
version: '0'
|
130
144
|
requirements: []
|
131
145
|
rubyforge_project:
|
132
|
-
rubygems_version: 2.
|
146
|
+
rubygems_version: 2.6.13
|
133
147
|
signing_key:
|
134
148
|
specification_version: 4
|
135
149
|
summary: Event Store in Ruby
|