ruby_event_store 0.25.2 → 0.26.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
- SHA256:
3
- metadata.gz: 17c8a7baa18f2bc50009615e332df2928e5dbdf834e496031b526687fc97cbc2
4
- data.tar.gz: 671448bb3373d5d81b34eeaa10d7afc95f7ac1c0f73368a0378b303630c7bfb1
2
+ SHA1:
3
+ metadata.gz: a57244de5351622091fa442885288c1775dc5ad0
4
+ data.tar.gz: 2280e2361f7c8466484caa459822c28e213d1b4d
5
5
  SHA512:
6
- metadata.gz: ed795c85091f01f0c1d13f368cedaf25d14be63ae086dd7d8a074d15c038ccc9a52631dc0d1227e81c87ca7b47af849989dc14884b9b3adac9454164405c4881
7
- data.tar.gz: 745277d650f8255bcf076443813b4425ea74003323526bee10f11c8639850d4b4369b72e656bd29036cffc087ce6c7c02fa44b906e4657b7c3f7fce45108d888
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
- def subscribe(subscriber, event_types, &proc)
86
- @event_broker.add_subscriber(subscriber, event_types).tap do |unsub|
87
- handle_subscribe(unsub, &proc)
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
- def subscribe_to_all_events(subscriber, &proc)
92
- @event_broker.add_global_subscriber(subscriber).tap do |unsub|
93
- handle_subscribe(unsub, &proc)
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, :any
81
- stream.size - 1
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, stream, stream_name, include_global)
86
+ append_with_synchronize(events, expected_version, stream_name, include_global)
88
87
  end
89
88
 
90
- def append_with_synchronize(events, expected_version, stream, stream_name, include_global)
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
- append(events, expected_version, stream, stream_name, include_global)
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, stream, stream_name, include_global)
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] + @global_subscribers
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 'notify subscribed handlers' do
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 'return lambda as an output of subscribe methods' do
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
@@ -1,3 +1,3 @@
1
1
  module RubyEventStore
2
- VERSION = "0.25.2"
2
+ VERSION = "0.26.0"
3
3
  end
@@ -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.25.2
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-02-10 00:00:00.000000000 Z
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.7.3
146
+ rubygems_version: 2.6.13
133
147
  signing_key:
134
148
  specification_version: 4
135
149
  summary: Event Store in Ruby