ruby_event_store 0.30.0 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +9 -1
- data/Makefile +15 -62
- data/lib/ruby_event_store/batch_enumerator.rb +15 -5
- data/lib/ruby_event_store/broker.rb +45 -0
- data/lib/ruby_event_store/client.rb +220 -130
- data/lib/ruby_event_store/composed_dispatcher.rb +24 -0
- data/lib/ruby_event_store/constants.rb +2 -0
- data/lib/ruby_event_store/correlated_commands.rb +42 -0
- data/lib/ruby_event_store/dispatcher.rb +20 -0
- data/lib/ruby_event_store/errors.rb +16 -16
- data/lib/ruby_event_store/event.rb +70 -14
- data/lib/ruby_event_store/expected_version.rb +2 -0
- data/lib/ruby_event_store/immediate_async_dispatcher.rb +17 -0
- data/lib/ruby_event_store/in_memory_repository.rb +45 -17
- data/lib/ruby_event_store/instrumented_dispatcher.rb +23 -0
- data/lib/ruby_event_store/instrumented_repository.rb +63 -0
- data/lib/ruby_event_store/link_by_metadata.rb +57 -0
- data/lib/ruby_event_store/mappers/default.rb +10 -26
- data/lib/ruby_event_store/mappers/encryption_key.rb +74 -0
- data/lib/ruby_event_store/mappers/encryption_mapper.rb +16 -0
- data/lib/ruby_event_store/mappers/forgotten_data.rb +30 -0
- data/lib/ruby_event_store/mappers/in_memory_encryption_key_repository.rb +34 -0
- data/lib/ruby_event_store/mappers/instrumented_mapper.rb +28 -0
- data/lib/ruby_event_store/mappers/json_mapper.rb +16 -0
- data/lib/ruby_event_store/mappers/null_mapper.rb +5 -8
- data/lib/ruby_event_store/mappers/pipeline.rb +31 -0
- data/lib/ruby_event_store/mappers/pipeline_mapper.rb +22 -0
- data/lib/ruby_event_store/mappers/protobuf.rb +13 -67
- data/lib/ruby_event_store/mappers/transformation/domain_event.rb +26 -0
- data/lib/ruby_event_store/mappers/transformation/encryption.rb +128 -0
- data/lib/ruby_event_store/mappers/transformation/event_class_remapper.rb +24 -0
- data/lib/ruby_event_store/mappers/transformation/item.rb +56 -0
- data/lib/ruby_event_store/mappers/transformation/proto_event.rb +17 -0
- data/lib/ruby_event_store/mappers/transformation/protobuf_encoder.rb +30 -0
- data/lib/ruby_event_store/mappers/transformation/protobuf_nested_struct_metadata.rb +30 -0
- data/lib/ruby_event_store/mappers/transformation/serialization.rb +34 -0
- data/lib/ruby_event_store/mappers/transformation/serialized_record.rb +27 -0
- data/lib/ruby_event_store/mappers/transformation/stringify_metadata_keys.rb +24 -0
- data/lib/ruby_event_store/mappers/transformation/symbolize_metadata_keys.rb +24 -0
- data/lib/ruby_event_store/metadata.rb +4 -2
- data/lib/ruby_event_store/projection.rb +34 -12
- data/lib/ruby_event_store/serialized_record.rb +3 -1
- data/lib/ruby_event_store/spec/broker_lint.rb +92 -0
- data/lib/ruby_event_store/spec/dispatcher_lint.rb +4 -36
- data/lib/ruby_event_store/spec/event_lint.rb +71 -0
- data/lib/ruby_event_store/spec/event_repository_lint.rb +1092 -962
- data/lib/ruby_event_store/spec/mapper_lint.rb +17 -0
- data/lib/ruby_event_store/spec/scheduler_lint.rb +9 -0
- data/lib/ruby_event_store/spec/subscriptions_lint.rb +111 -0
- data/lib/ruby_event_store/specification.rb +201 -56
- data/lib/ruby_event_store/specification_reader.rb +43 -0
- data/lib/ruby_event_store/specification_result.rb +212 -0
- data/lib/ruby_event_store/stream.rb +2 -0
- data/lib/ruby_event_store/subscriptions.rb +110 -0
- data/lib/ruby_event_store/transform_keys.rb +31 -0
- data/lib/ruby_event_store/version.rb +3 -1
- data/lib/ruby_event_store.rb +34 -4
- data/ruby_event_store.gemspec +1 -10
- metadata +47 -126
- data/exe/res-deprecated-read-api-migrator +0 -19
- data/lib/ruby_event_store/deprecated_read_api_rewriter.rb +0 -67
- data/lib/ruby_event_store/deprecated_read_api_runner.rb +0 -64
- data/lib/ruby_event_store/deprecations.rb +0 -7
- data/lib/ruby_event_store/pub_sub/broker.rb +0 -73
- data/lib/ruby_event_store/pub_sub/dispatcher.rb +0 -25
- data/lib/ruby_event_store/spec/event_broker_lint.rb +0 -211
@@ -0,0 +1,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
|
10
|
-
|
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
|
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
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
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
|