ruby_event_store 1.2.2 → 2.1.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 (51) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -1
  3. data/lib/ruby_event_store.rb +3 -7
  4. data/lib/ruby_event_store/broker.rb +3 -3
  5. data/lib/ruby_event_store/client.rb +47 -23
  6. data/lib/ruby_event_store/composed_dispatcher.rb +2 -2
  7. data/lib/ruby_event_store/constants.rb +1 -0
  8. data/lib/ruby_event_store/errors.rb +0 -1
  9. data/lib/ruby_event_store/event.rb +8 -1
  10. data/lib/ruby_event_store/immediate_async_dispatcher.rb +2 -2
  11. data/lib/ruby_event_store/in_memory_repository.rb +98 -59
  12. data/lib/ruby_event_store/instrumented_dispatcher.rb +2 -2
  13. data/lib/ruby_event_store/instrumented_repository.rb +3 -3
  14. data/lib/ruby_event_store/mappers/default.rb +3 -8
  15. data/lib/ruby_event_store/mappers/encryption_mapper.rb +3 -4
  16. data/lib/ruby_event_store/mappers/instrumented_mapper.rb +4 -4
  17. data/lib/ruby_event_store/mappers/json_mapper.rb +7 -7
  18. data/lib/ruby_event_store/mappers/pipeline.rb +2 -5
  19. data/lib/ruby_event_store/mappers/pipeline_mapper.rb +2 -2
  20. data/lib/ruby_event_store/mappers/transformation/domain_event.rb +16 -8
  21. data/lib/ruby_event_store/mappers/transformation/encryption.rb +20 -12
  22. data/lib/ruby_event_store/mappers/transformation/event_class_remapper.rb +11 -4
  23. data/lib/ruby_event_store/mappers/transformation/stringify_metadata_keys.rb +12 -7
  24. data/lib/ruby_event_store/mappers/transformation/symbolize_metadata_keys.rb +12 -7
  25. data/lib/ruby_event_store/mappers/transformation/upcast.rb +37 -0
  26. data/lib/ruby_event_store/null.rb +13 -0
  27. data/lib/ruby_event_store/projection.rb +2 -1
  28. data/lib/ruby_event_store/record.rb +68 -0
  29. data/lib/ruby_event_store/serialized_record.rb +23 -4
  30. data/lib/ruby_event_store/spec/broker_lint.rb +9 -9
  31. data/lib/ruby_event_store/spec/event_repository_lint.rb +267 -105
  32. data/lib/ruby_event_store/spec/mapper_lint.rb +6 -6
  33. data/lib/ruby_event_store/spec/subscriptions_lint.rb +25 -0
  34. data/lib/ruby_event_store/specification.rb +100 -7
  35. data/lib/ruby_event_store/specification_reader.rb +2 -2
  36. data/lib/ruby_event_store/specification_result.rb +86 -2
  37. data/lib/ruby_event_store/subscriptions.rb +23 -9
  38. data/lib/ruby_event_store/transform_keys.rb +5 -5
  39. data/lib/ruby_event_store/version.rb +1 -1
  40. metadata +15 -21
  41. data/CHANGELOG.md +0 -93
  42. data/Gemfile +0 -11
  43. data/Makefile +0 -22
  44. data/lib/ruby_event_store/mappers/protobuf.rb +0 -24
  45. data/lib/ruby_event_store/mappers/transformation/item.rb +0 -56
  46. data/lib/ruby_event_store/mappers/transformation/proto_event.rb +0 -17
  47. data/lib/ruby_event_store/mappers/transformation/protobuf_encoder.rb +0 -30
  48. data/lib/ruby_event_store/mappers/transformation/protobuf_nested_struct_metadata.rb +0 -30
  49. data/lib/ruby_event_store/mappers/transformation/serialization.rb +0 -34
  50. data/lib/ruby_event_store/mappers/transformation/serialized_record.rb +0 -27
  51. data/ruby_event_store.gemspec +0 -29
@@ -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
 
@@ -7,9 +7,9 @@ module RubyEventStore
7
7
  @instrumentation = instrumentation
8
8
  end
9
9
 
10
- def append_to_stream(events, stream, expected_version)
11
- instrumentation.instrument("append_to_stream.repository.rails_event_store", events: events, stream: stream) do
12
- repository.append_to_stream(events, stream, expected_version)
10
+ def append_to_stream(records, stream, expected_version)
11
+ instrumentation.instrument("append_to_stream.repository.rails_event_store", events: records, stream: stream) do
12
+ repository.append_to_stream(records, stream, expected_version)
13
13
  end
14
14
  end
15
15
 
@@ -1,17 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'yaml'
4
-
5
3
  module RubyEventStore
6
4
  module Mappers
7
5
  class Default < PipelineMapper
8
- def initialize(serializer: YAML, events_class_remapping: {})
6
+ def initialize(events_class_remapping: {})
9
7
  super(Pipeline.new(
10
- transformations: [
11
- Transformation::EventClassRemapper.new(events_class_remapping),
12
- Transformation::SymbolizeMetadataKeys.new,
13
- Transformation::Serialization.new(serializer: serializer),
14
- ]
8
+ Transformation::EventClassRemapper.new(events_class_remapping),
9
+ Transformation::SymbolizeMetadataKeys.new,
15
10
  ))
16
11
  end
17
12
  end
@@ -1,14 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'yaml'
4
+
3
5
  module RubyEventStore
4
6
  module Mappers
5
7
  class EncryptionMapper < PipelineMapper
6
8
  def initialize(key_repository, serializer: YAML, forgotten_data: ForgottenData.new)
7
9
  super(Pipeline.new(
8
- transformations: [
9
- Transformation::Encryption.new(key_repository, serializer: serializer, forgotten_data: forgotten_data),
10
- Transformation::Serialization.new(serializer: serializer),
11
- ]
10
+ Transformation::Encryption.new(key_repository, serializer: serializer, forgotten_data: forgotten_data),
12
11
  ))
13
12
  end
14
13
  end
@@ -8,15 +8,15 @@ 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
 
@@ -2,14 +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
- transformations: [
9
- Transformation::EventClassRemapper.new(events_class_remapping),
10
- Transformation::SymbolizeMetadataKeys.new,
11
- ],
12
- ))
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
13
13
  end
14
14
  end
15
15
  end
@@ -3,13 +3,10 @@
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
+ def initialize(*transformations, to_domain_event: Transformation::DomainEvent.new)
9
7
  @transformations = [
10
8
  to_domain_event,
11
- Array(transformations),
12
- to_serialized_record
9
+ transformations,
13
10
  ].flatten.freeze
14
11
  end
15
12
 
@@ -7,11 +7,11 @@ 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
 
@@ -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
@@ -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,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
@@ -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
@@ -4,7 +4,8 @@ module RubyEventStore
4
4
  class Projection
5
5
  private_class_method :new
6
6
 
7
- def self.from_stream(*streams)
7
+ def self.from_stream(stream_or_streams)
8
+ streams = Array(stream_or_streams)
8
9
  raise(ArgumentError, "At least one stream must be given") if streams.empty?
9
10
  new(streams: streams)
10
11
  end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyEventStore
4
+ class Record
5
+ StringsRequired = Class.new(StandardError)
6
+ def initialize(event_id:, data:, metadata:, event_type:, timestamp:, valid_at:)
7
+ raise StringsRequired unless [event_id, event_type].all? { |v| v.instance_of?(String) }
8
+ @event_id = event_id
9
+ @data = data
10
+ @metadata = metadata
11
+ @event_type = event_type
12
+ @timestamp = timestamp
13
+ @valid_at = valid_at
14
+ @serialized_records = {}
15
+ freeze
16
+ end
17
+
18
+ attr_reader :event_id, :data, :metadata, :event_type, :timestamp, :valid_at
19
+
20
+ BIG_VALUE = 0b110011100100000010010010110011101011110101010101001100111110011
21
+ def hash
22
+ [
23
+ self.class,
24
+ event_id,
25
+ data,
26
+ metadata,
27
+ event_type,
28
+ timestamp,
29
+ valid_at,
30
+ ].hash ^ BIG_VALUE
31
+ end
32
+
33
+ def ==(other)
34
+ other.instance_of?(self.class) &&
35
+ other.event_id.eql?(event_id) &&
36
+ other.data.eql?(data) &&
37
+ other.metadata.eql?(metadata) &&
38
+ other.event_type.eql?(event_type) &&
39
+ other.timestamp.eql?(timestamp) &&
40
+ other.valid_at.eql?(valid_at)
41
+ end
42
+
43
+ def to_h
44
+ {
45
+ event_id: event_id,
46
+ data: data,
47
+ metadata: metadata,
48
+ event_type: event_type,
49
+ timestamp: timestamp,
50
+ valid_at: valid_at,
51
+ }
52
+ end
53
+
54
+ def serialize(serializer)
55
+ @serialized_records[serializer] ||=
56
+ SerializedRecord.new(
57
+ event_id: event_id,
58
+ event_type: event_type,
59
+ data: serializer.dump(data),
60
+ metadata: serializer.dump(metadata),
61
+ timestamp: timestamp.iso8601(TIMESTAMP_PRECISION),
62
+ valid_at: valid_at.iso8601(TIMESTAMP_PRECISION),
63
+ )
64
+ end
65
+
66
+ alias_method :eql?, :==
67
+ end
68
+ end