event_store_client 1.4.9 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (116) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +30 -145
  3. data/docs/appending_events.md +155 -0
  4. data/docs/catch_up_subscriptions.md +253 -0
  5. data/docs/configuration.md +83 -0
  6. data/docs/deleting_streams.md +25 -0
  7. data/docs/encrypting_events.md +84 -0
  8. data/docs/linking_events.md +149 -0
  9. data/docs/reading_events.md +200 -0
  10. data/lib/event_store_client/adapters/grpc/client.rb +244 -105
  11. data/lib/event_store_client/adapters/grpc/cluster/gossip_discover.rb +131 -0
  12. data/lib/event_store_client/adapters/grpc/cluster/insecure_connection.rb +21 -0
  13. data/lib/event_store_client/adapters/grpc/cluster/member.rb +18 -0
  14. data/lib/event_store_client/adapters/grpc/cluster/queryless_discover.rb +25 -0
  15. data/lib/event_store_client/adapters/grpc/cluster/secure_connection.rb +71 -0
  16. data/lib/event_store_client/adapters/grpc/command_registrar.rb +7 -7
  17. data/lib/event_store_client/adapters/grpc/commands/command.rb +63 -25
  18. data/lib/event_store_client/adapters/grpc/commands/gossip/cluster_info.rb +24 -0
  19. data/lib/event_store_client/adapters/grpc/commands/streams/append.rb +43 -68
  20. data/lib/event_store_client/adapters/grpc/commands/streams/append_multiple.rb +44 -0
  21. data/lib/event_store_client/adapters/grpc/commands/streams/delete.rb +21 -17
  22. data/lib/event_store_client/adapters/grpc/commands/streams/hard_delete.rb +39 -0
  23. data/lib/event_store_client/adapters/grpc/commands/streams/link_to.rb +7 -52
  24. data/lib/event_store_client/adapters/grpc/commands/streams/link_to_multiple.rb +44 -0
  25. data/lib/event_store_client/adapters/grpc/commands/streams/read.rb +20 -85
  26. data/lib/event_store_client/adapters/grpc/commands/streams/read_paginated.rb +174 -0
  27. data/lib/event_store_client/adapters/grpc/commands/streams/subscribe.rb +31 -106
  28. data/lib/event_store_client/adapters/grpc/connection.rb +56 -36
  29. data/lib/event_store_client/adapters/grpc/discover.rb +75 -0
  30. data/lib/event_store_client/adapters/grpc/generated/cluster_pb.rb +106 -18
  31. data/lib/event_store_client/adapters/grpc/generated/cluster_services_pb.rb +12 -12
  32. data/lib/event_store_client/adapters/grpc/generated/code_pb.rb +34 -0
  33. data/lib/event_store_client/adapters/grpc/generated/gossip_pb.rb +3 -2
  34. data/lib/event_store_client/adapters/grpc/generated/gossip_services_pb.rb +3 -3
  35. data/lib/event_store_client/adapters/grpc/generated/monitoring_pb.rb +25 -0
  36. data/lib/event_store_client/adapters/grpc/generated/monitoring_services_pb.rb +26 -0
  37. data/lib/event_store_client/adapters/grpc/generated/operations_pb.rb +2 -1
  38. data/lib/event_store_client/adapters/grpc/generated/operations_services_pb.rb +8 -7
  39. data/lib/event_store_client/adapters/grpc/generated/persistent_pb.rb +199 -38
  40. data/lib/event_store_client/adapters/grpc/generated/persistent_services_pb.rb +7 -3
  41. data/lib/event_store_client/adapters/grpc/generated/projections_pb.rb +9 -26
  42. data/lib/event_store_client/adapters/grpc/generated/projections_services_pb.rb +4 -3
  43. data/lib/event_store_client/adapters/grpc/generated/serverfeatures_pb.rb +29 -0
  44. data/lib/event_store_client/adapters/grpc/generated/serverfeatures_services_pb.rb +26 -0
  45. data/lib/event_store_client/adapters/grpc/generated/shared_pb.rb +54 -12
  46. data/lib/event_store_client/adapters/grpc/generated/status_pb.rb +23 -0
  47. data/lib/event_store_client/adapters/grpc/generated/streams_pb.rb +104 -64
  48. data/lib/event_store_client/adapters/grpc/generated/streams_services_pb.rb +3 -2
  49. data/lib/event_store_client/adapters/grpc/generated/users_services_pb.rb +2 -2
  50. data/lib/event_store_client/adapters/grpc/options/streams/read_options.rb +78 -0
  51. data/lib/event_store_client/adapters/grpc/options/streams/write_options.rb +39 -0
  52. data/lib/event_store_client/adapters/grpc/shared/event_deserializer.rb +52 -0
  53. data/lib/event_store_client/adapters/grpc/shared/options/filter_options.rb +76 -0
  54. data/lib/event_store_client/adapters/grpc/shared/options/stream_options.rb +91 -0
  55. data/lib/event_store_client/adapters/grpc/shared/streams/process_response.rb +28 -0
  56. data/lib/event_store_client/adapters/grpc/shared/streams/process_responses.rb +33 -0
  57. data/lib/event_store_client/adapters/grpc.rb +28 -12
  58. data/lib/event_store_client/configuration.rb +39 -54
  59. data/lib/event_store_client/connection/url.rb +57 -0
  60. data/lib/event_store_client/connection/url_parser.rb +144 -0
  61. data/lib/event_store_client/data_decryptor.rb +2 -9
  62. data/lib/event_store_client/deserialized_event.rb +35 -10
  63. data/lib/event_store_client/encryption_metadata.rb +0 -1
  64. data/lib/event_store_client/event.rb +4 -2
  65. data/lib/event_store_client/extensions/options_extension.rb +87 -0
  66. data/lib/event_store_client/mapper/default.rb +12 -9
  67. data/lib/event_store_client/mapper/encrypted.rb +18 -17
  68. data/lib/event_store_client/types.rb +1 -1
  69. data/lib/event_store_client/utils.rb +30 -0
  70. data/lib/event_store_client/version.rb +1 -1
  71. data/lib/event_store_client.rb +8 -7
  72. metadata +75 -84
  73. data/lib/event_store_client/adapters/grpc/Protos/cluster.proto +0 -149
  74. data/lib/event_store_client/adapters/grpc/Protos/gossip.proto +0 -44
  75. data/lib/event_store_client/adapters/grpc/Protos/operations.proto +0 -45
  76. data/lib/event_store_client/adapters/grpc/Protos/persistent.proto +0 -180
  77. data/lib/event_store_client/adapters/grpc/Protos/projections.proto +0 -174
  78. data/lib/event_store_client/adapters/grpc/Protos/shared.proto +0 -22
  79. data/lib/event_store_client/adapters/grpc/Protos/streams.proto +0 -242
  80. data/lib/event_store_client/adapters/grpc/Protos/users.proto +0 -119
  81. data/lib/event_store_client/adapters/grpc/README.md +0 -16
  82. data/lib/event_store_client/adapters/grpc/commands/persistent_subscriptions/create.rb +0 -46
  83. data/lib/event_store_client/adapters/grpc/commands/persistent_subscriptions/delete.rb +0 -34
  84. data/lib/event_store_client/adapters/grpc/commands/persistent_subscriptions/read.rb +0 -77
  85. data/lib/event_store_client/adapters/grpc/commands/persistent_subscriptions/settings_schema.rb +0 -38
  86. data/lib/event_store_client/adapters/grpc/commands/persistent_subscriptions/update.rb +0 -48
  87. data/lib/event_store_client/adapters/grpc/commands/projections/create.rb +0 -48
  88. data/lib/event_store_client/adapters/grpc/commands/projections/delete.rb +0 -34
  89. data/lib/event_store_client/adapters/grpc/commands/projections/update.rb +0 -44
  90. data/lib/event_store_client/adapters/grpc/commands/streams/read_all.rb +0 -43
  91. data/lib/event_store_client/adapters/grpc/commands/streams/tombstone.rb +0 -35
  92. data/lib/event_store_client/adapters/http/README.md +0 -16
  93. data/lib/event_store_client/adapters/http/client.rb +0 -161
  94. data/lib/event_store_client/adapters/http/commands/command.rb +0 -27
  95. data/lib/event_store_client/adapters/http/commands/persistent_subscriptions/ack.rb +0 -15
  96. data/lib/event_store_client/adapters/http/commands/persistent_subscriptions/create.rb +0 -35
  97. data/lib/event_store_client/adapters/http/commands/persistent_subscriptions/read.rb +0 -60
  98. data/lib/event_store_client/adapters/http/commands/projections/create.rb +0 -33
  99. data/lib/event_store_client/adapters/http/commands/projections/update.rb +0 -31
  100. data/lib/event_store_client/adapters/http/commands/streams/append.rb +0 -49
  101. data/lib/event_store_client/adapters/http/commands/streams/delete.rb +0 -16
  102. data/lib/event_store_client/adapters/http/commands/streams/link_to.rb +0 -49
  103. data/lib/event_store_client/adapters/http/commands/streams/read.rb +0 -52
  104. data/lib/event_store_client/adapters/http/commands/streams/tombstone.rb +0 -17
  105. data/lib/event_store_client/adapters/http/connection.rb +0 -46
  106. data/lib/event_store_client/adapters/http/request_method.rb +0 -28
  107. data/lib/event_store_client/adapters/http.rb +0 -17
  108. data/lib/event_store_client/adapters/in_memory.rb +0 -144
  109. data/lib/event_store_client/broker.rb +0 -40
  110. data/lib/event_store_client/catch_up_subscription.rb +0 -42
  111. data/lib/event_store_client/catch_up_subscriptions.rb +0 -92
  112. data/lib/event_store_client/client.rb +0 -73
  113. data/lib/event_store_client/error_handler.rb +0 -10
  114. data/lib/event_store_client/subscription.rb +0 -23
  115. data/lib/event_store_client/subscriptions.rb +0 -38
  116. data/lib/event_store_client/value_objects/read_direction.rb +0 -43
@@ -1,44 +0,0 @@
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 Update < Command
14
- use_request EventStore::Client::Projections::UpdateReq
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
- name: name,
31
- emit_enabled: true
32
- }
33
-
34
- service.update(request.new(options: options), metadata: metadata)
35
-
36
- Success()
37
- rescue ::GRPC::AlreadyExists
38
- Failure(:conflict)
39
- end
40
- end
41
- end
42
- end
43
- end
44
- end
@@ -1,43 +0,0 @@
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/configuration'
8
- require 'event_store_client/adapters/grpc/commands/command'
9
- require 'event_store_client/adapters/grpc/commands/streams/read'
10
-
11
- module EventStoreClient
12
- module GRPC
13
- module Commands
14
- module Streams
15
- class ReadAll < Command
16
- include Configuration
17
-
18
- use_request EventStore::Client::Streams::ReadReq
19
- use_service EventStore::Client::Streams::Streams::Stub
20
-
21
- def call(stream_name, options: {})
22
- start ||= options[:start] || 0
23
- count ||= options[:count] || 20
24
- events = []
25
-
26
- loop do
27
- res = Read.new.call(
28
- stream_name, options: options.merge(start: start, count: count)
29
- )
30
- break if res.failure?
31
- break if (entries = res.value!).empty?
32
-
33
- events += entries
34
- start += count
35
- end
36
-
37
- Success(events)
38
- end
39
- end
40
- end
41
- end
42
- end
43
- end
@@ -1,35 +0,0 @@
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 Streams
13
- class Tombstone < Command
14
- use_request EventStore::Client::Streams::TombstoneReq
15
- use_service EventStore::Client::Streams::Streams::Stub
16
-
17
- def call(name, options: {})
18
- opts =
19
- {
20
- stream_identifier: {
21
- streamName: name
22
- },
23
- any: {}
24
- }
25
-
26
- service.tombstone(request.new(options: opts), metadata: metadata)
27
- Success()
28
- rescue ::GRPC::FailedPrecondition
29
- Failure(:not_found)
30
- end
31
- end
32
- end
33
- end
34
- end
35
- end
@@ -1,16 +0,0 @@
1
- ### HTTP adapter
2
-
3
- This adapter targets the EventstoreDB version `>= "20.*"
4
-
5
- ### Configuration
6
-
7
- As by default EventStoreClient uses gRPC adapter, to switch to http you need to configure it first.
8
- Place the snippet below in your initializer or when you boot your application.
9
-
10
- ```ruby
11
- require 'event_store_client/adapters/http'
12
-
13
- EventStoreClient.configure do |config|
14
- config.adapter = :http
15
- end
16
- ```
@@ -1,161 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'event_store_client/adapters/http/connection'
4
- require 'dry/monads/result'
5
-
6
- module EventStoreClient
7
- module HTTP
8
- class Client
9
- include Configuration
10
- include Dry::Monads[:result]
11
- # Appends given events to the stream
12
- # @param [String] Stream name to append events to
13
- # @param [Array](each: EventStoreClient::DeserializedEvent) list of events to publish
14
- # @return Dry::Monads::Result::Success or Dry::Monads::Result::Failure
15
- #
16
- def append_to_stream(stream_name, events, options: {})
17
- Commands::Streams::Append.new(connection).call(
18
- stream_name, events, options: options
19
- )
20
- end
21
-
22
- # Softly deletes the given stream
23
- # @param [String] Stream name to delete
24
- # @param options [Hash] additional options to the request
25
- # @return Dry::Monads::Result::Success or Dry::Monads::Result::Failure
26
- #
27
- def delete_stream(stream_name, options: {})
28
- Commands::Streams::Delete.new(connection).call(
29
- stream_name, options: options
30
- )
31
- end
32
-
33
- # Completely removes the given stream
34
- # @param [String] Stream name to delete
35
- # @param options [Hash] additional options to the request
36
- # @return Dry::Monads::Result::Success or Dry::Monads::Result::Failure
37
- #
38
- def tombstone_stream(stream_name, options: {})
39
- Commands::Streams::Tombstone.new(connection).call(
40
- stream_name, options: options
41
- )
42
- end
43
-
44
- # Reads a page of events from the given stream
45
- # @param [String] Stream name to read events from
46
- # @param options [Hash] additional options to the request
47
- # @return Dry::Monads::Result::Success with returned events or Dry::Monads::Result::Failure
48
- #
49
- def read(stream_name, options: {})
50
- Commands::Streams::Read.new(connection).call(stream_name, options: options)
51
- end
52
-
53
- # Reads all events from the given stream
54
- # @param [String] Stream name to read events from
55
- # @param options [Hash] additional options to the request
56
- # @return Dry::Monads::Result::Success with returned events or Dry::Monads::Result::Failure
57
- #
58
- def read_all_from_stream(stream_name, options: {})
59
- start ||= options[:start] || 0
60
- count ||= options[:count] || 20
61
- events = []
62
- failed_requests_count = 0
63
-
64
- while failed_requests_count < 3
65
- res = read(stream_name, options: options.merge(start: start, count: count))
66
- if res.failure?
67
- failed_requests_count += 1
68
- else
69
- break if res.value!.empty?
70
- events += res.value!
71
- failed_requests_count = 0
72
- start += count
73
- end
74
- end
75
- return Failure(:connection_failed) if failed_requests_count >= 3
76
-
77
- Success(events)
78
- end
79
-
80
- # Creates the subscription for the given stream
81
- # @param [EventStoreClient::Subscription] subscription to observe
82
- # @param options [Hash] additional options to the request
83
- # @return Dry::Monads::Result::Success or Dry::Monads::Result::Failure
84
- #
85
- def subscribe_to_stream(subscription, options: {})
86
- join_streams(subscription.name, subscription.observed_streams)
87
- Commands::PersistentSubscriptions::Create.new(connection).call(
88
- subscription.stream,
89
- subscription.name,
90
- options: options
91
- )
92
- end
93
-
94
- # Links given events with the given stream
95
- # @param [String] Stream name to link events to
96
- # @param [Array](each: EventStoreClient::DeserializedEvent) a list of events to link
97
- # @param expected_version [Integer] expected number of events in the stream
98
- # @return Dry::Monads::Result::Success or Dry::Monads::Result::Failure
99
- #
100
- def link_to(stream_name, events, options: {})
101
- Commands::Streams::LinkTo.new(connection).call(
102
- stream_name, events, options: options
103
- )
104
- end
105
-
106
- # Runs the persistent subscription indeinitely
107
- # @param [EventStoreClient::Subscription] subscription to observe
108
- # @param options [Hash] additional options to the request
109
- # @return - Nothing, it is a blocking operation, yields the given block with event instead
110
- #
111
- def listen(subscription, options: {})
112
- loop do
113
- begin
114
- consume_feed(subscription) do |event|
115
- yield event if block_given?
116
- end
117
- rescue StandardError => e
118
- config.error_handler&.call(e)
119
- end
120
- sleep(options[:interval] || 5) # wait for events to be processed
121
- end
122
- end
123
-
124
- private
125
-
126
- attr_reader :connection
127
-
128
- def initialize
129
- @connection =
130
- Connection.new(config.eventstore_url, ssl: { verify: config.verify_ssl })
131
- end
132
-
133
- # @api private
134
- # Joins multiple streams into the new one under the given name
135
- # @param [String] Name of the stream containing the ones to join
136
- # @param [Array] (each: String) list of streams to join together
137
- # @return Dry::Monads::Result::Success or Dry::Monads::Result::Failure
138
- #
139
- def join_streams(name, streams, options: {})
140
- res = Commands::Projections::Create.new(connection).call(name, streams, options: options)
141
- return res if res.success?
142
-
143
- Commands::Projections::Update.new(connection).call(name, streams, options: options)
144
- end
145
-
146
- # @api private
147
- # Consumes the new events from the subscription
148
- # @param [EventStoreClient::Subscription] subscription to observe
149
- # @param options [Hash] additional options to the request
150
- # @return Dry::Monads::Result::Success or Dry::Monads::Result::Failure
151
- #
152
- def consume_feed(subscription, options: {})
153
- Commands::PersistentSubscriptions::Read.new(connection).call(
154
- subscription.stream, subscription.name, options: options
155
- ) do |event|
156
- yield event if block_given?
157
- end
158
- end
159
- end
160
- end
161
- end
@@ -1,27 +0,0 @@
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 HTTP
8
- module Commands
9
- class Command
10
- def self.inherited(klass)
11
- super
12
- klass.class_eval do
13
- include Dry::Monads[:result]
14
- end
15
- end
16
-
17
- protected
18
-
19
- attr_reader :connection
20
-
21
- def initialize(connection)
22
- @connection = connection
23
- end
24
- end
25
- end
26
- end
27
- end
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module EventStoreClient
4
- module HTTP
5
- module Commands
6
- module PersistentSubscriptions
7
- class Ack < Command
8
- def call(url)
9
- connection.call(:post, url)
10
- end
11
- end
12
- end
13
- end
14
- end
15
- end
@@ -1,35 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module EventStoreClient
4
- module HTTP
5
- module Commands
6
- module PersistentSubscriptions
7
- class Create < Command
8
- def call(stream_name, subscription_name, options: {})
9
- stats = options[:stats] || true
10
- start = options[:start] || 0
11
- retries = options[:retries] || 5
12
- max_checkpoint_count = options[:max_checkpoint_count] || 0
13
- min_checkpoint_count = options[:min_checkpoint_count] || 0
14
-
15
- connection.call(
16
- :put,
17
- "/subscriptions/#{stream_name}/#{subscription_name}",
18
- body: {
19
- extraStatistics: stats,
20
- startFrom: start,
21
- maxRetryCount: retries,
22
- maxCheckPointCount: max_checkpoint_count,
23
- minCheckPointCount: min_checkpoint_count,
24
- resolveLinkTos: true
25
- },
26
- headers: {
27
- 'Content-Type' => 'application/json'
28
- }
29
- )
30
- end
31
- end
32
- end
33
- end
34
- end
35
- end
@@ -1,60 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'event_store_client/adapters/http/commands/persistent_subscriptions/ack'
4
- module EventStoreClient
5
- module HTTP
6
- module Commands
7
- module PersistentSubscriptions
8
- class Read < Command
9
- include Configuration
10
-
11
- def call(stream_name, subscription_name, options: {})
12
- count = options[:count] || 20
13
- long_poll = options[:long_poll].to_i
14
- headers = long_poll.positive? ? { 'ES-LongPoll' => long_poll.to_s } : {}
15
- headers['Content-Type'] = 'application/vnd.eventstore.competingatom+json'
16
- headers['Accept'] = 'application/vnd.eventstore.competingatom+json'
17
- headers['ES-ResolveLinktos'] = (options[:resolve_links] || true).to_s
18
-
19
- response = connection.call(
20
- :get,
21
- "/subscriptions/#{stream_name}/#{subscription_name}/#{count}",
22
- headers: headers
23
- )
24
-
25
- return { events: [] } if response.body.nil? || response.body.empty?
26
-
27
- body = JSON.parse(response.body)
28
-
29
- ack_info = body['links'].find { |link| link['relation'] == 'ackAll' }
30
- return { events: [] } unless ack_info
31
-
32
- skip_decryption = options[:skip_decryption] || false
33
- body['entries'].map do |entry|
34
- yield deserialize_event(entry, skip_decryption: skip_decryption)
35
- end
36
-
37
- Ack.new(connection).call(ack_info['uri'])
38
- Success()
39
- end
40
-
41
- private
42
-
43
- def deserialize_event(entry, skip_decryption: false)
44
- event = EventStoreClient::Event.new(
45
- id: entry['eventId'],
46
- title: entry['title'],
47
- type: entry['eventType'],
48
- data: entry['data'] || '{}',
49
- metadata: entry['isMetaData'] ? entry['metaData'] : '{}'
50
- )
51
-
52
- config.mapper.deserialize(event, skip_decryption: skip_decryption)
53
- rescue EventStoreClient::DeserializedEvent::InvalidDataError
54
- event
55
- end
56
- end
57
- end
58
- end
59
- end
60
- end
@@ -1,33 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module EventStoreClient
4
- module HTTP
5
- module Commands
6
- module Projections
7
- class Create < Command
8
- def call(name, streams, options: {})
9
- data =
10
- <<~STRING
11
- fromStreams(#{streams})
12
- .when({
13
- $any: function(s,e) {
14
- linkTo("#{name}", e)
15
- }
16
- })
17
- STRING
18
-
19
-
20
- res = connection.call(
21
- :post,
22
- "/projections/continuous?name=#{name}&type=js&enabled=yes&emit=true&trackemittedstreams=true", # rubocop:disable Metrics/LineLength
23
- body: data,
24
- headers: {}
25
- )
26
-
27
- (200...300).cover?(res.status) ? Success() : Failure(res)
28
- end
29
- end
30
- end
31
- end
32
- end
33
- end
@@ -1,31 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module EventStoreClient
4
- module HTTP
5
- module Commands
6
- module Projections
7
- class Update < Command
8
- def call(name, streams, options: {})
9
- data =
10
- <<~STRING
11
- fromStreams(#{streams})
12
- .when({
13
- $any: function(s,e) {
14
- linkTo("#{name}", e)
15
- }
16
- })
17
- STRING
18
- res = connection.call(
19
- :put,
20
- "/projection/#{name}/query?type=js&enabled=yes&emit=true&trackemittedstreams=true", # rubocop:disable Metrics/LineLength
21
- body: data,
22
- headers: {}
23
- )
24
-
25
- (200...300).cover?(res.status) ? Success() : Failure(res)
26
- end
27
- end
28
- end
29
- end
30
- end
31
- end
@@ -1,49 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module EventStoreClient
4
- module HTTP
5
- module Commands
6
- module Streams
7
- class Append < Command
8
- include Configuration
9
-
10
- def call(stream_name, events, options: {})
11
- expected_version = options[:expected_version]
12
- serialized_events = events.map { |event| config.mapper.serialize(event) }
13
- headers = {
14
- 'ES-ExpectedVersion' => expected_version&.to_s
15
- }.reject { |_key, val| val.nil? || val.empty? }
16
-
17
- data = build_events_data(serialized_events)
18
- response =
19
- connection.call(:post, "/streams/#{stream_name}", body: data, headers: headers)
20
- validate_response(response, expected_version)
21
- end
22
-
23
- private
24
-
25
- def build_events_data(events)
26
- [events].flatten.map do |event|
27
- {
28
- eventId: event.id,
29
- eventType: event.type,
30
- data: event.data,
31
- metadata: event.metadata
32
- }
33
- end
34
- end
35
-
36
- def validate_response(resp, expected_version)
37
- wrong_version = resp.status == 400 && resp.reason_phrase == 'Wrong expected EventNumber'
38
- return Success() unless wrong_version
39
-
40
- Failure(
41
- "current version: #{resp.headers.fetch('es-currentversion')} | "\
42
- "expected: #{expected_version}"
43
- )
44
- end
45
- end
46
- end
47
- end
48
- end
49
- end
@@ -1,16 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module EventStoreClient
4
- module HTTP
5
- module Commands
6
- module Streams
7
- class Delete < Command
8
- def call(stream_name, options: {}) # rubocop:disable Lint/UnusedMethodArgument
9
- connection.call(:delete, "/streams/#{stream_name}", body: {})
10
- Success()
11
- end
12
- end
13
- end
14
- end
15
- end
16
- end
@@ -1,49 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module EventStoreClient
4
- module HTTP
5
- module Commands
6
- module Streams
7
- class LinkTo < Command
8
- def call(stream_name, events, options: {})
9
- expected_version = options[:expected_version]
10
- data = build_linking_data(events)
11
- headers = {
12
- 'ES-ExpectedVersion' => expected_version&.to_s
13
- }.reject { |_key, val| val.nil? || val.empty? }
14
-
15
- response = connection.call(
16
- :post,
17
- "/streams/#{stream_name}",
18
- body: data,
19
- headers: headers
20
- )
21
- validate_response(response, expected_version)
22
- end
23
-
24
- private
25
-
26
- def validate_response(resp, expected_version)
27
- wrong_version = resp.status == 400 && resp.reason_phrase == 'Wrong expected EventNumber'
28
- return Success() unless wrong_version
29
-
30
- Failure(
31
- "current version: #{resp.headers.fetch('es-currentversion')} | "\
32
- "expected: #{expected_version}"
33
- )
34
- end
35
-
36
- def build_linking_data(events)
37
- [events].flatten.map do |event|
38
- {
39
- eventId: event.id,
40
- eventType: '$>',
41
- data: event.title
42
- }
43
- end
44
- end
45
- end
46
- end
47
- end
48
- end
49
- end
@@ -1,52 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module EventStoreClient
4
- module HTTP
5
- module Commands
6
- module Streams
7
- class Read < Command
8
- include Configuration
9
-
10
- def call(stream_name, options: {})
11
- count = options[:count] || config.per_page
12
- start = options[:start].to_i
13
- direction = options[:direction] || 'forward'
14
- headers = { 'Accept' => 'application/vnd.eventstore.atom+json' }
15
- headers['ES-ResolveLinkTos'] = true if options.key?(:resolve_links)
16
-
17
- response =
18
- connection.call(
19
- :get,
20
- "/streams/#{stream_name}/#{start}/#{direction}/#{count}",
21
- headers: headers
22
- )
23
-
24
- return Failure(:stream_not_found) unless response.success? || response.status == 404
25
- return Failure(:connection_failed) if response.body.nil? || response.body.empty?
26
- skip_decryption = options[:skip_decryption] || false
27
- entries = JSON.parse(response.body)['entries'].map do |entry|
28
- deserialize_event(entry, skip_decryption: skip_decryption)
29
- end.reverse
30
- Success(entries)
31
- rescue Faraday::ConnectionFailed
32
- Failure(:connection_failed)
33
- end
34
-
35
- private
36
-
37
- def deserialize_event(entry, skip_decryption: false)
38
- event = EventStoreClient::Event.new(
39
- id: entry['eventId'],
40
- title: entry['title'],
41
- type: entry['eventType'],
42
- data: entry['data'] || '{}',
43
- metadata: entry['isMetaData'] ? entry['metaData'] : '{}'
44
- )
45
-
46
- config.mapper.deserialize(event, skip_decryption: skip_decryption)
47
- end
48
- end
49
- end
50
- end
51
- end
52
- end