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
@@ -0,0 +1,17 @@
|
|
1
|
+
module RubyEventStore
|
2
|
+
RSpec.shared_examples :mapper do |mapper, domain_event|
|
3
|
+
specify "event_to_serialized_record returns instance of SerializedRecord" do
|
4
|
+
record = mapper.event_to_serialized_record(domain_event)
|
5
|
+
|
6
|
+
expect(record).to be_kind_of(SerializedRecord)
|
7
|
+
expect(record.event_id).to eq(domain_event.event_id)
|
8
|
+
expect(record.event_type).to eq(domain_event.event_type)
|
9
|
+
end
|
10
|
+
|
11
|
+
specify "serialize and deserialize gives equal event" do
|
12
|
+
record = mapper.event_to_serialized_record(domain_event)
|
13
|
+
|
14
|
+
expect(mapper.serialized_record_to_event(record)).to eq(domain_event)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
RSpec.shared_examples :subscriptions do |subscriptions_class|
|
2
|
+
Test1DomainEvent = Class.new(RubyEventStore::Event)
|
3
|
+
Test2DomainEvent = Class.new(RubyEventStore::Event)
|
4
|
+
Test3DomainEvent = Class.new(RubyEventStore::Event)
|
5
|
+
|
6
|
+
class TestHandler
|
7
|
+
def initialize
|
8
|
+
@events = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def call(event)
|
12
|
+
@events << event
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_reader :events
|
16
|
+
end
|
17
|
+
|
18
|
+
subject(:subscriptions) { subscriptions_class.new }
|
19
|
+
|
20
|
+
it 'returns all subscribed handlers' do
|
21
|
+
handler = TestHandler.new
|
22
|
+
another_handler = TestHandler.new
|
23
|
+
global_handler = TestHandler.new
|
24
|
+
|
25
|
+
subscriptions.add_subscription(handler, [Test1DomainEvent, Test3DomainEvent])
|
26
|
+
subscriptions.add_subscription(another_handler, [Test2DomainEvent])
|
27
|
+
subscriptions.add_global_subscription(global_handler)
|
28
|
+
|
29
|
+
expect(subscriptions.all_for('Test1DomainEvent')).to eq([handler, global_handler])
|
30
|
+
expect(subscriptions.all_for('Test2DomainEvent')).to eq([another_handler, global_handler])
|
31
|
+
expect(subscriptions.all_for('Test3DomainEvent')).to eq([handler, global_handler])
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'returns subscribed thread handlers' do
|
35
|
+
handler = TestHandler.new
|
36
|
+
another_handler = TestHandler.new
|
37
|
+
global_handler = TestHandler.new
|
38
|
+
|
39
|
+
subscriptions.add_thread_subscription(handler, [Test1DomainEvent, Test3DomainEvent])
|
40
|
+
subscriptions.add_thread_subscription(another_handler, [Test2DomainEvent])
|
41
|
+
subscriptions.add_thread_global_subscription(global_handler)
|
42
|
+
|
43
|
+
expect(subscriptions.all_for('Test1DomainEvent')).to eq([global_handler, handler])
|
44
|
+
expect(subscriptions.all_for('Test2DomainEvent')).to eq([global_handler, another_handler])
|
45
|
+
expect(subscriptions.all_for('Test3DomainEvent')).to eq([global_handler, handler])
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'returns lambda as an output of global subscribe methods' do
|
49
|
+
handler = TestHandler.new
|
50
|
+
result = subscriptions.add_global_subscription(handler)
|
51
|
+
expect(result).to respond_to(:call)
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'returns lambda as an output of subscribe methods' do
|
55
|
+
handler = TestHandler.new
|
56
|
+
result = subscriptions.add_subscription(handler, [Test1DomainEvent, Test2DomainEvent])
|
57
|
+
expect(result).to respond_to(:call)
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'revokes global subscription' do
|
61
|
+
handler = TestHandler.new
|
62
|
+
|
63
|
+
revoke = subscriptions.add_global_subscription(handler)
|
64
|
+
expect(subscriptions.all_for('Test1DomainEvent')).to eq([handler])
|
65
|
+
expect(subscriptions.all_for('Test2DomainEvent')).to eq([handler])
|
66
|
+
revoke.()
|
67
|
+
expect(subscriptions.all_for('Test1DomainEvent')).to eq([])
|
68
|
+
expect(subscriptions.all_for('Test2DomainEvent')).to eq([])
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'revokes subscription' do
|
72
|
+
handler = TestHandler.new
|
73
|
+
|
74
|
+
revoke = subscriptions.add_subscription(handler, [Test1DomainEvent, Test2DomainEvent])
|
75
|
+
expect(subscriptions.all_for('Test1DomainEvent')).to eq([handler])
|
76
|
+
expect(subscriptions.all_for('Test2DomainEvent')).to eq([handler])
|
77
|
+
revoke.()
|
78
|
+
expect(subscriptions.all_for('Test1DomainEvent')).to eq([])
|
79
|
+
expect(subscriptions.all_for('Test2DomainEvent')).to eq([])
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'revokes thread global subscription' do
|
83
|
+
handler = TestHandler.new
|
84
|
+
|
85
|
+
revoke = subscriptions.add_thread_global_subscription(handler)
|
86
|
+
expect(subscriptions.all_for('Test1DomainEvent')).to eq([handler])
|
87
|
+
expect(subscriptions.all_for('Test2DomainEvent')).to eq([handler])
|
88
|
+
revoke.()
|
89
|
+
expect(subscriptions.all_for('Test1DomainEvent')).to eq([])
|
90
|
+
expect(subscriptions.all_for('Test2DomainEvent')).to eq([])
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'revokes thread subscription' do
|
94
|
+
handler = TestHandler.new
|
95
|
+
|
96
|
+
revoke = subscriptions.add_thread_subscription(handler, [Test1DomainEvent, Test2DomainEvent])
|
97
|
+
expect(subscriptions.all_for('Test1DomainEvent')).to eq([handler])
|
98
|
+
expect(subscriptions.all_for('Test2DomainEvent')).to eq([handler])
|
99
|
+
revoke.()
|
100
|
+
expect(subscriptions.all_for('Test1DomainEvent')).to eq([])
|
101
|
+
expect(subscriptions.all_for('Test2DomainEvent')).to eq([])
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'subscribes by type of event which is a String' do
|
105
|
+
handler = TestHandler.new
|
106
|
+
subscriptions.add_subscription(handler, ["Test1DomainEvent"])
|
107
|
+
subscriptions.add_thread_subscription(handler, ["Test1DomainEvent"])
|
108
|
+
|
109
|
+
expect(subscriptions.all_for('Test1DomainEvent')).to eq([handler, handler])
|
110
|
+
end
|
111
|
+
end
|
@@ -1,85 +1,94 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module RubyEventStore
|
4
|
+
|
5
|
+
# Used for building and executing the query specification.
|
2
6
|
class Specification
|
3
|
-
NO_LIMIT = Object.new.freeze
|
4
|
-
NO_BATCH = Object.new.freeze
|
5
7
|
DEFAULT_BATCH_SIZE = 100
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
end
|
11
|
-
|
12
|
-
def global_stream?
|
13
|
-
stream.global?
|
14
|
-
end
|
15
|
-
|
16
|
-
def stream_name
|
17
|
-
stream.name
|
18
|
-
end
|
19
|
-
|
20
|
-
def head?
|
21
|
-
start.equal?(:head)
|
22
|
-
end
|
23
|
-
|
24
|
-
def forward?
|
25
|
-
direction.equal?(:forward)
|
26
|
-
end
|
27
|
-
|
28
|
-
def backward?
|
29
|
-
!forward?
|
30
|
-
end
|
31
|
-
|
32
|
-
def batched?
|
33
|
-
!batch_size.equal?(NO_BATCH)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
private_constant :Result
|
37
|
-
|
38
|
-
attr_reader :result
|
39
|
-
|
40
|
-
def initialize(repository, mapper, result = Result.new(:forward, :head, NO_LIMIT, Stream.new(GLOBAL_STREAM), NO_BATCH))
|
41
|
-
@mapper = mapper
|
42
|
-
@repository = repository
|
8
|
+
# @api private
|
9
|
+
# @private
|
10
|
+
def initialize(reader, result = SpecificationResult.new)
|
11
|
+
@reader = reader
|
43
12
|
@result = result
|
44
13
|
end
|
45
14
|
|
15
|
+
# Limits the query to certain stream.
|
16
|
+
# {http://railseventstore.org/docs/read/ Find out more}.
|
17
|
+
#
|
18
|
+
# @param stream_name [String] name of the stream to get events from
|
19
|
+
# @return [Specification]
|
46
20
|
def stream(stream_name)
|
47
|
-
Specification.new(
|
21
|
+
Specification.new(reader, result.dup { |r| r.stream = Stream.new(stream_name) })
|
48
22
|
end
|
49
23
|
|
24
|
+
# Limits the query to events before or after another event.
|
25
|
+
# {http://railseventstore.org/docs/read/ Find out more}.
|
26
|
+
#
|
27
|
+
# @param start [String] id of event to start reading from.
|
28
|
+
# @return [Specification]
|
50
29
|
def from(start)
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
30
|
+
raise InvalidPageStart if start.nil? || start.empty?
|
31
|
+
raise EventNotFound.new(start) unless reader.has_event?(start)
|
32
|
+
Specification.new(reader, result.dup { |r| r.start = start })
|
33
|
+
end
|
34
|
+
|
35
|
+
# Limits the query to events before or after another event.
|
36
|
+
# {http://railseventstore.org/docs/read/ Find out more}.
|
37
|
+
#
|
38
|
+
# @param start [String] id of event to start reading from.
|
39
|
+
# @return [Specification]
|
40
|
+
def to(stop)
|
41
|
+
raise InvalidPageStop if stop.nil? || stop.empty?
|
42
|
+
raise EventNotFound.new(stop) unless reader.has_event?(stop)
|
43
|
+
Specification.new(reader, result.dup { |r| r.stop = stop })
|
59
44
|
end
|
60
45
|
|
46
|
+
# Sets the order of reading events to ascending (forward from the start).
|
47
|
+
# {http://railseventstore.org/docs/read/ Find out more}.
|
48
|
+
#
|
49
|
+
# @return [Specification]
|
61
50
|
def forward
|
62
|
-
Specification.new(
|
51
|
+
Specification.new(reader, result.dup { |r| r.direction = :forward })
|
63
52
|
end
|
64
53
|
|
54
|
+
# Sets the order of reading events to descending (backward from the start).
|
55
|
+
# {http://railseventstore.org/docs/read/ Find out more}.
|
56
|
+
#
|
57
|
+
# @return [Specification]
|
65
58
|
def backward
|
66
|
-
Specification.new(
|
59
|
+
Specification.new(reader, result.dup { |r| r.direction = :backward })
|
67
60
|
end
|
68
61
|
|
62
|
+
# Limits the query to specified number of events.
|
63
|
+
# {http://railseventstore.org/docs/read/ Find out more}.
|
64
|
+
#
|
65
|
+
# @param count [Integer] maximal number of events to retrieve
|
66
|
+
# @return [Specification]
|
69
67
|
def limit(count)
|
70
68
|
raise InvalidPageSize unless count && count > 0
|
71
|
-
Specification.new(
|
69
|
+
Specification.new(reader, result.dup { |r| r.count = count })
|
72
70
|
end
|
73
71
|
|
72
|
+
# Executes the query based on the specification built up to this point.
|
73
|
+
# Yields each batch of records that was retrieved from the store.
|
74
|
+
# {http://railseventstore.org/docs/read/ Find out more}.
|
75
|
+
#
|
76
|
+
# @yield [Array<Event, Proto>] batch of events
|
77
|
+
# @return [Enumerator, nil] Enumerator is returned when block not given
|
74
78
|
def each_batch
|
75
79
|
return to_enum(:each_batch) unless block_given?
|
76
80
|
|
77
|
-
|
78
|
-
|
79
|
-
yield batch.map { |serialized_record| mapper.serialized_record_to_event(serialized_record) }
|
81
|
+
reader.each(in_batches(result.batch_size).result) do |batch|
|
82
|
+
yield batch
|
80
83
|
end
|
81
84
|
end
|
82
85
|
|
86
|
+
# Executes the query based on the specification built up to this point.
|
87
|
+
# Yields events read from the store if block given. Otherwise, returns enumerable collection.
|
88
|
+
# {http://railseventstore.org/docs/read/ Find out more}.
|
89
|
+
#
|
90
|
+
# @yield [Event, Proto] event
|
91
|
+
# @return [Enumerator, nil] Enumerator is returned when block not given
|
83
92
|
def each
|
84
93
|
return to_enum unless block_given?
|
85
94
|
|
@@ -88,12 +97,148 @@ module RubyEventStore
|
|
88
97
|
end
|
89
98
|
end
|
90
99
|
|
100
|
+
# Executes the query based on the specification built up to this point
|
101
|
+
# and maps the result using provided block.
|
102
|
+
# {http://railseventstore.org/docs/read/ Find out more}.
|
103
|
+
#
|
104
|
+
# @return [Array] of mapped result
|
105
|
+
def map(&block)
|
106
|
+
raise ArgumentError.new("Block must be given") unless block_given?
|
107
|
+
each.map(&block)
|
108
|
+
end
|
109
|
+
|
110
|
+
# Reduces the results of the query based on the specification
|
111
|
+
# built up to this point result using provided block.
|
112
|
+
# {http://railseventstore.org/docs/read/ Find out more}.
|
113
|
+
#
|
114
|
+
# @accumulator starting state for reduce operation
|
115
|
+
# @return reduce result as defined by block given
|
116
|
+
def reduce(accumulator = nil, &block)
|
117
|
+
raise ArgumentError.new("Block must be given") unless block_given?
|
118
|
+
each.reduce(accumulator, &block)
|
119
|
+
end
|
120
|
+
|
121
|
+
# Calculates the size of result set based on the specification build up to this point.
|
122
|
+
# {http://railseventstore.org/docs/read/ Find out more}.
|
123
|
+
#
|
124
|
+
# @return [Integer] Number of events to read
|
125
|
+
def count
|
126
|
+
reader.count(result)
|
127
|
+
end
|
128
|
+
|
129
|
+
# Executes the query based on the specification built up to this point.
|
130
|
+
# Returns array of domain events.
|
131
|
+
# {http://railseventstore.org/docs/read/ Find out more}.
|
132
|
+
#
|
133
|
+
# @return [Array<Event, Proto>]
|
134
|
+
def to_a
|
135
|
+
each.to_a
|
136
|
+
end
|
137
|
+
|
138
|
+
# Specifies that events should be obtained in batches.
|
139
|
+
# {http://railseventstore.org/docs/read/ Find out more}.
|
140
|
+
#
|
141
|
+
# Looping through a collection of events from the store
|
142
|
+
# can be inefficient since it will try to instantiate all
|
143
|
+
# the events at once.
|
144
|
+
#
|
145
|
+
# In that case, batch processing methods allow you to work
|
146
|
+
# with the records in batches, thereby greatly reducing
|
147
|
+
# memory consumption.
|
148
|
+
#
|
149
|
+
# @param batch_size [Integer] number of events to read in a single batch
|
150
|
+
# @return [Specification]
|
91
151
|
def in_batches(batch_size = DEFAULT_BATCH_SIZE)
|
92
|
-
Specification.new(
|
152
|
+
Specification.new(reader, result.dup { |r| r.read_as = :batch; r.batch_size = batch_size })
|
93
153
|
end
|
94
154
|
alias :in_batches_of :in_batches
|
95
155
|
|
156
|
+
# Specifies that only first event should be read.
|
157
|
+
# {http://railseventstore.org/docs/read/ Find out more}.
|
158
|
+
#
|
159
|
+
# @return [Specification]
|
160
|
+
def read_first
|
161
|
+
Specification.new(reader, result.dup { |r| r.read_as = :first })
|
162
|
+
end
|
163
|
+
|
164
|
+
# Specifies that only last event should be read.
|
165
|
+
# {http://railseventstore.org/docs/read/ Find out more}.
|
166
|
+
#
|
167
|
+
# @return [Specification]
|
168
|
+
def read_last
|
169
|
+
Specification.new(reader, result.dup { |r| r.read_as = :last })
|
170
|
+
end
|
171
|
+
|
172
|
+
# Executes the query based on the specification built up to this point.
|
173
|
+
# Returns the first event in specified collection of events.
|
174
|
+
# {http://railseventstore.org/docs/read/ Find out more}.
|
175
|
+
#
|
176
|
+
# @return [Event, nil]
|
177
|
+
def first
|
178
|
+
reader.one(read_first.result)
|
179
|
+
end
|
180
|
+
|
181
|
+
# Executes the query based on the specification built up to this point.
|
182
|
+
# Returns the last event in specified collection of events.
|
183
|
+
# {http://railseventstore.org/docs/read/ Find out more}.
|
184
|
+
#
|
185
|
+
# @return [Event, nil]
|
186
|
+
def last
|
187
|
+
reader.one(read_last.result)
|
188
|
+
end
|
189
|
+
|
190
|
+
# Limits the query to certain event type(s).
|
191
|
+
# {http://railseventstore.org/docs/read/ Find out more}.
|
192
|
+
#
|
193
|
+
# @types [Class, Array(Class)] types of event to look for.
|
194
|
+
# @return [Specification]
|
195
|
+
def of_type(*types)
|
196
|
+
Specification.new(reader, result.dup{ |r| r.with_types = types.flatten })
|
197
|
+
end
|
198
|
+
alias_method :of_types, :of_type
|
199
|
+
|
200
|
+
# Limits the query to certain events by given even ids.
|
201
|
+
# {http://railseventstore.org/docs/read/ Find out more}.
|
202
|
+
#
|
203
|
+
# @param even_ids [Array(String)] ids of event to look for.
|
204
|
+
# @return [Specification]
|
205
|
+
def with_id(event_ids)
|
206
|
+
Specification.new(reader, result.dup{ |r| r.with_ids = event_ids })
|
207
|
+
end
|
208
|
+
|
209
|
+
# Reads single event from repository.
|
210
|
+
# Returns the event with specified id or nil if event is not found
|
211
|
+
# in specified collection of events.
|
212
|
+
# {http://railseventstore.org/docs/read/ Find out more}.
|
213
|
+
#
|
214
|
+
# @return [Event, nil]
|
215
|
+
def event(event_id)
|
216
|
+
reader.one(read_first.with_id([event_id]).result)
|
217
|
+
end
|
218
|
+
|
219
|
+
# Reads single existing event from repository.
|
220
|
+
# Returns the event with specified id or raises [EventNotFound] error if
|
221
|
+
# event is not found in specified collection of events.
|
222
|
+
# {http://railseventstore.org/docs/read/ Find out more}.
|
223
|
+
#
|
224
|
+
# @return [Event]
|
225
|
+
def event!(event_id)
|
226
|
+
event(event_id) or raise EventNotFound.new(event_id)
|
227
|
+
end
|
228
|
+
|
229
|
+
# Reads all events of given ids from repository.
|
230
|
+
# Yields each event (found by id in specified collection of events)
|
231
|
+
# read from the store if block given. Otherwise, returns enumerable collection.
|
232
|
+
# {http://railseventstore.org/docs/read/ Find out more}.
|
233
|
+
#
|
234
|
+
# @yield [Event, Proto] event
|
235
|
+
# @return [Enumerator] Enumerator is returned when block not given
|
236
|
+
def events(event_ids)
|
237
|
+
with_id(event_ids).each
|
238
|
+
end
|
239
|
+
|
240
|
+
attr_reader :result
|
96
241
|
private
|
97
|
-
attr_reader :
|
242
|
+
attr_reader :reader
|
98
243
|
end
|
99
244
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyEventStore
|
4
|
+
# Used for fetching events based on given query specification.
|
5
|
+
class SpecificationReader
|
6
|
+
# @api private
|
7
|
+
# @private
|
8
|
+
def initialize(repository, mapper)
|
9
|
+
@repository = repository
|
10
|
+
@mapper = mapper
|
11
|
+
end
|
12
|
+
|
13
|
+
# @api private
|
14
|
+
# @private
|
15
|
+
def one(specification_result)
|
16
|
+
record = repository.read(specification_result)
|
17
|
+
mapper.serialized_record_to_event(record) if record
|
18
|
+
end
|
19
|
+
|
20
|
+
# @api private
|
21
|
+
# @private
|
22
|
+
def each(specification_result)
|
23
|
+
repository.read(specification_result).each do |batch|
|
24
|
+
yield batch.map { |serialized_record| mapper.serialized_record_to_event(serialized_record) }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# @api private
|
29
|
+
# @private
|
30
|
+
def count(specification_result)
|
31
|
+
repository.count(specification_result)
|
32
|
+
end
|
33
|
+
|
34
|
+
# @api private
|
35
|
+
# @private
|
36
|
+
def has_event?(event_id)
|
37
|
+
repository.has_event?(event_id)
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
attr_reader :repository, :mapper
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,212 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyEventStore
|
4
|
+
class SpecificationResult
|
5
|
+
def initialize(direction: :forward,
|
6
|
+
start: nil,
|
7
|
+
stop: nil,
|
8
|
+
count: nil,
|
9
|
+
stream: Stream.new(GLOBAL_STREAM),
|
10
|
+
read_as: :all,
|
11
|
+
batch_size: Specification::DEFAULT_BATCH_SIZE,
|
12
|
+
with_ids: nil,
|
13
|
+
with_types: nil)
|
14
|
+
@attributes = Struct.new(:direction, :start, :stop, :count, :stream, :read_as, :batch_size, :with_ids, :with_types)
|
15
|
+
.new(direction, start, stop, count, stream, read_as, batch_size, with_ids, with_types)
|
16
|
+
freeze
|
17
|
+
end
|
18
|
+
|
19
|
+
# Limited results. True if number of read elements are limited
|
20
|
+
# {http://railseventstore.org/docs/read/ Find out more}.
|
21
|
+
#
|
22
|
+
# @return [Boolean]
|
23
|
+
def limit?
|
24
|
+
!attributes.count.nil?
|
25
|
+
end
|
26
|
+
|
27
|
+
# Results limit or infinity if limit not defined
|
28
|
+
# {http://railseventstore.org/docs/read/ Find out more}.
|
29
|
+
#
|
30
|
+
# @return [Integer|Infinity]
|
31
|
+
def limit
|
32
|
+
attributes.count || Float::INFINITY
|
33
|
+
end
|
34
|
+
|
35
|
+
# Stream definition. Stream to be read or nil
|
36
|
+
# {http://railseventstore.org/docs/read/ Find out more}.
|
37
|
+
#
|
38
|
+
# @return [Stream|nil]
|
39
|
+
def stream
|
40
|
+
attributes.stream
|
41
|
+
end
|
42
|
+
|
43
|
+
# Starting position. Event id of starting event
|
44
|
+
# {http://railseventstore.org/docs/read/ Find out more}.
|
45
|
+
#
|
46
|
+
# @return [String]
|
47
|
+
def start
|
48
|
+
attributes.start
|
49
|
+
end
|
50
|
+
|
51
|
+
# Stop position. Event id of stopping event
|
52
|
+
# {http://railseventstore.org/docs/read/ Find out more}.
|
53
|
+
#
|
54
|
+
# @return [String|Symbol]
|
55
|
+
def stop
|
56
|
+
attributes.stop
|
57
|
+
end
|
58
|
+
|
59
|
+
# Read direction. True is reading forward
|
60
|
+
# {http://railseventstore.org/docs/read/ Find out more}.
|
61
|
+
#
|
62
|
+
# @return [Boolean]
|
63
|
+
def forward?
|
64
|
+
get_direction.equal?(:forward)
|
65
|
+
end
|
66
|
+
|
67
|
+
# Read direction. True is reading backward
|
68
|
+
# {http://railseventstore.org/docs/read/ Find out more}.
|
69
|
+
#
|
70
|
+
# @return [Boolean]
|
71
|
+
def backward?
|
72
|
+
get_direction.equal?(:backward)
|
73
|
+
end
|
74
|
+
|
75
|
+
# Size of batch to read (only for :batch read strategy)
|
76
|
+
# {http://railseventstore.org/docs/read/ Find out more}.
|
77
|
+
#
|
78
|
+
# @return [Integer]
|
79
|
+
def batch_size
|
80
|
+
attributes.batch_size
|
81
|
+
end
|
82
|
+
|
83
|
+
# Ids of specified event to be read (if any given)
|
84
|
+
# {http://railseventstore.org/docs/read/ Find out more}.
|
85
|
+
#
|
86
|
+
# @return [Array|nil]
|
87
|
+
def with_ids
|
88
|
+
attributes.with_ids
|
89
|
+
end
|
90
|
+
|
91
|
+
# Read by specified ids. True if event ids have been specified.
|
92
|
+
# {http://railseventstore.org/docs/read/ Find out more}.
|
93
|
+
#
|
94
|
+
# @return [Boolean]
|
95
|
+
def with_ids?
|
96
|
+
!with_ids.nil?
|
97
|
+
end
|
98
|
+
|
99
|
+
# Event types to be read (if any given)
|
100
|
+
# {http://railseventstore.org/docs/read/ Find out more}.
|
101
|
+
#
|
102
|
+
# @return [Array|nil]
|
103
|
+
def with_types
|
104
|
+
attributes.with_types&.map(&:to_s)
|
105
|
+
end
|
106
|
+
|
107
|
+
# Read by specified event types. True if event types have been specified.
|
108
|
+
# {http://railseventstore.org/docs/read/ Find out more}.
|
109
|
+
#
|
110
|
+
# @return [Boolean]
|
111
|
+
def with_types?
|
112
|
+
!(with_types || []).empty?
|
113
|
+
end
|
114
|
+
|
115
|
+
# Read strategy. True if items will be read in batches
|
116
|
+
# {http://railseventstore.org/docs/read/ Find out more}.
|
117
|
+
#
|
118
|
+
# @return [Boolean]
|
119
|
+
def batched?
|
120
|
+
attributes.read_as.equal?(:batch)
|
121
|
+
end
|
122
|
+
|
123
|
+
# Read strategy. True if first item will be read
|
124
|
+
# {http://railseventstore.org/docs/read/ Find out more}.
|
125
|
+
#
|
126
|
+
# @return [Boolean]
|
127
|
+
def first?
|
128
|
+
attributes.read_as.equal?(:first)
|
129
|
+
end
|
130
|
+
|
131
|
+
# Read strategy. True if last item will be read
|
132
|
+
# {http://railseventstore.org/docs/read/ Find out more}.
|
133
|
+
#
|
134
|
+
# @return [Boolean]
|
135
|
+
def last?
|
136
|
+
attributes.read_as.equal?(:last)
|
137
|
+
end
|
138
|
+
|
139
|
+
# Read strategy. True if all items will be read
|
140
|
+
# {http://railseventstore.org/docs/read/ Find out more}.
|
141
|
+
#
|
142
|
+
# @return [Boolean]
|
143
|
+
def all?
|
144
|
+
attributes.read_as.equal?(:all)
|
145
|
+
end
|
146
|
+
|
147
|
+
# Clone [SpecificationResult]
|
148
|
+
# If block is given cloned attributes might be modified.
|
149
|
+
#
|
150
|
+
# @return [SpecificationResult]
|
151
|
+
def dup
|
152
|
+
new_attributes = attributes.dup
|
153
|
+
yield new_attributes if block_given?
|
154
|
+
SpecificationResult.new(**new_attributes.to_h)
|
155
|
+
end
|
156
|
+
|
157
|
+
# Two specification attributess are equal if:
|
158
|
+
# * they are of the same class
|
159
|
+
# * have identical data (verified with eql? method)
|
160
|
+
#
|
161
|
+
# @param other_spec [SpecificationResult, Object] object to compare
|
162
|
+
#
|
163
|
+
# @return [TrueClass, FalseClass]
|
164
|
+
def ==(other_spec)
|
165
|
+
other_spec.hash.eql?(hash)
|
166
|
+
end
|
167
|
+
|
168
|
+
# @private
|
169
|
+
BIG_VALUE = 0b100010010100011110111101100001011111100101001010111110101000000
|
170
|
+
|
171
|
+
# Generates a Fixnum hash value for this object. This function
|
172
|
+
# have the property that a.eql?(b) implies a.hash == b.hash.
|
173
|
+
#
|
174
|
+
# The hash value is used along with eql? by the Hash class to
|
175
|
+
# determine if two objects reference the same hash key.
|
176
|
+
#
|
177
|
+
# This hash is based on
|
178
|
+
# * class
|
179
|
+
# * direction
|
180
|
+
# * start
|
181
|
+
# * stop
|
182
|
+
# * count
|
183
|
+
# * stream
|
184
|
+
# * read_as
|
185
|
+
# * batch_size
|
186
|
+
# * with_ids
|
187
|
+
# * with_types
|
188
|
+
#
|
189
|
+
# @return [Integer]
|
190
|
+
def hash
|
191
|
+
[
|
192
|
+
self.class,
|
193
|
+
get_direction,
|
194
|
+
start,
|
195
|
+
stop,
|
196
|
+
limit,
|
197
|
+
stream,
|
198
|
+
attributes.read_as,
|
199
|
+
batch_size,
|
200
|
+
with_ids,
|
201
|
+
with_types,
|
202
|
+
].hash ^ BIG_VALUE
|
203
|
+
end
|
204
|
+
|
205
|
+
private
|
206
|
+
attr_reader :attributes
|
207
|
+
|
208
|
+
def get_direction
|
209
|
+
attributes.direction
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|