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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 88193e00bf9ebd58347de1cb3cf58848cc4b09abc603ffef5fb85b2565bf0b74
|
4
|
+
data.tar.gz: 744d44d76c00843f897c321919eed85b9597063d44a52328f7616c6682063d90
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ffd5f11e365d901d7bdf7a6c5d78cad674166416dcd44cd8448982dbe23d8a243ea72b3f66e02c4cab134ef87e3f5d0e519e4de0a913bf26390f7867cc5318d8
|
7
|
+
data.tar.gz: 3044ebfc2ca93c1b5c5fa40afd250c8aac8edc1c5299444b6094df17d1b5214b19400070761a408f8816dbe507fb52c2063587fdd428f911470310ef26434778
|
data/Gemfile
CHANGED
@@ -1,3 +1,11 @@
|
|
1
1
|
source 'https://rubygems.org'
|
2
|
+
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
|
3
|
+
|
2
4
|
gemspec
|
3
|
-
|
5
|
+
|
6
|
+
eval_gemfile File.expand_path('../support/bundler/Gemfile.shared', __dir__)
|
7
|
+
|
8
|
+
gem 'protobuf_nested_struct'
|
9
|
+
gem 'google-protobuf', '~> 3.12.2', '>= 3.12.2'
|
10
|
+
gem 'activesupport', '~> 5.0'
|
11
|
+
gem 'concurrent-ruby', github: 'ruby-concurrency/concurrent-ruby', ref: 'c4cbc968c55e5b983dae953095761896220c46d1'
|
data/Makefile
CHANGED
@@ -1,69 +1,22 @@
|
|
1
1
|
GEM_VERSION = $(shell cat ../RES_VERSION)
|
2
2
|
GEM_NAME = ruby_event_store
|
3
3
|
REQUIRE = $(GEM_NAME)
|
4
|
-
IGNORE = RubyEventStore
|
5
|
-
RubyEventStore::InMemoryRepository\#append_with_synchronize \
|
6
|
-
RubyEventStore::InMemoryRepository\#normalize_to_array \
|
7
|
-
RubyEventStore::Client\#normalize_to_array \
|
8
|
-
RubyEventStore::Client::Within\#normalize_to_array \
|
4
|
+
IGNORE = RubyEventStore::InMemoryRepository\#append_with_synchronize \
|
9
5
|
RubyEventStore::Client::Within\#add_thread_subscribers \
|
10
6
|
RubyEventStore::Client::Within\#add_thread_global_subscribers \
|
11
|
-
RubyEventStore::Client\#
|
12
|
-
RubyEventStore::Client\#
|
13
|
-
RubyEventStore::
|
14
|
-
RubyEventStore::
|
15
|
-
RubyEventStore::
|
16
|
-
RubyEventStore::
|
17
|
-
RubyEventStore::
|
18
|
-
RubyEventStore::
|
19
|
-
SUBJECT ?= RubyEventStore*
|
20
|
-
|
21
|
-
install: ## Install gem dependencies
|
22
|
-
@echo "Installing gem dependencies"
|
23
|
-
@bundle install
|
24
|
-
|
25
|
-
remove-lock:
|
26
|
-
@echo "Removing resolved dependency versions"
|
27
|
-
-rm Gemfile.lock
|
28
|
-
|
29
|
-
reinstall: remove-lock install ## Removing resolved dependency versions
|
30
|
-
|
31
|
-
test: ## Run unit tests
|
32
|
-
@echo "Running unit tests"
|
33
|
-
@bundle exec rspec
|
34
|
-
|
35
|
-
mutate: test ## Run mutation tests
|
36
|
-
@echo "Running mutation tests"
|
37
|
-
@MUTATING=true bundle exec mutant --include lib \
|
38
|
-
$(addprefix --require ,$(REQUIRE)) \
|
39
|
-
$(addprefix --ignore-subject ,$(IGNORE)) \
|
40
|
-
--use rspec "$(SUBJECT)"
|
7
|
+
RubyEventStore::Client::Within\#call \
|
8
|
+
RubyEventStore::Client\#default_correlation_id_generator \
|
9
|
+
RubyEventStore::Mappers::InMemoryEncryptionKeyRepository\#prepare_encrypt \
|
10
|
+
RubyEventStore::Mappers::EncryptionKey\#prepare_encrypt \
|
11
|
+
RubyEventStore::Mappers::EncryptionKey\#prepare_decrypt \
|
12
|
+
RubyEventStore::Mappers::EncryptionKey\#prepare_auth_data \
|
13
|
+
RubyEventStore::Mappers::EncryptionKey\#encrypt_authenticated \
|
14
|
+
RubyEventStore::Mappers::EncryptionKey\#ciphertext_from_authenticated
|
41
15
|
|
42
|
-
|
43
|
-
@echo "Running mutation tests"
|
44
|
-
@MUTATING=true bundle exec mutant --include lib \
|
45
|
-
$(addprefix --require ,$(REQUIRE)) \
|
46
|
-
$(addprefix --ignore-subject ,$(IGNORE)) \
|
47
|
-
--fail-fast \
|
48
|
-
--use rspec "$(SUBJECT)"
|
49
|
-
|
50
|
-
build:
|
51
|
-
@echo "Building gem package"
|
52
|
-
@gem build -V $(GEM_NAME).gemspec
|
53
|
-
@mkdir -p pkg/
|
54
|
-
@mv $(GEM_NAME)-$(GEM_VERSION).gem pkg/
|
55
|
-
|
56
|
-
push:
|
57
|
-
@echo "Pushing package to RubyGems"
|
58
|
-
@gem push -k dev_arkency pkg/$(GEM_NAME)-$(GEM_VERSION).gem
|
59
|
-
|
60
|
-
clean:
|
61
|
-
@echo "Removing previously built package"
|
62
|
-
-rm pkg/$(GEM_NAME)-$(GEM_VERSION).gem
|
63
|
-
|
64
|
-
help:
|
65
|
-
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
|
66
|
-
|
67
|
-
.PHONY: help
|
68
|
-
.DEFAULT_GOAL := help
|
16
|
+
SUBJECT ?= RubyEventStore*
|
69
17
|
|
18
|
+
include ../support/make/install.mk
|
19
|
+
include ../support/make/test.mk
|
20
|
+
include ../support/make/mutant.mk
|
21
|
+
include ../support/make/gem.mk
|
22
|
+
include ../support/make/help.mk
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module RubyEventStore
|
2
4
|
class BatchEnumerator
|
3
5
|
def initialize(batch_size, total_limit, reader)
|
@@ -8,18 +10,26 @@ module RubyEventStore
|
|
8
10
|
|
9
11
|
def each
|
10
12
|
return to_enum unless block_given?
|
11
|
-
|
12
|
-
|
13
|
-
batch_limit
|
14
|
-
result
|
13
|
+
|
14
|
+
0.step(total_limit - 1, batch_size) do |batch_offset|
|
15
|
+
batch_limit = [batch_size, total_limit - batch_offset].min
|
16
|
+
result = reader.call(batch_offset, batch_limit)
|
15
17
|
|
16
18
|
break if result.empty?
|
17
19
|
yield result
|
18
20
|
end
|
19
21
|
end
|
20
22
|
|
23
|
+
def first
|
24
|
+
each.first
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_a
|
28
|
+
each.to_a
|
29
|
+
end
|
30
|
+
|
21
31
|
private
|
22
32
|
|
23
|
-
|
33
|
+
attr_reader :batch_size, :total_limit, :reader
|
24
34
|
end
|
25
35
|
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyEventStore
|
4
|
+
class Broker
|
5
|
+
def initialize(subscriptions:, dispatcher:)
|
6
|
+
@subscriptions = subscriptions
|
7
|
+
@dispatcher = dispatcher
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(event, serialized_event)
|
11
|
+
subscribers = subscriptions.all_for(event.event_type)
|
12
|
+
subscribers.each do |subscriber|
|
13
|
+
dispatcher.call(subscriber, event, serialized_event)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def add_subscription(subscriber, event_types)
|
18
|
+
verify_subscription(subscriber)
|
19
|
+
subscriptions.add_subscription(subscriber, event_types)
|
20
|
+
end
|
21
|
+
|
22
|
+
def add_global_subscription(subscriber)
|
23
|
+
verify_subscription(subscriber)
|
24
|
+
subscriptions.add_global_subscription(subscriber)
|
25
|
+
end
|
26
|
+
|
27
|
+
def add_thread_subscription(subscriber, event_types)
|
28
|
+
verify_subscription(subscriber)
|
29
|
+
subscriptions.add_thread_subscription(subscriber, event_types)
|
30
|
+
end
|
31
|
+
|
32
|
+
def add_thread_global_subscription(subscriber)
|
33
|
+
verify_subscription(subscriber)
|
34
|
+
subscriptions.add_thread_global_subscription(subscriber)
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
attr_reader :subscriptions, :dispatcher
|
39
|
+
|
40
|
+
def verify_subscription(subscriber)
|
41
|
+
raise SubscriberNotExist, "subscriber must be first argument or block" unless subscriber
|
42
|
+
raise InvalidHandler.new("Handler #{subscriber} is invalid for dispatcher #{dispatcher}") unless dispatcher.verify(subscriber)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -1,231 +1,321 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'concurrent'
|
4
|
+
|
1
5
|
module RubyEventStore
|
2
6
|
class Client
|
3
7
|
def initialize(repository:,
|
4
8
|
mapper: Mappers::Default.new,
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
+
subscriptions: Subscriptions.new,
|
10
|
+
dispatcher: Dispatcher.new,
|
11
|
+
clock: default_clock,
|
12
|
+
correlation_id_generator: default_correlation_id_generator)
|
9
13
|
@repository = repository
|
10
14
|
@mapper = mapper
|
11
|
-
@
|
12
|
-
@page_size = page_size
|
13
|
-
warn "`RubyEventStore::Client#metadata_proc` has been deprecated. Use `RubyEventStore::Client#with_metadata` instead." if metadata_proc
|
14
|
-
@metadata_proc = metadata_proc
|
15
|
+
@broker = Broker.new(subscriptions: subscriptions, dispatcher: dispatcher)
|
15
16
|
@clock = clock
|
17
|
+
@metadata = Concurrent::ThreadLocalVar.new
|
18
|
+
@correlation_id_generator = correlation_id_generator
|
16
19
|
end
|
17
20
|
|
18
|
-
def publish_events(events, stream_name: GLOBAL_STREAM, expected_version: :any)
|
19
|
-
append_to_stream(events, stream_name: stream_name, expected_version: expected_version)
|
20
|
-
events.each do |ev|
|
21
|
-
event_broker.notify_subscribers(ev)
|
22
|
-
end
|
23
|
-
:ok
|
24
|
-
end
|
25
21
|
|
26
|
-
|
27
|
-
|
22
|
+
# Persists events and notifies subscribed handlers about them
|
23
|
+
#
|
24
|
+
# @param events [Array<Event, Proto>, Event, Proto] event(s)
|
25
|
+
# @param stream_name [String] name of the stream for persisting events.
|
26
|
+
# @param expected_version [:any, :auto, :none, Integer] controls optimistic locking strategy. {http://railseventstore.org/docs/expected_version/ Read more}
|
27
|
+
# @return [self]
|
28
|
+
def publish(events, stream_name: GLOBAL_STREAM, expected_version: :any)
|
29
|
+
enriched_events = enrich_events_metadata(events)
|
30
|
+
serialized_events = serialize_events(enriched_events)
|
31
|
+
append_to_stream_serialized_events(serialized_events, stream_name: stream_name, expected_version: expected_version)
|
32
|
+
enriched_events.zip(serialized_events) do |event, serialized_event|
|
33
|
+
with_metadata(
|
34
|
+
correlation_id: event.metadata.fetch(:correlation_id),
|
35
|
+
causation_id: event.event_id,
|
36
|
+
) do
|
37
|
+
broker.(event, serialized_event)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
self
|
28
41
|
end
|
29
42
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
43
|
+
# Persists new event(s) without notifying any subscribed handlers
|
44
|
+
#
|
45
|
+
# @param (see #publish)
|
46
|
+
# @return [self]
|
47
|
+
def append(events, stream_name: GLOBAL_STREAM, expected_version: :any)
|
48
|
+
serialized_events = serialize_events(enrich_events_metadata(events))
|
49
|
+
append_to_stream_serialized_events(serialized_events, stream_name: stream_name, expected_version: expected_version)
|
50
|
+
self
|
35
51
|
end
|
36
52
|
|
37
|
-
|
53
|
+
# Links already persisted event(s) to a different stream.
|
54
|
+
# Does not notify any subscribed handlers.
|
55
|
+
#
|
56
|
+
# @param event_ids [String, Array<String>] ids of events
|
57
|
+
# @param stream_name (see #publish)
|
58
|
+
# @param expected_version (see #publish)
|
59
|
+
# @return [self]
|
60
|
+
def link(event_ids, stream_name:, expected_version: :any)
|
38
61
|
repository.link_to_stream(event_ids, Stream.new(stream_name), ExpectedVersion.new(expected_version))
|
39
62
|
self
|
40
63
|
end
|
41
64
|
|
65
|
+
# Deletes a stream.
|
66
|
+
# All events from the stream remain intact but they are no
|
67
|
+
# longer linked to the stream.
|
68
|
+
#
|
69
|
+
# @param stream_name [String] name of the stream to be cleared.
|
70
|
+
# @return [self]
|
42
71
|
def delete_stream(stream_name)
|
43
72
|
repository.delete_stream(Stream.new(stream_name))
|
44
|
-
|
45
|
-
end
|
46
|
-
|
47
|
-
def read_events_forward(stream_name, start: :head, count: page_size)
|
48
|
-
warn <<~EOW
|
49
|
-
RubyEventStore::Client#read_events_forward has been deprecated.
|
50
|
-
|
51
|
-
Use following fluent API to receive exact results:
|
52
|
-
client.read.stream(stream_name).limit(count).from(start).each.to_a
|
53
|
-
EOW
|
54
|
-
read.stream(stream_name).limit(count).from(start).each.to_a
|
55
|
-
end
|
56
|
-
|
57
|
-
def read_events_backward(stream_name, start: :head, count: page_size)
|
58
|
-
warn <<~EOW
|
59
|
-
RubyEventStore::Client#read_events_backward has been deprecated.
|
60
|
-
|
61
|
-
Use following fluent API to receive exact results:
|
62
|
-
client.read.stream(stream_name).limit(count).from(start).backward.each.to_a
|
63
|
-
EOW
|
64
|
-
read.stream(stream_name).limit(count).from(start).backward.each.to_a
|
65
|
-
end
|
66
|
-
|
67
|
-
def read_stream_events_forward(stream_name)
|
68
|
-
warn <<~EOW
|
69
|
-
RubyEventStore::Client#read_stream_events_forward has been deprecated.
|
70
|
-
|
71
|
-
Use following fluent API to receive exact results:
|
72
|
-
client.read.stream(stream_name).each.to_a
|
73
|
-
EOW
|
74
|
-
read.stream(stream_name).each.to_a
|
75
|
-
end
|
76
|
-
|
77
|
-
def read_stream_events_backward(stream_name)
|
78
|
-
warn <<~EOW
|
79
|
-
RubyEventStore::Client#read_stream_events_backward has been deprecated.
|
80
|
-
|
81
|
-
Use following fluent API to receive exact results:
|
82
|
-
client.read.stream(stream_name).backward.each.to_a
|
83
|
-
EOW
|
84
|
-
read.stream(stream_name).backward.each.to_a
|
85
|
-
end
|
86
|
-
|
87
|
-
def read_all_streams_forward(start: :head, count: page_size)
|
88
|
-
warn <<~EOW
|
89
|
-
RubyEventStore::Client#read_all_streams_forward has been deprecated.
|
90
|
-
|
91
|
-
Use following fluent API to receive exact results:
|
92
|
-
client.read.limit(count).from(start).each.to_a
|
93
|
-
EOW
|
94
|
-
read.limit(count).from(start).each.to_a
|
95
|
-
end
|
96
|
-
|
97
|
-
def read_all_streams_backward(start: :head, count: page_size)
|
98
|
-
warn <<~EOW
|
99
|
-
RubyEventStore::Client#read_all_streams_backward has been deprecated.
|
100
|
-
|
101
|
-
Use following fluent API to receive exact results:
|
102
|
-
client.read.limit(count).from(start).backward.each.to_a
|
103
|
-
EOW
|
104
|
-
read.limit(count).from(start).backward.each.to_a
|
73
|
+
self
|
105
74
|
end
|
106
75
|
|
107
|
-
|
108
|
-
|
76
|
+
# Starts building a query specification for reading events.
|
77
|
+
# {http://railseventstore.org/docs/read/ More info.}
|
78
|
+
#
|
79
|
+
# @return [Specification]
|
80
|
+
def read
|
81
|
+
Specification.new(SpecificationReader.new(repository, mapper))
|
109
82
|
end
|
110
83
|
|
111
|
-
|
112
|
-
|
84
|
+
# Gets list of streams where event is stored or linked
|
85
|
+
#
|
86
|
+
# @return [Array<Stream>] where event is stored or linked
|
87
|
+
def streams_of(event_id)
|
88
|
+
repository.streams_of(event_id)
|
113
89
|
end
|
114
90
|
|
115
|
-
#
|
116
|
-
#
|
91
|
+
# Subscribes a handler (subscriber) that will be invoked for published events of provided type.
|
92
|
+
#
|
93
|
+
# @overload subscribe(subscriber, to:)
|
94
|
+
# @param to [Array<Class>] types of events to subscribe
|
95
|
+
# @param subscriber [Object, Class] handler
|
96
|
+
# @return [Proc] - unsubscribe proc. Call to unsubscribe.
|
97
|
+
# @raise [ArgumentError, SubscriberNotExist]
|
98
|
+
# @overload subscribe(to:, &subscriber)
|
99
|
+
# @param to [Array<Class>] types of events to subscribe
|
100
|
+
# @param subscriber [Proc] handler
|
101
|
+
# @return [Proc] - unsubscribe proc. Call to unsubscribe.
|
102
|
+
# @raise [ArgumentError, SubscriberNotExist]
|
117
103
|
def subscribe(subscriber = nil, to:, &proc)
|
118
104
|
raise ArgumentError, "subscriber must be first argument or block, cannot be both" if subscriber && proc
|
119
|
-
raise SubscriberNotExist, "subscriber must be first argument or block" unless subscriber || proc
|
120
105
|
subscriber ||= proc
|
121
|
-
|
106
|
+
broker.add_subscription(subscriber, to)
|
122
107
|
end
|
123
108
|
|
124
|
-
#
|
125
|
-
#
|
109
|
+
# Subscribes a handler (subscriber) that will be invoked for all published events
|
110
|
+
#
|
111
|
+
# @overload subscribe_to_all_events(subscriber)
|
112
|
+
# @param subscriber [Object, Class] handler
|
113
|
+
# @return [Proc] - unsubscribe proc. Call to unsubscribe.
|
114
|
+
# @raise [ArgumentError, SubscriberNotExist]
|
115
|
+
# @overload subscribe_to_all_events(&subscriber)
|
116
|
+
# @param subscriber [Proc] handler
|
117
|
+
# @return [Proc] - unsubscribe proc. Call to unsubscribe.
|
118
|
+
# @raise [ArgumentError, SubscriberNotExist]
|
126
119
|
def subscribe_to_all_events(subscriber = nil, &proc)
|
127
120
|
raise ArgumentError, "subscriber must be first argument or block, cannot be both" if subscriber && proc
|
128
|
-
|
129
|
-
event_broker.add_global_subscriber(subscriber || proc)
|
121
|
+
broker.add_global_subscription(subscriber || proc)
|
130
122
|
end
|
131
123
|
|
124
|
+
# Builder object for collecting temporary handlers (subscribers)
|
125
|
+
# which are active only during the invocation of the provided
|
126
|
+
# block of code.
|
132
127
|
class Within
|
133
|
-
def initialize(block,
|
128
|
+
def initialize(block, broker)
|
134
129
|
@block = block
|
135
|
-
@
|
130
|
+
@broker = broker
|
136
131
|
@global_subscribers = []
|
137
132
|
@subscribers = Hash.new {[]}
|
138
133
|
end
|
139
134
|
|
135
|
+
# Subscribes temporary handlers that
|
136
|
+
# will be called for all published events.
|
137
|
+
# The subscription is active only during the invocation
|
138
|
+
# of the block of code provided to {Client#within}.
|
139
|
+
# {http://railseventstore.org/docs/subscribe/#temporary-subscriptions Read more.}
|
140
|
+
#
|
141
|
+
# @param handlers [Object, Class] handlers passed as objects or classes
|
142
|
+
# @param handler2 [Proc] handler passed as proc
|
143
|
+
# @return [self]
|
140
144
|
def subscribe_to_all_events(*handlers, &handler2)
|
141
145
|
handlers << handler2 if handler2
|
142
146
|
@global_subscribers += handlers
|
143
147
|
self
|
144
148
|
end
|
145
149
|
|
150
|
+
# Subscribes temporary handlers that
|
151
|
+
# will be called for published events of provided type.
|
152
|
+
# The subscription is active only during the invocation
|
153
|
+
# of the block of code provided to {Client#within}.
|
154
|
+
# {http://railseventstore.org/docs/subscribe/#temporary-subscriptions Read more.}
|
155
|
+
#
|
156
|
+
# @overload subscribe(handler, to:)
|
157
|
+
# @param handler [Object, Class] handler passed as objects or classes
|
158
|
+
# @param to [Array<Class>] types of events to subscribe
|
159
|
+
# @return [self]
|
160
|
+
# @overload subscribe(to:, &handler)
|
161
|
+
# @param to [Array<Class>] types of events to subscribe
|
162
|
+
# @param handler [Proc] handler passed as proc
|
163
|
+
# @return [self]
|
146
164
|
def subscribe(handler=nil, to:, &handler2)
|
147
165
|
raise ArgumentError if handler && handler2
|
148
|
-
@subscribers[handler || handler2] +=
|
166
|
+
@subscribers[handler || handler2] += Array(to)
|
149
167
|
self
|
150
168
|
end
|
151
169
|
|
170
|
+
# Invokes the block of code provided to {Client#within}
|
171
|
+
# and then unsubscribes temporary handlers.
|
172
|
+
# {http://railseventstore.org/docs/subscribe/#temporary-subscriptions Read more.}
|
173
|
+
#
|
174
|
+
# @return [Object] value returned by the invoked block of code
|
152
175
|
def call
|
153
176
|
unsubs = add_thread_global_subscribers
|
154
177
|
unsubs += add_thread_subscribers
|
155
178
|
@block.call
|
156
179
|
ensure
|
157
|
-
unsubs.each(&:call)
|
180
|
+
unsubs.each(&:call) if unsubs
|
158
181
|
end
|
159
182
|
|
160
183
|
private
|
161
184
|
|
162
185
|
def add_thread_subscribers
|
163
|
-
@subscribers.map do |
|
164
|
-
@
|
186
|
+
@subscribers.map do |subscriber, types|
|
187
|
+
@broker.add_thread_subscription(subscriber, types)
|
165
188
|
end
|
166
189
|
end
|
167
190
|
|
168
191
|
def add_thread_global_subscribers
|
169
|
-
@global_subscribers.map do |
|
170
|
-
@
|
192
|
+
@global_subscribers.map do |subscriber|
|
193
|
+
@broker.add_thread_global_subscription(subscriber)
|
171
194
|
end
|
172
195
|
end
|
173
|
-
|
174
|
-
def normalize_to_array(objs)
|
175
|
-
return *objs
|
176
|
-
end
|
177
196
|
end
|
178
197
|
|
198
|
+
# Use for starting temporary subscriptions.
|
199
|
+
# {http://railseventstore.org/docs/subscribe/#temporary-subscriptions Read more}
|
200
|
+
#
|
201
|
+
# @param block [Proc] block of code during which the temporary subscriptions will be active
|
202
|
+
# @return [Within] builder object which collects temporary subscriptions
|
179
203
|
def within(&block)
|
180
204
|
raise ArgumentError if block.nil?
|
181
|
-
Within.new(block,
|
205
|
+
Within.new(block, broker)
|
182
206
|
end
|
183
207
|
|
208
|
+
# Set additional metadata for all events published within the provided block
|
209
|
+
# {http://railseventstore.org/docs/request_metadata#passing-your-own-metadata-using-with_metadata-method Read more}
|
210
|
+
#
|
211
|
+
# @param metadata [Hash] metadata to set for events
|
212
|
+
# @param block [Proc] block of code during which the metadata will be added
|
213
|
+
# @return [Object] last value returned by the provided block
|
184
214
|
def with_metadata(metadata, &block)
|
185
215
|
previous_metadata = metadata()
|
186
|
-
self.metadata =
|
216
|
+
self.metadata = previous_metadata.merge(metadata)
|
187
217
|
block.call if block_given?
|
188
218
|
ensure
|
189
219
|
self.metadata = previous_metadata
|
190
220
|
end
|
191
221
|
|
222
|
+
# Deserialize event which was serialized for async event handlers
|
223
|
+
# {http://railseventstore.org/docs/subscribe/#async-handlers Read more}
|
224
|
+
#
|
225
|
+
# @return [Event, Proto] deserialized event
|
226
|
+
def deserialize(event_type:, event_id:, data:, metadata:)
|
227
|
+
mapper.serialized_record_to_event(SerializedRecord.new(event_type: event_type, event_id: event_id, data: data, metadata: metadata))
|
228
|
+
end
|
229
|
+
|
230
|
+
# Read additional metadata which will be added for published events
|
231
|
+
# {http://railseventstore.org/docs/request_metadata#passing-your-own-metadata-using-with_metadata-method Read more}
|
232
|
+
#
|
233
|
+
# @return [Hash]
|
234
|
+
def metadata
|
235
|
+
@metadata.value || EMPTY_HASH
|
236
|
+
end
|
237
|
+
|
238
|
+
# Overwrite existing event(s) with the same ID.
|
239
|
+
#
|
240
|
+
# Does not notify any subscribed handlers.
|
241
|
+
# Does not enrich with additional current metadata.
|
242
|
+
# Does not allow changing which streams these events are in.
|
243
|
+
# {http://railseventstore.org/docs/migrating_messages Read more}
|
244
|
+
#
|
245
|
+
# @example Add data and metadata to existing events
|
246
|
+
#
|
247
|
+
# events = event_store.read.limit(10).to_a
|
248
|
+
# events.each do |ev|
|
249
|
+
# ev.data[:tenant_id] = 1
|
250
|
+
# ev.metadata[:server_id] = "eu-west-2"
|
251
|
+
# end
|
252
|
+
# event_store.overwrite(events)
|
253
|
+
#
|
254
|
+
# @example Change event type
|
255
|
+
#
|
256
|
+
# events = event_store.read.limit(10).each.select{|ev| OldType === ev }.map do |ev|
|
257
|
+
# NewType.new(
|
258
|
+
# event_id: ev.event_id,
|
259
|
+
# data: ev.data,
|
260
|
+
# metadata: ev.metadata,
|
261
|
+
# )
|
262
|
+
# end
|
263
|
+
# event_store.overwrite(events)
|
264
|
+
#
|
265
|
+
# @param events [Array<Event, Proto>, Event, Proto] event(s) to serialize and overwrite again
|
266
|
+
# @return [self]
|
267
|
+
def overwrite(events_or_event)
|
268
|
+
events = Array(events_or_event)
|
269
|
+
serialized_events = serialize_events(events)
|
270
|
+
repository.update_messages(serialized_events)
|
271
|
+
self
|
272
|
+
end
|
273
|
+
|
274
|
+
def inspect
|
275
|
+
"#<#{self.class}:0x#{__id__.to_s(16)}>"
|
276
|
+
end
|
277
|
+
|
278
|
+
EMPTY_HASH = {}.freeze
|
279
|
+
private_constant :EMPTY_HASH
|
280
|
+
|
192
281
|
private
|
193
282
|
|
194
|
-
def
|
283
|
+
def serialize_events(events)
|
195
284
|
events.map do |ev|
|
196
285
|
mapper.event_to_serialized_record(ev)
|
197
286
|
end
|
198
287
|
end
|
199
288
|
|
200
|
-
def
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
def normalize_to_array(events)
|
205
|
-
return *events
|
289
|
+
def enrich_events_metadata(events)
|
290
|
+
events = Array(events)
|
291
|
+
events.each{|event| enrich_event_metadata(event) }
|
292
|
+
events
|
206
293
|
end
|
207
294
|
|
208
295
|
def enrich_event_metadata(event)
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
end
|
213
|
-
if metadata
|
214
|
-
metadata.each { |key, value| event.metadata[key] = value }
|
215
|
-
end
|
216
|
-
event.metadata[:timestamp] ||= clock.call
|
296
|
+
metadata.each { |key, value| event.metadata[key] ||= value }
|
297
|
+
event.metadata[:timestamp] ||= clock.call
|
298
|
+
event.metadata[:correlation_id] ||= correlation_id_generator.call
|
217
299
|
end
|
218
300
|
|
219
|
-
|
301
|
+
def append_to_stream_serialized_events(serialized_events, stream_name:, expected_version:)
|
302
|
+
repository.append_to_stream(serialized_events, Stream.new(stream_name), ExpectedVersion.new(expected_version))
|
303
|
+
end
|
220
304
|
|
221
305
|
protected
|
222
306
|
|
223
|
-
def metadata
|
224
|
-
|
307
|
+
def metadata=(value)
|
308
|
+
@metadata.value = value
|
225
309
|
end
|
226
310
|
|
227
|
-
def
|
228
|
-
|
311
|
+
def default_clock
|
312
|
+
->{ Time.now.utc }
|
229
313
|
end
|
314
|
+
|
315
|
+
def default_correlation_id_generator
|
316
|
+
->{ SecureRandom.uuid }
|
317
|
+
end
|
318
|
+
|
319
|
+
attr_reader :repository, :mapper, :broker, :clock, :correlation_id_generator
|
230
320
|
end
|
231
321
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyEventStore
|
4
|
+
class ComposedDispatcher
|
5
|
+
def initialize(*dispatchers)
|
6
|
+
@dispatchers = dispatchers
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(subscriber, event, serialized_event)
|
10
|
+
@dispatchers.each do |dispatcher|
|
11
|
+
if dispatcher.verify(subscriber)
|
12
|
+
dispatcher.call(subscriber, event, serialized_event)
|
13
|
+
break
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def verify(subscriber)
|
19
|
+
@dispatchers.any? do |dispatcher|
|
20
|
+
dispatcher.verify(subscriber)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|