event_store_client 0.2.0 → 0.2.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 721e082b623b85e16696eb5844e8684757e31f10bf067b264fab176439a8b13f
4
- data.tar.gz: 00bed48b77fe8ea55edcb25840b4f111758efca348507a5395970b6cfecffe00
3
+ metadata.gz: daaf4a7e189d14224fa8b520345b9108f6c9c02316d57742d599b3fe5fb15e22
4
+ data.tar.gz: 9eb7350e33cd14b7e9aff5ed2d8cf313838b6fe1df739ba5c4348111f18ec323
5
5
  SHA512:
6
- metadata.gz: b882a2aa01f9d40debf44418c2e232307c414ec77688822615e7aaa911586523700286d1581c68b3916246ccff8cd098a8211646910d5d995e9bc71306fd852f
7
- data.tar.gz: 6f3f2d4dc03dcfdfc7355bd9a4bbf1bb519b6dfc14b33feff7cc285facaf4f28977ed3ff119a3b55e51dfeb1201aaca29b2341b64fa52570e8528a9ba49e5e70
6
+ metadata.gz: 803a1ac900741c28a9437135e48343d015eec4d55c3b1df5d536575bed13341f276aa85d24cb177cdf376284b1be7a0220b8b1bdde4bab558481b39f6ae930a4
7
+ data.tar.gz: 0fa249206dcbe74719fae1ba82e85de615d332cd82dc69d890154839e2fcccc7e6feb4269afc94fb9d46156816582a71a71afe364767c005e6ac101545c4b6e8
data/README.md CHANGED
@@ -1,3 +1,6 @@
1
+ ![Run tests](https://github.com/yousty/event_store_client/workflows/Run%20tests/badge.svg?branch=master&event=push)
2
+ [![Gem Version](https://badge.fury.io/rb/event_store_client.svg)](https://badge.fury.io/rb/event_store_client)
3
+
1
4
  # EventStoreClient
2
5
 
3
6
  An easy-to use API client for connecting ruby applications with https://eventstore.org/
@@ -252,6 +255,11 @@ Do you want to contribute? Welcome!
252
255
  2. Create Issue
253
256
  3. Create PR ;)
254
257
 
258
+ ### Publishing new version
259
+
260
+ 1. Push commit with updated `version.rb` file to the `release` branch. The new version will be automatically pushed to [rubygems](https://rubygems.org).
261
+ 2. Create release on github including change log.
262
+
255
263
  ## License
256
264
 
257
265
  The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
@@ -1,27 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module EventStoreClient
4
- def self.configure(&block)
5
- config = Configuration.instance
6
- config.configure(&block)
7
- end
8
4
  end
9
5
 
10
- require 'event_store_client/configuration'
11
6
  require 'event_store_client/types'
12
7
  require 'event_store_client/event'
13
8
  require 'event_store_client/deserialized_event'
14
-
15
9
  require 'event_store_client/serializer/json'
16
10
 
17
11
  require 'event_store_client/mapper'
18
12
 
19
- require 'event_store_client/endpoint'
13
+ require 'event_store_client/configuration'
20
14
 
21
15
  require 'event_store_client/store_adapter'
22
16
 
23
- require 'event_store_client/connection'
24
-
25
17
  require 'event_store_client/subscription'
26
18
  require 'event_store_client/subscriptions'
27
19
  require 'event_store_client/broker'
@@ -4,9 +4,10 @@ module EventStoreClient
4
4
  class Broker
5
5
  def call(subscriptions)
6
6
  subscriptions.each do |subscription|
7
- new_events = connection.consume_feed(subscription.stream, subscription.name)
8
- next if new_events.none?
9
- new_events.each { |event| subscription.subscriber.call(event) }
7
+ res = connection.consume_feed(subscription.stream, subscription.name) || { events: [] }
8
+ next if res[:events].none?
9
+ res[:events].each { |event| subscription.subscriber.call(event) }
10
+ connection.ack(res[:ack_uri])
10
11
  end
11
12
  end
12
13
 
@@ -8,13 +8,21 @@ module EventStoreClient
8
8
  WrongExpectedEventVersion = Class.new(StandardError)
9
9
 
10
10
  def publish(stream:, events:, expected_version: nil)
11
- connection.publish(stream: stream, events: events, expected_version: expected_version)
11
+ connection.append_to_stream(stream, events, expected_version: expected_version)
12
12
  rescue StoreAdapter::Api::Client::WrongExpectedEventVersion => e
13
13
  raise WrongExpectedEventVersion.new(e.message)
14
14
  end
15
15
 
16
- def read(stream, direction: 'forward', start: 0, all: false)
17
- connection.read(stream, direction: direction, start: start, all: all)
16
+ def read(stream, direction: 'forward', start: 0, all: false, resolve_links: true)
17
+ if all
18
+ connection.read_all_from_stream(
19
+ stream, start: start, direction: direction, resolve_links: resolve_links
20
+ )
21
+ else
22
+ connection.read(
23
+ stream, start: start, direction: direction, resolve_links: resolve_links
24
+ )
25
+ end
18
26
  end
19
27
 
20
28
  def subscribe(subscriber, to: [], polling: true)
@@ -81,12 +89,12 @@ module EventStoreClient
81
89
  attr_reader :subscriptions, :broker, :error_handler
82
90
 
83
91
  def config
84
- EventStoreClient::Configuration.instance
92
+ EventStoreClient.config
85
93
  end
86
94
 
87
95
  def initialize
88
96
  @threads = []
89
- @connection ||= Connection.new
97
+ @connection ||= EventStoreClient.adapter
90
98
  @error_handler ||= config.error_handler
91
99
  @service_name ||= 'default'
92
100
  @broker ||= Broker.new(connection: connection)
@@ -1,28 +1,47 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry-struct'
4
- require 'singleton'
3
+ require 'dry-configurable'
5
4
 
6
5
  module EventStoreClient
7
- class Configuration
8
- include Singleton
6
+ extend Dry::Configurable
9
7
 
10
- attr_accessor :per_page, :service_name, :mapper, :error_handler, :pid_path, :adapter
8
+ # Supported adapters: %i[api in_memory]
9
+ #
10
+ setting :adapter, :api
11
11
 
12
- def configure
13
- yield(self) if block_given?
14
- end
12
+ setting :error_handler
13
+ setting :eventstore_url, 'http://localhost:2113' do |value|
14
+ value.is_a?(URI) ? value : URI(value)
15
+ end
16
+
17
+ setting :eventstore_user, 'admin'
18
+ setting :eventstore_password, 'changeit'
19
+
20
+ setting :db_port, 2113
21
+
22
+ setting :per_page, 20
23
+ setting :pid_path, 'tmp/poll.pid'
15
24
 
16
- private
25
+ setting :service_name, 'default'
17
26
 
18
- def initialize
19
- @per_page = 20
20
- @pid_path = 'tmp/poll.pid'
21
- @mapper = Mapper::Default.new
22
- @service_name = 'default'
23
- @error_handler = nil
24
- @adapter = EventStoreClient::StoreAdapter::Api::Client.new(
25
- host: 'http://localhost', port: 2113, per_page: per_page
27
+ setting :mapper, Mapper::Default.new
28
+
29
+ def self.configure
30
+ yield(config) if block_given?
31
+ end
32
+
33
+ def self.adapter
34
+ case config.adapter
35
+ when :api
36
+ StoreAdapter::Api::Client.new(
37
+ config.eventstore_url,
38
+ per_page: config.per_page,
39
+ mapper: config.mapper,
40
+ connection_options: {}
41
+ )
42
+ else
43
+ StoreAdapter::InMemory.new(
44
+ mapper: config.mapper, per_page: config.per_page
26
45
  )
27
46
  end
28
47
  end
@@ -28,7 +28,7 @@ module EventStoreClient
28
28
 
29
29
  def decrypt_attributes(key:, data:, attributes:)
30
30
  decrypted_text = key_repository.decrypt(
31
- key_id: key.id, text: data[:es_encrypted], cipher: key.cipher, iv: key.iv
31
+ key_id: key.id, text: data['es_encrypted'], cipher: key.cipher, iv: key.iv
32
32
  )
33
33
  decrypted = JSON.parse(decrypted_text).transform_keys(&:to_s)
34
34
  decrypted.each { |key, value| data[key] = value if data.key?(key) }
@@ -11,7 +11,7 @@ module EventStoreClient
11
11
  encrypt_attributes(
12
12
  key: key,
13
13
  data: encrypted_data,
14
- attributes: encryption_metadata[:attributes]
14
+ attributes: encryption_metadata[:attributes].map(&:to_s)
15
15
  )
16
16
  end
17
17
 
@@ -17,7 +17,7 @@ module EventStoreClient
17
17
  attr_reader :data, :schema
18
18
 
19
19
  def initialize(data:, schema:)
20
- @data = data
20
+ @data = data.transform_keys(&:to_sym)
21
21
  @schema = schema
22
22
  end
23
23
  end
@@ -9,8 +9,8 @@ module EventStoreClient
9
9
  attribute :id, Types::Strict::String.optional.default(nil)
10
10
  attribute :type, Types::Strict::String
11
11
  attribute :title, Types::Strict::String.optional.default(nil)
12
- attribute :data, Types::Strict::String.default('{}')
13
- attribute :metadata, Types::Strict::String.default('{}')
12
+ attribute :data, Types::Coercible::String.default('{}')
13
+ attribute :metadata, Types::Coercible::String.default('{}')
14
14
 
15
15
  private
16
16
 
@@ -5,7 +5,8 @@ module EventStoreClient
5
5
  class Default
6
6
  def serialize(event)
7
7
  Event.new(
8
- type: event.class.to_s,
8
+ id: event.respond_to?(:id) ? event.id : nil,
9
+ type: (event.respond_to?(:type) ? event.type : nil) || event.class.to_s,
9
10
  data: serializer.serialize(event.data),
10
11
  metadata: serializer.serialize(event.metadata)
11
12
  )
@@ -26,13 +26,13 @@ module EventStoreClient
26
26
  event.class.respond_to?(:encryption_schema) &&
27
27
  event.class.encryption_schema
28
28
  )
29
- encryptor = DataEncryptor.new(
29
+ encryptor = EventStoreClient::DataEncryptor.new(
30
30
  data: event.data,
31
31
  schema: encryption_schema,
32
32
  repository: key_repository
33
33
  )
34
34
  encryptor.call
35
- Event.new(
35
+ EventStoreClient::Event.new(
36
36
  data: serializer.serialize(encryptor.encrypted_data),
37
37
  metadata: serializer.serialize(
38
38
  event.metadata.merge(encryption: encryptor.encryption_metadata)
@@ -52,7 +52,7 @@ module EventStoreClient
52
52
  def deserialize(event)
53
53
  metadata = serializer.deserialize(event.metadata)
54
54
  encryption_schema = serializer.deserialize(event.metadata)['encryption']
55
- decrypted_data = DataDecryptor.new(
55
+ decrypted_data = EventStoreClient::DataDecryptor.new(
56
56
  data: serializer.deserialize(event.data),
57
57
  schema: encryption_schema,
58
58
  repository: key_repository
@@ -3,10 +3,14 @@
3
3
  module Serializer
4
4
  module Json
5
5
  def self.deserialize(data)
6
+ return data if data.is_a?(Hash)
7
+
6
8
  JSON.parse(data)
7
9
  end
8
10
 
9
11
  def self.serialize(data)
12
+ return data if data.is_a?(String)
13
+
10
14
  JSON.generate(data)
11
15
  end
12
16
  end
@@ -7,14 +7,16 @@ module EventStoreClient
7
7
  WrongExpectedEventVersion = Class.new(StandardError)
8
8
 
9
9
  def append_to_stream(stream_name, events, expected_version: nil)
10
+ serialized_events = events.map { |event| mapper.serialize(event) }
10
11
  headers = {
11
12
  'ES-ExpectedVersion' => expected_version&.to_s
12
13
  }.reject { |_key, val| val.nil? || val.empty? }
13
14
 
14
- data = build_events_data(events)
15
+ data = build_events_data(serialized_events)
15
16
  response = make_request(:post, "/streams/#{stream_name}", body: data, headers: headers)
16
17
  validate_response(response, expected_version)
17
18
  response
19
+ serialized_events
18
20
  end
19
21
 
20
22
  def delete_stream(stream_name, hard_delete: false)
@@ -31,11 +33,39 @@ module EventStoreClient
31
33
  'Accept' => 'application/vnd.eventstore.atom+json'
32
34
  }
33
35
 
34
- make_request(
36
+ response = make_request(
35
37
  :get,
36
38
  "/streams/#{stream_name}/#{start}/#{direction}/#{count}",
37
39
  headers: headers
38
40
  )
41
+ return [] if response.body.nil? || response.body.empty?
42
+ JSON.parse(response.body)['entries'].map do |entry|
43
+ deserialize_event(entry)
44
+ end.reverse
45
+ end
46
+
47
+ def read_all_from_stream(stream, start: 0, resolve_links: true)
48
+ count = per_page
49
+ events = []
50
+ failed_requests_count = 0
51
+
52
+ while failed_requests_count < 3
53
+ begin
54
+ response =
55
+ read(stream, start: start, direction: 'forward', resolve_links: resolve_links)
56
+ failed_requests_count += 1 && next unless response.success? || response.status == 404
57
+ rescue Faraday::ConnectionFailed
58
+ failed_requests_count += 1
59
+ next
60
+ end
61
+ failed_requests_count = 0
62
+ break if response.body.nil? || response.body.empty?
63
+ entries = JSON.parse(response.body)['entries']
64
+ break if entries.empty?
65
+ events += entries.map { |entry| deserialize_event(entry) }.reverse
66
+ start += count
67
+ end
68
+ events
39
69
  end
40
70
 
41
71
  def join_streams(name, streams)
@@ -79,18 +109,31 @@ module EventStoreClient
79
109
  subscription_name,
80
110
  count: 1,
81
111
  long_poll: 0,
82
- resolve_links: true
112
+ resolve_links: true,
113
+ per_page: 20
83
114
  )
84
115
  headers = long_poll.positive? ? { 'ES-LongPoll' => long_poll.to_s } : {}
85
116
  headers['Content-Type'] = 'application/vnd.eventstore.competingatom+json'
86
117
  headers['Accept'] = 'application/vnd.eventstore.competingatom+json'
87
118
  headers['ES-ResolveLinktos'] = resolve_links.to_s
88
119
 
89
- make_request(
120
+ response = make_request(
90
121
  :get,
91
122
  "/subscriptions/#{stream_name}/#{subscription_name}/#{count}",
92
123
  headers: headers
93
124
  )
125
+
126
+ return { events: [] } if response.body || response.body.empty?
127
+
128
+ body = JSON.parse(response.body)
129
+
130
+ ack_info = body['links'].find { |link| link['relation'] == 'ackAll' }
131
+ return unless ack_info
132
+ ack_uri = ack_info['uri']
133
+ events = body['entries'].map do |entry|
134
+ deserialize_event(entry)
135
+ end
136
+ { ack_uri: ack_uri, events: events }
94
137
  end
95
138
 
96
139
  def link_to(stream_name, events, expected_version: nil)
@@ -106,7 +149,7 @@ module EventStoreClient
106
149
  headers: headers
107
150
  )
108
151
  validate_response(response, expected_version)
109
- response
152
+ true
110
153
  end
111
154
 
112
155
  def ack(url)
@@ -115,11 +158,13 @@ module EventStoreClient
115
158
 
116
159
  private
117
160
 
118
- attr_reader :endpoint, :per_page
161
+ attr_reader :uri, :per_page, :connection_options, :mapper
119
162
 
120
- def initialize(host:, port:, per_page: 20)
121
- @endpoint = Endpoint.new(host: host, port: port)
163
+ def initialize(uri, per_page: 20, mapper:, connection_options: {})
164
+ @uri = uri
122
165
  @per_page = per_page
166
+ @mapper = mapper
167
+ @connection_options = connection_options
123
168
  end
124
169
 
125
170
  def build_events_data(events)
@@ -153,7 +198,7 @@ module EventStoreClient
153
198
  end
154
199
 
155
200
  def connection
156
- @connection ||= Api::Connection.new(endpoint).call
201
+ @connection ||= Api::Connection.new(uri, connection_options).call
157
202
  end
158
203
 
159
204
  def validate_response(resp, expected_version)
@@ -163,6 +208,18 @@ module EventStoreClient
163
208
  "expected: #{expected_version}"
164
209
  )
165
210
  end
211
+
212
+ def deserialize_event(entry)
213
+ event = EventStoreClient::Event.new(
214
+ id: entry['eventId'],
215
+ title: entry['title'],
216
+ type: entry['eventType'],
217
+ data: entry['data'] || '{}',
218
+ metadata: entry['isMetaData'] ? entry['metaData'] : '{}'
219
+ )
220
+
221
+ mapper.deserialize(event)
222
+ end
166
223
  end
167
224
  end
168
225
  end
@@ -8,21 +8,28 @@ module EventStoreClient
8
8
  class Connection
9
9
  def call
10
10
  Faraday.new(
11
- url: endpoint.url,
12
- headers: DEFAULT_HEADERS
11
+ {
12
+ url: uri.to_s,
13
+ headers: DEFAULT_HEADERS
14
+ }.merge(options)
13
15
  ) do |conn|
14
- conn.basic_auth(ENV['EVENT_STORE_USER'], ENV['EVENT_STORE_PASSWORD'])
16
+ conn.basic_auth(config.eventstore_user, config.eventstore_password)
15
17
  conn.adapter Faraday.default_adapter
16
18
  end
17
19
  end
18
20
 
19
21
  private
20
22
 
21
- def initialize(endpoint)
22
- @endpoint = endpoint
23
+ def config
24
+ EventStoreClient.config
23
25
  end
24
26
 
25
- attr_reader :endpoint
27
+ def initialize(uri, options = {})
28
+ @uri = uri
29
+ @options = options
30
+ end
31
+
32
+ attr_reader :uri, :options
26
33
 
27
34
  DEFAULT_HEADERS = {
28
35
  'Content-Type' => 'application/vnd.eventstore.events+json'
@@ -13,7 +13,6 @@ module EventStoreClient
13
13
 
14
14
  def append_to_stream(stream_name, events, expected_version: nil) # rubocop:disable Lint/UnusedMethodArgument,Metrics/LineLength
15
15
  event_store[stream_name] = [] unless event_store.key?(stream_name)
16
-
17
16
  [events].flatten.each do |event|
18
17
  event_store[stream_name].unshift(
19
18
  'eventId' => event.id,
@@ -33,7 +32,27 @@ module EventStoreClient
33
32
  read_stream_backward(stream_name, start: start)
34
33
  end
35
34
 
36
- Response.new(response.to_json, 200)
35
+ res = Response.new(response.to_json, 200)
36
+
37
+ return [] if res.body.nil? || res.body.empty?
38
+ JSON.parse(res.body)['entries'].map do |entry|
39
+ deserialize_event(entry)
40
+ end.reverse
41
+ end
42
+
43
+ def read_all_from_stream(stream_name, direction: 'forward', start: 0, resolve_links: true)
44
+ response =
45
+ if direction == 'forward'
46
+ read_stream_forward(stream_name, start: start)
47
+ else
48
+ read_stream_backward(stream_name, start: start)
49
+ end
50
+ res = Response.new(response.to_json, 200)
51
+
52
+ return [] if res.body.nil? || res.body.empty?
53
+ JSON.parse(res.body)['entries'].map do |entry|
54
+ deserialize_event(entry)
55
+ end.reverse
37
56
  end
38
57
 
39
58
  def subscribe_to_stream(stream_name, subscription_name, **)
@@ -54,6 +73,7 @@ module EventStoreClient
54
73
 
55
74
  def link_to(stream_name, events, **)
56
75
  append_to_stream(stream_name, events)
76
+ events
57
77
  end
58
78
 
59
79
  def ack(url)
@@ -64,11 +84,11 @@ module EventStoreClient
64
84
 
65
85
  private
66
86
 
67
- attr_reader :endpoint, :per_page
87
+ attr_reader :per_page, :mapper
68
88
 
69
- def initialize(host:, port:, per_page: 20)
70
- @endpoint = Endpoint.new(host: host, port: port)
89
+ def initialize(mapper:, per_page: 20)
71
90
  @per_page = per_page
91
+ @mapper = mapper
72
92
  @event_store = {}
73
93
  end
74
94
 
@@ -115,11 +135,26 @@ module EventStoreClient
115
135
  else
116
136
  [{
117
137
  'uri' =>
118
- "http://#{endpoint.url}/streams/#{stream_name}/#{batch_size}/#{direction}/#{count}",
138
+ "/streams/#{stream_name}/#{batch_size}/#{direction}/#{count}",
119
139
  'relation' => direction
120
140
  }]
121
141
  end
122
142
  end
143
+
144
+ private
145
+
146
+ def deserialize_event(entry)
147
+ data = (entry['data'].is_a?(Hash) ? entry['data'].to_json.presence : entry['data']) || '{}'
148
+ event = EventStoreClient::Event.new(
149
+ id: entry['eventId'],
150
+ title: entry['title'],
151
+ type: entry['eventType'],
152
+ data: data,
153
+ metadata: entry['isMetaData'] ? entry['metaData'] : '{}'
154
+ )
155
+
156
+ mapper.deserialize(event)
157
+ end
123
158
  end
124
159
  end
125
160
  end
@@ -25,8 +25,9 @@ module EventStoreClient
25
25
  private
26
26
 
27
27
  def create_subscription(subscription)
28
+ # store position somewhere.
28
29
  connection.join_streams(subscription.name, subscription.observed_streams)
29
- connection.subscribe(subscription.stream, name: subscription.name)
30
+ connection.subscribe_to_stream(subscription.stream, subscription.name)
30
31
  end
31
32
 
32
33
  attr_reader :connection, :subscriptions, :service
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module EventStoreClient
4
- VERSION = '0.2.0'
4
+ VERSION = '0.2.5'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: event_store_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sebastian Wilgosz
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-04-27 00:00:00.000000000 Z
11
+ date: 2020-12-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dry-schema
@@ -16,56 +16,70 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 1.4.1
19
+ version: '1'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 1.4.1
26
+ version: '1'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: dry-struct
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 1.1.1
33
+ version: '1'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 1.1.1
40
+ version: '1'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: faraday
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 0.17.0
47
+ version: '1.0'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: 0.17.0
54
+ version: '1.0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rss
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - "~>"
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
61
  version: 0.2.8
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - "~>"
66
+ - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: 0.2.8
69
+ - !ruby/object:Gem::Dependency
70
+ name: dry-configurable
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0.11'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0.11'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: rspec
71
85
  requirement: !ruby/object:Gem::Requirement
@@ -108,12 +122,10 @@ files:
108
122
  - lib/event_store_client/broker.rb
109
123
  - lib/event_store_client/client.rb
110
124
  - lib/event_store_client/configuration.rb
111
- - lib/event_store_client/connection.rb
112
125
  - lib/event_store_client/data_decryptor.rb
113
126
  - lib/event_store_client/data_encryptor.rb
114
127
  - lib/event_store_client/deserialized_event.rb
115
128
  - lib/event_store_client/encryption_metadata.rb
116
- - lib/event_store_client/endpoint.rb
117
129
  - lib/event_store_client/event.rb
118
130
  - lib/event_store_client/mapper.rb
119
131
  - lib/event_store_client/mapper/default.rb
@@ -133,7 +145,7 @@ licenses:
133
145
  - MIT
134
146
  metadata:
135
147
  allowed_push_host: https://rubygems.org
136
- post_install_message:
148
+ post_install_message:
137
149
  rdoc_options: []
138
150
  require_paths:
139
151
  - lib
@@ -148,8 +160,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
148
160
  - !ruby/object:Gem::Version
149
161
  version: '0'
150
162
  requirements: []
151
- rubygems_version: 3.0.6
152
- signing_key:
163
+ rubygems_version: 3.1.4
164
+ signing_key:
153
165
  specification_version: 4
154
166
  summary: Ruby integration for https://eventstore.org
155
167
  test_files: []
@@ -1,112 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module EventStoreClient
4
- class Connection
5
- def publish(stream:, events:, expected_version: nil)
6
- serialized_events = events.map { |event| mapper.serialize(event) }
7
- client.append_to_stream(
8
- stream, serialized_events, expected_version: expected_version
9
- )
10
- serialized_events
11
- end
12
-
13
- def read(stream, direction:, start:, all:, resolve_links: true)
14
- return read_all_from_stream(stream, start: start, resolve_links: resolve_links) if all
15
- read_from_stream(
16
- stream, direction: direction, start: start, resolve_links: resolve_links
17
- )
18
- end
19
-
20
- def delete_stream(stream); end
21
-
22
- def join_streams(name, streams)
23
- client.join_streams(name, streams)
24
- end
25
-
26
- def subscribe(stream, name:)
27
- client.subscribe_to_stream(stream, name)
28
- end
29
-
30
- def consume_feed(stream, subscription)
31
- response = client.consume_feed(stream, subscription)
32
- return [] unless response.body
33
- body = JSON.parse(response.body)
34
-
35
- ack = body['links'].find { |link| link['relation'] == 'ackAll' }
36
- return unless ack
37
- ack_uri = ack['uri']
38
- events = body['entries'].map do |entry|
39
- deserialize_event(entry)
40
- end
41
- client.ack(ack_uri)
42
- events
43
- end
44
-
45
- def link_to(stream, events, expected_version: nil)
46
- client.link_to(stream, events, expected_version: expected_version)
47
-
48
- true
49
- end
50
-
51
- private
52
-
53
- attr_reader :mapper, :per_page, :client
54
-
55
- def config
56
- EventStoreClient::Configuration.instance
57
- end
58
-
59
- def initialize
60
- @per_page = config.per_page
61
- @mapper = config.mapper
62
- @client = config.adapter
63
- end
64
-
65
- def read_from_stream(stream, direction:, start:, resolve_links:)
66
- response =
67
- client.read(
68
- stream, start: start, direction: direction, resolve_links: resolve_links
69
- )
70
- return [] if response.body.nil? || response.body.empty?
71
- JSON.parse(response.body)['entries'].map do |entry|
72
- deserialize_event(entry)
73
- end.reverse
74
- end
75
-
76
- def read_all_from_stream(stream, start:, resolve_links:)
77
- count = per_page
78
- events = []
79
- failed_requests_count = 0
80
-
81
- while failed_requests_count < 3
82
- begin
83
- response =
84
- client.read(stream, start: start, direction: 'forward', resolve_links: resolve_links)
85
- failed_requests_count += 1 && next unless response.success? || response.status == 404
86
- rescue Faraday::ConnectionFailed
87
- failed_requests_count += 1
88
- next
89
- end
90
- failed_requests_count = 0
91
- break if response.body.nil? || response.body.empty?
92
- entries = JSON.parse(response.body)['entries']
93
- break if entries.empty?
94
- events += entries.map { |entry| deserialize_event(entry) }.reverse
95
- start += count
96
- end
97
- events
98
- end
99
-
100
- def deserialize_event(entry)
101
- event = EventStoreClient::Event.new(
102
- id: entry['eventId'],
103
- title: entry['title'],
104
- type: entry['eventType'],
105
- data: entry['data'] || '{}',
106
- metadata: entry['isMetaData'] ? entry['metaData'] : '{}'
107
- )
108
-
109
- mapper.deserialize(event)
110
- end
111
- end
112
- end
@@ -1,14 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'dry-struct'
4
-
5
- module EventStoreClient
6
- class Endpoint < Dry::Struct
7
- attribute :host, Types::String
8
- attribute :port, Types::Coercible::Integer
9
-
10
- def url
11
- "#{host}:#{port}"
12
- end
13
- end
14
- end