event_store_client 1.4.9 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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 +74 -83
  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