event_store_client 2.3.0 → 3.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/docs/appending_events.md +16 -22
- data/docs/catch_up_subscriptions.md +35 -70
- data/docs/configuration.md +6 -10
- data/docs/deleting_streams.md +14 -4
- data/docs/encrypting_events.md +2 -6
- data/docs/linking_events.md +20 -26
- data/docs/reading_events.md +33 -62
- data/lib/event_store_client/adapters/grpc/client.rb +13 -9
- data/lib/event_store_client/adapters/grpc/commands/command.rb +0 -2
- data/lib/event_store_client/adapters/grpc/commands/gossip/cluster_info.rb +1 -1
- data/lib/event_store_client/adapters/grpc/commands/streams/append.rb +11 -5
- data/lib/event_store_client/adapters/grpc/commands/streams/append_multiple.rb +2 -6
- data/lib/event_store_client/adapters/grpc/commands/streams/delete.rb +7 -5
- data/lib/event_store_client/adapters/grpc/commands/streams/hard_delete.rb +7 -5
- data/lib/event_store_client/adapters/grpc/commands/streams/link_to_multiple.rb +5 -10
- data/lib/event_store_client/adapters/grpc/commands/streams/read_paginated.rb +5 -8
- data/lib/event_store_client/adapters/grpc/commands/streams/subscribe.rb +3 -5
- data/lib/event_store_client/adapters/grpc/shared/streams/process_response.rb +6 -8
- data/lib/event_store_client/adapters/grpc/shared/streams/process_responses.rb +11 -13
- data/lib/event_store_client/adapters/grpc.rb +0 -1
- data/lib/event_store_client/deserialized_event.rb +21 -3
- data/lib/event_store_client/errors.rb +110 -0
- data/lib/event_store_client/mapper/default.rb +1 -1
- data/lib/event_store_client/mapper/encrypted.rb +2 -2
- data/lib/event_store_client/rspec/has_option_matcher.rb +88 -0
- data/lib/event_store_client/serializer/event_deserializer.rb +4 -2
- data/lib/event_store_client/serializer/event_serializer.rb +41 -17
- data/lib/event_store_client/version.rb +1 -1
- data/lib/event_store_client.rb +3 -1
- metadata +24 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 82b73db66b7feef1d17e010f9e410476ab900bd6b137af03ee57106f2aefea6b
|
4
|
+
data.tar.gz: 926d40bfa51a581de7f9e7942d7092e4e0f0d7c23d1c932cb689946ef3a690f5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 59dc478314bb1a15895dfe851248d6c1b62a381c26d03c8f7d1d18465a1407a28f007a959f2c655222b54dd310929df5430528125c3c97221393e3ce3b937256
|
7
|
+
data.tar.gz: bb92b9f60639f5d0552c69b493e0e6dbb8e6985e89d7f4f78de6df45c12e6098554e7de13f8880e45fd84a8ddc8528eec778a78715ebd591fcc5c331709bea4a
|
data/README.md
CHANGED
data/docs/appending_events.md
CHANGED
@@ -1,6 +1,4 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
# Append your first event
|
1
|
+
# Appending Events
|
4
2
|
|
5
3
|
## Append your first event
|
6
4
|
|
@@ -14,11 +12,11 @@ event = SomethingHappened.new(
|
|
14
12
|
id: SecureRandom.uuid, type: 'some-event', data: { user_id: SecureRandom.uuid, title: "Something happened" }
|
15
13
|
)
|
16
14
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
15
|
+
begin
|
16
|
+
EventStoreClient.client.append_to_stream('some-stream', event)
|
17
|
+
# => EventStore::Client::Streams::AppendResp
|
18
|
+
rescue EventStoreClient::WrongExpectedVersionError => e
|
19
|
+
puts e.message
|
22
20
|
end
|
23
21
|
```
|
24
22
|
|
@@ -37,15 +35,13 @@ event2 = SomethingHappened.new(
|
|
37
35
|
id: SecureRandom.uuid, type: 'some-event', data: { user_id: SecureRandom.uuid, title: "Something happened 2" }
|
38
36
|
)
|
39
37
|
|
40
|
-
|
41
|
-
|
42
|
-
#
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
end
|
38
|
+
begin
|
39
|
+
EventStoreClient.client.append_to_stream('some-stream', [event1, event2])
|
40
|
+
# => Array<EventStore::Client::Streams::AppendResp>
|
41
|
+
rescue EventStoreClient::WrongExpectedVersionError => e
|
42
|
+
puts e.message
|
43
|
+
puts e.caused_by # event which caused the error
|
47
44
|
end
|
48
|
-
|
49
45
|
```
|
50
46
|
|
51
47
|
## Working with EventStoreClient::DeserializedEvent
|
@@ -62,8 +58,8 @@ EventStoreClient::DeserializedEvent.new(
|
|
62
58
|
type: 'some-event-name',
|
63
59
|
# Event data. Optional. Will default to `{}` (empty hash) if omitted
|
64
60
|
data: { foo: :bar },
|
65
|
-
# Optional.
|
66
|
-
|
61
|
+
# Optional. You can put here any value which is not supposed to be present in data.
|
62
|
+
custom_metadata: {}
|
67
63
|
)
|
68
64
|
```
|
69
65
|
|
@@ -128,13 +124,11 @@ event1 = SomethingHappened.new(
|
|
128
124
|
event2 = SomethingHappened.new(
|
129
125
|
type: 'some-event', data: {}
|
130
126
|
)
|
131
|
-
|
132
|
-
type: 'some-event', data: {}
|
133
|
-
)
|
127
|
+
|
134
128
|
# Pre-populate stream with some event
|
135
129
|
EventStoreClient.client.append_to_stream(stream_name, event1)
|
136
130
|
# Get the revision number of latest event
|
137
|
-
revision = EventStoreClient.client.read(stream_name).
|
131
|
+
revision = EventStoreClient.client.read(stream_name).last.stream_revision
|
138
132
|
# Expected revision matches => will succeed
|
139
133
|
EventStoreClient.client.append_to_stream(stream_name, event2, options: { expected_revision: revision })
|
140
134
|
# Will fail with revisions mismatch error
|
@@ -1,6 +1,4 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
# Catch-up subscriptions
|
1
|
+
# Catch-up Subscriptions
|
4
2
|
|
5
3
|
Subscriptions allow you to subscribe to a stream and receive notifications about new events added to the stream.
|
6
4
|
|
@@ -17,13 +15,8 @@ When you need to process all the events in the store, including historical event
|
|
17
15
|
The most simple stream subscription looks like the following:
|
18
16
|
|
19
17
|
```ruby
|
20
|
-
handler = proc do |
|
21
|
-
|
22
|
-
event = result.success # retrieve a result
|
23
|
-
# ... do something with event
|
24
|
-
else # result.failure?
|
25
|
-
puts result.failure # prints error
|
26
|
-
end
|
18
|
+
handler = proc do |event|
|
19
|
+
p event
|
27
20
|
end
|
28
21
|
EventStoreClient.client.subscribe_to_stream('some-stream', handler: handler)
|
29
22
|
```
|
@@ -32,13 +25,8 @@ The provided handler will be called for every event in the stream. You may provi
|
|
32
25
|
|
33
26
|
```ruby
|
34
27
|
class SomeStreamHandler
|
35
|
-
def call(
|
36
|
-
|
37
|
-
event = result.success # retrieve a result
|
38
|
-
# ... do something with event
|
39
|
-
else # result.failure?
|
40
|
-
puts result.failure # prints error
|
41
|
-
end
|
28
|
+
def call(event)
|
29
|
+
p event
|
42
30
|
end
|
43
31
|
end
|
44
32
|
EventStoreClient.client.subscribe_to_stream('some-stream', handler: SomeStreamHandler.new)
|
@@ -49,13 +37,8 @@ EventStoreClient.client.subscribe_to_stream('some-stream', handler: SomeStreamHa
|
|
49
37
|
Subscribing to `$all` is much the same as subscribing to a single stream. The handler will be called for every event appended after the starting position.
|
50
38
|
|
51
39
|
```ruby
|
52
|
-
handler = proc do |
|
53
|
-
|
54
|
-
event = result.success # retrieve a result
|
55
|
-
# ... do something with event
|
56
|
-
else # result.failure?
|
57
|
-
puts result.failure # prints error
|
58
|
-
end
|
40
|
+
handler = proc do |event|
|
41
|
+
p event
|
59
42
|
end
|
60
43
|
EventStoreClient.client.subscribe_to_all(handler: handler)
|
61
44
|
```
|
@@ -75,7 +58,7 @@ To subscribe to a stream from a specific position, you need to provide a _stream
|
|
75
58
|
The following subscribes to the stream `some-stream` at position `20`, this means that events `21` and onward will be handled:
|
76
59
|
|
77
60
|
```ruby
|
78
|
-
EventStoreClient.client.subscribe_to_stream('some-stream', handler: proc { |
|
61
|
+
EventStoreClient.client.subscribe_to_stream('some-stream', handler: proc { |event| }, options: { from_revision: 20 })
|
79
62
|
```
|
80
63
|
|
81
64
|
### Subscribing to $all
|
@@ -85,7 +68,7 @@ Subscribing to the `$all` stream is much like subscribing to a regular stream. T
|
|
85
68
|
The following `$all` subscription will subscribe from the event after the one at commit position `1056` and prepare position `1056`:
|
86
69
|
|
87
70
|
```ruby
|
88
|
-
EventStoreClient.client.subscribe_to_all(handler: proc { |
|
71
|
+
EventStoreClient.client.subscribe_to_all(handler: proc { |event| }, options: { from_position: { commit_position: 1056, prepare_position: 1056 } })
|
89
72
|
```
|
90
73
|
|
91
74
|
Please note that the given position needs to be a legitimate position in the `$all` stream.
|
@@ -95,13 +78,13 @@ Please note that the given position needs to be a legitimate position in the `$a
|
|
95
78
|
You can subscribe to a stream to get live updates by subscribing to the end of the stream:
|
96
79
|
|
97
80
|
```ruby
|
98
|
-
EventStoreClient.client.subscribe_to_stream('some-stream', handler: proc { |
|
81
|
+
EventStoreClient.client.subscribe_to_stream('some-stream', handler: proc { |event| }, options: { from_revision: :end })
|
99
82
|
```
|
100
83
|
|
101
84
|
And the same works with `$all` :
|
102
85
|
|
103
86
|
```ruby
|
104
|
-
EventStoreClient.client.subscribe_to_all(handler: proc { |
|
87
|
+
EventStoreClient.client.subscribe_to_all(handler: proc { |event| }, options: { from_position: :end })
|
105
88
|
```
|
106
89
|
|
107
90
|
This won't read through the history of the stream, but will rather notify the handler when a new event appears in the respective stream.
|
@@ -115,7 +98,7 @@ Link-to events point to events in other streams in EventStoreDB. These are gener
|
|
115
98
|
When reading a stream you can specify whether to resolve link-to's or not. By default, link-to events are not resolved. You can change this behaviour by setting the `resolve_link_tos` option to `true`:
|
116
99
|
|
117
100
|
```ruby
|
118
|
-
EventStoreClient.client.subscribe_to_stream('$et-myEventType', handler: proc { |
|
101
|
+
EventStoreClient.client.subscribe_to_stream('$et-myEventType', handler: proc { |event| }, options: { resolve_link_tos: true })
|
119
102
|
```
|
120
103
|
|
121
104
|
## Handling subscription drops
|
@@ -124,14 +107,9 @@ An application, which hosts the subscription, can go offline for a period of tim
|
|
124
107
|
|
125
108
|
```ruby
|
126
109
|
checkpoint = :start
|
127
|
-
handler = proc do |
|
128
|
-
|
129
|
-
|
130
|
-
handle_event(event)
|
131
|
-
checkpoint = event.stream_revision
|
132
|
-
else
|
133
|
-
# do something in case of error
|
134
|
-
end
|
110
|
+
handler = proc do |event|
|
111
|
+
handle_event(event)
|
112
|
+
checkpoint = event.stream_revision
|
135
113
|
end
|
136
114
|
|
137
115
|
EventStoreClient.client.subscribe_to_stream('some-stream', handler: handler, options: { from_revision: checkpoint })
|
@@ -141,14 +119,9 @@ When subscribed to `$all` you want to keep the position of the event in the `$al
|
|
141
119
|
|
142
120
|
```ruby
|
143
121
|
checkpoint = :start
|
144
|
-
handler = proc do |
|
145
|
-
|
146
|
-
|
147
|
-
handle_event(event)
|
148
|
-
checkpoint = { prepare_position: event.prepare_position, commit_position: event.commit_position }
|
149
|
-
else
|
150
|
-
# do something in case of error
|
151
|
-
end
|
122
|
+
handler = proc do |event|
|
123
|
+
handle_event(event)
|
124
|
+
checkpoint = { prepare_position: event.prepare_position, commit_position: event.commit_position }
|
152
125
|
end
|
153
126
|
|
154
127
|
EventStoreClient.client.subscribe_to_all(handler: handler, options: { from_position: checkpoint })
|
@@ -156,28 +129,20 @@ EventStoreClient.client.subscribe_to_all(handler: handler, options: { from_posit
|
|
156
129
|
|
157
130
|
### Checkpoints and other responses
|
158
131
|
|
159
|
-
By default `event_store_client` will skip such EventStore DB responses as checkpoints, confirmations, etc. If you would like to handle them in the subscription handler, you can provide the`skip_deserialization` keyword argument, and then handle deserialization by yourself:
|
132
|
+
By default `event_store_client` will skip such EventStore DB responses as checkpoints, confirmations, etc. If you would like to handle them in the subscription handler, you can provide the `skip_deserialization` keyword argument, and then handle deserialization by yourself:
|
160
133
|
|
161
134
|
```ruby
|
162
135
|
checkpoint = :start
|
163
|
-
handler = proc do |
|
164
|
-
if
|
165
|
-
|
166
|
-
if response.checkpoint
|
167
|
-
handle_checkpoint(response.checkpoint)
|
168
|
-
else
|
169
|
-
result = EventStoreClient::GRPC::Shared::Streams::ProcessResponse.new.call(
|
170
|
-
response,
|
171
|
-
false,
|
172
|
-
false
|
173
|
-
)
|
174
|
-
if result&.success?
|
175
|
-
event = result.success
|
176
|
-
handle_event(event)
|
177
|
-
end
|
178
|
-
end
|
136
|
+
handler = proc do |raw_response|
|
137
|
+
if raw_response.checkpoint
|
138
|
+
handle_checkpoint(raw_response.checkpoint)
|
179
139
|
else
|
180
|
-
|
140
|
+
event = EventStoreClient::GRPC::Shared::Streams::ProcessResponse.new(config: EventStoreClient.config).call(
|
141
|
+
raw_response,
|
142
|
+
false,
|
143
|
+
false
|
144
|
+
)
|
145
|
+
handle_event(event) if event
|
181
146
|
end
|
182
147
|
end
|
183
148
|
|
@@ -191,7 +156,7 @@ The user creating a subscription must have read access to the stream it's subscr
|
|
191
156
|
The code below shows how you can provide user credentials for a subscription. When you specify subscription credentials explicitly, it will override the default credentials set for the client. If you don't specify any credentials, the client will use the credentials specified for the client, if you specified those.
|
192
157
|
|
193
158
|
```ruby
|
194
|
-
EventStoreClient.client.subscribe_to_stream('some-stream', handler: proc { |
|
159
|
+
EventStoreClient.client.subscribe_to_stream('some-stream', handler: proc { |event| }, credentials: { username: 'admin', password: 'changeit' })
|
195
160
|
```
|
196
161
|
|
197
162
|
## Server-side filtering
|
@@ -203,7 +168,7 @@ You can filter by event type or stream name using either a regular expression or
|
|
203
168
|
A simple stream prefix filter looks like this:
|
204
169
|
|
205
170
|
```ruby
|
206
|
-
EventStoreClient.client.subscribe_to_all(handler: proc { |
|
171
|
+
EventStoreClient.client.subscribe_to_all(handler: proc { |event| }, options: { filter: { stream_identifier: { prefix: ['test-', 'other-'] } } })
|
207
172
|
```
|
208
173
|
|
209
174
|
### Filtering out system events
|
@@ -211,7 +176,7 @@ EventStoreClient.client.subscribe_to_all(handler: proc { |res| }, options: { fil
|
|
211
176
|
There are a number of events in EventStoreDB called system events. These are prefixed with a `$` and under most circumstances you won't care about these. They can be filtered out by event type.
|
212
177
|
|
213
178
|
```ruby
|
214
|
-
EventStoreClient.client.subscribe_to_all(handler: proc { |
|
179
|
+
EventStoreClient.client.subscribe_to_all(handler: proc { |event| }, options: { filter: { event_type: { regex: /^[^\$].*/.to_s } } })
|
215
180
|
```
|
216
181
|
|
217
182
|
### Filtering by event type
|
@@ -223,7 +188,7 @@ If you only want to subscribe to events of a given type there are two options. Y
|
|
223
188
|
This will only subscribe to events with a type that begin with `customer-`:
|
224
189
|
|
225
190
|
```ruby
|
226
|
-
EventStoreClient.client.subscribe_to_all(handler: proc { |
|
191
|
+
EventStoreClient.client.subscribe_to_all(handler: proc { |event| }, options: { filter: { event_type: { prefix: ['customer-'] } } })
|
227
192
|
```
|
228
193
|
|
229
194
|
#### Filtering by regular expression
|
@@ -231,7 +196,7 @@ EventStoreClient.client.subscribe_to_all(handler: proc { |res| }, options: { fil
|
|
231
196
|
If you want to subscribe to multiple event types then it might be better to provide a regular expression. This will subscribe to any event that begins with `user` or `company`:
|
232
197
|
|
233
198
|
```ruby
|
234
|
-
EventStoreClient.client.subscribe_to_all(handler: proc { |
|
199
|
+
EventStoreClient.client.subscribe_to_all(handler: proc { |event| }, options: { filter: { event_type: { regex: '^user|^company' } } })
|
235
200
|
```
|
236
201
|
|
237
202
|
### Filtering by stream name
|
@@ -243,7 +208,7 @@ If you only want to subscribe to a stream with a given name there are two option
|
|
243
208
|
This will only subscribe to all streams with a name that begins with `user-`:
|
244
209
|
|
245
210
|
```ruby
|
246
|
-
EventStoreClient.client.subscribe_to_all(handler: proc { |
|
211
|
+
EventStoreClient.client.subscribe_to_all(handler: proc { |event| }, options: { filter: { stream_identifier: { prefix: ['user-'] } } })
|
247
212
|
```
|
248
213
|
|
249
214
|
#### Filtering by regular expression
|
@@ -251,5 +216,5 @@ EventStoreClient.client.subscribe_to_all(handler: proc { |res| }, options: { fil
|
|
251
216
|
If you want to subscribe to multiple streams then it might be better to provide a regular expression.
|
252
217
|
|
253
218
|
```ruby
|
254
|
-
EventStoreClient.client.subscribe_to_all(handler: proc { |
|
219
|
+
EventStoreClient.client.subscribe_to_all(handler: proc { |event| }, options: { filter: { stream_identifier: { regex: '^account|^savings' } } })
|
255
220
|
```
|
data/docs/configuration.md
CHANGED
@@ -1,9 +1,5 @@
|
|
1
|
-
# @title Configuration
|
2
|
-
|
3
1
|
# Configuration
|
4
2
|
|
5
|
-
Currently only one setup is supported. For example, you can't configure a connection to multiple clusters.
|
6
|
-
|
7
3
|
Configuration options:
|
8
4
|
|
9
5
|
| name | value | default value | description |
|
@@ -30,9 +26,9 @@ end
|
|
30
26
|
the resulting `channel_args` value will be
|
31
27
|
|
32
28
|
```ruby
|
33
|
-
{
|
34
|
-
"grpc.min_reconnect_backoff_ms" => 200,
|
35
|
-
"grpc.max_reconnect_backoff_ms" => 100,
|
29
|
+
{
|
30
|
+
"grpc.min_reconnect_backoff_ms" => 200,
|
31
|
+
"grpc.max_reconnect_backoff_ms" => 100,
|
36
32
|
"grpc.initial_reconnect_backoff_ms" => 100
|
37
33
|
}
|
38
34
|
```
|
@@ -41,7 +37,7 @@ This behaviour is intentional. So, if you want to override them all - you should
|
|
41
37
|
|
42
38
|
```ruby
|
43
39
|
EventStoreClient.configure do |config|
|
44
|
-
config.channel_args = {
|
40
|
+
config.channel_args = {
|
45
41
|
'grpc.min_reconnect_backoff_ms' => 500,
|
46
42
|
'grpc.max_reconnect_backoff_ms' => 500,
|
47
43
|
'grpc.initial_reconnect_backoff_ms' => 500
|
@@ -141,7 +137,7 @@ EventStoreClient.configure(name: :es_db_1) do |config|
|
|
141
137
|
end
|
142
138
|
EventStoreClient.configure(name: :es_db_2) do |config|
|
143
139
|
# adjust your second config here
|
144
|
-
config.eventstore_url = 'esdb://localhost:2114'
|
140
|
+
config.eventstore_url = 'esdb://localhost:2114'
|
145
141
|
end
|
146
142
|
```
|
147
143
|
|
@@ -164,7 +160,7 @@ Setup your default config:
|
|
164
160
|
```ruby
|
165
161
|
EventStoreClient.configure do |config|
|
166
162
|
# config goes here
|
167
|
-
config.eventstore_url = 'esdb://localhost:2113'
|
163
|
+
config.eventstore_url = 'esdb://localhost:2113'
|
168
164
|
end
|
169
165
|
```
|
170
166
|
|
data/docs/deleting_streams.md
CHANGED
@@ -1,10 +1,8 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
# Deleting streams
|
1
|
+
# Deleting Streams
|
4
2
|
|
5
3
|
## Soft deleting streams
|
6
4
|
|
7
|
-
When you read a soft deleted stream, the read
|
5
|
+
When you read a soft deleted stream, the read raises `EventStoreClient::StreamNotFoundError` error. After deleting the stream, you are able to append to it again, continuing from where it left off.
|
8
6
|
|
9
7
|
```ruby
|
10
8
|
EventStoreClient.client.delete_stream('some-stream')
|
@@ -25,3 +23,15 @@ You can provide user credentials to be used to delete the stream as follows. Thi
|
|
25
23
|
```ruby
|
26
24
|
EventStoreClient.client.delete_stream('some-stream', credentials: { username: 'admin', password: 'changeit' })
|
27
25
|
```
|
26
|
+
|
27
|
+
## Possible errors during stream deletion
|
28
|
+
|
29
|
+
If you try to delete non-existing stream, or if you provided `:expected_revision` option with a value which doesn't match current stream's state - `EventStoreClient::StreamDeletionError` error will be raised:
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
begin
|
33
|
+
EventStoreClient.client.delete_stream('non-existing-stream')
|
34
|
+
rescue => e
|
35
|
+
puts e.message
|
36
|
+
end
|
37
|
+
```
|
data/docs/encrypting_events.md
CHANGED
@@ -1,15 +1,11 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
# Encrypting events
|
1
|
+
# Encrypting Events
|
4
2
|
|
5
3
|
To encrypt/decrypt events payload, you can use an encrypted mapper.
|
6
4
|
|
7
5
|
|
8
6
|
```ruby
|
9
|
-
mapper = EventStoreClient::Mapper::Encrypted.new(key_repository)
|
10
|
-
|
11
7
|
EventStoreClient.configure do |config|
|
12
|
-
config.mapper =
|
8
|
+
config.mapper = EventStoreClient::Mapper::Encrypted.new(key_repository, config: config)
|
13
9
|
end
|
14
10
|
```
|
15
11
|
|
data/docs/linking_events.md
CHANGED
@@ -1,6 +1,4 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
# Linking events
|
1
|
+
# Linking Events
|
4
2
|
|
5
3
|
## Linking single event
|
6
4
|
|
@@ -18,18 +16,16 @@ stream_name_1 = 'some-stream-1'
|
|
18
16
|
stream_name_2 = 'some-stream-2'
|
19
17
|
EventStoreClient.client.append_to_stream(stream_name_1, event)
|
20
18
|
# Get persisted event
|
21
|
-
event = EventStoreClient.client.read(stream_name_1).
|
19
|
+
event = EventStoreClient.client.read(stream_name_1).first
|
22
20
|
# Link event from first stream into second stream
|
23
|
-
|
24
|
-
|
25
|
-
else # event was not linked, result.failure? => true
|
26
|
-
end
|
21
|
+
EventStoreClient.client.link_to(stream_name_2, event)
|
22
|
+
# => EventStore::Client::Streams::AppendResp
|
27
23
|
```
|
28
24
|
|
29
25
|
The linked event can later be fetched by providing the `:resolve_link_tos` option when reading from the stream:
|
30
26
|
|
31
27
|
```ruby
|
32
|
-
EventStoreClient.client.read('some-stream-2', options: { resolve_link_tos: true })
|
28
|
+
EventStoreClient.client.read('some-stream-2', options: { resolve_link_tos: true })
|
33
29
|
```
|
34
30
|
|
35
31
|
If you don't provide the `:resolve_link_tos` option, the "linked" event will be returned instead of the original one.
|
@@ -55,14 +51,10 @@ events.each do |event|
|
|
55
51
|
EventStoreClient.client.append_to_stream(stream_name_1, event)
|
56
52
|
end
|
57
53
|
# Get persisted events
|
58
|
-
events = EventStoreClient.client.read(stream_name_1)
|
54
|
+
events = EventStoreClient.client.read(stream_name_1)
|
59
55
|
# Link events from first stream into second stream one by one
|
60
|
-
|
61
|
-
|
62
|
-
if result.success? # Event was successfully linked
|
63
|
-
else # event was not linked, result.failure? => true
|
64
|
-
end
|
65
|
-
end
|
56
|
+
EventStoreClient.client.link_to(stream_name_2, events)
|
57
|
+
# => Array<EventStore::Client::Streams::AppendResp>
|
66
58
|
```
|
67
59
|
|
68
60
|
## Handling concurrency
|
@@ -87,11 +79,13 @@ stream_name_1 = "some-stream-1$#{SecureRandom.uuid}"
|
|
87
79
|
stream_name_2 = "some-stream-2$#{SecureRandom.uuid}"
|
88
80
|
|
89
81
|
EventStoreClient.client.append_to_stream(stream_name_1, [event1, event2])
|
90
|
-
events = EventStoreClient.client.read(stream_name_1)
|
82
|
+
events = EventStoreClient.client.read(stream_name_1)
|
91
83
|
|
92
|
-
|
93
|
-
|
94
|
-
|
84
|
+
begin
|
85
|
+
EventStoreClient.client.link_to(stream_name_2, events, options: { expected_revision: :no_stream })
|
86
|
+
rescue EventStoreClient::WrongExpectedVersionError => e
|
87
|
+
puts e.message
|
88
|
+
end
|
95
89
|
```
|
96
90
|
|
97
91
|
There are three available stream states:
|
@@ -119,13 +113,13 @@ event2 = SomethingHappened.new(
|
|
119
113
|
EventStoreClient.client.append_to_stream(stream_name_1, event1)
|
120
114
|
EventStoreClient.client.append_to_stream(stream_name_2, event2)
|
121
115
|
# Load events from DB
|
122
|
-
event1 = EventStoreClient.client.read(stream_name_1).
|
123
|
-
event2 = EventStoreClient.client.read(stream_name_2).
|
116
|
+
event1 = EventStoreClient.client.read(stream_name_1).first
|
117
|
+
event2 = EventStoreClient.client.read(stream_name_2).first
|
124
118
|
# Get the revision number of latest event
|
125
|
-
revision = EventStoreClient.client.read(stream_name_2).
|
119
|
+
revision = EventStoreClient.client.read(stream_name_2).last.stream_revision
|
126
120
|
# Expected revision matches => will succeed
|
127
121
|
EventStoreClient.client.link_to(stream_name_2, event1, options: { expected_revision: revision })
|
128
|
-
# Will fail with revisions mismatch
|
122
|
+
# Will fail with EventStoreClient::WrongExpectedVersionError error due to revisions mismatch
|
129
123
|
EventStoreClient.client.link_to(stream_name_2, event2, options: { expected_revision: revision })
|
130
124
|
```
|
131
125
|
|
@@ -145,7 +139,7 @@ stream_name_1 = 'some-stream-1'
|
|
145
139
|
stream_name_2 = 'some-stream-2'
|
146
140
|
EventStoreClient.client.append_to_stream(stream_name_1, event)
|
147
141
|
# Get persisted event
|
148
|
-
event = EventStoreClient.client.read(stream_name_1).
|
142
|
+
event = EventStoreClient.client.read(stream_name_1).first
|
149
143
|
# Link event from first stream into second stream
|
150
|
-
|
144
|
+
EventStoreClient.client.link_to(stream_name_2, event, credentials: { username: 'admin', password: 'changeit' })
|
151
145
|
```
|