ruby_event_store 1.3.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/.mutant.yml +1 -0
  3. data/Gemfile +2 -4
  4. data/Gemfile.lock +118 -0
  5. data/Makefile +13 -3
  6. data/lib/ruby_event_store/broker.rb +3 -3
  7. data/lib/ruby_event_store/client.rb +47 -23
  8. data/lib/ruby_event_store/composed_dispatcher.rb +2 -2
  9. data/lib/ruby_event_store/constants.rb +1 -0
  10. data/lib/ruby_event_store/errors.rb +0 -1
  11. data/lib/ruby_event_store/event.rb +8 -1
  12. data/lib/ruby_event_store/immediate_async_dispatcher.rb +2 -2
  13. data/lib/ruby_event_store/in_memory_repository.rb +98 -59
  14. data/lib/ruby_event_store/instrumented_dispatcher.rb +2 -2
  15. data/lib/ruby_event_store/mappers/default.rb +28 -6
  16. data/lib/ruby_event_store/mappers/deprecated_wrapper.rb +33 -0
  17. data/lib/ruby_event_store/mappers/encryption_mapper.rb +1 -4
  18. data/lib/ruby_event_store/mappers/instrumented_mapper.rb +8 -4
  19. data/lib/ruby_event_store/mappers/json_mapper.rb +2 -4
  20. data/lib/ruby_event_store/mappers/pipeline.rb +26 -5
  21. data/lib/ruby_event_store/mappers/pipeline_mapper.rb +6 -2
  22. data/lib/ruby_event_store/mappers/transformation/domain_event.rb +16 -8
  23. data/lib/ruby_event_store/mappers/transformation/encryption.rb +20 -12
  24. data/lib/ruby_event_store/mappers/transformation/event_class_remapper.rb +11 -4
  25. data/lib/ruby_event_store/mappers/transformation/serialization.rb +16 -14
  26. data/lib/ruby_event_store/mappers/transformation/stringify_metadata_keys.rb +12 -7
  27. data/lib/ruby_event_store/mappers/transformation/symbolize_metadata_keys.rb +12 -7
  28. data/lib/ruby_event_store/null.rb +13 -0
  29. data/lib/ruby_event_store/projection.rb +2 -13
  30. data/lib/ruby_event_store/record.rb +68 -0
  31. data/lib/ruby_event_store/serialized_record.rb +23 -4
  32. data/lib/ruby_event_store/spec/broker_lint.rb +9 -9
  33. data/lib/ruby_event_store/spec/event_repository_lint.rb +200 -36
  34. data/lib/ruby_event_store/spec/mapper_lint.rb +6 -6
  35. data/lib/ruby_event_store/spec/subscriptions_lint.rb +6 -0
  36. data/lib/ruby_event_store/specification.rb +100 -7
  37. data/lib/ruby_event_store/specification_reader.rb +2 -2
  38. data/lib/ruby_event_store/specification_result.rb +86 -2
  39. data/lib/ruby_event_store/version.rb +1 -1
  40. data/lib/ruby_event_store.rb +4 -7
  41. data/ruby_event_store.gemspec +0 -2
  42. metadata +8 -9
  43. data/lib/ruby_event_store/mappers/protobuf.rb +0 -24
  44. data/lib/ruby_event_store/mappers/transformation/item.rb +0 -56
  45. data/lib/ruby_event_store/mappers/transformation/proto_event.rb +0 -17
  46. data/lib/ruby_event_store/mappers/transformation/protobuf_encoder.rb +0 -30
  47. data/lib/ruby_event_store/mappers/transformation/protobuf_nested_struct_metadata.rb +0 -30
  48. data/lib/ruby_event_store/mappers/transformation/serialized_record.rb +0 -27
@@ -7,9 +7,9 @@ module RubyEventStore
7
7
  @instrumentation = instrumentation
8
8
  end
9
9
 
10
- def call(subscriber, event, serialized_event)
10
+ def call(subscriber, event, record)
11
11
  instrumentation.instrument("call.dispatcher.rails_event_store", event: event, subscriber: subscriber) do
12
- dispatcher.call(subscriber, event, serialized_event)
12
+ dispatcher.call(subscriber, event, record)
13
13
  end
14
14
  end
15
15
 
@@ -5,13 +5,35 @@ require 'yaml'
5
5
  module RubyEventStore
6
6
  module Mappers
7
7
  class Default < PipelineMapper
8
- def initialize(serializer: YAML, events_class_remapping: {})
8
+ UNSET = Object.new.freeze
9
+
10
+ attr_reader :serializer
11
+
12
+ def initialize(serializer: UNSET, events_class_remapping: {})
13
+ case serializer
14
+ when UNSET
15
+ @serializer = YAML
16
+ else
17
+ warn <<~EOW
18
+ Passing serializer: to #{self.class} has been deprecated.
19
+
20
+ Pass it directly to the repository and the scheduler. For example:
21
+
22
+ Rails.configuration.event_store = RailsEventStore::Client.new(
23
+ mapper: RubyEventStore::Mappers::Default.new,
24
+ repository: RailsEventStoreActiveRecord::EventRepository.new(serializer: #{serializer}),
25
+ dispatcher: RubyEventStore::ComposedDispatcher.new(
26
+ RailsEventStore::AfterCommitAsyncDispatcher.new(scheduler: RailsEventStore::ActiveJobScheduler.new(serializer: #{serializer}),
27
+ RubyEventStore::Dispatcher.new
28
+ )
29
+ )
30
+ EOW
31
+ @serializer = serializer
32
+ end
33
+
9
34
  super(Pipeline.new(
10
- transformations: [
11
- Transformation::EventClassRemapper.new(events_class_remapping),
12
- Transformation::SymbolizeMetadataKeys.new,
13
- Transformation::Serialization.new(serializer: serializer),
14
- ]
35
+ Transformation::EventClassRemapper.new(events_class_remapping),
36
+ Transformation::SymbolizeMetadataKeys.new,
15
37
  ))
16
38
  end
17
39
  end
@@ -0,0 +1,33 @@
1
+ module RubyEventStore
2
+ module Mappers
3
+ class DeprecatedWrapper
4
+ def initialize(mapper)
5
+ @mapper = mapper
6
+ end
7
+
8
+ def serializer
9
+ @mapper.serializer
10
+ end
11
+
12
+ def event_to_record(any)
13
+ @mapper.event_to_record(any)
14
+ rescue NoMethodError => e
15
+ raise unless e.message =~ /undefined method `event_to_record/
16
+ warn <<~EOW
17
+ Deprecation: Please rename #{@mapper.class}#event_to_serialized_record to #{@mapper.class}#event_to_record.
18
+ EOW
19
+ @mapper.event_to_serialized_record(any)
20
+ end
21
+
22
+ def record_to_event(any)
23
+ @mapper.record_to_event(any)
24
+ rescue NoMethodError => e
25
+ raise unless e.message =~ /undefined method `record_to_event/
26
+ warn <<~EOW
27
+ Deprecation: Please rename #{@mapper.class}#serialized_record_to_event to #{@mapper.class}#record_to_event.
28
+ EOW
29
+ @mapper.serialized_record_to_event(any)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -5,10 +5,7 @@ module RubyEventStore
5
5
  class EncryptionMapper < PipelineMapper
6
6
  def initialize(key_repository, serializer: YAML, forgotten_data: ForgottenData.new)
7
7
  super(Pipeline.new(
8
- transformations: [
9
- Transformation::Encryption.new(key_repository, serializer: serializer, forgotten_data: forgotten_data),
10
- Transformation::Serialization.new(serializer: serializer),
11
- ]
8
+ Transformation::Encryption.new(key_repository, serializer: serializer, forgotten_data: forgotten_data),
12
9
  ))
13
10
  end
14
11
  end
@@ -8,18 +8,22 @@ module RubyEventStore
8
8
  @instrumentation = instrumentation
9
9
  end
10
10
 
11
- def event_to_serialized_record(domain_event)
11
+ def event_to_record(domain_event)
12
12
  instrumentation.instrument("serialize.mapper.rails_event_store", domain_event: domain_event) do
13
- mapper.event_to_serialized_record(domain_event)
13
+ mapper.event_to_record(domain_event)
14
14
  end
15
15
  end
16
16
 
17
- def serialized_record_to_event(record)
17
+ def record_to_event(record)
18
18
  instrumentation.instrument("deserialize.mapper.rails_event_store", record: record) do
19
- mapper.serialized_record_to_event(record)
19
+ mapper.record_to_event(record)
20
20
  end
21
21
  end
22
22
 
23
+ def serializer
24
+ mapper.serializer
25
+ end
26
+
23
27
  private
24
28
 
25
29
  attr_reader :instrumentation, :mapper
@@ -5,10 +5,8 @@ module RubyEventStore
5
5
  class JSONMapper < PipelineMapper
6
6
  def initialize(events_class_remapping: {})
7
7
  super(Pipeline.new(
8
- transformations: [
9
- Transformation::EventClassRemapper.new(events_class_remapping),
10
- Transformation::SymbolizeMetadataKeys.new,
11
- ],
8
+ Transformation::EventClassRemapper.new(events_class_remapping),
9
+ Transformation::SymbolizeMetadataKeys.new,
12
10
  ))
13
11
  end
14
12
  end
@@ -3,13 +3,13 @@
3
3
  module RubyEventStore
4
4
  module Mappers
5
5
  class Pipeline
6
- def initialize(to_domain_event: Transformation::DomainEvent.new,
7
- to_serialized_record: Transformation::SerializedRecord.new,
8
- transformations: nil)
6
+ UNSET = Object.new.freeze
7
+
8
+ def initialize(*transformations_, transformations: UNSET, to_domain_event: Transformation::DomainEvent.new)
9
9
  @transformations = [
10
10
  to_domain_event,
11
- Array(transformations),
12
- to_serialized_record
11
+ deprecated_transformations(transformations),
12
+ transformations_,
13
13
  ].flatten.freeze
14
14
  end
15
15
 
@@ -26,6 +26,27 @@ module RubyEventStore
26
26
  end
27
27
 
28
28
  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
29
50
  end
30
51
  end
31
52
  end
@@ -7,14 +7,18 @@ module RubyEventStore
7
7
  @pipeline = pipeline
8
8
  end
9
9
 
10
- def event_to_serialized_record(domain_event)
10
+ def event_to_record(domain_event)
11
11
  pipeline.dump(domain_event)
12
12
  end
13
13
 
14
- def serialized_record_to_event(record)
14
+ def record_to_event(record)
15
15
  pipeline.load(record)
16
16
  end
17
17
 
18
+ def serializer
19
+ NULL
20
+ end
21
+
18
22
  private
19
23
  attr_reader :pipeline
20
24
  end
@@ -5,19 +5,27 @@ module RubyEventStore
5
5
  module Transformation
6
6
  class DomainEvent
7
7
  def dump(domain_event)
8
- Item.new(
8
+ metadata = domain_event.metadata.to_h
9
+ timestamp = metadata.delete(:timestamp)
10
+ valid_at = metadata.delete(:valid_at)
11
+ Record.new(
9
12
  event_id: domain_event.event_id,
10
- metadata: domain_event.metadata.to_h,
13
+ metadata: metadata,
11
14
  data: domain_event.data,
12
- event_type: domain_event.event_type
15
+ event_type: domain_event.event_type,
16
+ timestamp: timestamp,
17
+ valid_at: valid_at,
13
18
  )
14
19
  end
15
20
 
16
- def load(item)
17
- Object.const_get(item.event_type).new(
18
- event_id: item.event_id,
19
- metadata: item.metadata,
20
- data: item.data
21
+ def load(record)
22
+ Object.const_get(record.event_type).new(
23
+ event_id: record.event_id,
24
+ metadata: record.metadata.merge(
25
+ timestamp: record.timestamp,
26
+ valid_at: record.valid_at,
27
+ ),
28
+ data: record.data,
21
29
  )
22
30
  end
23
31
  end
@@ -23,27 +23,35 @@ module RubyEventStore
23
23
  @forgotten_data = forgotten_data
24
24
  end
25
25
 
26
- def dump(item)
27
- data = item.data
28
- metadata = item.metadata.dup
29
- event_class = Object.const_get(item.event_type)
26
+ def dump(record)
27
+ data = record.data
28
+ metadata = record.metadata.dup
29
+ event_class = Object.const_get(record.event_type)
30
30
 
31
31
  crypto_description = encryption_metadata(data, encryption_schema(event_class))
32
32
  metadata[:encryption] = crypto_description unless crypto_description.empty?
33
33
 
34
- item.merge(
35
- data: encrypt_data(deep_dup(data), crypto_description),
36
- metadata: metadata
34
+ Record.new(
35
+ event_id: record.event_id,
36
+ event_type: record.event_type,
37
+ data: encrypt_data(deep_dup(data), crypto_description),
38
+ metadata: metadata,
39
+ timestamp: record.timestamp,
40
+ valid_at: record.valid_at,
37
41
  )
38
42
  end
39
43
 
40
- def load(item)
41
- metadata = item.metadata.dup
44
+ def load(record)
45
+ metadata = record.metadata.dup
42
46
  crypto_description = Hash(metadata.delete(:encryption))
43
47
 
44
- item.merge(
45
- data: decrypt_data(item.data, crypto_description),
46
- metadata: metadata
48
+ Record.new(
49
+ event_id: record.event_id,
50
+ event_type: record.event_type,
51
+ data: decrypt_data(record.data, crypto_description),
52
+ metadata: metadata,
53
+ timestamp: record.timestamp,
54
+ valid_at: record.valid_at,
47
55
  )
48
56
  end
49
57
 
@@ -8,12 +8,19 @@ module RubyEventStore
8
8
  @class_map = class_map
9
9
  end
10
10
 
11
- def dump(item)
12
- item
11
+ def dump(record)
12
+ record
13
13
  end
14
14
 
15
- def load(item)
16
- item.merge(event_type: class_map[item.fetch(:event_type)] || item.fetch(:event_type))
15
+ def load(record)
16
+ Record.new(
17
+ event_id: record.event_id,
18
+ event_type: class_map[record.event_type] || record.event_type,
19
+ data: record.data,
20
+ metadata: record.metadata,
21
+ timestamp: record.timestamp,
22
+ valid_at: record.valid_at,
23
+ )
17
24
  end
18
25
 
19
26
  private
@@ -7,26 +7,28 @@ module RubyEventStore
7
7
  module Transformation
8
8
  class Serialization
9
9
  def initialize(serializer: YAML)
10
- @serializer = serializer
10
+ warn <<~EOW
11
+ #{self.class} has been deprecated and is effectively no-op. You should remove this transformation from your pipeline.
12
+
13
+ Instead, pass the serializer directly to the repository and the scheduler. For example:
14
+
15
+ Rails.configuration.event_store = RailsEventStore::Client.new(
16
+ mapper: RubyEventStore::Mappers::Default.new,
17
+ repository: RailsEventStoreActiveRecord::EventRepository.new(serializer: #{serializer}),
18
+ dispatcher: RubyEventStore::ComposedDispatcher.new(
19
+ RubyEventStore::ImmediateAsyncDispatcher.new(scheduler: ActiveJobScheduler.new(serializer: #{serializer}),
20
+ RubyEventStore::Dispatcher.new
21
+ )
22
+ )
23
+ EOW
11
24
  end
12
- attr_reader :serializer
13
25
 
14
26
  def dump(item)
15
- Item.new(
16
- event_id: item.event_id,
17
- metadata: serializer.dump(item.metadata),
18
- data: serializer.dump(item.data),
19
- event_type: item.event_type
20
- )
27
+ item
21
28
  end
22
29
 
23
30
  def load(item)
24
- Item.new(
25
- event_id: item.event_id,
26
- metadata: serializer.load(item.metadata),
27
- data: serializer.load(item.data),
28
- event_type: item.event_type
29
- )
31
+ item
30
32
  end
31
33
  end
32
34
  end
@@ -4,18 +4,23 @@ module RubyEventStore
4
4
  module Mappers
5
5
  module Transformation
6
6
  class StringifyMetadataKeys
7
- def dump(item)
8
- stringify(item)
7
+ def dump(record)
8
+ stringify(record)
9
9
  end
10
10
 
11
- def load(item)
12
- stringify(item)
11
+ def load(record)
12
+ stringify(record)
13
13
  end
14
14
 
15
15
  private
16
- def stringify(item)
17
- item.merge(
18
- metadata: TransformKeys.stringify(item.metadata),
16
+ def stringify(record)
17
+ Record.new(
18
+ event_id: record.event_id,
19
+ event_type: record.event_type,
20
+ data: record.data,
21
+ metadata: TransformKeys.stringify(record.metadata),
22
+ timestamp: record.timestamp,
23
+ valid_at: record.valid_at,
19
24
  )
20
25
  end
21
26
  end
@@ -4,18 +4,23 @@ module RubyEventStore
4
4
  module Mappers
5
5
  module Transformation
6
6
  class SymbolizeMetadataKeys
7
- def dump(item)
8
- symbolize(item)
7
+ def dump(record)
8
+ symbolize(record)
9
9
  end
10
10
 
11
- def load(item)
12
- symbolize(item)
11
+ def load(record)
12
+ symbolize(record)
13
13
  end
14
14
 
15
15
  private
16
- def symbolize(item)
17
- item.merge(
18
- metadata: TransformKeys.symbolize(item.metadata),
16
+ def symbolize(record)
17
+ Record.new(
18
+ event_id: record.event_id,
19
+ event_type: record.event_type,
20
+ data: record.data,
21
+ metadata: TransformKeys.symbolize(record.metadata),
22
+ timestamp: record.timestamp,
23
+ valid_at: record.valid_at,
19
24
  )
20
25
  end
21
26
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyEventStore
4
+ module NULL
5
+ def self.dump(value)
6
+ value
7
+ end
8
+
9
+ def self.load(value)
10
+ value
11
+ end
12
+ end
13
+ end