event_store_client 0.2.7 → 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +27 -37
  3. data/lib/event_store_client.rb +0 -2
  4. data/lib/event_store_client/adapters/grpc.rb +21 -0
  5. data/lib/event_store_client/adapters/grpc/Protos/cluster.proto +149 -0
  6. data/lib/event_store_client/adapters/grpc/Protos/gossip.proto +44 -0
  7. data/lib/event_store_client/adapters/grpc/Protos/operations.proto +45 -0
  8. data/lib/event_store_client/adapters/grpc/Protos/persistent.proto +180 -0
  9. data/lib/event_store_client/adapters/grpc/Protos/projections.proto +174 -0
  10. data/lib/event_store_client/adapters/grpc/Protos/shared.proto +22 -0
  11. data/lib/event_store_client/adapters/grpc/Protos/streams.proto +242 -0
  12. data/lib/event_store_client/adapters/grpc/Protos/users.proto +119 -0
  13. data/lib/event_store_client/adapters/grpc/client.rb +119 -0
  14. data/lib/event_store_client/adapters/grpc/command_registrar.rb +32 -0
  15. data/lib/event_store_client/adapters/grpc/commands/command.rb +43 -0
  16. data/lib/event_store_client/adapters/grpc/commands/persistent_subscriptions/create.rb +46 -0
  17. data/lib/event_store_client/adapters/grpc/commands/persistent_subscriptions/delete.rb +34 -0
  18. data/lib/event_store_client/adapters/grpc/commands/persistent_subscriptions/read.rb +65 -0
  19. data/lib/event_store_client/adapters/grpc/commands/persistent_subscriptions/settings_schema.rb +38 -0
  20. data/lib/event_store_client/adapters/grpc/commands/persistent_subscriptions/update.rb +48 -0
  21. data/lib/event_store_client/adapters/grpc/commands/projections/create.rb +45 -0
  22. data/lib/event_store_client/adapters/grpc/commands/projections/delete.rb +34 -0
  23. data/lib/event_store_client/adapters/grpc/commands/projections/update.rb +42 -0
  24. data/lib/event_store_client/adapters/grpc/commands/streams/append.rb +61 -0
  25. data/lib/event_store_client/adapters/grpc/commands/streams/delete.rb +35 -0
  26. data/lib/event_store_client/adapters/grpc/commands/streams/link_to.rb +61 -0
  27. data/lib/event_store_client/adapters/grpc/commands/streams/read.rb +80 -0
  28. data/lib/event_store_client/adapters/grpc/commands/streams/read_all.rb +43 -0
  29. data/lib/event_store_client/adapters/grpc/commands/streams/tombstone.rb +35 -0
  30. data/lib/event_store_client/adapters/grpc/connection.rb +50 -0
  31. data/lib/event_store_client/adapters/grpc/generated/cluster_pb.rb +140 -0
  32. data/lib/event_store_client/adapters/grpc/generated/cluster_services_pb.rb +46 -0
  33. data/lib/event_store_client/adapters/grpc/generated/gossip_pb.rb +53 -0
  34. data/lib/event_store_client/adapters/grpc/generated/gossip_services_pb.rb +26 -0
  35. data/lib/event_store_client/adapters/grpc/generated/operations_pb.rb +49 -0
  36. data/lib/event_store_client/adapters/grpc/generated/operations_services_pb.rb +31 -0
  37. data/lib/event_store_client/adapters/grpc/generated/persistent_pb.rb +213 -0
  38. data/lib/event_store_client/adapters/grpc/generated/persistent_services_pb.rb +29 -0
  39. data/lib/event_store_client/adapters/grpc/generated/projections_pb.rb +193 -0
  40. data/lib/event_store_client/adapters/grpc/generated/projections_services_pb.rb +34 -0
  41. data/lib/event_store_client/adapters/grpc/generated/shared_pb.rb +35 -0
  42. data/lib/event_store_client/adapters/grpc/generated/streams_pb.rb +283 -0
  43. data/lib/event_store_client/adapters/grpc/generated/streams_services_pb.rb +29 -0
  44. data/lib/event_store_client/adapters/grpc/generated/users_pb.rb +126 -0
  45. data/lib/event_store_client/adapters/grpc/generated/users_services_pb.rb +33 -0
  46. data/lib/event_store_client/adapters/http.rb +16 -0
  47. data/lib/event_store_client/adapters/http/README.md +16 -0
  48. data/lib/event_store_client/adapters/http/client.rb +160 -0
  49. data/lib/event_store_client/adapters/http/commands/command.rb +27 -0
  50. data/lib/event_store_client/adapters/http/commands/persistent_subscriptions/ack.rb +15 -0
  51. data/lib/event_store_client/adapters/http/commands/persistent_subscriptions/create.rb +31 -0
  52. data/lib/event_store_client/adapters/http/commands/persistent_subscriptions/read.rb +57 -0
  53. data/lib/event_store_client/adapters/http/commands/projections/create.rb +30 -0
  54. data/lib/event_store_client/adapters/http/commands/streams/append.rb +49 -0
  55. data/lib/event_store_client/adapters/http/commands/streams/delete.rb +16 -0
  56. data/lib/event_store_client/adapters/http/commands/streams/link_to.rb +49 -0
  57. data/lib/event_store_client/adapters/http/commands/streams/read.rb +53 -0
  58. data/lib/event_store_client/adapters/http/commands/streams/tombstone.rb +17 -0
  59. data/lib/event_store_client/adapters/http/connection.rb +46 -0
  60. data/lib/event_store_client/adapters/http/request_method.rb +28 -0
  61. data/lib/event_store_client/adapters/in_memory.rb +142 -0
  62. data/lib/event_store_client/broker.rb +16 -5
  63. data/lib/event_store_client/client.rb +18 -72
  64. data/lib/event_store_client/configuration.rb +28 -14
  65. data/lib/event_store_client/data_decryptor.rb +13 -8
  66. data/lib/event_store_client/data_encryptor.rb +7 -6
  67. data/lib/event_store_client/deserialized_event.rb +10 -1
  68. data/lib/event_store_client/event.rb +2 -2
  69. data/lib/event_store_client/mapper/default.rb +0 -1
  70. data/lib/event_store_client/serializer/json.rb +2 -0
  71. data/lib/event_store_client/subscriptions.rb +4 -13
  72. data/lib/event_store_client/types.rb +3 -1
  73. data/lib/event_store_client/value_objects/read_direction.rb +43 -0
  74. data/lib/event_store_client/version.rb +1 -1
  75. metadata +97 -15
  76. data/lib/event_store_client/store_adapter.rb +0 -10
  77. data/lib/event_store_client/store_adapter/api/client.rb +0 -224
  78. data/lib/event_store_client/store_adapter/api/connection.rb +0 -43
  79. data/lib/event_store_client/store_adapter/api/request_method.rb +0 -30
  80. data/lib/event_store_client/store_adapter/in_memory.rb +0 -160
@@ -0,0 +1,119 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EventStoreClient
4
+ module GRPC
5
+ class Client
6
+ include Configuration
7
+ # Appends given events to the stream
8
+ # @param [String] Stream name to append events to
9
+ # @param [Array](each: EventStoreClient::DeserializedEvent) list of events to publish
10
+ # @return Dry::Monads::Result::Success or Dry::Monads::Result::Failure
11
+ #
12
+ def append_to_stream(stream_name, events, options: {})
13
+ Commands::Streams::Append.new.call(
14
+ stream_name, events, options: {}
15
+ )
16
+ end
17
+
18
+ # Softly deletes the given stream
19
+ # @param [String] Stream name to delete
20
+ # @param options [Hash] additional options to the request
21
+ # @return Dry::Monads::Result::Success or Dry::Monads::Result::Failure
22
+ #
23
+ def delete_stream(stream_name, options: {})
24
+ Commands::Streams::Delete.new.call(
25
+ stream_name, options: options
26
+ )
27
+ end
28
+
29
+ # Completely removes the given stream
30
+ # @param [String] Stream name to delete
31
+ # @param options [Hash] additional options to the request
32
+ # @return Dry::Monads::Result::Success or Dry::Monads::Result::Failure
33
+ #
34
+ def tombstone_stream(stream_name, options: {})
35
+ Commands::Streams::Tombstone.new.call(stream_name, options: options)
36
+ end
37
+
38
+ # Reads a page of events from the given stream
39
+ # @param [String] Stream name to read events from
40
+ # @param options [Hash] additional options to the request
41
+ # @return Dry::Monads::Result::Success with returned events or Dry::Monads::Result::Failure
42
+ #
43
+ def read(stream_name, options: {})
44
+ Commands::Streams::Read.new.call(stream_name, options: options)
45
+ end
46
+
47
+ # Reads all events from the given stream
48
+ # @param [String] Stream name to read events from
49
+ # @param options [Hash] additional options to the request
50
+ # @return Dry::Monads::Result::Success with returned events or Dry::Monads::Result::Failure
51
+ #
52
+ def read_all_from_stream(stream_name, options: {})
53
+ Commands::Streams::ReadAll.new.call(stream_name, options: options)
54
+ end
55
+
56
+ # Creates the subscription for the given stream
57
+ # @param [EventStoreClient::Subscription] subscription to observe
58
+ # @param options [Hash] additional options to the request
59
+ # @return Dry::Monads::Result::Success or Dry::Monads::Result::Failure
60
+ #
61
+ def subscribe_to_stream(subscription, options: {})
62
+ join_streams(subscription.name, subscription.observed_streams)
63
+ Commands::PersistentSubscriptions::Create.new.call(
64
+ subscription.stream,
65
+ subscription.name,
66
+ options: options
67
+ )
68
+ end
69
+
70
+ # Links given events with the given stream
71
+ # @param [String] Stream name to link events to
72
+ # @param [Array](each: EventStoreClient::DeserializedEvent) a list of events to link
73
+ # @param expected_version [Integer] expected number of events in the stream
74
+ # @return Dry::Monads::Result::Success or Dry::Monads::Result::Failure
75
+ #
76
+ def link_to(stream_name, events, options: {})
77
+ Commands::Streams::LinkTo.new.call(stream_name, events, options: options)
78
+ end
79
+
80
+ # Runs the persistent subscription indeinitely
81
+ # @param [EventStoreClient::Subscription] subscription to observe
82
+ # @param options [Hash] additional options to the request
83
+ # @return - Nothing, it is a blocking operation, yields the given block with event instead
84
+ #
85
+ def listen(subscription, options: {})
86
+ consume_feed(subscription, options: options) do |event|
87
+ yield event if block_given?
88
+ end
89
+ rescue StandardError => e
90
+ config.error_handler&.call(e)
91
+ end
92
+
93
+ private
94
+
95
+ # Joins multiple streams into the new one under the given name
96
+ # @param [String] Name of the stream containing the ones to join
97
+ # @param [Array] (each: String) list of streams to join together
98
+ # @return Dry::Monads::Result::Success or Dry::Monads::Result::Failure
99
+ #
100
+ def join_streams(name, streams)
101
+ Commands::Projections::Create.new.call(name, streams)
102
+ end
103
+
104
+ # @api private
105
+ # Consumes the new events from the subscription
106
+ # @param [EventStoreClient::Subscription] subscription to observe
107
+ # @param options [Hash] additional options to the request
108
+ # @return Dry::Monads::Result::Success or Dry::Monads::Result::Failure
109
+ #
110
+ def consume_feed(subscription, options: {})
111
+ Commands::PersistentSubscriptions::Read.new.call(
112
+ subscription.stream, subscription.name, options: options
113
+ ) do |event|
114
+ yield event if block_given?
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'grpc'
4
+ require 'event_store_client/adapters/grpc/connection'
5
+
6
+ module EventStoreClient
7
+ module GRPC
8
+ class CommandRegistrar
9
+ @commands = {}
10
+
11
+ def self.register_request(command_klass, request:)
12
+ @commands[command_klass] ||= {}
13
+ @commands[command_klass][:request] = request
14
+ end
15
+
16
+ def self.register_service(command_klass, service:)
17
+ @commands[command_klass] ||= {}
18
+ @commands[command_klass][:service] = service
19
+ end
20
+
21
+ def self.request(command_klass)
22
+ @commands[command_klass][:request]
23
+ end
24
+
25
+ def self.service(command_klass)
26
+ EventStoreClient::GRPC::Connection.new.call(
27
+ @commands[command_klass][:service]
28
+ )
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dry-monads'
4
+ require 'event_store_client/adapters/grpc/command_registrar'
5
+
6
+ module EventStoreClient
7
+ module GRPC
8
+ module Commands
9
+ class Command
10
+ include Configuration
11
+
12
+ def self.inherited(klass)
13
+ super
14
+ klass.class_eval do
15
+ include Dry::Monads[:result]
16
+
17
+ def self.use_request(request_klass)
18
+ CommandRegistrar.register_request(self, request: request_klass)
19
+ end
20
+
21
+ def self.use_service(service_klass)
22
+ CommandRegistrar.register_service(self, service: service_klass)
23
+ end
24
+
25
+ def request
26
+ CommandRegistrar.request(self.class)
27
+ end
28
+
29
+ def service
30
+ CommandRegistrar.service(self.class)
31
+ end
32
+ end
33
+ end
34
+
35
+ def metadata
36
+ credentials =
37
+ Base64.encode64("#{config.eventstore_user}:#{config.eventstore_password}")
38
+ { 'authorization' => "Basic #{credentials.delete("\n")}" }
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'grpc'
4
+ require 'event_store_client/adapters/grpc/generated/persistent_pb.rb'
5
+ require 'event_store_client/adapters/grpc/generated/persistent_services_pb.rb'
6
+
7
+ require 'event_store_client/adapters/grpc/commands/command'
8
+ require 'event_store_client/adapters/grpc/commands/persistent_subscriptions/settings_schema'
9
+
10
+ module EventStoreClient
11
+ module GRPC
12
+ module Commands
13
+ module PersistentSubscriptions
14
+ class Create < Command
15
+ use_request EventStore::Client::PersistentSubscriptions::CreateReq
16
+ use_service EventStore::Client::PersistentSubscriptions::PersistentSubscriptions::Stub
17
+
18
+ # Creates persistent subscription in a given group
19
+ # @param [String] name of the stream to subscribe
20
+ # @param [String] name of the subscription group
21
+ # @param [Hash] options - additional settings to be set on subscription.
22
+ # Refer to SettingsSchema for detailed attributes allowed
23
+ # @return [Dry::Monads::Result::Success, Dry::Monads::Result::Failure]
24
+ #
25
+ def call(stream, group, options: {})
26
+ schema = SettingsSchema.call(options)
27
+ return Failure(schema.errors) if schema.failure?
28
+ opts =
29
+ {
30
+ stream_identifier: {
31
+ streamName: stream
32
+ },
33
+ group_name: group,
34
+ settings: schema.to_h
35
+ }
36
+
37
+ service.create(request.new(options: opts), metadata: metadata)
38
+ Success()
39
+ rescue ::GRPC::AlreadyExists
40
+ Failure(:conflict)
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'grpc'
4
+ require 'event_store_client/adapters/grpc/generated/persistent_pb.rb'
5
+ require 'event_store_client/adapters/grpc/generated/persistent_services_pb.rb'
6
+
7
+ require 'event_store_client/adapters/grpc/commands/command'
8
+
9
+ module EventStoreClient
10
+ module GRPC
11
+ module Commands
12
+ module PersistentSubscriptions
13
+ class Delete < Command
14
+ use_request EventStore::Client::PersistentSubscriptions::DeleteReq
15
+ use_service EventStore::Client::PersistentSubscriptions::PersistentSubscriptions::Stub
16
+
17
+ def call(stream, group)
18
+ opts =
19
+ {
20
+ stream_identifier: {
21
+ streamName: stream
22
+ },
23
+ group_name: group
24
+ }
25
+ service.delete(request.new(options: opts), metadata: metadata)
26
+ Success()
27
+ rescue ::GRPC::NotFound
28
+ Failure(:not_found)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'grpc'
4
+ require 'event_store_client/adapters/grpc/generated/persistent_pb.rb'
5
+ require 'event_store_client/adapters/grpc/generated/persistent_services_pb.rb'
6
+
7
+ require 'event_store_client/adapters/grpc/commands/command'
8
+ require 'event_store_client/adapters/grpc/commands/persistent_subscriptions/settings_schema'
9
+ require 'irb'
10
+ module EventStoreClient
11
+ module GRPC
12
+ module Commands
13
+ module PersistentSubscriptions
14
+ class Read < Command
15
+ use_request EventStore::Client::PersistentSubscriptions::ReadReq
16
+ use_service EventStore::Client::PersistentSubscriptions::PersistentSubscriptions::Stub
17
+
18
+ # Read given persistent subscription
19
+ # @param [String] name of the stream to subscribe
20
+ # @param [String] name of the subscription group
21
+ # @param [Hash] options - additional settings to be set on subscription.
22
+ # Refer to SettingsSchema for detailed attributes allowed
23
+ # @return [Dry::Monads::Result::Success, Dry::Monads::Result::Failure]
24
+ #
25
+ def call(stream, group, options: {})
26
+ count = options[:count].to_i
27
+ opts =
28
+ {
29
+ stream_identifier: {
30
+ streamName: stream
31
+ },
32
+ buffer_size: count,
33
+ group_name: group,
34
+ uuid_option: {
35
+ structured: {}
36
+ }
37
+ }
38
+
39
+ requests = [request.new(options: opts)] # please notice that it's an array. Should be?
40
+
41
+ service.read(requests, metadata: metadata).each do |res|
42
+ next if res.subscription_confirmation
43
+ yield deserialize_event(res.event.event) if block_given?
44
+ end
45
+ Success()
46
+ end
47
+
48
+ private
49
+
50
+ def deserialize_event(entry)
51
+ config.mapper.deserialize(
52
+ EventStoreClient::Event.new(
53
+ id: entry.id.string,
54
+ title: "#{entry.stream_revision}@#{entry.stream_identifier.streamName}",
55
+ type: entry.metadata['type'],
56
+ data: entry.data || '{}',
57
+ metadata: (entry.metadata.to_h || {}).to_json
58
+ )
59
+ )
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'grpc'
4
+ require 'event_store_client/adapters/grpc/generated/persistent_pb.rb'
5
+ require 'event_store_client/adapters/grpc/generated/persistent_services_pb.rb'
6
+
7
+ require 'event_store_client/adapters/grpc/commands/command'
8
+
9
+ module EventStoreClient
10
+ module GRPC
11
+ module Commands
12
+ module PersistentSubscriptions
13
+ # Ensures the proper format of the parameters passed to the subscirption request
14
+ #
15
+ SettingsSchema = Dry::Schema.Params do
16
+ optional(:resolve_links).value(Dry::Types['bool'].default(true))
17
+ optional(:revision).value(Dry::Types['integer'])
18
+ optional(:extra_statistics).value(Dry::Types['bool'])
19
+ optional(:max_retry_count).value(Dry::Types['integer'])
20
+ optional(:min_checkpoint_count).value(Dry::Types['integer'])
21
+ optional(:max_checkpoint_count).value(Dry::Types['integer'])
22
+ optional(:max_subscriber_count).value(Dry::Types['integer'])
23
+ optional(:live_buffer_size).value(Dry::Types['integer'])
24
+ optional(:read_batch_size).value(Dry::Types['integer'])
25
+ optional(:history_buffer_size).value(Dry::Types['integer'].default(500))
26
+ optional(:message_timeout_ms).value(Dry::Types['integer'].default(10_000))
27
+ # optional(:message_timeout_ticks).value(Dry::Types['integer'].default(10000))
28
+
29
+ optional(:checkpoint_after_ms).value(Dry::Types['integer'].default(1000))
30
+ optional(:named_consumer_strategy).value(
31
+ Dry::Types['symbol'].default(:RoundRobin),
32
+ included_in?: %i[DispatchToSingle RoundRobin Pinned]
33
+ )
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'grpc'
4
+ require 'event_store_client/adapters/grpc/generated/persistent_pb.rb'
5
+ require 'event_store_client/adapters/grpc/generated/persistent_services_pb.rb'
6
+
7
+ require 'event_store_client/adapters/grpc/commands/command'
8
+ require 'event_store_client/adapters/grpc/commands/persistent_subscriptions/settings_schema'
9
+
10
+ module EventStoreClient
11
+ module GRPC
12
+ module Commands
13
+ module PersistentSubscriptions
14
+ class Update < Command
15
+ use_request EventStore::Client::PersistentSubscriptions::UpdateReq
16
+ use_service EventStore::Client::PersistentSubscriptions::PersistentSubscriptions::Stub
17
+
18
+ # Creates persistent subscription in a given group
19
+ # @param [String] name of the subscription stream to update
20
+ # @param [String] name of the subscription group
21
+ # @param [Hash] options - additional settings to be set on subscription.
22
+ # Refer to EventStoreClient::GRPC::Commands::SettingsSchema
23
+ # for detailed attributes schema
24
+ # @return [Dry::Monads::Result::Success, Dry::Monads::Result::Failure]
25
+ #
26
+ def call(stream, group, options: {})
27
+ schema = SettingsSchema.call(options)
28
+ return Failure(schema.errors) if schema.failure?
29
+
30
+ opts =
31
+ {
32
+ stream_identifier: {
33
+ streamName: stream
34
+ },
35
+ group_name: group,
36
+ settings: schema.to_h
37
+ }
38
+ service.update(request.new(options: opts), metadata: metadata)
39
+ Success()
40
+ rescue ::GRPC::Unknown => e
41
+ return Failure(:not_found) if e.message.include?('DoesNotExist')
42
+ raise e
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'grpc'
4
+ require 'event_store_client/adapters/grpc/generated/projections_pb.rb'
5
+ require 'event_store_client/adapters/grpc/generated/projections_services_pb.rb'
6
+
7
+ require 'event_store_client/adapters/grpc/commands/command'
8
+
9
+ module EventStoreClient
10
+ module GRPC
11
+ module Commands
12
+ module Projections
13
+ class Create < Command
14
+ use_request EventStore::Client::Projections::CreateReq
15
+ use_service EventStore::Client::Projections::Projections::Stub
16
+
17
+ def call(name, streams)
18
+ data = <<~STRING
19
+ fromStreams(#{streams})
20
+ .when({
21
+ $any: function(s,e) {
22
+ linkTo("#{name}", e)
23
+ }
24
+ })
25
+ STRING
26
+
27
+ options =
28
+ {
29
+ query: data,
30
+ continuous: {
31
+ name: name,
32
+ track_emitted_streams: true
33
+ }
34
+ }
35
+
36
+ service.create(request.new(options: options), metadata: metadata)
37
+ Success()
38
+ rescue ::GRPC::Unknown => e
39
+ Failure(:conflict) if e.message.include?('Conflict')
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end