ruby_event_store 0.30.0 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +9 -1
  3. data/Makefile +15 -62
  4. data/lib/ruby_event_store/batch_enumerator.rb +15 -5
  5. data/lib/ruby_event_store/broker.rb +45 -0
  6. data/lib/ruby_event_store/client.rb +220 -130
  7. data/lib/ruby_event_store/composed_dispatcher.rb +24 -0
  8. data/lib/ruby_event_store/constants.rb +2 -0
  9. data/lib/ruby_event_store/correlated_commands.rb +42 -0
  10. data/lib/ruby_event_store/dispatcher.rb +20 -0
  11. data/lib/ruby_event_store/errors.rb +16 -16
  12. data/lib/ruby_event_store/event.rb +70 -14
  13. data/lib/ruby_event_store/expected_version.rb +2 -0
  14. data/lib/ruby_event_store/immediate_async_dispatcher.rb +17 -0
  15. data/lib/ruby_event_store/in_memory_repository.rb +45 -17
  16. data/lib/ruby_event_store/instrumented_dispatcher.rb +23 -0
  17. data/lib/ruby_event_store/instrumented_repository.rb +63 -0
  18. data/lib/ruby_event_store/link_by_metadata.rb +57 -0
  19. data/lib/ruby_event_store/mappers/default.rb +10 -26
  20. data/lib/ruby_event_store/mappers/encryption_key.rb +74 -0
  21. data/lib/ruby_event_store/mappers/encryption_mapper.rb +16 -0
  22. data/lib/ruby_event_store/mappers/forgotten_data.rb +30 -0
  23. data/lib/ruby_event_store/mappers/in_memory_encryption_key_repository.rb +34 -0
  24. data/lib/ruby_event_store/mappers/instrumented_mapper.rb +28 -0
  25. data/lib/ruby_event_store/mappers/json_mapper.rb +16 -0
  26. data/lib/ruby_event_store/mappers/null_mapper.rb +5 -8
  27. data/lib/ruby_event_store/mappers/pipeline.rb +31 -0
  28. data/lib/ruby_event_store/mappers/pipeline_mapper.rb +22 -0
  29. data/lib/ruby_event_store/mappers/protobuf.rb +13 -67
  30. data/lib/ruby_event_store/mappers/transformation/domain_event.rb +26 -0
  31. data/lib/ruby_event_store/mappers/transformation/encryption.rb +128 -0
  32. data/lib/ruby_event_store/mappers/transformation/event_class_remapper.rb +24 -0
  33. data/lib/ruby_event_store/mappers/transformation/item.rb +56 -0
  34. data/lib/ruby_event_store/mappers/transformation/proto_event.rb +17 -0
  35. data/lib/ruby_event_store/mappers/transformation/protobuf_encoder.rb +30 -0
  36. data/lib/ruby_event_store/mappers/transformation/protobuf_nested_struct_metadata.rb +30 -0
  37. data/lib/ruby_event_store/mappers/transformation/serialization.rb +34 -0
  38. data/lib/ruby_event_store/mappers/transformation/serialized_record.rb +27 -0
  39. data/lib/ruby_event_store/mappers/transformation/stringify_metadata_keys.rb +24 -0
  40. data/lib/ruby_event_store/mappers/transformation/symbolize_metadata_keys.rb +24 -0
  41. data/lib/ruby_event_store/metadata.rb +4 -2
  42. data/lib/ruby_event_store/projection.rb +34 -12
  43. data/lib/ruby_event_store/serialized_record.rb +3 -1
  44. data/lib/ruby_event_store/spec/broker_lint.rb +92 -0
  45. data/lib/ruby_event_store/spec/dispatcher_lint.rb +4 -36
  46. data/lib/ruby_event_store/spec/event_lint.rb +71 -0
  47. data/lib/ruby_event_store/spec/event_repository_lint.rb +1092 -962
  48. data/lib/ruby_event_store/spec/mapper_lint.rb +17 -0
  49. data/lib/ruby_event_store/spec/scheduler_lint.rb +9 -0
  50. data/lib/ruby_event_store/spec/subscriptions_lint.rb +111 -0
  51. data/lib/ruby_event_store/specification.rb +201 -56
  52. data/lib/ruby_event_store/specification_reader.rb +43 -0
  53. data/lib/ruby_event_store/specification_result.rb +212 -0
  54. data/lib/ruby_event_store/stream.rb +2 -0
  55. data/lib/ruby_event_store/subscriptions.rb +110 -0
  56. data/lib/ruby_event_store/transform_keys.rb +31 -0
  57. data/lib/ruby_event_store/version.rb +3 -1
  58. data/lib/ruby_event_store.rb +34 -4
  59. data/ruby_event_store.gemspec +1 -10
  60. metadata +47 -126
  61. data/exe/res-deprecated-read-api-migrator +0 -19
  62. data/lib/ruby_event_store/deprecated_read_api_rewriter.rb +0 -67
  63. data/lib/ruby_event_store/deprecated_read_api_runner.rb +0 -64
  64. data/lib/ruby_event_store/deprecations.rb +0 -7
  65. data/lib/ruby_event_store/pub_sub/broker.rb +0 -73
  66. data/lib/ruby_event_store/pub_sub/dispatcher.rb +0 -25
  67. data/lib/ruby_event_store/spec/event_broker_lint.rb +0 -211
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyEventStore
4
+ module Mappers
5
+ class InMemoryEncryptionKeyRepository
6
+ DEFAULT_CIPHER = 'aes-256-gcm'.freeze
7
+
8
+ def initialize
9
+ @keys = {}
10
+ end
11
+
12
+ def key_of(identifier, cipher: DEFAULT_CIPHER)
13
+ @keys[[identifier, cipher]]
14
+ end
15
+
16
+ def create(identifier, cipher: DEFAULT_CIPHER)
17
+ crypto = prepare_encrypt(cipher)
18
+ @keys[[identifier, cipher]] = EncryptionKey.new(cipher: cipher, key: crypto.random_key)
19
+ end
20
+
21
+ def forget(identifier)
22
+ @keys = @keys.reject { |(id, _)| id.eql?(identifier) }
23
+ end
24
+
25
+ private
26
+
27
+ def prepare_encrypt(cipher)
28
+ crypto = OpenSSL::Cipher.new(cipher)
29
+ crypto.encrypt
30
+ crypto
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyEventStore
4
+ module Mappers
5
+ class InstrumentedMapper
6
+ def initialize(mapper, instrumentation)
7
+ @mapper = mapper
8
+ @instrumentation = instrumentation
9
+ end
10
+
11
+ def event_to_serialized_record(domain_event)
12
+ instrumentation.instrument("serialize.mapper.rails_event_store", domain_event: domain_event) do
13
+ mapper.event_to_serialized_record(domain_event)
14
+ end
15
+ end
16
+
17
+ def serialized_record_to_event(record)
18
+ instrumentation.instrument("deserialize.mapper.rails_event_store", record: record) do
19
+ mapper.serialized_record_to_event(record)
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ attr_reader :instrumentation, :mapper
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyEventStore
4
+ module Mappers
5
+ class JSONMapper < PipelineMapper
6
+ def initialize(events_class_remapping: {})
7
+ super(Pipeline.new(
8
+ transformations: [
9
+ Transformation::EventClassRemapper.new(events_class_remapping),
10
+ Transformation::SymbolizeMetadataKeys.new,
11
+ ],
12
+ ))
13
+ end
14
+ end
15
+ end
16
+ end
@@ -1,15 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RubyEventStore
2
4
  module Mappers
3
- class NullMapper
4
-
5
- def event_to_serialized_record(domain_event)
6
- domain_event
7
- end
5
+ class NullMapper < PipelineMapper
8
6
 
9
- def serialized_record_to_event(record)
10
- record
7
+ def initialize
8
+ super(Pipeline.new)
11
9
  end
12
-
13
10
  end
14
11
  end
15
12
  end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyEventStore
4
+ module Mappers
5
+ class Pipeline
6
+ def initialize(to_domain_event: Transformation::DomainEvent.new,
7
+ to_serialized_record: Transformation::SerializedRecord.new,
8
+ transformations: nil)
9
+ @transformations = [
10
+ to_domain_event,
11
+ Array(transformations),
12
+ to_serialized_record
13
+ ].flatten.freeze
14
+ end
15
+
16
+ def dump(domain_event)
17
+ transformations.reduce(domain_event) do |item, transform|
18
+ transform.dump(item)
19
+ end
20
+ end
21
+
22
+ def load(record)
23
+ transformations.reverse.reduce(record) do |item, transform|
24
+ transform.load(item)
25
+ end
26
+ end
27
+
28
+ attr_reader :transformations
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyEventStore
4
+ module Mappers
5
+ class PipelineMapper
6
+ def initialize(pipeline)
7
+ @pipeline = pipeline
8
+ end
9
+
10
+ def event_to_serialized_record(domain_event)
11
+ pipeline.dump(domain_event)
12
+ end
13
+
14
+ def serialized_record_to_event(record)
15
+ pipeline.load(record)
16
+ end
17
+
18
+ private
19
+ attr_reader :pipeline
20
+ end
21
+ end
22
+ end
@@ -1,78 +1,24 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RubyEventStore
2
4
  class Proto < RubyEventStore::Event
3
- def initialize(event_id: SecureRandom.uuid, metadata: nil, data:)
4
- @event_id = event_id
5
- @metadata = Metadata.new(metadata.to_h)
6
- @data = data
7
- end
8
-
9
- def type
5
+ def event_type
10
6
  data.class.descriptor.name
11
7
  end
12
-
13
- def encode_with(coder)
14
- coder['event_id'] = event_id
15
- coder['metadata'] = ProtobufNestedStruct::HashMapStringValue.dump(metadata.each_with_object({}){|(k,v),h| h[k.to_s] =v })
16
- coder['data.proto'] = data.class.encode(data)
17
- coder['data.type'] = type
18
- end
19
-
20
- def init_with(coder)
21
- @event_id = coder['event_id']
22
- @metadata = Metadata.new
23
- ProtobufNestedStruct::HashMapStringValue.load(coder['metadata']).each_with_object(metadata){|(k,v),meta| meta[k.to_sym] = v }
24
- @data = pool.lookup(coder['data.type']).msgclass.decode(coder['data.proto'])
25
- end
26
-
27
- def ==(other_event)
28
- other_event.instance_of?(self.class) &&
29
- other_event.event_id.eql?(event_id) &&
30
- other_event.data == data # https://github.com/google/protobuf/issues/4455
31
- end
32
-
33
- private
34
-
35
- def pool
36
- Google::Protobuf::DescriptorPool.generated_pool
37
- end
38
8
  end
39
9
 
40
10
  module Mappers
41
- class Protobuf
11
+ class Protobuf < PipelineMapper
42
12
  def initialize(events_class_remapping: {})
43
- require_optional_dependency
44
- @events_class_remapping = events_class_remapping
45
- end
46
-
47
- def event_to_serialized_record(domain_event)
48
- SerializedRecord.new(
49
- event_id: domain_event.event_id,
50
- metadata: ProtobufNestedStruct::HashMapStringValue.dump(domain_event.metadata.each_with_object({}){|(k,v),h| h[k.to_s] =v }),
51
- data: domain_event.data.class.encode(domain_event.data),
52
- event_type: domain_event.type
53
- )
54
- end
55
-
56
- def serialized_record_to_event(record)
57
- event_type = events_class_remapping.fetch(record.event_type) { record.event_type }
58
- data = Google::Protobuf::DescriptorPool.generated_pool.lookup(event_type).msgclass.decode(record.data)
59
- Proto.new(
60
- event_id: record.event_id,
61
- data: data,
62
- ).tap do |p|
63
- ProtobufNestedStruct::HashMapStringValue.load(record.metadata).each_with_object(p.metadata) {|(k, v), meta| meta[k.to_sym] = v}
64
- end
65
- end
66
-
67
- private
68
-
69
- attr_reader :event_id_getter, :events_class_remapping
70
-
71
- def require_optional_dependency
72
- require 'protobuf_nested_struct'
73
- rescue LoadError
74
- raise LoadError, "cannot load such file -- protobuf_nested_struct. Add protobuf_nested_struct gem to Gemfile"
13
+ super(Pipeline.new(
14
+ to_domain_event: Transformation::ProtoEvent.new,
15
+ transformations: [
16
+ Transformation::ProtobufEncoder.new,
17
+ Transformation::EventClassRemapper.new(events_class_remapping),
18
+ Transformation::ProtobufNestedStructMetadata.new,
19
+ ]
20
+ ))
75
21
  end
76
22
  end
77
23
  end
78
- end
24
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyEventStore
4
+ module Mappers
5
+ module Transformation
6
+ class DomainEvent
7
+ def dump(domain_event)
8
+ Item.new(
9
+ event_id: domain_event.event_id,
10
+ metadata: domain_event.metadata.to_h,
11
+ data: domain_event.data,
12
+ event_type: domain_event.event_type
13
+ )
14
+ end
15
+
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
+ )
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,128 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyEventStore
4
+ module Mappers
5
+ module Transformation
6
+ class Encryption
7
+ class Leaf
8
+ def self.===(hash)
9
+ hash.keys.sort.eql? %i(cipher identifier iv)
10
+ end
11
+ end
12
+ private_constant :Leaf
13
+
14
+ class MissingEncryptionKey < StandardError
15
+ def initialize(key_identifier)
16
+ super %Q|Could not find encryption key for '#{key_identifier}'|
17
+ end
18
+ end
19
+
20
+ def initialize(key_repository, serializer: YAML, forgotten_data: ForgottenData.new)
21
+ @key_repository = key_repository
22
+ @serializer = serializer
23
+ @forgotten_data = forgotten_data
24
+ end
25
+
26
+ def dump(item)
27
+ data = item.data
28
+ metadata = item.metadata.dup
29
+ event_class = Object.const_get(item.event_type)
30
+
31
+ crypto_description = encryption_metadata(data, encryption_schema(event_class))
32
+ metadata[:encryption] = crypto_description unless crypto_description.empty?
33
+
34
+ item.merge(
35
+ data: encrypt_data(deep_dup(data), crypto_description),
36
+ metadata: metadata
37
+ )
38
+ end
39
+
40
+ def load(item)
41
+ metadata = item.metadata.dup
42
+ crypto_description = Hash(metadata.delete(:encryption))
43
+
44
+ item.merge(
45
+ data: decrypt_data(item.data, crypto_description),
46
+ metadata: metadata
47
+ )
48
+ end
49
+
50
+ private
51
+ attr_reader :key_repository, :serializer, :forgotten_data
52
+
53
+ def encryption_schema(event_class)
54
+ event_class.respond_to?(:encryption_schema) ? event_class.encryption_schema : {}
55
+ end
56
+
57
+ def deep_dup(hash)
58
+ duplicate = hash.dup
59
+ duplicate.each do |k, v|
60
+ duplicate[k] = v.instance_of?(Hash) ? deep_dup(v) : v
61
+ end
62
+ duplicate
63
+ end
64
+
65
+ def encryption_metadata(data, schema)
66
+ schema.inject({}) do |acc, (key, value)|
67
+ case value
68
+ when Hash
69
+ acc[key] = encryption_metadata(data, value)
70
+ when Proc
71
+ key_identifier = value.call(data)
72
+ encryption_key = key_repository.key_of(key_identifier)
73
+ raise MissingEncryptionKey.new(key_identifier) unless encryption_key
74
+ acc[key] = {
75
+ cipher: encryption_key.cipher,
76
+ iv: encryption_key.random_iv,
77
+ identifier: key_identifier,
78
+ }
79
+ end
80
+ acc
81
+ end
82
+ end
83
+
84
+ def encrypt_data(data, meta)
85
+ meta.reduce(data) do |acc, (key, value)|
86
+ acc[key] = encrypt_attribute(acc, key, value) if data.has_key?(key)
87
+ acc
88
+ end
89
+ end
90
+
91
+ def decrypt_data(data, meta)
92
+ meta.reduce(data) do |acc, (key, value)|
93
+ acc[key] = decrypt_attribute(data, key, value) if data.has_key?(key)
94
+ acc
95
+ end
96
+ end
97
+
98
+ def encrypt_attribute(data, attribute, meta)
99
+ case meta
100
+ when Leaf
101
+ value = data.fetch(attribute)
102
+ return if value.nil?
103
+
104
+ encryption_key = key_repository.key_of(meta.fetch(:identifier))
105
+ encryption_key.encrypt(serializer.dump(value), meta.fetch(:iv))
106
+ when Hash
107
+ encrypt_data(data.fetch(attribute), meta)
108
+ end
109
+ end
110
+
111
+ def decrypt_attribute(data, attribute, meta)
112
+ case meta
113
+ when Leaf
114
+ cryptogram = data.fetch(attribute)
115
+ return unless cryptogram
116
+
117
+ encryption_key = key_repository.key_of(meta.fetch(:identifier), cipher: meta.fetch(:cipher)) or return forgotten_data
118
+ serializer.load(encryption_key.decrypt(cryptogram, meta.fetch(:iv)))
119
+ when Hash
120
+ decrypt_data(data.fetch(attribute), meta)
121
+ end
122
+ rescue OpenSSL::Cipher::CipherError
123
+ forgotten_data
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyEventStore
4
+ module Mappers
5
+ module Transformation
6
+ class EventClassRemapper
7
+ def initialize(class_map)
8
+ @class_map = class_map
9
+ end
10
+
11
+ def dump(item)
12
+ item
13
+ end
14
+
15
+ def load(item)
16
+ item.merge(event_type: class_map[item.fetch(:event_type)] || item.fetch(:event_type))
17
+ end
18
+
19
+ private
20
+ attr_reader :class_map
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+
5
+ module RubyEventStore
6
+ module Mappers
7
+ module Transformation
8
+ class Item
9
+ include Enumerable
10
+ extend Forwardable
11
+
12
+ def initialize(h)
13
+ @h = {}
14
+ h.each do |k, v|
15
+ @h[k] = (v)
16
+ end
17
+ end
18
+
19
+ def event_id
20
+ fetch(:event_id)
21
+ end
22
+
23
+ def metadata
24
+ fetch(:metadata)
25
+ end
26
+
27
+ def data
28
+ fetch(:data)
29
+ end
30
+
31
+ def event_type
32
+ fetch(:event_type)
33
+ end
34
+
35
+ def ==(other_event)
36
+ other_event.instance_of?(self.class) &&
37
+ other_event.to_h.eql?(to_h)
38
+ end
39
+ alias_method :eql?, :==
40
+
41
+ def merge(args)
42
+ Item.new(@h.merge(args))
43
+ end
44
+
45
+ def to_h
46
+ @h.dup
47
+ end
48
+
49
+ SAFE_HASH_METHODS = [:[], :fetch]
50
+ delegate SAFE_HASH_METHODS => :@h
51
+
52
+ private_constant :SAFE_HASH_METHODS
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyEventStore
4
+ module Mappers
5
+ module Transformation
6
+ class ProtoEvent < DomainEvent
7
+ def load(item)
8
+ Proto.new(
9
+ event_id: item.event_id,
10
+ data: item.data,
11
+ metadata: item.metadata
12
+ )
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyEventStore
4
+ module Mappers
5
+ module Transformation
6
+ class ProtobufEncoder
7
+ def dump(item)
8
+ item.merge(data: encode_data(item.data))
9
+ end
10
+
11
+ def load(item)
12
+ item.merge(data: load_data(item.event_type, item.data))
13
+ end
14
+
15
+ private
16
+ def encode_data(data)
17
+ begin
18
+ data.class.encode(data)
19
+ rescue NoMethodError
20
+ raise ProtobufEncodingFailed
21
+ end
22
+ end
23
+
24
+ def load_data(event_type, protobuf_data)
25
+ Google::Protobuf::DescriptorPool.generated_pool.lookup(event_type).msgclass.decode(protobuf_data)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyEventStore
4
+ module Mappers
5
+ module Transformation
6
+ class ProtobufNestedStructMetadata
7
+ def initialize
8
+ require_optional_dependency
9
+ end
10
+
11
+ def dump(item)
12
+ metadata = ProtobufNestedStruct::HashMapStringValue.dump(item.metadata)
13
+ item.merge(metadata: metadata)
14
+ end
15
+
16
+ def load(item)
17
+ metadata = ProtobufNestedStruct::HashMapStringValue.load(item.metadata)
18
+ symbolize = SymbolizeMetadataKeys.new
19
+ symbolize.load(item.merge(metadata: metadata))
20
+ end
21
+
22
+ def require_optional_dependency
23
+ require 'protobuf_nested_struct'
24
+ rescue LoadError
25
+ raise LoadError, "cannot load such file -- protobuf_nested_struct. Add protobuf_nested_struct gem to Gemfile"
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'yaml'
4
+
5
+ module RubyEventStore
6
+ module Mappers
7
+ module Transformation
8
+ class Serialization
9
+ def initialize(serializer: YAML)
10
+ @serializer = serializer
11
+ end
12
+ attr_reader :serializer
13
+
14
+ 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
+ )
21
+ end
22
+
23
+ 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
+ )
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyEventStore
4
+ module Mappers
5
+ module Transformation
6
+ class SerializedRecord
7
+ def dump(item)
8
+ RubyEventStore::SerializedRecord.new(
9
+ event_id: item.event_id,
10
+ metadata: item.metadata,
11
+ data: item.data,
12
+ event_type: item.event_type
13
+ )
14
+ end
15
+
16
+ def load(serialized_record)
17
+ Item.new(
18
+ event_id: serialized_record.event_id,
19
+ metadata: serialized_record.metadata,
20
+ data: serialized_record.data,
21
+ event_type: serialized_record.event_type
22
+ )
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyEventStore
4
+ module Mappers
5
+ module Transformation
6
+ class StringifyMetadataKeys
7
+ def dump(item)
8
+ stringify(item)
9
+ end
10
+
11
+ def load(item)
12
+ stringify(item)
13
+ end
14
+
15
+ private
16
+ def stringify(item)
17
+ item.merge(
18
+ metadata: TransformKeys.stringify(item.metadata),
19
+ )
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyEventStore
4
+ module Mappers
5
+ module Transformation
6
+ class SymbolizeMetadataKeys
7
+ def dump(item)
8
+ symbolize(item)
9
+ end
10
+
11
+ def load(item)
12
+ symbolize(item)
13
+ end
14
+
15
+ private
16
+ def symbolize(item)
17
+ item.merge(
18
+ metadata: TransformKeys.symbolize(item.metadata),
19
+ )
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end