ruby_event_store 1.3.1 → 2.0.3

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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -4
  3. data/Gemfile.lock +121 -0
  4. data/Makefile +13 -3
  5. data/lib/ruby_event_store/broker.rb +3 -3
  6. data/lib/ruby_event_store/client.rb +47 -23
  7. data/lib/ruby_event_store/composed_dispatcher.rb +2 -2
  8. data/lib/ruby_event_store/constants.rb +1 -0
  9. data/lib/ruby_event_store/errors.rb +0 -1
  10. data/lib/ruby_event_store/event.rb +8 -1
  11. data/lib/ruby_event_store/immediate_async_dispatcher.rb +2 -2
  12. data/lib/ruby_event_store/in_memory_repository.rb +98 -59
  13. data/lib/ruby_event_store/instrumented_dispatcher.rb +2 -2
  14. data/lib/ruby_event_store/mappers/default.rb +28 -6
  15. data/lib/ruby_event_store/mappers/deprecated_wrapper.rb +33 -0
  16. data/lib/ruby_event_store/mappers/encryption_mapper.rb +1 -4
  17. data/lib/ruby_event_store/mappers/instrumented_mapper.rb +8 -4
  18. data/lib/ruby_event_store/mappers/json_mapper.rb +2 -4
  19. data/lib/ruby_event_store/mappers/pipeline.rb +26 -5
  20. data/lib/ruby_event_store/mappers/pipeline_mapper.rb +6 -2
  21. data/lib/ruby_event_store/mappers/transformation/domain_event.rb +16 -8
  22. data/lib/ruby_event_store/mappers/transformation/encryption.rb +20 -12
  23. data/lib/ruby_event_store/mappers/transformation/event_class_remapper.rb +11 -4
  24. data/lib/ruby_event_store/mappers/transformation/serialization.rb +16 -14
  25. data/lib/ruby_event_store/mappers/transformation/stringify_metadata_keys.rb +12 -7
  26. data/lib/ruby_event_store/mappers/transformation/symbolize_metadata_keys.rb +12 -7
  27. data/lib/ruby_event_store/null.rb +13 -0
  28. data/lib/ruby_event_store/projection.rb +2 -13
  29. data/lib/ruby_event_store/record.rb +68 -0
  30. data/lib/ruby_event_store/serialized_record.rb +23 -4
  31. data/lib/ruby_event_store/spec/broker_lint.rb +9 -9
  32. data/lib/ruby_event_store/spec/event_repository_lint.rb +200 -36
  33. data/lib/ruby_event_store/spec/mapper_lint.rb +6 -6
  34. data/lib/ruby_event_store/spec/subscriptions_lint.rb +6 -0
  35. data/lib/ruby_event_store/specification.rb +100 -7
  36. data/lib/ruby_event_store/specification_reader.rb +2 -2
  37. data/lib/ruby_event_store/specification_result.rb +86 -2
  38. data/lib/ruby_event_store/version.rb +1 -1
  39. data/lib/ruby_event_store.rb +4 -7
  40. data/ruby_event_store.gemspec +1 -3
  41. metadata +7 -9
  42. data/lib/ruby_event_store/mappers/protobuf.rb +0 -24
  43. data/lib/ruby_event_store/mappers/transformation/item.rb +0 -56
  44. data/lib/ruby_event_store/mappers/transformation/proto_event.rb +0 -17
  45. data/lib/ruby_event_store/mappers/transformation/protobuf_encoder.rb +0 -30
  46. data/lib/ruby_event_store/mappers/transformation/protobuf_nested_struct_metadata.rb +0 -30
  47. data/lib/ruby_event_store/mappers/transformation/serialized_record.rb +0 -27
@@ -3,15 +3,19 @@ module RubyEventStore
3
3
  class SRecord
4
4
  def self.new(
5
5
  event_id: SecureRandom.uuid,
6
- data: '{}',
7
- metadata: '{}',
8
- event_type: 'SRecordTestEvent'
6
+ data: {},
7
+ metadata: {},
8
+ event_type: 'SRecordTestEvent',
9
+ timestamp: Time.new.utc,
10
+ valid_at: nil
9
11
  )
10
- SerializedRecord.new(
12
+ Record.new(
11
13
  event_id: event_id,
12
14
  data: data,
13
15
  metadata: metadata,
14
16
  event_type: event_type,
17
+ timestamp: timestamp.round(TIMESTAMP_PRECISION),
18
+ valid_at: (valid_at || timestamp).round(TIMESTAMP_PRECISION),
15
19
  )
16
20
  end
17
21
  end
@@ -22,13 +26,45 @@ module RubyEventStore
22
26
  Type2 = Class.new(RubyEventStore::Event)
23
27
  # @private
24
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
25
62
  end
26
63
 
27
64
  module RubyEventStore
28
- RSpec.shared_examples :event_repository do |repository_class, rescuable_concurrency_test_errors = []|
29
- let(:repository) { subject || repository_class.new }
30
- let(:mapper) { Mappers::NullMapper.new }
31
- let(:specification) { Specification.new(SpecificationReader.new(repository, mapper)) }
65
+ ::RSpec.shared_examples :event_repository do
66
+ let(:helper) { EventRepositoryHelper.new }
67
+ let(:specification) { Specification.new(SpecificationReader.new(repository, Mappers::NullMapper.new)) }
32
68
  let(:global_stream) { Stream.new(GLOBAL_STREAM) }
33
69
  let(:stream) { Stream.new(SecureRandom.uuid) }
34
70
  let(:stream_flow) { Stream.new('flow') }
@@ -42,6 +78,11 @@ module RubyEventStore
42
78
  let(:version_2) { ExpectedVersion.new(2) }
43
79
  let(:version_3) { ExpectedVersion.new(3) }
44
80
 
81
+ def verify_conncurency_assumptions
82
+ return unless helper.has_connection_pooling?
83
+ expect(helper.connection_pool_size).to eq(5)
84
+ end
85
+
45
86
  def read_events(scope, stream = nil, from: nil, to: nil, count: nil)
46
87
  scope = scope.stream(stream.name) if stream
47
88
  scope = scope.from(from) if from
@@ -393,7 +434,7 @@ module RubyEventStore
393
434
  end
394
435
 
395
436
  specify 'unlimited concurrency for :any - everything should succeed', timeout: 10, mutant: false do
396
- skip unless test_race_conditions_any
437
+ skip unless helper.supports_concurrent_any?
397
438
  verify_conncurency_assumptions
398
439
  begin
399
440
  concurrency_level = 4
@@ -426,12 +467,12 @@ module RubyEventStore
426
467
  end
427
468
  expect(events0).to eq(events0.sort_by{|ev| ev.event_id })
428
469
  ensure
429
- cleanup_concurrency_test
470
+ helper.cleanup_concurrency_test
430
471
  end
431
472
  end
432
473
 
433
474
  specify 'unlimited concurrency for :any - everything should succeed when linking', timeout: 10, mutant: false do
434
- skip unless test_race_conditions_any
475
+ skip unless helper.supports_concurrent_any?
435
476
  verify_conncurency_assumptions
436
477
  begin
437
478
  concurrency_level = 4
@@ -471,12 +512,12 @@ module RubyEventStore
471
512
  end
472
513
  expect(events0).to eq(events0.sort_by{|ev| ev.event_id })
473
514
  ensure
474
- cleanup_concurrency_test
515
+ helper.cleanup_concurrency_test
475
516
  end
476
517
  end
477
518
 
478
519
  specify 'limited concurrency for :auto - some operations will fail without outside lock, stream is ordered', mutant: false do
479
- skip unless test_race_conditions_auto
520
+ skip unless helper.supports_concurrent_auto?
480
521
  verify_conncurency_assumptions
481
522
  begin
482
523
  concurrency_level = 4
@@ -494,7 +535,7 @@ module RubyEventStore
494
535
  SRecord.new(event_id: eid),
495
536
  ], stream, version_auto)
496
537
  sleep(rand(concurrency_level) / 1000.0)
497
- rescue WrongExpectedEventVersion, *rescuable_concurrency_test_errors
538
+ rescue WrongExpectedEventVersion, *helper.rescuable_concurrency_test_errors
498
539
  fail_occurred +=1
499
540
  end
500
541
  end
@@ -510,14 +551,14 @@ module RubyEventStore
510
551
  ev.event_id.start_with?("0-")
511
552
  end
512
553
  expect(events0).to eq(events0.sort_by{|ev| ev.event_id })
513
- additional_limited_concurrency_for_auto_check
554
+ additional_limited_concurrency_for_auto_check if defined? additional_limited_concurrency_for_auto_check
514
555
  ensure
515
- cleanup_concurrency_test
556
+ helper.cleanup_concurrency_test
516
557
  end
517
558
  end
518
559
 
519
560
  specify 'limited concurrency for :auto - some operations will fail without outside lock, stream is ordered', mutant: false do
520
- skip unless test_race_conditions_auto
561
+ skip unless helper.supports_concurrent_auto?
521
562
  verify_conncurency_assumptions
522
563
  begin
523
564
  concurrency_level = 4
@@ -542,7 +583,7 @@ module RubyEventStore
542
583
  eid = "0000000#{i}-#{sprintf("%04d", j)}-0000-0000-000000000000"
543
584
  repository.link_to_stream(eid, stream, version_auto)
544
585
  sleep(rand(concurrency_level) / 1000.0)
545
- rescue WrongExpectedEventVersion, *rescuable_concurrency_test_errors
586
+ rescue WrongExpectedEventVersion, *helper.rescuable_concurrency_test_errors
546
587
  fail_occurred +=1
547
588
  end
548
589
  end
@@ -558,9 +599,9 @@ module RubyEventStore
558
599
  ev.event_id.start_with?("0-")
559
600
  end
560
601
  expect(events0).to eq(events0.sort_by{|ev| ev.event_id })
561
- additional_limited_concurrency_for_auto_check
602
+ additional_limited_concurrency_for_auto_check if defined? additional_limited_concurrency_for_auto_check
562
603
  ensure
563
- cleanup_concurrency_test
604
+ helper.cleanup_concurrency_test
564
605
  end
565
606
  end
566
607
 
@@ -573,30 +614,30 @@ module RubyEventStore
573
614
  end
574
615
 
575
616
  it 'data attributes are retrieved' do
576
- event = SRecord.new(data: '{"order_id":3}')
617
+ event = SRecord.new(data: { "order_id" => 3 })
577
618
  repository.append_to_stream(event, stream, version_any)
578
619
  retrieved_event = read_events_forward(repository, count: 1).first
579
- expect(retrieved_event.data).to eq('{"order_id":3}')
620
+ expect(retrieved_event.data).to eq({ "order_id" => 3 })
580
621
  end
581
622
 
582
623
  it 'metadata attributes are retrieved' do
583
- event = SRecord.new(metadata: '{"request_id":3}')
624
+ event = SRecord.new(metadata: { "request_id" => 3 })
584
625
  repository.append_to_stream(event, stream, version_any)
585
626
  retrieved_event = read_events_forward(repository, count: 1).first
586
- expect(retrieved_event.metadata).to eq('{"request_id":3}')
627
+ expect(retrieved_event.metadata).to eq({ "request_id" => 3 })
587
628
  end
588
629
 
589
630
  it 'data and metadata attributes are retrieved when linking' do
590
631
  event = SRecord.new(
591
- data: '{"order_id":3}',
592
- metadata: '{"request_id":4}',
632
+ data: { "order_id" => 3 },
633
+ metadata: { "request_id" => 4},
593
634
  )
594
635
  repository
595
636
  .append_to_stream(event, stream, version_any)
596
637
  .link_to_stream(event.event_id, stream_flow, version_any)
597
638
  retrieved_event = read_events_forward(repository, stream_flow).first
598
- expect(retrieved_event.metadata).to eq('{"request_id":4}')
599
- expect(retrieved_event.data).to eq('{"order_id":3}')
639
+ expect(retrieved_event.metadata).to eq({ "request_id" => 4 })
640
+ expect(retrieved_event.data).to eq({ "order_id" => 3 })
600
641
  expect(event).to eq(retrieved_event)
601
642
  end
602
643
 
@@ -918,7 +959,7 @@ module RubyEventStore
918
959
  end
919
960
 
920
961
  specify 'can store arbitrary binary data' do
921
- skip unless test_binary
962
+ skip unless helper.supports_binary?
922
963
  binary = "\xB0"
923
964
  expect(binary.valid_encoding?).to eq(false)
924
965
  binary.force_encoding("binary")
@@ -1091,7 +1132,7 @@ module RubyEventStore
1091
1132
 
1092
1133
  context "#update_messages" do
1093
1134
  specify "changes events" do
1094
- skip unless test_change
1135
+ skip unless helper.supports_upsert?
1095
1136
  events = Array.new(5) { SRecord.new }
1096
1137
  repository.append_to_stream(
1097
1138
  events[0..2],
@@ -1104,19 +1145,20 @@ module RubyEventStore
1104
1145
  ExpectedVersion.any
1105
1146
  )
1106
1147
  repository.update_messages([
1107
- a = SRecord.new(event_id: events[0].event_id.clone, data: events[0].data, metadata: events[0].metadata, event_type: events[0].event_type),
1108
- b = SRecord.new(event_id: events[1].event_id.dup, data: '{"test":1}', metadata: events[1].metadata, event_type: events[1].event_type),
1109
- c = SRecord.new(event_id: events[2].event_id, data: events[2].data, metadata: '{"test":2}', event_type: events[2].event_type),
1110
- d = SRecord.new(event_id: events[3].event_id.clone, data: events[3].data, metadata: events[3].metadata, event_type: "event_type3"),
1111
- e = SRecord.new(event_id: events[4].event_id.dup, data: '{"test":4}', metadata: '{"test":42}', event_type: "event_type4"),
1148
+ a = SRecord.new(event_id: events[0].event_id.clone, data: events[0].data, metadata: events[0].metadata, event_type: events[0].event_type, timestamp: events[0].timestamp),
1149
+ b = SRecord.new(event_id: events[1].event_id.dup, data: { "test" => 1 }, metadata: events[1].metadata, event_type: events[1].event_type, timestamp: events[1].timestamp),
1150
+ c = SRecord.new(event_id: events[2].event_id, data: events[2].data, metadata: { "test" => 2 }, event_type: events[2].event_type, timestamp: events[2].timestamp),
1151
+ d = SRecord.new(event_id: events[3].event_id.clone, data: events[3].data, metadata: events[3].metadata, event_type: "event_type3", timestamp: events[3].timestamp),
1152
+ e = SRecord.new(event_id: events[4].event_id.dup, data: { "test" => 4 }, metadata: { "test" => 42 }, event_type: "event_type4", timestamp: events[4].timestamp),
1112
1153
  ])
1154
+
1113
1155
  expect(repository.read(specification.result).to_a).to eq([a,b,c,d,e])
1114
1156
  expect(repository.read(specification.stream("whatever").result).to_a).to eq([a,b,c])
1115
1157
  expect(repository.read(specification.stream("elo").result).to_a).to eq([d,e])
1116
1158
  end
1117
1159
 
1118
1160
  specify "cannot change unexisting event" do
1119
- skip unless test_change
1161
+ skip unless helper.supports_upsert?
1120
1162
  e = SRecord.new
1121
1163
  expect{ repository.update_messages([e]) }.to raise_error do |err|
1122
1164
  expect(err).to be_a(EventNotFound)
@@ -1124,6 +1166,14 @@ module RubyEventStore
1124
1166
  expect(err.message).to eq("Event not found: #{e.event_id}")
1125
1167
  end
1126
1168
  end
1169
+
1170
+ specify "does not change timestamp" do
1171
+ r = SRecord.new(timestamp: Time.utc(2020, 1, 1))
1172
+ repository.append_to_stream([r], Stream.new("whatever"), ExpectedVersion.any)
1173
+ repository.update_messages([SRecord.new(event_id: r.event_id, timestamp: Time.utc(2020, 1, 20))])
1174
+
1175
+ expect(repository.read(specification.result).first.timestamp).to eq(Time.utc(2020, 1, 1))
1176
+ end
1127
1177
  end
1128
1178
 
1129
1179
  specify do
@@ -1228,5 +1278,119 @@ module RubyEventStore
1228
1278
  expect(repository.count(specification.stream("Dummy").of_type([Type3]).result)).to eq(2)
1229
1279
  expect(repository.count(specification.stream(stream.name).of_type([Type3]).result)).to eq(0)
1230
1280
  end
1281
+
1282
+ specify 'timestamp precision' do
1283
+ time = Time.utc(2020, 9, 11, 12, 26, 0, 123456)
1284
+ repository.append_to_stream(SRecord.new(timestamp: time), stream, version_none)
1285
+ event = read_events_forward(repository, count: 1).first
1286
+
1287
+ expect(event.timestamp).to eq(time)
1288
+ end
1289
+
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)
1295
+
1296
+ expect(repository.read(specification.stream('whatever').older_than(Time.utc(2020, 1, 2)).result).to_a).to eq([event_1])
1297
+ end
1298
+
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)
1304
+
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])
1306
+ end
1307
+
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)
1313
+
1314
+ expect(repository.read(specification.stream('whatever').newer_than(Time.utc(2020, 1, 2)).result).to_a).to eq([event_3])
1315
+ end
1316
+
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)
1322
+
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])
1324
+ end
1325
+
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)
1331
+
1332
+ expect(repository.read(specification.older_than(Time.utc(2020, 1, 2)).result).to_a).to eq([event_1])
1333
+ end
1334
+
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)
1340
+
1341
+ expect(repository.read(specification.older_than_or_equal(Time.utc(2020, 1, 2)).result).to_a).to eq([event_1, event_2])
1342
+ end
1343
+
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)
1349
+
1350
+ expect(repository.read(specification.newer_than(Time.utc(2020, 1, 2)).result).to_a).to eq([event_3])
1351
+ end
1352
+
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)
1358
+
1359
+ expect(repository.read(specification.newer_than_or_equal(Time.utc(2020, 1, 2)).result).to_a).to eq([event_2, event_3])
1360
+ end
1361
+
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)
1367
+
1368
+ expect(repository.read(specification.older_than(Time.utc(2020, 1, 2)).newer_than(Time.utc(2020, 1, 2)).result).to_a).to eq([])
1369
+ end
1370
+
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)
1376
+
1377
+ 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
+ end
1379
+
1380
+ specify "time order is respected" do
1381
+ repository.append_to_stream([
1382
+ SRecord.new(event_id: e1 = SecureRandom.uuid, timestamp: Time.new(2020,1,1), valid_at: Time.new(2020,1,9)),
1383
+ SRecord.new(event_id: e2 = SecureRandom.uuid, timestamp: Time.new(2020,1,3), valid_at: Time.new(2020,1,6)),
1384
+ SRecord.new(event_id: e3 = SecureRandom.uuid, timestamp: Time.new(2020,1,2), valid_at: Time.new(2020,1,3)),
1385
+ ],
1386
+ Stream.new("Dummy"),
1387
+ ExpectedVersion.any
1388
+ )
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]
1394
+ end
1231
1395
  end
1232
1396
  end
@@ -1,17 +1,17 @@
1
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)
2
+ ::RSpec.shared_examples :mapper do |mapper, domain_event|
3
+ specify "event_to_record returns instance of Record" do
4
+ record = mapper.event_to_record(domain_event)
5
5
 
6
- expect(record).to be_kind_of(SerializedRecord)
6
+ expect(record).to be_kind_of(Record)
7
7
  expect(record.event_id).to eq(domain_event.event_id)
8
8
  expect(record.event_type).to eq(domain_event.event_type)
9
9
  end
10
10
 
11
11
  specify "serialize and deserialize gives equal event" do
12
- record = mapper.event_to_serialized_record(domain_event)
12
+ record = mapper.event_to_record(domain_event)
13
13
 
14
- expect(mapper.serialized_record_to_event(record)).to eq(domain_event)
14
+ expect(mapper.record_to_event(record)).to eq(domain_event)
15
15
  end
16
16
  end
17
17
  end
@@ -39,10 +39,16 @@ RSpec.shared_examples :subscriptions do |subscriptions_class|
39
39
  subscriptions.add_thread_subscription(handler, [Test1DomainEvent, Test3DomainEvent])
40
40
  subscriptions.add_thread_subscription(another_handler, [Test2DomainEvent])
41
41
  subscriptions.add_thread_global_subscription(global_handler)
42
+ t = Thread.new do
43
+ subscriptions.add_thread_subscription(handler, [Test2DomainEvent])
44
+ subscriptions.add_thread_global_subscription(another_handler)
45
+ expect(subscriptions.all_for('Test2DomainEvent')).to eq([another_handler, handler])
46
+ end
42
47
 
43
48
  expect(subscriptions.all_for('Test1DomainEvent')).to eq([global_handler, handler])
44
49
  expect(subscriptions.all_for('Test2DomainEvent')).to eq([global_handler, another_handler])
45
50
  expect(subscriptions.all_for('Test3DomainEvent')).to eq([global_handler, handler])
51
+ t.join
46
52
  end
47
53
 
48
54
  it 'returns lambda as an output of global subscribe methods' do
@@ -35,7 +35,7 @@ module RubyEventStore
35
35
  # Limits the query to events before or after another event.
36
36
  # {http://railseventstore.org/docs/read/ Find out more}.
37
37
  #
38
- # @param start [String] id of event to start reading from.
38
+ # @param stop [String] id of event to start reading from.
39
39
  # @return [Specification]
40
40
  def to(stop)
41
41
  raise InvalidPageStop if stop.nil? || stop.empty?
@@ -43,6 +43,99 @@ module RubyEventStore
43
43
  Specification.new(reader, result.dup { |r| r.stop = stop })
44
44
  end
45
45
 
46
+ # Limits the query to events that later than given time.
47
+ # {http://railseventstore.org/docs/read/ Find out more}.
48
+ #
49
+ # @param time [Time]
50
+ # @return [Specification]
51
+ def older_than(time)
52
+ raise ArgumentError unless time.respond_to?(:to_time)
53
+ Specification.new(
54
+ reader,
55
+ result.dup do |r|
56
+ r.older_than = time
57
+ r.older_than_or_equal = nil
58
+ end
59
+ )
60
+ end
61
+
62
+ # Limits the query to events that occurred on given time or later.
63
+ # {http://railseventstore.org/docs/read/ Find out more}.
64
+ #
65
+ # @param time [Time]
66
+ # @return [Specification]
67
+ def older_than_or_equal(time)
68
+ raise ArgumentError unless time.respond_to?(:to_time)
69
+ Specification.new(
70
+ reader,
71
+ result.dup do |r|
72
+ r.older_than = nil
73
+ r.older_than_or_equal = time
74
+ end
75
+ )
76
+ end
77
+
78
+ # Limits the query to events that occurred earlier than given time.
79
+ # {http://railseventstore.org/docs/read/ Find out more}.
80
+ #
81
+ # @param time [Time]
82
+ # @return [Specification]
83
+ def newer_than(time)
84
+ raise ArgumentError unless time.respond_to?(:to_time)
85
+ Specification.new(
86
+ reader,
87
+ result.dup do |r|
88
+ r.newer_than_or_equal = nil
89
+ r.newer_than = time
90
+ end
91
+ )
92
+ end
93
+
94
+ # Limits the query to events that occurred on given time or earlier.
95
+ # {http://railseventstore.org/docs/read/ Find out more}.
96
+ #
97
+ # @param time [Time]
98
+ # @return [Specification]
99
+ def newer_than_or_equal(time)
100
+ raise ArgumentError unless time.respond_to?(:to_time)
101
+ Specification.new(
102
+ reader,
103
+ result.dup do |r|
104
+ r.newer_than_or_equal = time
105
+ r.newer_than = nil
106
+ end
107
+ )
108
+ end
109
+
110
+ # Limits the query to events within given time range.
111
+ # {http://railseventstore.org/docs/read/ Find out more}.
112
+ #
113
+ # @param time_range [Range]
114
+ # @return [Specification]
115
+ def between(time_range)
116
+ if time_range.exclude_end?
117
+ newer_than_or_equal(time_range.first).older_than(time_range.last)
118
+ else
119
+ newer_than_or_equal(time_range.first).older_than_or_equal(time_range.last)
120
+ end
121
+ end
122
+
123
+ # Sets the order of time sorting using transaction time
124
+ # {http://railseventstore.org/docs/read/ Find out more}
125
+ #
126
+ # @return [Specification]
127
+ def as_at
128
+ Specification.new(reader, result.dup { |r| r.time_sort_by = :as_at})
129
+ end
130
+
131
+ # Sets the order of time sorting using validity time
132
+ # {http://railseventstore.org/docs/read/ Find out more}
133
+ #
134
+ # @return [Specification]
135
+ def as_of
136
+ Specification.new(reader, result.dup { |r| r.time_sort_by = :as_of })
137
+ end
138
+
46
139
  # Sets the order of reading events to ascending (forward from the start).
47
140
  # {http://railseventstore.org/docs/read/ Find out more}.
48
141
  #
@@ -73,7 +166,7 @@ module RubyEventStore
73
166
  # Yields each batch of records that was retrieved from the store.
74
167
  # {http://railseventstore.org/docs/read/ Find out more}.
75
168
  #
76
- # @yield [Array<Event, Proto>] batch of events
169
+ # @yield [Array<Event>] batch of events
77
170
  # @return [Enumerator, nil] Enumerator is returned when block not given
78
171
  def each_batch
79
172
  return to_enum(:each_batch) unless block_given?
@@ -87,7 +180,7 @@ module RubyEventStore
87
180
  # Yields events read from the store if block given. Otherwise, returns enumerable collection.
88
181
  # {http://railseventstore.org/docs/read/ Find out more}.
89
182
  #
90
- # @yield [Event, Proto] event
183
+ # @yield [Event] event
91
184
  # @return [Enumerator, nil] Enumerator is returned when block not given
92
185
  def each
93
186
  return to_enum unless block_given?
@@ -111,7 +204,7 @@ module RubyEventStore
111
204
  # built up to this point result using provided block.
112
205
  # {http://railseventstore.org/docs/read/ Find out more}.
113
206
  #
114
- # @accumulator starting state for reduce operation
207
+ # @param accumulator starting state for reduce operation
115
208
  # @return reduce result as defined by block given
116
209
  def reduce(accumulator = nil, &block)
117
210
  raise ArgumentError.new("Block must be given") unless block_given?
@@ -130,7 +223,7 @@ module RubyEventStore
130
223
  # Returns array of domain events.
131
224
  # {http://railseventstore.org/docs/read/ Find out more}.
132
225
  #
133
- # @return [Array<Event, Proto>]
226
+ # @return [Array<Event>]
134
227
  def to_a
135
228
  each.to_a
136
229
  end
@@ -200,7 +293,7 @@ module RubyEventStore
200
293
  # Limits the query to certain events by given even ids.
201
294
  # {http://railseventstore.org/docs/read/ Find out more}.
202
295
  #
203
- # @param even_ids [Array(String)] ids of event to look for.
296
+ # @param event_ids [Array(String)] ids of event to look for.
204
297
  # @return [Specification]
205
298
  def with_id(event_ids)
206
299
  Specification.new(reader, result.dup{ |r| r.with_ids = event_ids })
@@ -231,7 +324,7 @@ module RubyEventStore
231
324
  # read from the store if block given. Otherwise, returns enumerable collection.
232
325
  # {http://railseventstore.org/docs/read/ Find out more}.
233
326
  #
234
- # @yield [Event, Proto] event
327
+ # @yield [Event] event
235
328
  # @return [Enumerator] Enumerator is returned when block not given
236
329
  def events(event_ids)
237
330
  with_id(event_ids).each
@@ -14,14 +14,14 @@ module RubyEventStore
14
14
  # @private
15
15
  def one(specification_result)
16
16
  record = repository.read(specification_result)
17
- mapper.serialized_record_to_event(record) if record
17
+ mapper.record_to_event(record) if record
18
18
  end
19
19
 
20
20
  # @api private
21
21
  # @private
22
22
  def each(specification_result)
23
23
  repository.read(specification_result).each do |batch|
24
- yield batch.map { |serialized_record| mapper.serialized_record_to_event(serialized_record) }
24
+ yield batch.map { |record| mapper.record_to_event(record) }
25
25
  end
26
26
  end
27
27