ruby_event_store 2.0.0 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -1
  3. data/lib/ruby_event_store/client.rb +37 -6
  4. data/lib/ruby_event_store/errors.rb +1 -0
  5. data/lib/ruby_event_store/event.rb +5 -2
  6. data/lib/ruby_event_store/in_memory_repository.rb +67 -15
  7. data/lib/ruby_event_store/instrumented_dispatcher.rb +12 -2
  8. data/lib/ruby_event_store/instrumented_repository.rb +17 -11
  9. data/lib/ruby_event_store/mappers/default.rb +1 -28
  10. data/lib/ruby_event_store/mappers/encryption_mapper.rb +2 -0
  11. data/lib/ruby_event_store/mappers/forgotten_data.rb +1 -1
  12. data/lib/ruby_event_store/mappers/in_memory_encryption_key_repository.rb +1 -1
  13. data/lib/ruby_event_store/mappers/instrumented_mapper.rb +0 -4
  14. data/lib/ruby_event_store/mappers/json_mapper.rb +7 -5
  15. data/lib/ruby_event_store/mappers/pipeline.rb +2 -26
  16. data/lib/ruby_event_store/mappers/pipeline_mapper.rb +0 -4
  17. data/lib/ruby_event_store/mappers/transformation/domain_event.rb +13 -3
  18. data/lib/ruby_event_store/mappers/transformation/upcast.rb +37 -0
  19. data/lib/ruby_event_store/metadata.rb +3 -3
  20. data/lib/ruby_event_store/projection.rb +2 -2
  21. data/lib/ruby_event_store/spec/broker_lint.rb +11 -11
  22. data/lib/ruby_event_store/spec/event_lint.rb +9 -9
  23. data/lib/ruby_event_store/spec/event_repository_lint.rb +338 -281
  24. data/lib/ruby_event_store/spec/subscriptions_lint.rb +41 -33
  25. data/lib/ruby_event_store/subscriptions.rb +24 -9
  26. data/lib/ruby_event_store/transform_keys.rb +5 -5
  27. data/lib/ruby_event_store/version.rb +1 -1
  28. data/lib/ruby_event_store.rb +43 -44
  29. metadata +26 -17
  30. data/.mutant.yml +0 -1
  31. data/CHANGELOG.md +0 -93
  32. data/Gemfile +0 -9
  33. data/Gemfile.lock +0 -118
  34. data/Makefile +0 -32
  35. data/lib/ruby_event_store/mappers/deprecated_wrapper.rb +0 -33
  36. data/lib/ruby_event_store/mappers/transformation/serialization.rb +0 -36
  37. data/ruby_event_store.gemspec +0 -27
@@ -3,7 +3,7 @@
3
3
  module RubyEventStore
4
4
  module Mappers
5
5
  class InMemoryEncryptionKeyRepository
6
- DEFAULT_CIPHER = 'aes-256-gcm'.freeze
6
+ DEFAULT_CIPHER = "aes-256-gcm".freeze
7
7
 
8
8
  def initialize
9
9
  @keys = {}
@@ -20,10 +20,6 @@ module RubyEventStore
20
20
  end
21
21
  end
22
22
 
23
- def serializer
24
- mapper.serializer
25
- end
26
-
27
23
  private
28
24
 
29
25
  attr_reader :instrumentation, :mapper
@@ -2,12 +2,14 @@
2
2
 
3
3
  module RubyEventStore
4
4
  module Mappers
5
- class JSONMapper < PipelineMapper
5
+ class JSONMapper < Default
6
6
  def initialize(events_class_remapping: {})
7
- super(Pipeline.new(
8
- Transformation::EventClassRemapper.new(events_class_remapping),
9
- Transformation::SymbolizeMetadataKeys.new,
10
- ))
7
+ warn <<~EOW
8
+ Please replace RubyEventStore::Mappers::JSONMapper with RubyEventStore::Mappers::Default
9
+
10
+ They're now identical and the former will be removed in next major release.
11
+ EOW
12
+ super
11
13
  end
12
14
  end
13
15
  end
@@ -3,13 +3,10 @@
3
3
  module RubyEventStore
4
4
  module Mappers
5
5
  class Pipeline
6
- UNSET = Object.new.freeze
7
-
8
- def initialize(*transformations_, transformations: UNSET, to_domain_event: Transformation::DomainEvent.new)
6
+ def initialize(*transformations, to_domain_event: Transformation::DomainEvent.new)
9
7
  @transformations = [
10
8
  to_domain_event,
11
- deprecated_transformations(transformations),
12
- transformations_,
9
+ transformations,
13
10
  ].flatten.freeze
14
11
  end
15
12
 
@@ -26,27 +23,6 @@ module RubyEventStore
26
23
  end
27
24
 
28
25
  attr_reader :transformations
29
-
30
- private
31
-
32
- def deprecated_transformations(transformations)
33
- case transformations
34
- when UNSET
35
- []
36
- else
37
- warn <<~EOW
38
- Passing transformations via keyword parameter is deprecated.
39
- Please use positional arguments from now on.
40
-
41
- Was:
42
- RubyEventStore::Mappers::Pipeline.new(transformations: transformations)
43
-
44
- Is now:
45
- RubyEventStore::Mappers::Pipeline.new(*transformations)
46
- EOW
47
- transformations
48
- end
49
- end
50
26
  end
51
27
  end
52
28
  end
@@ -15,10 +15,6 @@ module RubyEventStore
15
15
  pipeline.load(record)
16
16
  end
17
17
 
18
- def serializer
19
- NULL
20
- end
21
-
22
18
  private
23
19
  attr_reader :pipeline
24
20
  end
@@ -5,9 +5,9 @@ module RubyEventStore
5
5
  module Transformation
6
6
  class DomainEvent
7
7
  def dump(domain_event)
8
- metadata = domain_event.metadata.to_h
8
+ metadata = domain_event.metadata.dup.to_h
9
9
  timestamp = metadata.delete(:timestamp)
10
- valid_at = metadata.delete(:valid_at)
10
+ valid_at = metadata.delete(:valid_at)
11
11
  Record.new(
12
12
  event_id: domain_event.event_id,
13
13
  metadata: metadata,
@@ -21,11 +21,21 @@ module RubyEventStore
21
21
  def load(record)
22
22
  Object.const_get(record.event_type).new(
23
23
  event_id: record.event_id,
24
+ data: record.data,
24
25
  metadata: record.metadata.merge(
25
26
  timestamp: record.timestamp,
26
- valid_at: record.valid_at,
27
+ valid_at: record.valid_at,
27
28
  ),
29
+ )
30
+ rescue NameError
31
+ Event.new(
32
+ event_id: record.event_id,
28
33
  data: record.data,
34
+ metadata: record.metadata.merge(
35
+ timestamp: record.timestamp,
36
+ valid_at: record.valid_at,
37
+ event_type: record.event_type,
38
+ ),
29
39
  )
30
40
  end
31
41
  end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyEventStore
4
+ module Mappers
5
+ module Transformation
6
+ class Upcast
7
+ class RecordUpcaster
8
+ def initialize(upcast_map)
9
+ @upcast_map = upcast_map
10
+ end
11
+
12
+ def call(record)
13
+ identity = lambda { |r| r }
14
+ new_record = @upcast_map.fetch(record.event_type, identity)[record]
15
+ if new_record.equal?(record)
16
+ record
17
+ else
18
+ call(new_record)
19
+ end
20
+ end
21
+ end
22
+
23
+ def initialize(upcast_map)
24
+ @record_upcaster = RecordUpcaster.new(upcast_map)
25
+ end
26
+
27
+ def dump(record)
28
+ record
29
+ end
30
+
31
+ def load(record)
32
+ @record_upcaster.call(record)
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'date'
4
- require 'time'
5
- require 'forwardable'
3
+ require "date"
4
+ require "time"
5
+ require "forwardable"
6
6
 
7
7
  module RubyEventStore
8
8
  class Metadata
@@ -72,14 +72,14 @@ module RubyEventStore
72
72
  end
73
73
 
74
74
  def reduce_from_streams(event_store, start, count)
75
- raise ArgumentError.new('Start must be an array with event ids') unless valid_starting_point?(start)
75
+ raise ArgumentError.new("Start must be an array with event ids") unless valid_starting_point?(start)
76
76
  streams.zip(start_events(start)).reduce(initial_state) do |state, (stream_name, start_event_id)|
77
77
  read_scope(event_store, stream_name, count, start_event_id).reduce(state, &method(:transition))
78
78
  end
79
79
  end
80
80
 
81
81
  def reduce_from_all_streams(event_store, start, count)
82
- raise ArgumentError.new('Start must be valid event id') unless valid_starting_point?(start)
82
+ raise ArgumentError.new("Start must be valid event id") unless valid_starting_point?(start)
83
83
  read_scope(event_store, nil, count, start).reduce(initial_state, &method(:transition))
84
84
  end
85
85
 
@@ -1,5 +1,5 @@
1
1
  RSpec.shared_examples :broker do |broker_klass|
2
- let(:event) { instance_double(::RubyEventStore::Event, event_type: 'EventType') }
2
+ let(:event) { instance_double(::RubyEventStore::Event, event_type: "EventType") }
3
3
  let(:record) { instance_double(::RubyEventStore::Record) }
4
4
  let(:handler) { HandlerClass.new }
5
5
  let(:subscriptions) { ::RubyEventStore::Subscriptions.new }
@@ -7,38 +7,38 @@ RSpec.shared_examples :broker do |broker_klass|
7
7
  let(:broker) { broker_klass.new(subscriptions: subscriptions, dispatcher: dispatcher) }
8
8
 
9
9
  specify "no dispatch when no subscriptions" do
10
- expect(subscriptions).to receive(:all_for).with('EventType').and_return([])
10
+ expect(subscriptions).to receive(:all_for).with("EventType").and_return([])
11
11
  expect(dispatcher).not_to receive(:call)
12
12
  broker.call(event, record)
13
13
  end
14
14
 
15
15
  specify "calls subscription" do
16
- expect(subscriptions).to receive(:all_for).with('EventType').and_return([handler])
16
+ expect(subscriptions).to receive(:all_for).with("EventType").and_return([handler])
17
17
  expect(dispatcher).to receive(:call).with(handler, event, record)
18
18
  broker.call(event, record)
19
19
  end
20
20
 
21
21
  specify "calls subscribed class" do
22
- expect(subscriptions).to receive(:all_for).with('EventType').and_return([HandlerClass])
22
+ expect(subscriptions).to receive(:all_for).with("EventType").and_return([HandlerClass])
23
23
  expect(dispatcher).to receive(:call).with(HandlerClass, event, record)
24
24
  broker.call(event, record)
25
25
  end
26
26
 
27
27
  specify "calls all subscriptions" do
28
- expect(subscriptions).to receive(:all_for).with('EventType').and_return([handler, HandlerClass])
28
+ expect(subscriptions).to receive(:all_for).with("EventType").and_return([handler, HandlerClass])
29
29
  expect(dispatcher).to receive(:call).with(handler, event, record)
30
30
  expect(dispatcher).to receive(:call).with(HandlerClass, event, record)
31
31
  broker.call(event, record)
32
32
  end
33
33
 
34
- specify 'raise error when no subscriber' do
34
+ specify "raise error when no subscriber" do
35
35
  expect { broker.add_subscription(nil, [])}.to raise_error(RubyEventStore::SubscriberNotExist, "subscriber must be first argument or block")
36
36
  expect { broker.add_global_subscription(nil)}.to raise_error(RubyEventStore::SubscriberNotExist), "subscriber must be first argument or block"
37
37
  expect { broker.add_thread_subscription(nil, []).call}.to raise_error(RubyEventStore::SubscriberNotExist), "subscriber must be first argument or block"
38
38
  expect { broker.add_thread_global_subscription(nil).call}.to raise_error(RubyEventStore::SubscriberNotExist), "subscriber must be first argument or block"
39
39
  end
40
40
 
41
- specify 'raise error when wrong subscriber' do
41
+ specify "raise error when wrong subscriber" do
42
42
  allow(dispatcher).to receive(:verify).and_return(false)
43
43
  expect do
44
44
  broker.add_subscription(HandlerClass, [])
@@ -56,8 +56,8 @@ RSpec.shared_examples :broker do |broker_klass|
56
56
 
57
57
  specify "verify and add - local subscriptions" do
58
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'])
59
+ expect(subscriptions).to receive(:add_subscription).with(handler, ["EventType"])
60
+ broker.add_subscription(handler, ["EventType"])
61
61
  end
62
62
 
63
63
  specify "verify and add - global subscriptions" do
@@ -68,8 +68,8 @@ RSpec.shared_examples :broker do |broker_klass|
68
68
 
69
69
  specify "verify and add - thread local subscriptions" do
70
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'])
71
+ expect(subscriptions).to receive(:add_thread_subscription).with(handler, ["EventType"])
72
+ broker.add_thread_subscription(handler, ["EventType"])
73
73
  end
74
74
 
75
75
  specify "verify and add - thread global subscriptions" do
@@ -1,36 +1,36 @@
1
1
  RSpec.shared_examples :event do |event_class, data, metadata|
2
- it 'allows initialization' do
2
+ it "allows initialization" do
3
3
  expect {
4
4
  event_class.new(event_id: Object.new, data: data || Object.new, metadata: metadata || {})
5
5
  }.not_to raise_error
6
6
  end
7
7
 
8
- it 'provides event_id as string' do
8
+ it "provides event_id as string" do
9
9
  event = event_class.new
10
10
  expect(event.event_id).to be_an_instance_of(String)
11
- expect(event.event_id).not_to eq ''
11
+ expect(event.event_id).not_to eq ""
12
12
  expect(event.event_id).not_to eq nil
13
13
  end
14
14
 
15
- it 'provides message_id as string' do
15
+ it "provides message_id as string" do
16
16
  event = event_class.new
17
17
  expect(event.message_id).to be_an_instance_of(String)
18
18
  end
19
19
 
20
- it 'message_id is the same as event_id' do
20
+ it "message_id is the same as event_id" do
21
21
  event = event_class.new
22
22
  expect(event.event_id).to eq event.message_id
23
23
  end
24
24
 
25
- it 'exposes given event_id to string' do
25
+ it "exposes given event_id to string" do
26
26
  event = event_class.new(event_id: 1234567890)
27
- expect(event.event_id).to eq '1234567890'
27
+ expect(event.event_id).to eq "1234567890"
28
28
  end
29
29
 
30
- it 'provides event type as string' do
30
+ it "provides event type as string" do
31
31
  event = event_class.new
32
32
  expect(event.event_type).to be_an_instance_of(String)
33
- expect(event.event_type).not_to eq ''
33
+ expect(event.event_type).not_to eq ""
34
34
  expect(event.event_type).not_to eq nil
35
35
  end
36
36
 
@@ -5,7 +5,7 @@ module RubyEventStore
5
5
  event_id: SecureRandom.uuid,
6
6
  data: {},
7
7
  metadata: {},
8
- event_type: 'SRecordTestEvent',
8
+ event_type: "SRecordTestEvent",
9
9
  timestamp: Time.new.utc,
10
10
  valid_at: nil
11
11
  )
@@ -26,50 +26,17 @@ module RubyEventStore
26
26
  Type2 = Class.new(RubyEventStore::Event)
27
27
  # @private
28
28
  Type3 = Class.new(RubyEventStore::Event)
29
-
30
- # @private
31
- class EventRepositoryHelper
32
- def supports_concurrent_auto?
33
- true
34
- end
35
-
36
- def supports_concurrent_any?
37
- true
38
- end
39
-
40
- def supports_binary?
41
- true
42
- end
43
-
44
- def supports_upsert?
45
- true
46
- end
47
-
48
- def has_connection_pooling?
49
- false
50
- end
51
-
52
- def connection_pool_size
53
- end
54
-
55
- def cleanup_concurrency_test
56
- end
57
-
58
- def rescuable_concurrency_test_errors
59
- []
60
- end
61
- end
62
29
  end
63
30
 
64
31
  module RubyEventStore
65
- ::RSpec.shared_examples :event_repository do
66
- let(:helper) { EventRepositoryHelper.new }
32
+ ::RSpec.shared_examples :event_repository do |mk_repository, helper|
33
+ let(:repository) { mk_repository.call }
67
34
  let(:specification) { Specification.new(SpecificationReader.new(repository, Mappers::NullMapper.new)) }
68
35
  let(:global_stream) { Stream.new(GLOBAL_STREAM) }
69
36
  let(:stream) { Stream.new(SecureRandom.uuid) }
70
- let(:stream_flow) { Stream.new('flow') }
71
- let(:stream_other) { Stream.new('other') }
72
- let(:stream_test) { Stream.new('test') }
37
+ let(:stream_flow) { Stream.new("flow") }
38
+ let(:stream_other) { Stream.new("other") }
39
+ let(:stream_test) { Stream.new("test") }
73
40
  let(:version_none) { ExpectedVersion.none }
74
41
  let(:version_auto) { ExpectedVersion.auto }
75
42
  let(:version_any) { ExpectedVersion.any }
@@ -78,12 +45,12 @@ module RubyEventStore
78
45
  let(:version_2) { ExpectedVersion.new(2) }
79
46
  let(:version_3) { ExpectedVersion.new(3) }
80
47
 
81
- def verify_conncurency_assumptions
48
+ def verify_conncurency_assumptions(helper)
82
49
  return unless helper.has_connection_pooling?
83
- expect(helper.connection_pool_size).to eq(5)
50
+ expect(helper.connection_pool_size).to eq(5), "expected connection pool of size 5, got #{helper.connection_pool_size}"
84
51
  end
85
52
 
86
- def read_events(scope, stream = nil, from: nil, to: nil, count: nil)
53
+ def read_events(repository, scope, stream = nil, from: nil, to: nil, count: nil)
87
54
  scope = scope.stream(stream.name) if stream
88
55
  scope = scope.from(from) if from
89
56
  scope = scope.to(to) if to
@@ -91,44 +58,44 @@ module RubyEventStore
91
58
  repository.read(scope.result).to_a
92
59
  end
93
60
 
94
- def read_events_forward(_repository, stream = nil, from: nil, to: nil, count: nil)
95
- read_events(specification, stream, from: from, to: to, count: count)
61
+ def read_events_forward(repository, stream = nil, from: nil, to: nil, count: nil)
62
+ read_events(repository, specification, stream, from: from, to: to, count: count)
96
63
  end
97
64
 
98
- def read_events_backward(_repository, stream = nil, from: nil, to: nil, count: nil)
99
- read_events(specification.backward, stream, from: from, to: to, count: count)
65
+ def read_events_backward(repository, stream = nil, from: nil, to: nil, count: nil)
66
+ read_events(repository, specification.backward, stream, from: from, to: to, count: count)
100
67
  end
101
68
 
102
- it 'just created is empty' do
69
+ it "just created is empty" do
103
70
  expect(read_events_forward(repository)).to be_empty
104
71
  end
105
72
 
106
- specify 'append_to_stream returns self' do
73
+ specify "append_to_stream returns self" do
107
74
  repository
108
- .append_to_stream(event = SRecord.new, stream, version_none)
109
- .append_to_stream(event = SRecord.new, stream, version_0)
75
+ .append_to_stream([event = SRecord.new], stream, version_none)
76
+ .append_to_stream([event = SRecord.new], stream, version_0)
110
77
  end
111
78
 
112
- specify 'link_to_stream returns self' do
79
+ specify "link_to_stream returns self" do
113
80
  event0 = SRecord.new
114
81
  event1 = SRecord.new
115
82
  repository
116
83
  .append_to_stream([event0, event1], stream, version_none)
117
- .link_to_stream(event0.event_id, stream_flow, version_none)
118
- .link_to_stream(event1.event_id, stream_flow, version_0)
84
+ .link_to_stream([event0.event_id], stream_flow, version_none)
85
+ .link_to_stream([event1.event_id], stream_flow, version_0)
119
86
  end
120
87
 
121
- specify 'adds an initial event to a new stream' do
122
- repository.append_to_stream(event = SRecord.new, stream, version_none)
88
+ specify "adds an initial event to a new stream" do
89
+ repository.append_to_stream([event = SRecord.new], stream, version_none)
123
90
  expect(read_events_forward(repository).first).to eq(event)
124
91
  expect(read_events_forward(repository, stream).first).to eq(event)
125
92
  expect(read_events_forward(repository, stream_other)).to be_empty
126
93
  end
127
94
 
128
- specify 'links an initial event to a new stream' do
95
+ specify "links an initial event to a new stream" do
129
96
  repository
130
- .append_to_stream(event = SRecord.new, stream, version_none)
131
- .link_to_stream(event.event_id, stream_flow, version_none)
97
+ .append_to_stream([event = SRecord.new], stream, version_none)
98
+ .link_to_stream([event.event_id], stream_flow, version_none)
132
99
 
133
100
  expect(read_events_forward(repository, count: 1).first).to eq(event)
134
101
  expect(read_events_forward(repository, stream).first).to eq(event)
@@ -136,7 +103,7 @@ module RubyEventStore
136
103
  expect(read_events_forward(repository, stream_other)).to be_empty
137
104
  end
138
105
 
139
- specify 'adds multiple initial events to a new stream' do
106
+ specify "adds multiple initial events to a new stream" do
140
107
  repository.append_to_stream([
141
108
  event0 = SRecord.new,
142
109
  event1 = SRecord.new,
@@ -145,7 +112,7 @@ module RubyEventStore
145
112
  expect(read_events_forward(repository, stream)).to eq([event0, event1])
146
113
  end
147
114
 
148
- specify 'links multiple initial events to a new stream' do
115
+ specify "links multiple initial events to a new stream" do
149
116
  repository.append_to_stream([
150
117
  event0 = SRecord.new,
151
118
  event1 = SRecord.new,
@@ -157,7 +124,7 @@ module RubyEventStore
157
124
  expect(read_events_forward(repository, stream_flow)).to eq([event0, event1])
158
125
  end
159
126
 
160
- specify 'correct expected version on second write' do
127
+ specify "correct expected version on second write" do
161
128
  repository.append_to_stream([
162
129
  event0 = SRecord.new,
163
130
  event1 = SRecord.new,
@@ -170,7 +137,7 @@ module RubyEventStore
170
137
  expect(read_events_forward(repository, stream)).to eq([event0, event1, event2, event3])
171
138
  end
172
139
 
173
- specify 'correct expected version on second link' do
140
+ specify "correct expected version on second link" do
174
141
  repository.append_to_stream([
175
142
  event0 = SRecord.new,
176
143
  event1 = SRecord.new,
@@ -185,7 +152,7 @@ module RubyEventStore
185
152
  expect(read_events_forward(repository, stream_flow)).to eq([event2, event3, event0, event1])
186
153
  end
187
154
 
188
- specify 'incorrect expected version on second write' do
155
+ specify "incorrect expected version on second write" do
189
156
  repository.append_to_stream([
190
157
  event0 = SRecord.new,
191
158
  event1 = SRecord.new,
@@ -201,7 +168,7 @@ module RubyEventStore
201
168
  expect(read_events_forward(repository, stream)).to eq([event0, event1])
202
169
  end
203
170
 
204
- specify 'incorrect expected version on second link' do
171
+ specify "incorrect expected version on second link" do
205
172
  repository.append_to_stream([
206
173
  event0 = SRecord.new,
207
174
  event1 = SRecord.new,
@@ -221,7 +188,7 @@ module RubyEventStore
221
188
  expect(read_events_forward(repository, stream)).to eq([event0, event1])
222
189
  end
223
190
 
224
- specify ':none on first and subsequent write' do
191
+ specify ":none on first and subsequent write" do
225
192
  repository.append_to_stream([
226
193
  eventA = SRecord.new,
227
194
  ], stream, version_none)
@@ -234,7 +201,7 @@ module RubyEventStore
234
201
  expect(read_events_forward(repository, stream)).to eq([eventA])
235
202
  end
236
203
 
237
- specify ':none on first and subsequent link' do
204
+ specify ":none on first and subsequent link" do
238
205
  repository.append_to_stream([
239
206
  eventA = SRecord.new,
240
207
  eventB = SRecord.new,
@@ -249,7 +216,7 @@ module RubyEventStore
249
216
  expect(read_events_forward(repository, stream_flow)).to eq([eventA])
250
217
  end
251
218
 
252
- specify ':any allows stream with best-effort order and no guarantee' do
219
+ specify ":any allows stream with best-effort order and no guarantee" do
253
220
  repository.append_to_stream([
254
221
  event0 = SRecord.new,
255
222
  event1 = SRecord.new,
@@ -262,7 +229,7 @@ module RubyEventStore
262
229
  expect(read_events_forward(repository, stream).to_set).to eq(Set.new([event0, event1, event2, event3]))
263
230
  end
264
231
 
265
- specify ':any allows linking in stream with best-effort order and no guarantee' do
232
+ specify ":any allows linking in stream with best-effort order and no guarantee" do
266
233
  repository.append_to_stream([
267
234
  event0 = SRecord.new,
268
235
  event1 = SRecord.new,
@@ -281,7 +248,7 @@ module RubyEventStore
281
248
  expect(read_events_forward(repository, stream_flow).to_set).to eq(Set.new([event0, event1, event2, event3]))
282
249
  end
283
250
 
284
- specify ':auto queries for last position in given stream' do
251
+ specify ":auto queries for last position in given stream" do
285
252
  repository.append_to_stream([
286
253
  eventA = SRecord.new,
287
254
  eventB = SRecord.new,
@@ -297,7 +264,7 @@ module RubyEventStore
297
264
  ], stream, version_1)
298
265
  end
299
266
 
300
- specify ':auto queries for last position in given stream when linking' do
267
+ specify ":auto queries for last position in given stream when linking" do
301
268
  repository.append_to_stream([
302
269
  eventA = SRecord.new,
303
270
  eventB = SRecord.new,
@@ -314,7 +281,7 @@ module RubyEventStore
314
281
  ], stream, version_1)
315
282
  end
316
283
 
317
- specify ':auto starts from 0' do
284
+ specify ":auto starts from 0" do
318
285
  repository.append_to_stream([
319
286
  event0 = SRecord.new,
320
287
  ], stream, version_auto)
@@ -325,7 +292,7 @@ module RubyEventStore
325
292
  end.to raise_error(WrongExpectedEventVersion)
326
293
  end
327
294
 
328
- specify ':auto linking starts from 0' do
295
+ specify ":auto linking starts from 0" do
329
296
  repository.append_to_stream([
330
297
  event0 = SRecord.new,
331
298
  ], stream_other, version_auto)
@@ -339,7 +306,7 @@ module RubyEventStore
339
306
  end.to raise_error(WrongExpectedEventVersion)
340
307
  end
341
308
 
342
- specify ':auto queries for last position and follows in incremental way' do
309
+ specify ":auto queries for last position and follows in incremental way" do
343
310
  # It is expected that there is higher level lock
344
311
  # So this query is safe from race conditions
345
312
  repository.append_to_stream([
@@ -357,7 +324,7 @@ module RubyEventStore
357
324
  expect(read_events_forward(repository, stream)).to eq([event0, event1, event2, event3])
358
325
  end
359
326
 
360
- specify ':auto queries for last position and follows in incremental way when linking' do
327
+ specify ":auto queries for last position and follows in incremental way when linking" do
361
328
  repository.append_to_stream([
362
329
  event0 = SRecord.new,
363
330
  event1 = SRecord.new,
@@ -377,7 +344,7 @@ module RubyEventStore
377
344
  expect(read_events_forward(repository, stream_flow)).to eq([event0, event1, event2, event3])
378
345
  end
379
346
 
380
- specify ':auto is compatible with manual expectation' do
347
+ specify ":auto is compatible with manual expectation" do
381
348
  repository.append_to_stream([
382
349
  event0 = SRecord.new,
383
350
  event1 = SRecord.new,
@@ -390,7 +357,7 @@ module RubyEventStore
390
357
  expect(read_events_forward(repository, stream)).to eq([event0, event1, event2, event3])
391
358
  end
392
359
 
393
- specify ':auto is compatible with manual expectation when linking' do
360
+ specify ":auto is compatible with manual expectation when linking" do
394
361
  repository.append_to_stream([
395
362
  event0 = SRecord.new,
396
363
  event1 = SRecord.new,
@@ -405,7 +372,7 @@ module RubyEventStore
405
372
  expect(read_events_forward(repository, stream_flow)).to eq([event0, event1,])
406
373
  end
407
374
 
408
- specify 'manual is compatible with auto expectation' do
375
+ specify "manual is compatible with auto expectation" do
409
376
  repository.append_to_stream([
410
377
  event0 = SRecord.new,
411
378
  event1 = SRecord.new,
@@ -418,7 +385,7 @@ module RubyEventStore
418
385
  expect(read_events_forward(repository, stream)).to eq([event0, event1, event2, event3])
419
386
  end
420
387
 
421
- specify 'manual is compatible with auto expectation when linking' do
388
+ specify "manual is compatible with auto expectation when linking" do
422
389
  repository.append_to_stream([
423
390
  event0 = SRecord.new,
424
391
  event1 = SRecord.new,
@@ -433,9 +400,9 @@ module RubyEventStore
433
400
  expect(read_events_forward(repository, stream_flow)).to eq([event0, event1])
434
401
  end
435
402
 
436
- specify 'unlimited concurrency for :any - everything should succeed', timeout: 10, mutant: false do
403
+ specify "unlimited concurrency for :any - everything should succeed", timeout: 10, mutant: false do
437
404
  skip unless helper.supports_concurrent_any?
438
- verify_conncurency_assumptions
405
+ verify_conncurency_assumptions(helper)
439
406
  begin
440
407
  concurrency_level = 4
441
408
  fail_occurred = false
@@ -466,14 +433,12 @@ module RubyEventStore
466
433
  ev.event_id.start_with?("0-")
467
434
  end
468
435
  expect(events0).to eq(events0.sort_by{|ev| ev.event_id })
469
- ensure
470
- helper.cleanup_concurrency_test
471
436
  end
472
437
  end
473
438
 
474
- specify 'unlimited concurrency for :any - everything should succeed when linking', timeout: 10, mutant: false do
439
+ specify "unlimited concurrency for :any - everything should succeed when linking", timeout: 10, mutant: false do
475
440
  skip unless helper.supports_concurrent_any?
476
- verify_conncurency_assumptions
441
+ verify_conncurency_assumptions(helper)
477
442
  begin
478
443
  concurrency_level = 4
479
444
  fail_occurred = false
@@ -494,7 +459,7 @@ module RubyEventStore
494
459
  begin
495
460
  100.times do |j|
496
461
  eid = "0000000#{i}-#{sprintf("%04d", j)}-0000-0000-000000000000"
497
- repository.link_to_stream(eid, stream_flow, version_any)
462
+ repository.link_to_stream([eid], stream_flow, version_any)
498
463
  end
499
464
  rescue WrongExpectedEventVersion
500
465
  fail_occurred = true
@@ -511,14 +476,12 @@ module RubyEventStore
511
476
  ev.event_id.start_with?("0-")
512
477
  end
513
478
  expect(events0).to eq(events0.sort_by{|ev| ev.event_id })
514
- ensure
515
- helper.cleanup_concurrency_test
516
479
  end
517
480
  end
518
481
 
519
- specify 'limited concurrency for :auto - some operations will fail without outside lock, stream is ordered', mutant: false do
482
+ specify "limited concurrency for :auto - some operations will fail without outside lock, stream is ordered", mutant: false do
520
483
  skip unless helper.supports_concurrent_auto?
521
- verify_conncurency_assumptions
484
+ verify_conncurency_assumptions(helper)
522
485
  begin
523
486
  concurrency_level = 4
524
487
 
@@ -535,7 +498,7 @@ module RubyEventStore
535
498
  SRecord.new(event_id: eid),
536
499
  ], stream, version_auto)
537
500
  sleep(rand(concurrency_level) / 1000.0)
538
- rescue WrongExpectedEventVersion, *helper.rescuable_concurrency_test_errors
501
+ rescue WrongExpectedEventVersion
539
502
  fail_occurred +=1
540
503
  end
541
504
  end
@@ -551,15 +514,15 @@ module RubyEventStore
551
514
  ev.event_id.start_with?("0-")
552
515
  end
553
516
  expect(events0).to eq(events0.sort_by{|ev| ev.event_id })
554
- additional_limited_concurrency_for_auto_check if defined? additional_limited_concurrency_for_auto_check
555
- ensure
556
- helper.cleanup_concurrency_test
517
+
518
+ positions = repository.read(specification.stream(stream.name).result).map { |r| repository.position_in_stream(r.event_id, stream) }
519
+ expect(positions).to eq((0...positions.size).to_a)
557
520
  end
558
521
  end
559
522
 
560
- specify 'limited concurrency for :auto - some operations will fail without outside lock, stream is ordered', mutant: false do
523
+ specify "limited concurrency for :auto - some operations will fail without outside lock, stream is ordered", mutant: false do
561
524
  skip unless helper.supports_concurrent_auto?
562
- verify_conncurency_assumptions
525
+ verify_conncurency_assumptions(helper)
563
526
  begin
564
527
  concurrency_level = 4
565
528
 
@@ -581,9 +544,9 @@ module RubyEventStore
581
544
  100.times do |j|
582
545
  begin
583
546
  eid = "0000000#{i}-#{sprintf("%04d", j)}-0000-0000-000000000000"
584
- repository.link_to_stream(eid, stream, version_auto)
547
+ repository.link_to_stream([eid], stream, version_auto)
585
548
  sleep(rand(concurrency_level) / 1000.0)
586
- rescue WrongExpectedEventVersion, *helper.rescuable_concurrency_test_errors
549
+ rescue WrongExpectedEventVersion
587
550
  fail_occurred +=1
588
551
  end
589
552
  end
@@ -599,51 +562,51 @@ module RubyEventStore
599
562
  ev.event_id.start_with?("0-")
600
563
  end
601
564
  expect(events0).to eq(events0.sort_by{|ev| ev.event_id })
602
- additional_limited_concurrency_for_auto_check if defined? additional_limited_concurrency_for_auto_check
603
- ensure
604
- helper.cleanup_concurrency_test
565
+
566
+ positions = repository.read(specification.stream(stream.name).result).map { |r| repository.position_in_stream(r.event_id, stream) }
567
+ expect(positions).to eq((0...positions.size).to_a)
605
568
  end
606
569
  end
607
570
 
608
- it 'appended event is stored in given stream' do
571
+ it "appended event is stored in given stream" do
609
572
  expected_event = SRecord.new
610
- repository.append_to_stream(expected_event, stream, version_any)
573
+ repository.append_to_stream([expected_event], stream, version_any)
611
574
  expect(read_events_forward(repository, count: 1).first).to eq(expected_event)
612
575
  expect(read_events_forward(repository, stream).first).to eq(expected_event)
613
576
  expect(read_events_forward(repository, stream_other)).to be_empty
614
577
  end
615
578
 
616
- it 'data attributes are retrieved' do
579
+ it "data attributes are retrieved" do
617
580
  event = SRecord.new(data: { "order_id" => 3 })
618
- repository.append_to_stream(event, stream, version_any)
581
+ repository.append_to_stream([event], stream, version_any)
619
582
  retrieved_event = read_events_forward(repository, count: 1).first
620
583
  expect(retrieved_event.data).to eq({ "order_id" => 3 })
621
584
  end
622
585
 
623
- it 'metadata attributes are retrieved' do
586
+ it "metadata attributes are retrieved" do
624
587
  event = SRecord.new(metadata: { "request_id" => 3 })
625
- repository.append_to_stream(event, stream, version_any)
588
+ repository.append_to_stream([event], stream, version_any)
626
589
  retrieved_event = read_events_forward(repository, count: 1).first
627
590
  expect(retrieved_event.metadata).to eq({ "request_id" => 3 })
628
591
  end
629
592
 
630
- it 'data and metadata attributes are retrieved when linking' do
593
+ it "data and metadata attributes are retrieved when linking" do
631
594
  event = SRecord.new(
632
595
  data: { "order_id" => 3 },
633
596
  metadata: { "request_id" => 4},
634
597
  )
635
598
  repository
636
- .append_to_stream(event, stream, version_any)
637
- .link_to_stream(event.event_id, stream_flow, version_any)
599
+ .append_to_stream([event], stream, version_any)
600
+ .link_to_stream([event.event_id], stream_flow, version_any)
638
601
  retrieved_event = read_events_forward(repository, stream_flow).first
639
602
  expect(retrieved_event.metadata).to eq({ "request_id" => 4 })
640
603
  expect(retrieved_event.data).to eq({ "order_id" => 3 })
641
604
  expect(event).to eq(retrieved_event)
642
605
  end
643
606
 
644
- it 'does not have deleted streams' do
645
- repository.append_to_stream(e1 = SRecord.new, stream, version_none)
646
- repository.append_to_stream(e2 = SRecord.new, stream_other, version_none)
607
+ it "does not have deleted streams" do
608
+ repository.append_to_stream([e1 = SRecord.new], stream, version_none)
609
+ repository.append_to_stream([e2 = SRecord.new], stream_other, version_none)
647
610
 
648
611
  repository.delete_stream(stream)
649
612
  expect(read_events_forward(repository, stream)).to be_empty
@@ -651,41 +614,108 @@ module RubyEventStore
651
614
  expect(read_events_forward(repository, count: 10)).to eq([e1,e2])
652
615
  end
653
616
 
654
- it 'does not have deleted streams with linked events' do
617
+ it "does not have deleted streams with linked events" do
655
618
  repository
656
- .append_to_stream(e1 = SRecord.new, stream, version_none)
657
- .link_to_stream(e1.event_id, stream_flow, version_none)
619
+ .append_to_stream([e1 = SRecord.new], stream, version_none)
620
+ .link_to_stream([e1.event_id], stream_flow, version_none)
658
621
 
659
622
  repository.delete_stream(stream_flow)
660
623
  expect(read_events_forward(repository, stream_flow)).to be_empty
661
624
  expect(read_events_forward(repository, count: 10)).to eq([e1])
662
625
  end
663
626
 
664
- it 'has or has not domain event' do
665
- just_an_id = 'd5c134c2-db65-4e87-b6ea-d196f8f1a292'
666
- repository.append_to_stream(SRecord.new(event_id: just_an_id), stream, version_none)
627
+ it "has or has not domain event" do
628
+ just_an_id = "d5c134c2-db65-4e87-b6ea-d196f8f1a292"
629
+ repository.append_to_stream([SRecord.new(event_id: just_an_id)], stream, version_none)
667
630
 
668
631
  expect(repository.has_event?(just_an_id)).to be_truthy
669
632
  expect(repository.has_event?(just_an_id.clone)).to be_truthy
670
- expect(repository.has_event?('any other id')).to be_falsey
633
+ expect(repository.has_event?("any other id")).to be false
671
634
 
672
635
  repository.delete_stream(stream)
673
636
  expect(repository.has_event?(just_an_id)).to be_truthy
674
637
  expect(repository.has_event?(just_an_id.clone)).to be_truthy
675
638
  end
676
639
 
677
- it 'knows last event in stream' do
678
- repository.append_to_stream(a =SRecord.new(event_id: '00000000-0000-0000-0000-000000000001'), stream, version_none)
679
- repository.append_to_stream(b = SRecord.new(event_id: '00000000-0000-0000-0000-000000000002'), stream, version_0)
640
+ it "#position_in_stream happy path" do
641
+ skip unless helper.supports_position_queries?
642
+ repository.append_to_stream([
643
+ event0 = SRecord.new,
644
+ event1 = SRecord.new
645
+ ], stream, version_auto)
646
+
647
+ expect(repository.position_in_stream(event0.event_id, stream)).to eq(0)
648
+ expect(repository.position_in_stream(event1.event_id, stream)).to eq(1)
649
+ end
650
+
651
+ it "#position_in_stream happy path with linking" do
652
+ skip unless helper.supports_position_queries?
653
+ repository.append_to_stream([
654
+ event0 = SRecord.new,
655
+ event1 = SRecord.new
656
+ ], stream, version_auto)
657
+ repository.link_to_stream([
658
+ event1.event_id,
659
+ event0.event_id,
660
+ ], stream_other, version_auto)
661
+
662
+ expect(repository.position_in_stream(event0.event_id, stream)).to eq(0)
663
+ expect(repository.position_in_stream(event1.event_id, stream)).to eq(1)
664
+ expect(repository.position_in_stream(event1.event_id, stream_other)).to eq(0)
665
+ expect(repository.position_in_stream(event0.event_id, stream_other)).to eq(1)
666
+ end
667
+
668
+ it "#position_in_stream when event is not in the stream" do
669
+ skip unless helper.supports_position_queries?
670
+ just_an_id = "d5c134c2-db65-4e87-b6ea-d196f8f1a292"
671
+
672
+ expect do
673
+ repository.position_in_stream(just_an_id, stream)
674
+ end.to raise_error(EventNotFoundInStream)
675
+ end
676
+
677
+ it "#position_in_stream when event is published without position" do
678
+ skip unless helper.supports_position_queries?
679
+ repository.append_to_stream([event0 = SRecord.new], stream, version_any)
680
+
681
+ expect(repository.position_in_stream(event0.event_id, stream)).to eq(nil)
682
+ end
683
+
684
+ it "#global_position happy path" do
685
+ skip unless helper.supports_position_queries?
686
+ repository.append_to_stream([
687
+ event0 = SRecord.new,
688
+ event1 = SRecord.new
689
+ ], stream, version_any)
690
+
691
+ expect(repository.global_position(event0.event_id)).to eq(0)
692
+ expect(repository.global_position(event1.event_id)).to eq(1)
693
+ end
694
+
695
+ it "#global_position for not existing event" do
696
+ skip unless helper.supports_position_queries?
697
+ just_an_id = "d5c134c2-db65-4e87-b6ea-d196f8f1a292"
698
+
699
+ expect do
700
+ repository.global_position(just_an_id)
701
+ end.to raise_error do |err|
702
+ expect(err).to be_a(EventNotFound)
703
+ expect(err.event_id).to eq(just_an_id)
704
+ end
705
+ end
706
+
707
+ it "knows last event in stream" do
708
+ repository.append_to_stream([a =SRecord.new(event_id: "00000000-0000-0000-0000-000000000001")], stream, version_none)
709
+ repository.append_to_stream([b = SRecord.new(event_id: "00000000-0000-0000-0000-000000000002")], stream, version_0)
680
710
 
681
711
  expect(repository.last_stream_event(stream)).to eq(b)
682
712
  expect(repository.last_stream_event(stream_other)).to be_nil
683
713
  end
684
714
 
685
- it 'knows last event in stream when linked' do
715
+ it "knows last event in stream when linked" do
686
716
  repository.append_to_stream([
687
- e0 = SRecord.new(event_id: '00000000-0000-0000-0000-000000000001'),
688
- e1 = SRecord.new(event_id: '00000000-0000-0000-0000-000000000002'),
717
+ e0 = SRecord.new(event_id: "00000000-0000-0000-0000-000000000001"),
718
+ e1 = SRecord.new(event_id: "00000000-0000-0000-0000-000000000002"),
689
719
  ],
690
720
  stream,
691
721
  version_none
@@ -693,7 +723,7 @@ module RubyEventStore
693
723
  expect(repository.last_stream_event(stream_flow)).to eq(e0)
694
724
  end
695
725
 
696
- it 'reads batch of events from stream forward & backward' do
726
+ it "reads batch of events from stream forward & backward" do
697
727
  events = %w[
698
728
  96c920b1-cdd0-40f4-907c-861b9fff7d02
699
729
  56404f79-0ba0-4aa0-8524-dc3436368ca0
@@ -706,11 +736,11 @@ module RubyEventStore
706
736
  ab60114c-011d-4d58-ab31-7ba65d99975e
707
737
  868cac42-3d19-4b39-84e8-cd32d65c2445
708
738
  ].map { |id| SRecord.new(event_id: id) }
709
- repository.append_to_stream(SRecord.new, stream_other, version_none)
739
+ repository.append_to_stream([SRecord.new], stream_other, version_none)
710
740
  events.each.with_index do |event, index|
711
- repository.append_to_stream(event, stream, ExpectedVersion.new(index - 1))
741
+ repository.append_to_stream([event], stream, ExpectedVersion.new(index - 1))
712
742
  end
713
- repository.append_to_stream(SRecord.new, stream_other, version_0)
743
+ repository.append_to_stream([SRecord.new], stream_other, version_0)
714
744
 
715
745
  expect(read_events_forward(repository, stream, count: 3)).to eq(events.first(3))
716
746
  expect(read_events_forward(repository, stream, count: 100)).to eq(events)
@@ -728,7 +758,7 @@ module RubyEventStore
728
758
  expect(read_events_backward(repository, stream, to: events[4].event_id, count: 100)).to eq(events.last(5).reverse)
729
759
  end
730
760
 
731
- it 'reads batch of linked events from stream forward & backward' do
761
+ it "reads batch of linked events from stream forward & backward" do
732
762
  events = %w[
733
763
  96c920b1-cdd0-40f4-907c-861b9fff7d02
734
764
  56404f79-0ba0-4aa0-8524-dc3436368ca0
@@ -741,13 +771,13 @@ module RubyEventStore
741
771
  ab60114c-011d-4d58-ab31-7ba65d99975e
742
772
  868cac42-3d19-4b39-84e8-cd32d65c2445
743
773
  ].map { |id| SRecord.new(event_id: id) }
744
- repository.append_to_stream(SRecord.new, stream_other, version_none)
774
+ repository.append_to_stream([SRecord.new], stream_other, version_none)
745
775
  events.each.with_index do |event, index|
746
776
  repository
747
- .append_to_stream(event, stream, ExpectedVersion.new(index - 1))
748
- .link_to_stream(event.event_id, stream_flow, ExpectedVersion.new(index - 1))
777
+ .append_to_stream([event], stream, ExpectedVersion.new(index - 1))
778
+ .link_to_stream([event.event_id], stream_flow, ExpectedVersion.new(index - 1))
749
779
  end
750
- repository.append_to_stream(SRecord.new, stream_other, version_0)
780
+ repository.append_to_stream([SRecord.new], stream_other, version_0)
751
781
 
752
782
  expect(read_events_forward(repository, stream_flow, count: 3)).to eq(events.first(3))
753
783
  expect(read_events_forward(repository, stream_flow, count: 100)).to eq(events)
@@ -764,39 +794,39 @@ module RubyEventStore
764
794
  expect(read_events_backward(repository, stream_flow, to: events[4].event_id, count: 100)).to eq(events[5..9].reverse)
765
795
  end
766
796
 
767
- it 'reads all stream events forward & backward' do
797
+ it "reads all stream events forward & backward" do
768
798
  s1 = stream
769
799
  s2 = stream_other
770
800
  repository
771
- .append_to_stream(a = SRecord.new(event_id: '7010d298-ab69-4bb1-9251-f3466b5d1282'), s1, version_none)
772
- .append_to_stream(b = SRecord.new(event_id: '34f88aca-aaba-4ca0-9256-8017b47528c5'), s2, version_none)
773
- .append_to_stream(c = SRecord.new(event_id: '8e61c864-ceae-4684-8726-97c34eb8fc4f'), s1, version_0)
774
- .append_to_stream(d = SRecord.new(event_id: '30963ed9-6349-450b-ac9b-8ea50115b3bd'), s2, version_0)
775
- .append_to_stream(e = SRecord.new(event_id: '5bdc58b7-e8a7-4621-afd6-ccb828d72457'), s2, version_1)
801
+ .append_to_stream([a = SRecord.new(event_id: "7010d298-ab69-4bb1-9251-f3466b5d1282")], s1, version_none)
802
+ .append_to_stream([b = SRecord.new(event_id: "34f88aca-aaba-4ca0-9256-8017b47528c5")], s2, version_none)
803
+ .append_to_stream([c = SRecord.new(event_id: "8e61c864-ceae-4684-8726-97c34eb8fc4f")], s1, version_0)
804
+ .append_to_stream([d = SRecord.new(event_id: "30963ed9-6349-450b-ac9b-8ea50115b3bd")], s2, version_0)
805
+ .append_to_stream([e = SRecord.new(event_id: "5bdc58b7-e8a7-4621-afd6-ccb828d72457")], s2, version_1)
776
806
 
777
807
  expect(read_events_forward(repository, s1)).to eq [a,c]
778
808
  expect(read_events_backward(repository, s1)).to eq [c,a]
779
809
  end
780
810
 
781
- it 'reads all stream linked events forward & backward' do
811
+ it "reads all stream linked events forward & backward" do
782
812
  s1, fs1, fs2 = stream, stream_flow, stream_other
783
813
  repository
784
- .append_to_stream(a = SRecord.new(event_id: '7010d298-ab69-4bb1-9251-f3466b5d1282'), s1, version_none)
785
- .append_to_stream(b = SRecord.new(event_id: '34f88aca-aaba-4ca0-9256-8017b47528c5'), s1, version_0)
786
- .append_to_stream(c = SRecord.new(event_id: '8e61c864-ceae-4684-8726-97c34eb8fc4f'), s1, version_1)
787
- .append_to_stream(d = SRecord.new(event_id: '30963ed9-6349-450b-ac9b-8ea50115b3bd'), s1, version_2)
788
- .append_to_stream(e = SRecord.new(event_id: '5bdc58b7-e8a7-4621-afd6-ccb828d72457'), s1, version_3)
789
- .link_to_stream('7010d298-ab69-4bb1-9251-f3466b5d1282', fs1, version_none)
790
- .link_to_stream('34f88aca-aaba-4ca0-9256-8017b47528c5', fs2, version_none)
791
- .link_to_stream('8e61c864-ceae-4684-8726-97c34eb8fc4f', fs1, version_0)
792
- .link_to_stream('30963ed9-6349-450b-ac9b-8ea50115b3bd', fs2, version_0)
793
- .link_to_stream('5bdc58b7-e8a7-4621-afd6-ccb828d72457', fs2, version_1)
814
+ .append_to_stream([a = SRecord.new(event_id: "7010d298-ab69-4bb1-9251-f3466b5d1282")], s1, version_none)
815
+ .append_to_stream([b = SRecord.new(event_id: "34f88aca-aaba-4ca0-9256-8017b47528c5")], s1, version_0)
816
+ .append_to_stream([c = SRecord.new(event_id: "8e61c864-ceae-4684-8726-97c34eb8fc4f")], s1, version_1)
817
+ .append_to_stream([d = SRecord.new(event_id: "30963ed9-6349-450b-ac9b-8ea50115b3bd")], s1, version_2)
818
+ .append_to_stream([e = SRecord.new(event_id: "5bdc58b7-e8a7-4621-afd6-ccb828d72457")], s1, version_3)
819
+ .link_to_stream(["7010d298-ab69-4bb1-9251-f3466b5d1282"], fs1, version_none)
820
+ .link_to_stream(["34f88aca-aaba-4ca0-9256-8017b47528c5"], fs2, version_none)
821
+ .link_to_stream(["8e61c864-ceae-4684-8726-97c34eb8fc4f"], fs1, version_0)
822
+ .link_to_stream(["30963ed9-6349-450b-ac9b-8ea50115b3bd"], fs2, version_0)
823
+ .link_to_stream(["5bdc58b7-e8a7-4621-afd6-ccb828d72457"], fs2, version_1)
794
824
 
795
825
  expect(read_events_forward(repository, fs1)).to eq [a,c]
796
826
  expect(read_events_backward(repository, fs1)).to eq [c,a]
797
827
  end
798
828
 
799
- it 'reads batch of events from all streams forward & backward' do
829
+ it "reads batch of events from all streams forward & backward" do
800
830
  events = %w[
801
831
  96c920b1-cdd0-40f4-907c-861b9fff7d02
802
832
  56404f79-0ba0-4aa0-8524-dc3436368ca0
@@ -810,7 +840,7 @@ module RubyEventStore
810
840
  868cac42-3d19-4b39-84e8-cd32d65c2445
811
841
  ].map { |id| SRecord.new(event_id: id) }
812
842
  events.each do |ev|
813
- repository.append_to_stream(ev, Stream.new(SecureRandom.uuid), version_none)
843
+ repository.append_to_stream([ev], Stream.new(SecureRandom.uuid), version_none)
814
844
  end
815
845
 
816
846
  expect(read_events_forward(repository, count: 3)).to eq(events.first(3))
@@ -828,7 +858,7 @@ module RubyEventStore
828
858
  expect(read_events_backward(repository, to: events[4].event_id, count: 100)).to eq(events.last(5).reverse)
829
859
  end
830
860
 
831
- it 'linked events do not affect reading from all streams - no duplicates' do
861
+ it "linked events do not affect reading from all streams - no duplicates" do
832
862
  events = %w[
833
863
  96c920b1-cdd0-40f4-907c-861b9fff7d02
834
864
  56404f79-0ba0-4aa0-8524-dc3436368ca0
@@ -843,8 +873,8 @@ module RubyEventStore
843
873
  ].map { |id| SRecord.new(event_id: id) }
844
874
  events.each do |ev|
845
875
  repository
846
- .append_to_stream(ev, Stream.new(SecureRandom.uuid), version_none)
847
- .link_to_stream(ev.event_id, Stream.new(SecureRandom.uuid), version_none)
876
+ .append_to_stream([ev], Stream.new(SecureRandom.uuid), version_none)
877
+ .link_to_stream([ev.event_id], Stream.new(SecureRandom.uuid), version_none)
848
878
  end
849
879
 
850
880
  expect(read_events_forward(repository, count: 3)).to eq(events.first(3))
@@ -862,13 +892,13 @@ module RubyEventStore
862
892
  expect(read_events_backward(repository, to: events[4].event_id, count: 100)).to eq(events.last(5).reverse)
863
893
  end
864
894
 
865
- it 'reads events different uuid object but same content' do
895
+ it "reads events different uuid object but same content" do
866
896
  events = %w[
867
897
  96c920b1-cdd0-40f4-907c-861b9fff7d02
868
898
  56404f79-0ba0-4aa0-8524-dc3436368ca0
869
899
  ].map{|id| SRecord.new(event_id: id) }
870
- repository.append_to_stream(events.first, stream, version_none)
871
- repository.append_to_stream(events.last, stream, version_0)
900
+ repository.append_to_stream([events.first], stream, version_none)
901
+ repository.append_to_stream([events.last], stream, version_0)
872
902
 
873
903
  expect(read_events_forward(repository, from: "96c920b1-cdd0-40f4-907c-861b9fff7d02")).to eq([events.last])
874
904
  expect(read_events_backward(repository, from: "56404f79-0ba0-4aa0-8524-dc3436368ca0")).to eq([events.first])
@@ -881,84 +911,82 @@ module RubyEventStore
881
911
  expect(read_events_backward(repository, stream, to: "96c920b1-cdd0-40f4-907c-861b9fff7d02", count: 1)).to eq([events.last])
882
912
  end
883
913
 
884
- it 'does not allow same event twice in a stream' do
914
+ it "does not allow same event twice in a stream" do
885
915
  repository.append_to_stream(
886
- SRecord.new(event_id: "a1b49edb-7636-416f-874a-88f94b859bef"),
916
+ [SRecord.new(event_id: "a1b49edb-7636-416f-874a-88f94b859bef")],
887
917
  stream,
888
918
  version_none
889
919
  )
890
920
  expect do
891
921
  repository.append_to_stream(
892
- SRecord.new(event_id: "a1b49edb-7636-416f-874a-88f94b859bef"),
922
+ [SRecord.new(event_id: "a1b49edb-7636-416f-874a-88f94b859bef")],
893
923
  stream,
894
924
  version_0
895
925
  )
896
926
  end.to raise_error(EventDuplicatedInStream)
897
927
  end
898
928
 
899
- it 'does not allow same event twice' do
929
+ it "does not allow same event twice" do
900
930
  repository.append_to_stream(
901
- SRecord.new(event_id: "a1b49edb-7636-416f-874a-88f94b859bef"),
931
+ [SRecord.new(event_id: "a1b49edb-7636-416f-874a-88f94b859bef")],
902
932
  stream,
903
933
  version_none
904
934
  )
905
935
  expect do
906
936
  repository.append_to_stream(
907
- SRecord.new(event_id: "a1b49edb-7636-416f-874a-88f94b859bef"),
937
+ [SRecord.new(event_id: "a1b49edb-7636-416f-874a-88f94b859bef")],
908
938
  stream_other,
909
939
  version_none
910
940
  )
911
941
  end.to raise_error(EventDuplicatedInStream)
912
942
  end
913
943
 
914
- it 'does not allow linking same event twice in a stream' do
915
- repository.append_to_stream([
916
- SRecord.new(event_id: "a1b49edb-7636-416f-874a-88f94b859bef"),
917
- ], stream,
944
+ it "does not allow linking same event twice in a stream" do
945
+ repository.append_to_stream(
946
+ [SRecord.new(event_id: "a1b49edb-7636-416f-874a-88f94b859bef")],
947
+ stream,
918
948
  version_none
919
- ).link_to_stream("a1b49edb-7636-416f-874a-88f94b859bef", stream_flow, version_none)
949
+ ).link_to_stream(["a1b49edb-7636-416f-874a-88f94b859bef"], stream_flow, version_none)
920
950
  expect do
921
- repository.link_to_stream("a1b49edb-7636-416f-874a-88f94b859bef", stream_flow, version_0)
951
+ repository.link_to_stream(["a1b49edb-7636-416f-874a-88f94b859bef"], stream_flow, version_0)
922
952
  end.to raise_error(EventDuplicatedInStream)
923
953
  end
924
954
 
925
- it 'allows appending to GLOBAL_STREAM explicitly' do
955
+ it "allows appending to GLOBAL_STREAM explicitly" do
926
956
  event = SRecord.new(event_id: "df8b2ba3-4e2c-4888-8d14-4364855fa80e")
927
- repository.append_to_stream(event, global_stream, version_any)
957
+ repository.append_to_stream([event], global_stream, version_any)
928
958
 
929
959
  expect(read_events_forward(repository, count: 10)).to eq([event])
930
960
  end
931
961
 
932
962
  specify "events not persisted if append failed" do
933
- repository.append_to_stream([
934
- SRecord.new,
935
- ], stream, version_none)
963
+ repository.append_to_stream([SRecord.new], stream, version_none)
936
964
 
937
965
  expect do
938
- repository.append_to_stream([
939
- SRecord.new(
940
- event_id: '9bedf448-e4d0-41a3-a8cd-f94aec7aa763'
941
- ),
942
- ], stream, version_none)
966
+ repository.append_to_stream(
967
+ [SRecord.new(event_id: "9bedf448-e4d0-41a3-a8cd-f94aec7aa763")],
968
+ stream,
969
+ version_none
970
+ )
943
971
  end.to raise_error(WrongExpectedEventVersion)
944
- expect(repository.has_event?('9bedf448-e4d0-41a3-a8cd-f94aec7aa763')).to be_falsey
972
+ expect(repository.has_event?("9bedf448-e4d0-41a3-a8cd-f94aec7aa763")).to be false
945
973
  end
946
974
 
947
- specify 'linking non-existent event' do
975
+ specify "linking non-existent event" do
948
976
  expect do
949
- repository.link_to_stream('72922e65-1b32-4e97-8023-03ae81dd3a27', stream_flow, version_none)
977
+ repository.link_to_stream(["72922e65-1b32-4e97-8023-03ae81dd3a27"], stream_flow, version_none)
950
978
  end.to raise_error do |err|
951
979
  expect(err).to be_a(EventNotFound)
952
- expect(err.event_id).to eq('72922e65-1b32-4e97-8023-03ae81dd3a27')
953
- expect(err.message).to eq('Event not found: 72922e65-1b32-4e97-8023-03ae81dd3a27')
980
+ expect(err.event_id).to eq("72922e65-1b32-4e97-8023-03ae81dd3a27")
981
+ expect(err.message).to eq("Event not found: 72922e65-1b32-4e97-8023-03ae81dd3a27")
954
982
  end
955
983
  end
956
984
 
957
- specify 'read returns enumerator' do
985
+ specify "read returns enumerator" do
958
986
  expect(repository.read(specification.result)).to be_kind_of(Enumerator)
959
987
  end
960
988
 
961
- specify 'can store arbitrary binary data' do
989
+ specify "can store arbitrary binary data" do
962
990
  skip unless helper.supports_binary?
963
991
  binary = "\xB0"
964
992
  expect(binary.valid_encoding?).to eq(false)
@@ -966,7 +994,7 @@ module RubyEventStore
966
994
  expect(binary.valid_encoding?).to eq(true)
967
995
 
968
996
  repository.append_to_stream(
969
- event = SRecord.new(data: binary, metadata: binary),
997
+ [event = SRecord.new(data: binary, metadata: binary)],
970
998
  stream,
971
999
  version_none
972
1000
  )
@@ -974,6 +1002,8 @@ module RubyEventStore
974
1002
 
975
1003
  specify do
976
1004
  expect(repository.read(specification.in_batches.result)).to be_kind_of(Enumerator)
1005
+ expect(repository.read(specification.in_batches.as_at.result)).to be_kind_of(Enumerator)
1006
+ expect(repository.read(specification.in_batches.as_of.result)).to be_kind_of(Enumerator)
977
1007
  events = Array.new(10) { SRecord.new }
978
1008
  repository.append_to_stream(
979
1009
  events,
@@ -981,6 +1011,9 @@ module RubyEventStore
981
1011
  ExpectedVersion.none
982
1012
  )
983
1013
  expect(repository.read(specification.in_batches.result)).to be_kind_of(Enumerator)
1014
+ expect(repository.read(specification.in_batches.as_at.result)).to be_kind_of(Enumerator)
1015
+ expect(repository.read(specification.in_batches.as_of.result)).to be_kind_of(Enumerator)
1016
+
984
1017
  end
985
1018
 
986
1019
  specify do
@@ -1177,50 +1210,50 @@ module RubyEventStore
1177
1210
  end
1178
1211
 
1179
1212
  specify do
1180
- event_1 = SRecord.new(event_id: '8a6f053e-3ce2-4c82-a55b-4d02c66ae6ea')
1181
- event_2 = SRecord.new(event_id: '8cee1139-4f96-483a-a175-2b947283c3c7')
1182
- event_3 = SRecord.new(event_id: 'd345f86d-b903-4d78-803f-38990c078d9e')
1183
- stream_a = Stream.new('Stream A')
1184
- stream_b = Stream.new('Stream B')
1185
- stream_c = Stream.new('Stream C')
1213
+ event_1 = SRecord.new(event_id: "8a6f053e-3ce2-4c82-a55b-4d02c66ae6ea")
1214
+ event_2 = SRecord.new(event_id: "8cee1139-4f96-483a-a175-2b947283c3c7")
1215
+ event_3 = SRecord.new(event_id: "d345f86d-b903-4d78-803f-38990c078d9e")
1216
+ stream_a = Stream.new("Stream A")
1217
+ stream_b = Stream.new("Stream B")
1218
+ stream_c = Stream.new("Stream C")
1186
1219
  repository.append_to_stream([event_1, event_2], stream_a, version_any)
1187
1220
  repository.append_to_stream([event_3], stream_b, version_any)
1188
- repository.link_to_stream(event_1.event_id, stream_c, version_none)
1221
+ repository.link_to_stream([event_1.event_id], stream_c, version_none)
1189
1222
 
1190
- expect(repository.streams_of('8a6f053e-3ce2-4c82-a55b-4d02c66ae6ea')).to eq [stream_a, stream_c]
1191
- expect(repository.streams_of('8cee1139-4f96-483a-a175-2b947283c3c7')).to eq [stream_a]
1192
- expect(repository.streams_of('d345f86d-b903-4d78-803f-38990c078d9e')).to eq [stream_b]
1193
- expect(repository.streams_of('d10c8fe9-2163-418d-ba47-88c9a1f9391b')).to eq []
1223
+ expect(repository.streams_of("8a6f053e-3ce2-4c82-a55b-4d02c66ae6ea")).to eq [stream_a, stream_c]
1224
+ expect(repository.streams_of("8cee1139-4f96-483a-a175-2b947283c3c7")).to eq [stream_a]
1225
+ expect(repository.streams_of("d345f86d-b903-4d78-803f-38990c078d9e")).to eq [stream_b]
1226
+ expect(repository.streams_of("d10c8fe9-2163-418d-ba47-88c9a1f9391b")).to eq []
1194
1227
  end
1195
1228
 
1196
1229
  specify do
1197
- e1 = SRecord.new(event_id: '8a6f053e-3ce2-4c82-a55b-4d02c66ae6ea')
1198
- e2 = SRecord.new(event_id: '8cee1139-4f96-483a-a175-2b947283c3c7')
1199
- e3 = SRecord.new(event_id: 'd345f86d-b903-4d78-803f-38990c078d9e')
1200
- stream = Stream.new('Stream A')
1230
+ e1 = SRecord.new(event_id: "8a6f053e-3ce2-4c82-a55b-4d02c66ae6ea")
1231
+ e2 = SRecord.new(event_id: "8cee1139-4f96-483a-a175-2b947283c3c7")
1232
+ e3 = SRecord.new(event_id: "d345f86d-b903-4d78-803f-38990c078d9e")
1233
+ stream = Stream.new("Stream A")
1201
1234
  repository.append_to_stream([e1, e2, e3], stream, version_any)
1202
1235
 
1203
1236
  expect(repository.read(specification.with_id([
1204
- '8a6f053e-3ce2-4c82-a55b-4d02c66ae6ea'
1237
+ "8a6f053e-3ce2-4c82-a55b-4d02c66ae6ea"
1205
1238
  ]).read_first.result)).to eq(e1)
1206
1239
  expect(repository.read(specification.with_id([
1207
- 'd345f86d-b903-4d78-803f-38990c078d9e'
1240
+ "d345f86d-b903-4d78-803f-38990c078d9e"
1208
1241
  ]).read_first.result)).to eq(e3)
1209
1242
  expect(repository.read(specification.with_id([
1210
- 'c31b327c-0da1-4178-a3cd-d2f6bb5d0688'
1243
+ "c31b327c-0da1-4178-a3cd-d2f6bb5d0688"
1211
1244
  ]).read_first.result)).to eq(nil)
1212
1245
  expect(repository.read(specification.with_id([
1213
- '8a6f053e-3ce2-4c82-a55b-4d02c66ae6ea',
1214
- 'd345f86d-b903-4d78-803f-38990c078d9e'
1246
+ "8a6f053e-3ce2-4c82-a55b-4d02c66ae6ea",
1247
+ "d345f86d-b903-4d78-803f-38990c078d9e"
1215
1248
  ]).in_batches.result).to_a[0]).to eq([e1,e3])
1216
- expect(repository.read(specification.stream('Stream A').with_id([
1217
- '8cee1139-4f96-483a-a175-2b947283c3c7'
1249
+ expect(repository.read(specification.stream("Stream A").with_id([
1250
+ "8cee1139-4f96-483a-a175-2b947283c3c7"
1218
1251
  ]).read_first.result)).to eq(e2)
1219
- expect(repository.read(specification.stream('Stream B').with_id([
1220
- '8cee1139-4f96-483a-a175-2b947283c3c7'
1252
+ expect(repository.read(specification.stream("Stream B").with_id([
1253
+ "8cee1139-4f96-483a-a175-2b947283c3c7"
1221
1254
  ]).read_first.result)).to eq(nil)
1222
- expect(repository.read(specification.stream('Stream B').with_id([
1223
- 'c31b327c-0da1-4178-a3cd-d2f6bb5d0688'
1255
+ expect(repository.read(specification.stream("Stream B").with_id([
1256
+ "c31b327c-0da1-4178-a3cd-d2f6bb5d0688"
1224
1257
  ]).read_first.result)).to eq(nil)
1225
1258
  expect(repository.read(specification.with_id([]).result).to_a).to eq([])
1226
1259
  end
@@ -1229,7 +1262,7 @@ module RubyEventStore
1229
1262
  e1 = SRecord.new(event_type: Type1.to_s)
1230
1263
  e2 = SRecord.new(event_type: Type2.to_s)
1231
1264
  e3 = SRecord.new(event_type: Type1.to_s)
1232
- stream = Stream.new('Stream A')
1265
+ stream = Stream.new("Stream A")
1233
1266
  repository.append_to_stream([e1, e2, e3], stream, version_any)
1234
1267
 
1235
1268
  expect(repository.read(specification.of_type([Type1]).result).to_a).to eq([e1,e3])
@@ -1239,8 +1272,8 @@ module RubyEventStore
1239
1272
  end
1240
1273
 
1241
1274
  specify do
1242
- stream = Stream.new('Stream A')
1243
- dummy = Stream.new('Dummy')
1275
+ stream = Stream.new("Stream A")
1276
+ dummy = Stream.new("Dummy")
1244
1277
 
1245
1278
  expect(repository.count(specification.result)).to eq(0)
1246
1279
  (1..3).each do
@@ -1258,8 +1291,8 @@ module RubyEventStore
1258
1291
  expect(repository.count(specification.with_id([not_existing_uuid]).result)).to eq(0)
1259
1292
 
1260
1293
  expect(repository.count(specification.stream(stream.name).result)).to eq(3)
1261
- expect(repository.count(specification.stream('Dummy').result)).to eq(1)
1262
- expect(repository.count(specification.stream('not-existing-stream').result)).to eq(0)
1294
+ expect(repository.count(specification.stream("Dummy").result)).to eq(1)
1295
+ expect(repository.count(specification.stream("not-existing-stream").result)).to eq(0)
1263
1296
 
1264
1297
  repository.append_to_stream([SRecord.new(event_type: Type1.to_s)], dummy, version_any)
1265
1298
  expect(repository.count(specification.from(event_id).result)).to eq(1)
@@ -1279,100 +1312,100 @@ module RubyEventStore
1279
1312
  expect(repository.count(specification.stream(stream.name).of_type([Type3]).result)).to eq(0)
1280
1313
  end
1281
1314
 
1282
- specify 'timestamp precision' do
1315
+ specify "timestamp precision" do
1283
1316
  time = Time.utc(2020, 9, 11, 12, 26, 0, 123456)
1284
- repository.append_to_stream(SRecord.new(timestamp: time), stream, version_none)
1317
+ repository.append_to_stream([SRecord.new(timestamp: time)], stream, version_none)
1285
1318
  event = read_events_forward(repository, count: 1).first
1286
1319
 
1287
1320
  expect(event.timestamp).to eq(time)
1288
1321
  end
1289
1322
 
1290
- specify 'fetching records older than specified date in stream' do
1291
- event_1 = SRecord.new(event_id: '8a6f053e-3ce2-4c82-a55b-4d02c66ae6ea', timestamp: Time.utc(2020, 1, 1))
1292
- event_2 = SRecord.new(event_id: '8cee1139-4f96-483a-a175-2b947283c3c7', timestamp: Time.utc(2020, 1, 2))
1293
- event_3 = SRecord.new(event_id: 'd345f86d-b903-4d78-803f-38990c078d9e', timestamp: Time.utc(2020, 1, 3))
1294
- repository.append_to_stream([event_1, event_2, event_3], Stream.new('whatever'), version_any)
1323
+ specify "fetching records older than specified date in stream" do
1324
+ event_1 = SRecord.new(event_id: "8a6f053e-3ce2-4c82-a55b-4d02c66ae6ea", timestamp: Time.utc(2020, 1, 1))
1325
+ event_2 = SRecord.new(event_id: "8cee1139-4f96-483a-a175-2b947283c3c7", timestamp: Time.utc(2020, 1, 2))
1326
+ event_3 = SRecord.new(event_id: "d345f86d-b903-4d78-803f-38990c078d9e", timestamp: Time.utc(2020, 1, 3))
1327
+ repository.append_to_stream([event_1, event_2, event_3], Stream.new("whatever"), version_any)
1295
1328
 
1296
- expect(repository.read(specification.stream('whatever').older_than(Time.utc(2020, 1, 2)).result).to_a).to eq([event_1])
1329
+ expect(repository.read(specification.stream("whatever").older_than(Time.utc(2020, 1, 2)).result).to_a).to eq([event_1])
1297
1330
  end
1298
1331
 
1299
- specify 'fetching records older than or equal to specified date in stream' do
1300
- event_1 = SRecord.new(event_id: '8a6f053e-3ce2-4c82-a55b-4d02c66ae6ea', timestamp: Time.utc(2020, 1, 1))
1301
- event_2 = SRecord.new(event_id: '8cee1139-4f96-483a-a175-2b947283c3c7', timestamp: Time.utc(2020, 1, 2))
1302
- event_3 = SRecord.new(event_id: 'd345f86d-b903-4d78-803f-38990c078d9e', timestamp: Time.utc(2020, 1, 3))
1303
- repository.append_to_stream([event_1, event_2, event_3], Stream.new('whatever'), version_any)
1332
+ specify "fetching records older than or equal to specified date in stream" do
1333
+ event_1 = SRecord.new(event_id: "8a6f053e-3ce2-4c82-a55b-4d02c66ae6ea", timestamp: Time.utc(2020, 1, 1))
1334
+ event_2 = SRecord.new(event_id: "8cee1139-4f96-483a-a175-2b947283c3c7", timestamp: Time.utc(2020, 1, 2))
1335
+ event_3 = SRecord.new(event_id: "d345f86d-b903-4d78-803f-38990c078d9e", timestamp: Time.utc(2020, 1, 3))
1336
+ repository.append_to_stream([event_1, event_2, event_3], Stream.new("whatever"), version_any)
1304
1337
 
1305
- expect(repository.read(specification.stream('whatever').older_than_or_equal(Time.utc(2020, 1, 2)).result).to_a).to eq([event_1, event_2])
1338
+ expect(repository.read(specification.stream("whatever").older_than_or_equal(Time.utc(2020, 1, 2)).result).to_a).to eq([event_1, event_2])
1306
1339
  end
1307
1340
 
1308
- specify 'fetching records newer than specified date in stream' do
1309
- event_1 = SRecord.new(event_id: '8a6f053e-3ce2-4c82-a55b-4d02c66ae6ea', timestamp: Time.utc(2020, 1, 1))
1310
- event_2 = SRecord.new(event_id: '8cee1139-4f96-483a-a175-2b947283c3c7', timestamp: Time.utc(2020, 1, 2))
1311
- event_3 = SRecord.new(event_id: 'd345f86d-b903-4d78-803f-38990c078d9e', timestamp: Time.utc(2020, 1, 3))
1312
- repository.append_to_stream([event_1, event_2, event_3], Stream.new('whatever'), version_any)
1341
+ specify "fetching records newer than specified date in stream" do
1342
+ event_1 = SRecord.new(event_id: "8a6f053e-3ce2-4c82-a55b-4d02c66ae6ea", timestamp: Time.utc(2020, 1, 1))
1343
+ event_2 = SRecord.new(event_id: "8cee1139-4f96-483a-a175-2b947283c3c7", timestamp: Time.utc(2020, 1, 2))
1344
+ event_3 = SRecord.new(event_id: "d345f86d-b903-4d78-803f-38990c078d9e", timestamp: Time.utc(2020, 1, 3))
1345
+ repository.append_to_stream([event_1, event_2, event_3], Stream.new("whatever"), version_any)
1313
1346
 
1314
- expect(repository.read(specification.stream('whatever').newer_than(Time.utc(2020, 1, 2)).result).to_a).to eq([event_3])
1347
+ expect(repository.read(specification.stream("whatever").newer_than(Time.utc(2020, 1, 2)).result).to_a).to eq([event_3])
1315
1348
  end
1316
1349
 
1317
- specify 'fetching records newer than or equal to specified date in stream' do
1318
- event_1 = SRecord.new(event_id: '8a6f053e-3ce2-4c82-a55b-4d02c66ae6ea', timestamp: Time.utc(2020, 1, 1))
1319
- event_2 = SRecord.new(event_id: '8cee1139-4f96-483a-a175-2b947283c3c7', timestamp: Time.utc(2020, 1, 2))
1320
- event_3 = SRecord.new(event_id: 'd345f86d-b903-4d78-803f-38990c078d9e', timestamp: Time.utc(2020, 1, 3))
1321
- repository.append_to_stream([event_1, event_2, event_3], Stream.new('whatever'), version_any)
1350
+ specify "fetching records newer than or equal to specified date in stream" do
1351
+ event_1 = SRecord.new(event_id: "8a6f053e-3ce2-4c82-a55b-4d02c66ae6ea", timestamp: Time.utc(2020, 1, 1))
1352
+ event_2 = SRecord.new(event_id: "8cee1139-4f96-483a-a175-2b947283c3c7", timestamp: Time.utc(2020, 1, 2))
1353
+ event_3 = SRecord.new(event_id: "d345f86d-b903-4d78-803f-38990c078d9e", timestamp: Time.utc(2020, 1, 3))
1354
+ repository.append_to_stream([event_1, event_2, event_3], Stream.new("whatever"), version_any)
1322
1355
 
1323
- expect(repository.read(specification.stream('whatever').newer_than_or_equal(Time.utc(2020, 1, 2)).result).to_a).to eq([event_2, event_3])
1356
+ expect(repository.read(specification.stream("whatever").newer_than_or_equal(Time.utc(2020, 1, 2)).result).to_a).to eq([event_2, event_3])
1324
1357
  end
1325
1358
 
1326
- specify 'fetching records older than specified date' do
1327
- event_1 = SRecord.new(event_id: '8a6f053e-3ce2-4c82-a55b-4d02c66ae6ea', timestamp: Time.utc(2020, 1, 1))
1328
- event_2 = SRecord.new(event_id: '8cee1139-4f96-483a-a175-2b947283c3c7', timestamp: Time.utc(2020, 1, 2))
1329
- event_3 = SRecord.new(event_id: 'd345f86d-b903-4d78-803f-38990c078d9e', timestamp: Time.utc(2020, 1, 3))
1330
- repository.append_to_stream([event_1, event_2, event_3], Stream.new('whatever'), version_any)
1359
+ specify "fetching records older than specified date" do
1360
+ event_1 = SRecord.new(event_id: "8a6f053e-3ce2-4c82-a55b-4d02c66ae6ea", timestamp: Time.utc(2020, 1, 1))
1361
+ event_2 = SRecord.new(event_id: "8cee1139-4f96-483a-a175-2b947283c3c7", timestamp: Time.utc(2020, 1, 2))
1362
+ event_3 = SRecord.new(event_id: "d345f86d-b903-4d78-803f-38990c078d9e", timestamp: Time.utc(2020, 1, 3))
1363
+ repository.append_to_stream([event_1, event_2, event_3], Stream.new("whatever"), version_any)
1331
1364
 
1332
1365
  expect(repository.read(specification.older_than(Time.utc(2020, 1, 2)).result).to_a).to eq([event_1])
1333
1366
  end
1334
1367
 
1335
- specify 'fetching records older than or equal to specified date' do
1336
- event_1 = SRecord.new(event_id: '8a6f053e-3ce2-4c82-a55b-4d02c66ae6ea', timestamp: Time.utc(2020, 1, 1))
1337
- event_2 = SRecord.new(event_id: '8cee1139-4f96-483a-a175-2b947283c3c7', timestamp: Time.utc(2020, 1, 2))
1338
- event_3 = SRecord.new(event_id: 'd345f86d-b903-4d78-803f-38990c078d9e', timestamp: Time.utc(2020, 1, 3))
1339
- repository.append_to_stream([event_1, event_2, event_3], Stream.new('whatever'), version_any)
1368
+ specify "fetching records older than or equal to specified date" do
1369
+ event_1 = SRecord.new(event_id: "8a6f053e-3ce2-4c82-a55b-4d02c66ae6ea", timestamp: Time.utc(2020, 1, 1))
1370
+ event_2 = SRecord.new(event_id: "8cee1139-4f96-483a-a175-2b947283c3c7", timestamp: Time.utc(2020, 1, 2))
1371
+ event_3 = SRecord.new(event_id: "d345f86d-b903-4d78-803f-38990c078d9e", timestamp: Time.utc(2020, 1, 3))
1372
+ repository.append_to_stream([event_1, event_2, event_3], Stream.new("whatever"), version_any)
1340
1373
 
1341
1374
  expect(repository.read(specification.older_than_or_equal(Time.utc(2020, 1, 2)).result).to_a).to eq([event_1, event_2])
1342
1375
  end
1343
1376
 
1344
- specify 'fetching records newer than specified date' do
1345
- event_1 = SRecord.new(event_id: '8a6f053e-3ce2-4c82-a55b-4d02c66ae6ea', timestamp: Time.utc(2020, 1, 1))
1346
- event_2 = SRecord.new(event_id: '8cee1139-4f96-483a-a175-2b947283c3c7', timestamp: Time.utc(2020, 1, 2))
1347
- event_3 = SRecord.new(event_id: 'd345f86d-b903-4d78-803f-38990c078d9e', timestamp: Time.utc(2020, 1, 3))
1348
- repository.append_to_stream([event_1, event_2, event_3], Stream.new('whatever'), version_any)
1377
+ specify "fetching records newer than specified date" do
1378
+ event_1 = SRecord.new(event_id: "8a6f053e-3ce2-4c82-a55b-4d02c66ae6ea", timestamp: Time.utc(2020, 1, 1))
1379
+ event_2 = SRecord.new(event_id: "8cee1139-4f96-483a-a175-2b947283c3c7", timestamp: Time.utc(2020, 1, 2))
1380
+ event_3 = SRecord.new(event_id: "d345f86d-b903-4d78-803f-38990c078d9e", timestamp: Time.utc(2020, 1, 3))
1381
+ repository.append_to_stream([event_1, event_2, event_3], Stream.new("whatever"), version_any)
1349
1382
 
1350
1383
  expect(repository.read(specification.newer_than(Time.utc(2020, 1, 2)).result).to_a).to eq([event_3])
1351
1384
  end
1352
1385
 
1353
- specify 'fetching records newer than or equal to specified date' do
1354
- event_1 = SRecord.new(event_id: '8a6f053e-3ce2-4c82-a55b-4d02c66ae6ea', timestamp: Time.utc(2020, 1, 1))
1355
- event_2 = SRecord.new(event_id: '8cee1139-4f96-483a-a175-2b947283c3c7', timestamp: Time.utc(2020, 1, 2))
1356
- event_3 = SRecord.new(event_id: 'd345f86d-b903-4d78-803f-38990c078d9e', timestamp: Time.utc(2020, 1, 3))
1357
- repository.append_to_stream([event_1, event_2, event_3], Stream.new('whatever'), version_any)
1386
+ specify "fetching records newer than or equal to specified date" do
1387
+ event_1 = SRecord.new(event_id: "8a6f053e-3ce2-4c82-a55b-4d02c66ae6ea", timestamp: Time.utc(2020, 1, 1))
1388
+ event_2 = SRecord.new(event_id: "8cee1139-4f96-483a-a175-2b947283c3c7", timestamp: Time.utc(2020, 1, 2))
1389
+ event_3 = SRecord.new(event_id: "d345f86d-b903-4d78-803f-38990c078d9e", timestamp: Time.utc(2020, 1, 3))
1390
+ repository.append_to_stream([event_1, event_2, event_3], Stream.new("whatever"), version_any)
1358
1391
 
1359
1392
  expect(repository.read(specification.newer_than_or_equal(Time.utc(2020, 1, 2)).result).to_a).to eq([event_2, event_3])
1360
1393
  end
1361
1394
 
1362
- specify 'fetching records from disjoint periods' do
1363
- event_1 = SRecord.new(event_id: '8a6f053e-3ce2-4c82-a55b-4d02c66ae6ea', timestamp: Time.utc(2020, 1, 1))
1364
- event_2 = SRecord.new(event_id: '8cee1139-4f96-483a-a175-2b947283c3c7', timestamp: Time.utc(2020, 1, 2))
1365
- event_3 = SRecord.new(event_id: 'd345f86d-b903-4d78-803f-38990c078d9e', timestamp: Time.utc(2020, 1, 3))
1366
- repository.append_to_stream([event_1, event_2, event_3], Stream.new('whatever'), version_any)
1395
+ specify "fetching records from disjoint periods" do
1396
+ event_1 = SRecord.new(event_id: "8a6f053e-3ce2-4c82-a55b-4d02c66ae6ea", timestamp: Time.utc(2020, 1, 1))
1397
+ event_2 = SRecord.new(event_id: "8cee1139-4f96-483a-a175-2b947283c3c7", timestamp: Time.utc(2020, 1, 2))
1398
+ event_3 = SRecord.new(event_id: "d345f86d-b903-4d78-803f-38990c078d9e", timestamp: Time.utc(2020, 1, 3))
1399
+ repository.append_to_stream([event_1, event_2, event_3], Stream.new("whatever"), version_any)
1367
1400
 
1368
1401
  expect(repository.read(specification.older_than(Time.utc(2020, 1, 2)).newer_than(Time.utc(2020, 1, 2)).result).to_a).to eq([])
1369
1402
  end
1370
1403
 
1371
- specify 'fetching records within time range' do
1372
- event_1 = SRecord.new(event_id: '8a6f053e-3ce2-4c82-a55b-4d02c66ae6ea', timestamp: Time.utc(2020, 1, 1))
1373
- event_2 = SRecord.new(event_id: '8cee1139-4f96-483a-a175-2b947283c3c7', timestamp: Time.utc(2020, 1, 2))
1374
- event_3 = SRecord.new(event_id: 'd345f86d-b903-4d78-803f-38990c078d9e', timestamp: Time.utc(2020, 1, 3))
1375
- repository.append_to_stream([event_1, event_2, event_3], Stream.new('whatever'), version_any)
1404
+ specify "fetching records within time range" do
1405
+ event_1 = SRecord.new(event_id: "8a6f053e-3ce2-4c82-a55b-4d02c66ae6ea", timestamp: Time.utc(2020, 1, 1))
1406
+ event_2 = SRecord.new(event_id: "8cee1139-4f96-483a-a175-2b947283c3c7", timestamp: Time.utc(2020, 1, 2))
1407
+ event_3 = SRecord.new(event_id: "d345f86d-b903-4d78-803f-38990c078d9e", timestamp: Time.utc(2020, 1, 3))
1408
+ repository.append_to_stream([event_1, event_2, event_3], Stream.new("whatever"), version_any)
1376
1409
 
1377
1410
  expect(repository.read(specification.between(Time.utc(2020, 1, 1)...Time.utc(2020, 1, 3)).result).to_a).to eq([event_1, event_2])
1378
1411
  end
@@ -1386,11 +1419,35 @@ module RubyEventStore
1386
1419
  Stream.new("Dummy"),
1387
1420
  ExpectedVersion.any
1388
1421
  )
1389
- expect(repository.read(specification.result).map(&:event_id)).to eq [e1, e2, e3]
1390
- expect(repository.read(specification.as_at.result).map(&:event_id)).to eq [e1, e3, e2]
1391
- expect(repository.read(specification.as_at.backward.result).map(&:event_id)).to eq [e2, e3, e1]
1392
- expect(repository.read(specification.as_of.result).map(&:event_id)).to eq [e3, e2, e1]
1393
- expect(repository.read(specification.as_of.backward.result).map(&:event_id)).to eq [e1, e2, e3]
1422
+ expect(repository.read(specification.result)).to eq_ids([e1, e2, e3])
1423
+ expect(repository.read(specification.as_at.result)).to eq_ids([e1, e3, e2])
1424
+ expect(repository.read(specification.as_at.backward.result)).to eq_ids([e2, e3, e1])
1425
+ expect(repository.read(specification.as_of.result)).to eq_ids([e3, e2, e1])
1426
+ expect(repository.read(specification.as_of.backward.result)).to eq_ids([e1, e2, e3])
1427
+ end
1428
+
1429
+ specify "time order is respected with batches" do
1430
+ repository.append_to_stream([
1431
+ SRecord.new(event_id: e1 = SecureRandom.uuid, timestamp: Time.new(2020,1,1), valid_at: Time.new(2020,1,9)),
1432
+ SRecord.new(event_id: e2 = SecureRandom.uuid, timestamp: Time.new(2020,1,3), valid_at: Time.new(2020,1,6)),
1433
+ SRecord.new(event_id: e3 = SecureRandom.uuid, timestamp: Time.new(2020,1,2), valid_at: Time.new(2020,1,3)),
1434
+ ],
1435
+ Stream.new("Dummy"),
1436
+ ExpectedVersion.any
1437
+ )
1438
+ expect(repository.read(specification.in_batches.result).to_a.flatten).to eq_ids([e1, e2, e3])
1439
+ expect(repository.read(specification.in_batches.as_at.result).to_a.flatten).to eq_ids([e1, e3, e2])
1440
+ expect(repository.read(specification.in_batches.as_at.backward.result).to_a.flatten).to eq_ids([e2, e3, e1])
1441
+ expect(repository.read(specification.in_batches.as_of.result).to_a.flatten).to eq_ids([e3, e2, e1])
1442
+ expect(repository.read(specification.in_batches.as_of.backward.result).to_a.flatten).to eq_ids([e1, e2, e3])
1443
+ end
1444
+ end
1445
+
1446
+ ::RSpec::Matchers.define :eq_ids do |expected_ids|
1447
+ match do |enum|
1448
+ @actual = enum.map(&:event_id)
1449
+ expected_ids == @actual
1394
1450
  end
1451
+ diffable
1395
1452
  end
1396
1453
  end