event_store_client 1.0.6 → 1.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +70 -130
- data/lib/event_store_client.rb +3 -2
- data/lib/event_store_client/adapters/grpc/README.md +16 -0
- data/lib/event_store_client/adapters/grpc/commands/streams/append.rb +2 -2
- data/lib/event_store_client/adapters/http/README.md +4 -4
- data/lib/event_store_client/adapters/http/client.rb +1 -3
- data/lib/event_store_client/adapters/http/commands/streams/read.rb +2 -4
- data/lib/event_store_client/configuration.rb +2 -2
- data/lib/event_store_client/deserialized_event.rb +3 -1
- data/lib/event_store_client/error_handler.rb +10 -0
- data/lib/event_store_client/subscription.rb +2 -1
- data/lib/event_store_client/version.rb +1 -1
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7046a3740fb53a00a8c30786e4bf6af390ba8a93be973412514baff7065731d1
|
4
|
+
data.tar.gz: ba04c6804ebfa8d7e876f14766f87f806adff2dee66e2f1e02a6d0644acad357
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3657c4a696a35b85f37995cae37af7fd31d7c287f751a8444e1e63c640d7ec5dd9e874164c5448aa0cee5030029d8b80797308676a528a5ec42af71800ea5677
|
7
|
+
data.tar.gz: d17ed0da65846b1e79caa8bbef2ad9968de9627605c3eb0b7b64eee6558e1768171e087604e9c2563666334da4f148913e82df8d35acd6a74852b548af641cc1
|
data/README.md
CHANGED
@@ -3,19 +3,19 @@
|
|
3
3
|
|
4
4
|
# EventStoreClient
|
5
5
|
|
6
|
-
An easy-to use API client for connecting ruby applications with https://eventstore.
|
6
|
+
An easy-to use API client for connecting ruby applications with [EventStoreDB](https://eventstore.com/)
|
7
7
|
|
8
8
|
## Supported adapters
|
9
9
|
|
10
|
-
- GRPC - default
|
10
|
+
- [GRPC](https://github.com/yousty/event_store_client/tree/master/lib/event_store_client/adapters/grpc/README.md) - default
|
11
11
|
- [HTTP](https://github.com/yousty/event_store_client/tree/master/lib/event_store_client/adapters/http/README.md) - Deprecated
|
12
|
-
-
|
12
|
+
- InMemory - for testing
|
13
13
|
|
14
14
|
## Installation
|
15
15
|
Add this line to your application's Gemfile:
|
16
16
|
|
17
17
|
```ruby
|
18
|
-
gem 'event_store_client'
|
18
|
+
gem 'event_store_client', '~> 1.0'
|
19
19
|
```
|
20
20
|
|
21
21
|
And then execute:
|
@@ -30,19 +30,8 @@ $ gem install event_store_client
|
|
30
30
|
|
31
31
|
## Usage
|
32
32
|
|
33
|
-
Before you start, make sure you
|
34
|
-
|
35
|
-
### EventStore engine setup
|
36
|
-
|
37
|
-
1. Download Event Store From https://eventstore.org/downloads/ or docker
|
38
|
-
|
39
|
-
` docker pull eventstore/eventstore`
|
40
|
-
|
41
|
-
2. Run the Event Store server
|
42
|
-
|
43
|
-
`docker run --env EVENTSTORE_INSECURE=true --name eventstore -it -p 2113:2113 -p 1113:1113 eventstore/eventstore`
|
44
|
-
|
45
|
-
4. Visit the admin panel http://localhost:2113 and enable Projections for Event-Types
|
33
|
+
Before you start, make sure you are connecting to a running EventStoreDB instance. For a detailed guide see:
|
34
|
+
[EventStoreServerSetup](https://github.com/yousty/event_store_client/blob/master/docs/eventstore_server_setup.md)
|
46
35
|
|
47
36
|
### Create Dummy event and dummy Handler
|
48
37
|
|
@@ -76,71 +65,99 @@ class DummyHandler
|
|
76
65
|
end
|
77
66
|
end
|
78
67
|
```
|
79
|
-
|
68
|
+
|
80
69
|
|
81
70
|
```ruby
|
82
|
-
# initialize the client
|
83
|
-
client = EventStoreClient::Client.new
|
84
|
-
```
|
85
71
|
|
86
|
-
|
72
|
+
require 'event_store_client'
|
73
|
+
require "event_store_client/adapters/grpc"
|
87
74
|
|
88
|
-
|
89
|
-
|
90
|
-
|
75
|
+
EventStoreClient.configure do |config|
|
76
|
+
config.eventstore_url = ENV['EVENTSTORE_URL']
|
77
|
+
config.eventstore_user = ENV['EVENTSTORE_USER']
|
78
|
+
config.eventstore_password = ENV['EVENTSTORE_PASSWORD']
|
79
|
+
config.verify_ssl = false # remove this line if your server does have the host verified
|
80
|
+
end
|
91
81
|
|
92
|
-
|
82
|
+
event_store = EventStoreClient::Client.new
|
93
83
|
|
94
|
-
|
95
|
-
|
84
|
+
event_store.subscribe(
|
85
|
+
DummyHandler.new,
|
86
|
+
to: [SomethingHappened]
|
87
|
+
)
|
88
|
+
|
89
|
+
event_store.listen
|
96
90
|
```
|
97
91
|
|
98
|
-
|
92
|
+
## Features
|
99
93
|
|
100
|
-
|
101
|
-
events = client.read('newstream', direction: 'backwards') #default 'forwards'
|
102
|
-
```
|
94
|
+
## Basic Usage
|
103
95
|
|
104
|
-
|
96
|
+
The main interface allows for actions listed below which is enough for basic useage.
|
97
|
+
The actual adapter allows for more actions. Contributions as always welcome!
|
105
98
|
|
106
99
|
```ruby
|
107
|
-
|
108
|
-
|
100
|
+
# Publishing to a stream
|
101
|
+
event_store.publish(stream: 'newstream', events: [event])
|
109
102
|
|
110
|
-
|
103
|
+
# Reading from a stream
|
104
|
+
events = event_store.read('newstream').value!
|
111
105
|
|
112
|
-
|
113
|
-
|
106
|
+
# Reading all events from a stream
|
107
|
+
events = event_store.read('newstream', options: { all: true }).value! #default 'false'
|
114
108
|
|
115
|
-
#
|
116
|
-
|
109
|
+
# Linking existing events to a new stream
|
110
|
+
event_store.link_to(stream_name, events)
|
117
111
|
|
118
|
-
#
|
112
|
+
# Subscribing to events
|
113
|
+
event_store.subscribe(DummyHandler.new, to: [SomethingHappened])
|
119
114
|
|
120
|
-
events
|
121
|
-
|
115
|
+
# Listening to new events for all registered subscriptions
|
116
|
+
event_store.listen
|
122
117
|
|
118
|
+
# In the new terminal session publish some events
|
119
|
+
events = (1..10).map { event }
|
120
|
+
event_store.publish(stream: 'newstream', events: events)
|
123
121
|
# .... wait a little bit ... Your handler should be called for every single event you publish
|
124
122
|
```
|
125
123
|
|
126
|
-
###
|
124
|
+
### Extended usage
|
127
125
|
|
128
|
-
|
129
|
-
|
126
|
+
You can get access to more features by calling the adapter directly, for example:
|
127
|
+
|
128
|
+
```
|
129
|
+
event_store.connection.delete_stream(stream)
|
130
|
+
event_store.connection.tombstone_stream(stream)
|
130
131
|
```
|
131
132
|
|
132
|
-
|
133
|
+
See the adapters method list for the possible usage.
|
133
134
|
|
134
|
-
|
135
|
+
- [HTTP](https://github.com/yousty/event_store_client/blob/master/lib/event_store_client/adapters/http/client.rb)
|
136
|
+
- [GRPC](https://github.com/yousty/event_store_client/blob/master/lib/event_store_client/adapters/grpc/client.rb)
|
135
137
|
|
136
|
-
|
138
|
+
### Configuration
|
139
|
+
|
140
|
+
There are several configuration options you can pass to customize your client's instance.
|
141
|
+
All the config options can be passed the same way:
|
137
142
|
|
138
143
|
```ruby
|
139
144
|
EventStoreClient.configure do |config|
|
140
|
-
config.adapter =
|
145
|
+
config.adapter = :grpc
|
141
146
|
end
|
142
147
|
```
|
143
148
|
|
149
|
+
| name | value | default | description |
|
150
|
+
|:-------------:|:-------------:|:-----:|:-------------:|
|
151
|
+
| adapter | `:grpc`, `:http` or `:in_memory` | `:grpc` | different ways to connect with an event_store_db. The in_memory is a mock server useful for testing |
|
152
|
+
| verify_ssl | Boolean | true | Useful for self-signed certificates (Kubernetes, local development) |
|
153
|
+
| error_handler | Any callable ruby object | EvenStoreClient::ErrorHandler | You can pass a custom error handler for reacting on event_handler errors.|
|
154
|
+
| eventstore_url| String| 'http://localhost:2113'| An url for the server instance|
|
155
|
+
| user| String| 'admin' | a user used to connect the application with the server|
|
156
|
+
| password| String| 'changeit'| a password used to connect the application with the server|
|
157
|
+
| per_page| Integer| 20 | a batch size for events subscriptions |
|
158
|
+
| service_name| String| 'default' | a prefix (namespace) added to the subscriptions names|
|
159
|
+
| mapper| `Mapper::Default` or `Mapper::Encrypted`| `Mapper::Default.new` | an engine used to parse events.
|
160
|
+
|
144
161
|
## Event Mappers
|
145
162
|
|
146
163
|
At the moment we offer two types of mappers:
|
@@ -156,86 +173,7 @@ Event parsable by event_store and the other way around.
|
|
156
173
|
### Encrypted Mapper
|
157
174
|
|
158
175
|
This is implemented to match GDPR requirements. It allows you to encrypt any event using your
|
159
|
-
encryption_key repository.
|
160
|
-
|
161
|
-
```ruby
|
162
|
-
mapper = EventStoreClient::Mapper::Encrypted.new(key_repository)
|
163
|
-
EventStoreClient.configure do |config|
|
164
|
-
config.mapper = mapper
|
165
|
-
end
|
166
|
-
```
|
167
|
-
|
168
|
-
The Encrypted mapper uses the encryption key repository to encrypt data in your events according to the event definition.
|
169
|
-
|
170
|
-
Here is the minimal repository interface for this to work.
|
171
|
-
|
172
|
-
```ruby
|
173
|
-
class DummyRepository
|
174
|
-
class Key
|
175
|
-
attr_accessor :iv, :cipher, :id
|
176
|
-
def initialize(id:, **)
|
177
|
-
@id = id
|
178
|
-
end
|
179
|
-
end
|
180
|
-
|
181
|
-
def find(user_id)
|
182
|
-
Key.new(id: user_id)
|
183
|
-
end
|
184
|
-
|
185
|
-
def encrypt(*)
|
186
|
-
'darthvader'
|
187
|
-
end
|
188
|
-
|
189
|
-
def decrypt(*)
|
190
|
-
{ first_name: 'Anakin', last_name: 'Skylwalker'}
|
191
|
-
end
|
192
|
-
end
|
193
|
-
```
|
194
|
-
|
195
|
-
Now, having that, you only need to define the event encryption schema:
|
196
|
-
|
197
|
-
```ruby
|
198
|
-
class EncryptedEvent < EventStoreClient::DeserializedEvent
|
199
|
-
def schema
|
200
|
-
Dry::Schema.Params do
|
201
|
-
required(:user_id).value(:string)
|
202
|
-
required(:first_name).value(:string)
|
203
|
-
required(:last_name).value(:string)
|
204
|
-
required(:profession).value(:string)
|
205
|
-
end
|
206
|
-
end
|
207
|
-
|
208
|
-
def self.encryption_schema
|
209
|
-
{
|
210
|
-
key: ->(data) { data['user_id'] },
|
211
|
-
attributes: %i[first_name last_name email]
|
212
|
-
}
|
213
|
-
end
|
214
|
-
end
|
215
|
-
|
216
|
-
event = EncryptedEvent.new(
|
217
|
-
user_id: SecureRandom.uuid,
|
218
|
-
first_name: 'Anakin',
|
219
|
-
last_name: 'Skylwalker',
|
220
|
-
profession: 'Jedi'
|
221
|
-
)
|
222
|
-
```
|
223
|
-
|
224
|
-
When you'll publish this event, in the store will be saved:
|
225
|
-
|
226
|
-
```ruby
|
227
|
-
{
|
228
|
-
'data' => {
|
229
|
-
'user_id' => 'dab48d26-e4f8-41fc-a9a8-59657e590716',
|
230
|
-
'first_name' => 'encrypted',
|
231
|
-
'last_name' => 'encrypted',
|
232
|
-
'profession' => 'Jedi',
|
233
|
-
'encrypted' => '2345l423lj1#$!lkj24f1'
|
234
|
-
},
|
235
|
-
type: 'EncryptedEvent'
|
236
|
-
metadata: { ... }
|
237
|
-
}
|
238
|
-
```
|
176
|
+
encryption_key repository. For the detailed guide see the: [Encrypting Events](https://github.com/yousty/event_store_client/blob/master/docs/encrypting_events.md).
|
239
177
|
|
240
178
|
## Contributing
|
241
179
|
|
@@ -245,6 +183,8 @@ Do you want to contribute? Welcome!
|
|
245
183
|
2. Create Issue
|
246
184
|
3. Create PR ;)
|
247
185
|
|
186
|
+
For running the client in the dev mode, see: [Development Guide](https://github.com/yousty/event_store_client/blob/master/docs/eventstore_server_setup.md)
|
187
|
+
|
248
188
|
### Publishing new version
|
249
189
|
|
250
190
|
1. Push commit with updated `version.rb` file to the `release` branch. The new version will be automatically pushed to [rubygems](https://rubygems.org).
|
data/lib/event_store_client.rb
CHANGED
@@ -4,13 +4,14 @@ module EventStoreClient
|
|
4
4
|
end
|
5
5
|
|
6
6
|
require 'event_store_client/types'
|
7
|
-
|
8
|
-
require 'event_store_client/deserialized_event'
|
7
|
+
|
9
8
|
require 'event_store_client/serializer/json'
|
10
9
|
|
11
10
|
require 'event_store_client/mapper'
|
12
11
|
|
13
12
|
require 'event_store_client/configuration'
|
13
|
+
require 'event_store_client/event'
|
14
|
+
require 'event_store_client/deserialized_event'
|
14
15
|
|
15
16
|
require 'event_store_client/subscription'
|
16
17
|
require 'event_store_client/subscriptions'
|
@@ -0,0 +1,16 @@
|
|
1
|
+
### GRPC adapter
|
2
|
+
|
3
|
+
This adapter targets the EventstoreDB version `>= "20.*"
|
4
|
+
|
5
|
+
### Configuration
|
6
|
+
|
7
|
+
As by default EventStoreClient uses GRPC adapter. No need to configure anything if you want to use it,
|
8
|
+
however to set it explicitly, place the snippet below in your initializer or when you boot your application.
|
9
|
+
|
10
|
+
```ruby
|
11
|
+
require 'event_store_client/adapters/grpc'
|
12
|
+
|
13
|
+
EventStoreClient.configure do |config|
|
14
|
+
config.adapter = :grpc
|
15
|
+
end
|
16
|
+
```
|
@@ -1,8 +1,6 @@
|
|
1
1
|
### HTTP adapter
|
2
2
|
|
3
|
-
This adapter targets the EventstoreDB version `>= "
|
4
|
-
|
5
|
-
For detailed docs about the http protocol see [EventStoreDB Http Documentation](https://developers.eventstore.com/server/5.0.8/http-api/)
|
3
|
+
This adapter targets the EventstoreDB version `>= "20.*"
|
6
4
|
|
7
5
|
### Configuration
|
8
6
|
|
@@ -10,7 +8,9 @@ As by default EventStoreClient uses gRPC adapter, to switch to http you need to
|
|
10
8
|
Place the snippet below in your initializer or when you boot your application.
|
11
9
|
|
12
10
|
```ruby
|
11
|
+
require 'event_store_client/adapters/http'
|
12
|
+
|
13
13
|
EventStoreClient.configure do |config|
|
14
|
-
config.adapter = :
|
14
|
+
config.adapter = :http
|
15
15
|
end
|
16
16
|
```
|
@@ -47,9 +47,7 @@ module EventStoreClient
|
|
47
47
|
# @return Dry::Monads::Result::Success with returned events or Dry::Monads::Result::Failure
|
48
48
|
#
|
49
49
|
def read(stream_name, options: {})
|
50
|
-
Commands::Streams::Read.new(connection).call(
|
51
|
-
stream_name, options: options
|
52
|
-
)
|
50
|
+
Commands::Streams::Read.new(connection).call(stream_name, options: options)
|
53
51
|
end
|
54
52
|
|
55
53
|
# Reads all events from the given stream
|
@@ -11,10 +11,8 @@ module EventStoreClient
|
|
11
11
|
count = options[:count] || config.per_page
|
12
12
|
start = options[:start].to_i
|
13
13
|
direction = options[:direction] || 'forward'
|
14
|
-
headers = {
|
15
|
-
|
16
|
-
'Accept' => 'application/vnd.eventstore.atom+json'
|
17
|
-
}
|
14
|
+
headers = { 'Accept' => 'application/vnd.eventstore.atom+json' }
|
15
|
+
headers['ES-ResolveLinkTos'] = true if options.key?(:resolve_links)
|
18
16
|
|
19
17
|
response =
|
20
18
|
connection.call(
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'dry-configurable'
|
4
|
-
|
4
|
+
require 'event_store_client/error_handler'
|
5
5
|
module EventStoreClient
|
6
6
|
extend Dry::Configurable
|
7
7
|
|
@@ -10,7 +10,7 @@ module EventStoreClient
|
|
10
10
|
setting :adapter, :grpc
|
11
11
|
setting :verify_ssl, true
|
12
12
|
|
13
|
-
setting :error_handler
|
13
|
+
setting :error_handler, ErrorHandler.new
|
14
14
|
setting :eventstore_url, 'http://localhost:2113' do |value|
|
15
15
|
value.is_a?(URI) ? value : URI(value)
|
16
16
|
end
|
@@ -19,7 +19,9 @@ module EventStoreClient
|
|
19
19
|
|
20
20
|
def initialize(**args)
|
21
21
|
validation = schema.call(args[:data] || {})
|
22
|
-
|
22
|
+
if validation.errors.any?
|
23
|
+
raise InvalidDataError.new(message: "#{schema.class.name} #{validation.errors.to_h}")
|
24
|
+
end
|
23
25
|
|
24
26
|
@data = args.fetch(:data) { {} }
|
25
27
|
@metadata = args.fetch(:metadata) { {} }.merge(
|
@@ -13,7 +13,8 @@ module EventStoreClient
|
|
13
13
|
else
|
14
14
|
subscriber.class.name
|
15
15
|
end
|
16
|
-
@name =
|
16
|
+
@name = subscriber_class.to_s
|
17
|
+
@name = "#{service}-" + @name if service != ''
|
17
18
|
@subscriber = subscriber
|
18
19
|
@stream = name
|
19
20
|
@observed_streams = event_types.reduce([]) { |r, type| r << "$et-#{type}" }
|
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: 1.0.
|
4
|
+
version: 1.0.11
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sebastian Wilgosz
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-05-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: dry-configurable
|
@@ -156,6 +156,7 @@ files:
|
|
156
156
|
- lib/event_store_client/adapters/grpc/Protos/shared.proto
|
157
157
|
- lib/event_store_client/adapters/grpc/Protos/streams.proto
|
158
158
|
- lib/event_store_client/adapters/grpc/Protos/users.proto
|
159
|
+
- lib/event_store_client/adapters/grpc/README.md
|
159
160
|
- lib/event_store_client/adapters/grpc/client.rb
|
160
161
|
- lib/event_store_client/adapters/grpc/command_registrar.rb
|
161
162
|
- lib/event_store_client/adapters/grpc/commands/command.rb
|
@@ -212,6 +213,7 @@ files:
|
|
212
213
|
- lib/event_store_client/data_encryptor.rb
|
213
214
|
- lib/event_store_client/deserialized_event.rb
|
214
215
|
- lib/event_store_client/encryption_metadata.rb
|
216
|
+
- lib/event_store_client/error_handler.rb
|
215
217
|
- lib/event_store_client/event.rb
|
216
218
|
- lib/event_store_client/mapper.rb
|
217
219
|
- lib/event_store_client/mapper/default.rb
|
@@ -242,7 +244,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
242
244
|
- !ruby/object:Gem::Version
|
243
245
|
version: '0'
|
244
246
|
requirements: []
|
245
|
-
rubygems_version: 3.
|
247
|
+
rubygems_version: 3.0.6
|
246
248
|
signing_key:
|
247
249
|
specification_version: 4
|
248
250
|
summary: Ruby integration for https://eventstore.org
|