ruby_event_store 1.2.2 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
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