event_store_client 0.1.0 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d3deeba909c8bf46f05e7994ae5ebef841e622c17032f0259387871335f80e98
4
- data.tar.gz: 0bc3e13528fa696506b3d34ca2b00004a736f30bb62d379f41ef50e4a2b180ab
3
+ metadata.gz: 7d057f39fbb77d08d7c29b5f56e38e3aee78d6b39578e472afc736ad5bbd9576
4
+ data.tar.gz: 3fa3ce102d2f8f6866bef59760e76fe21038ded6b1f022e78c79918753d6911b
5
5
  SHA512:
6
- metadata.gz: 2606efc97b2695dc52d358a9c0bc967d0583c2b58b95b27289c6f9e4dbac04a87bb134dfc8a1e0b251ca11b08c5f0c28841c25f48fdbd4a33db2dd37a0369727
7
- data.tar.gz: f1b690148757d9f316127b272c03d70558fc53a8868dbf0058d7669bcdd702b92849d44002dd6eb2367982525fdf25299931d8c8563c5c7ed7d3527f24d9ddc3
6
+ metadata.gz: 91d278acb0560b2b1e5166a7ef0ecdbd398f9da524dd550edc496ddc41efeb260a056a43e6e4acde752e100321fef9d6120d2eeb50047072c428f374d504a309
7
+ data.tar.gz: f8e821b0ff1ca1f74bcc9252d31d83f84af2722c596651ca96e923ad701b13a2a97f7537fe57b86ac97a15790987bd762507b61eb707a8c70211e9ae11c54613
data/README.md CHANGED
@@ -50,29 +50,20 @@ Before you start, add this to the `initializer` or to the top of your script:
50
50
  To test out the behavior, you'll need a sample event and handler to work with:
51
51
 
52
52
  ```ruby
53
- # Sample Event using dry-struct (recommended)
54
- require 'dry-struct'
55
- class SomethingHappened < Dry::Struct
56
- attribute :data, EventStoreClient::Types::Strict::Hash
57
- attribute :metadata, EventStoreClient::Types::Strict::Hash
58
- end
59
-
60
- # Sample Event without types check (not recommended)
61
-
62
- class SomethingHappened < Dry::Struct
63
- attr_reader :data, :metadata
64
53
 
65
- private
54
+ require 'securerandom'
66
55
 
67
- def initialize(data: {}, metadata: {})
68
- @data = data
69
- @metadata = metadata
56
+ class SomethingHappened < EventStoreClient::DeserializedEvent
57
+ def schema
58
+ Dry::Schema.Params do
59
+ required(:user_id).value(:string)
60
+ required(:title).value(:string)
61
+ end
70
62
  end
71
63
  end
72
64
 
73
65
  event = SomethingHappened.new(
74
66
  data: { user_id: SecureRandom.uuid, title: "Something happened" },
75
- metadata: {}
76
67
  )
77
68
  ```
78
69
 
@@ -113,8 +104,6 @@ events = client.read('newstream', direction: 'backward') #default 'forward'
113
104
 
114
105
  ### Subscribing to events
115
106
 
116
- # Using automatic pooling
117
-
118
107
  ```ruby
119
108
  client.subscribe(DummyHandler, to: [SomethingHappened])
120
109
 
@@ -129,12 +118,25 @@ client.publish(stream: 'newstream', events: events)
129
118
  # .... wait a little bit ... Your handler should be called for every single event you publish
130
119
  ```
131
120
 
132
- ### Stop pooling
121
+ ### Stop polling for new events
122
+
123
+ ```ruby
124
+ client.stop_polling
125
+ ```
126
+
127
+ ### Linking existing events to the streem
128
+
129
+ Event to be linked properly has to coantians original event id.
130
+ Real events could be mixed with linked events in the same stream.
133
131
 
134
132
  ```ruby
135
- client.stop_pooling
133
+ exisiting_event1 = client.read('newstream').last
134
+ client.link_to(stream: 'anotherstream', events: [exisiting_event1, ...])
136
135
  ```
137
136
 
137
+ When you read from stream where links are placed. By default Event Store Client always resolve links for you returning the event that points to the link. You can use the ES-ResolveLinkTos: false HTTP header during readin stream to tell Event Store Client to return you the actual link and to not resolve it.
138
+ More info: [ES-ResolveLinkTos](https://eventstore.org/docs/http-api/optional-http-headers/resolve-linkto/index.html?tabs=tabid-1%2Ctabid-3).
139
+
138
140
  ## Contributing
139
141
 
140
142
  Do you want to contribute? Welcome!
@@ -1,11 +1,16 @@
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
4
8
  end
5
9
 
6
10
  require 'event_store_client/configuration'
7
11
  require 'event_store_client/types'
8
12
  require 'event_store_client/event'
13
+ require 'event_store_client/deserialized_event'
9
14
 
10
15
  require 'event_store_client/serializer/json'
11
16
 
@@ -10,55 +10,64 @@ module EventStoreClient
10
10
  connection.publish(stream: stream, events: events, expected_version: expected_version)
11
11
  end
12
12
 
13
- def read(stream, direction: 'forward')
14
- connection.read(stream, direction: direction)
13
+ def read(stream, direction: 'forward', start: 0, all: false)
14
+ connection.read(stream, direction: direction, start: start, all: all)
15
15
  end
16
16
 
17
- def subscribe(subscriber, to: [], pooling: true)
17
+ def subscribe(subscriber, to: [], polling: true)
18
18
  raise NoCallMethodOnSubscriber unless subscriber.respond_to?(:call)
19
19
  @subscriptions.create(subscriber, to)
20
- pool if pooling
20
+ poll if polling
21
21
  end
22
22
 
23
- def pool(interval: 5)
24
- return if @pooling_started
25
- @pooling_started = true
23
+ def poll(interval: 5)
24
+ return if @polling_started
25
+ @polling_started = true
26
26
  thread1 = Thread.new do
27
27
  loop do
28
28
  create_pid_file
29
- Thread.handle_interrupt(Interrupt => :never) {
30
- begin
31
- Thread.handle_interrupt(Interrupt => :immediate) {
29
+ Thread.handle_interrupt(Interrupt => :never) do
30
+ begin # rubocop:disable Style/RedundantBegin
31
+ Thread.handle_interrupt(Interrupt => :immediate) do
32
32
  broker.call(subscriptions)
33
- }
34
- rescue Exception => e
33
+ end
34
+ rescue Exception => e # rubocop:disable Lint/RescueException
35
35
  # When the thread had been interrupted or broker.call returned an error
36
36
  sleep(interval) # wait for events to be processed
37
37
  delete_pid_file
38
- error_handler.call(e) if error_handler
38
+ error_handler&.call(e)
39
39
  ensure
40
40
  # this code is run always
41
41
  Thread.stop
42
42
  end
43
- }
43
+ end
44
44
  end
45
45
  end
46
46
  thread2 = Thread.new do
47
- loop { sleep 1; break unless thread1.alive?; thread1.run }
47
+ loop do
48
+ sleep 1
49
+ break unless thread1.alive?
50
+ thread1.run
51
+ end
48
52
  end
49
53
  @threads = [thread1, thread2]
50
54
  nil
51
55
  end
52
56
 
53
- def stop_pooling
57
+ def stop_polling
54
58
  return if @threads.none?
55
- @threads.each do |thread|
56
- thread.kill
57
- end
58
- @pooling_started = false
59
+ @threads.each(&:kill)
60
+ @polling_started = false
59
61
  nil
60
62
  end
61
63
 
64
+ def link_to(stream:, events:)
65
+ raise ArgumentError if !stream || stream == ''
66
+ raise ArgumentError if events.nil? || (events.is_a?(Array) && events.empty?)
67
+
68
+ connection.link_to(stream, events)
69
+ end
70
+
62
71
  attr_accessor :connection, :service_name
63
72
 
64
73
  private
@@ -79,12 +88,12 @@ module EventStoreClient
79
88
  end
80
89
 
81
90
  def create_pid_file
82
- return unless File.exists?(config.pid_path)
83
- File.open(config.pid_path, 'w') { |file| file.write(SecureRandom.uuid) }
91
+ Dir.mkdir('tmp') unless File.exist?('tmp')
92
+ File.open(config.pid_path, 'w') { |file| file.write(Process.pid) }
84
93
  end
85
94
 
86
95
  def delete_pid_file
87
- File.delete(config.pid_path)
96
+ File.delete(config.pid_path) if File.exist?(config.pid_path)
88
97
  end
89
98
  end
90
99
  end
@@ -19,7 +19,7 @@ module EventStoreClient
19
19
  @host = 'http://localhost'
20
20
  @port = 2113
21
21
  @per_page = 20
22
- @pid_path = 'tmp/pool.pid'
22
+ @pid_path = 'tmp/poll.pid'
23
23
  @mapper = Mapper::Default.new
24
24
  @service_name = 'default'
25
25
  @error_handler = nil
@@ -10,19 +10,11 @@ module EventStoreClient
10
10
  serialized_events
11
11
  end
12
12
 
13
- def read(stream, direction: 'forward')
14
- response =
15
- client.read(stream, start: 0, direction: direction)
16
- return [] unless response.body&.present?
17
- JSON.parse(response.body)['entries'].map do |entry|
18
- event = EventStoreClient::Event.new(
19
- id: entry['eventId'],
20
- type: entry['eventType'],
21
- data: entry['data'],
22
- metadata: entry['metaData']
23
- )
24
- mapper.deserialize(event)
25
- end
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
+ )
26
18
  end
27
19
 
28
20
  def delete_stream(stream); end
@@ -51,6 +43,12 @@ module EventStoreClient
51
43
  events
52
44
  end
53
45
 
46
+ def link_to(stream, events)
47
+ client.link_to(stream, events)
48
+
49
+ true
50
+ end
51
+
54
52
  private
55
53
 
56
54
  attr_reader :host, :port, :mapper, :per_page
@@ -72,5 +70,51 @@ module EventStoreClient
72
70
  host: host, port: port, per_page: per_page
73
71
  )
74
72
  end
73
+
74
+ def read_from_stream(stream, direction:, start:, resolve_links:)
75
+ response =
76
+ client.read(
77
+ stream, start: start, direction: direction, resolve_links: resolve_links
78
+ )
79
+ return [] if response.body.nil? || response.body.empty?
80
+ JSON.parse(response.body)['entries'].map do |entry|
81
+ deserialize_event(entry)
82
+ end.reverse
83
+ end
84
+
85
+ def read_all_from_stream(stream, start:, resolve_links:)
86
+ count = per_page
87
+ events = []
88
+ failed_requests_count = 0
89
+
90
+ while failed_requests_count < 3
91
+ begin
92
+ response =
93
+ client.read(stream, start: start, direction: 'forward', resolve_links: resolve_links)
94
+ failed_requests_count += 1 && next unless response.success?
95
+ rescue Faraday::ConnectionFailed
96
+ failed_requests_count += 1
97
+ next
98
+ end
99
+ failed_requests_count = 0
100
+ break if response.body.nil? || response.body.empty?
101
+ entries = JSON.parse(response.body)['entries']
102
+ break if entries.empty?
103
+ events += entries.map { |entry| deserialize_event(entry) }.reverse
104
+ start += count
105
+ end
106
+ events
107
+ end
108
+
109
+ def deserialize_event(entry)
110
+ event = EventStoreClient::Event.new(
111
+ id: entry['eventId'],
112
+ title: entry['title'],
113
+ type: entry['eventType'],
114
+ data: entry['data'],
115
+ metadata: entry['metaData']
116
+ )
117
+ mapper.deserialize(event)
118
+ end
75
119
  end
76
120
  end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dry/schema'
4
+
5
+ module EventStoreClient
6
+ class DeserializedEvent
7
+ InvalidDataError = Class.new(StandardError)
8
+
9
+ attr_reader :id
10
+ attr_reader :type
11
+ attr_reader :title
12
+ attr_reader :data
13
+ attr_reader :metadata
14
+
15
+ def schema
16
+ Dry::Schema.Params do
17
+ end
18
+ end
19
+
20
+ def initialize(**args)
21
+ validation = schema.call(args[:data] || {})
22
+ raise InvalidDataError.new(message: validation.errors.to_h) if validation.errors.any?
23
+
24
+ @data = args.fetch(:data) { {} }
25
+ @metadata = args.fetch(:metadata) { {} }
26
+ @type = args[:type] || self.class.name
27
+ @title = args[:title]
28
+ @id = args[:id]
29
+ end
30
+ end
31
+ end
@@ -4,13 +4,11 @@ require 'dry-struct'
4
4
 
5
5
  module EventStoreClient
6
6
  class Endpoint < Dry::Struct
7
+ attribute :host, Types::String
8
+ attribute :port, Types::Coercible::Integer
9
+
7
10
  def url
8
11
  "#{host}:#{port}"
9
12
  end
10
-
11
- private
12
-
13
- attribute :host, Types::String
14
- attribute :port, Types::Coercible::Integer
15
13
  end
16
14
  end
@@ -8,16 +8,17 @@ module EventStoreClient
8
8
  class Event < Dry::Struct
9
9
  attr_reader :id
10
10
 
11
+ attribute :type, Types::Strict::String
12
+ attribute :title, Types::Strict::String.optional.default(nil)
11
13
  attribute :data, Types::Strict::String.default('{}')
12
14
  attribute :metadata, Types::Strict::String.default('{}')
13
- attribute :type, Types::Strict::String
14
15
 
15
16
  private
16
17
 
17
18
  def initialize(**args)
18
19
  @id = SecureRandom.uuid
19
- hash_meta =
20
- JSON.parse(args[:metadata] || '{}').merge(created_at: Time.now)
20
+ hash_meta = JSON.parse(args[:metadata] || '{}')
21
+ hash_meta['created_at'] ||= Time.now
21
22
  args[:metadata] = JSON.generate(hash_meta)
22
23
  super(args)
23
24
  end
@@ -5,9 +5,9 @@ module EventStoreClient
5
5
  class Default
6
6
  def serialize(event)
7
7
  Event.new(
8
- metadata: serializer.serialize(event.metadata),
8
+ type: event.class.to_s,
9
9
  data: serializer.serialize(event.data),
10
- type: event.class.to_s
10
+ metadata: serializer.serialize(event.metadata)
11
11
  )
12
12
  end
13
13
 
@@ -15,9 +15,19 @@ module EventStoreClient
15
15
  metadata = serializer.deserialize(event.metadata)
16
16
  data = serializer.deserialize(event.data)
17
17
 
18
- Object.const_get(event.type).new(
19
- metadata: metadata,
20
- data: data
18
+ event_class =
19
+ begin
20
+ Object.const_get(event.type)
21
+ rescue NameError
22
+ EventStoreClient::DeserializedEvent
23
+ end
24
+
25
+ event_class.new(
26
+ id: event.id,
27
+ type: event.type,
28
+ title: event.title,
29
+ data: data,
30
+ metadata: metadata
21
31
  )
22
32
  end
23
33
 
@@ -9,25 +9,30 @@ module EventStoreClient
9
9
  'ES-ExpectedVersion' => expected_version.to_s
10
10
  }.reject { |_key, val| val.empty? }
11
11
 
12
- data = [events].flatten.map do |event|
13
- {
14
- eventId: event.id,
15
- eventType: event.type,
16
- data: event.data,
17
- metadata: event.metadata
18
- }
19
- end
12
+ data = build_events_data(events)
20
13
 
21
14
  make_request(:post, "/streams/#{stream_name}", body: data, headers: headers)
22
15
  end
23
16
 
24
17
  def delete_stream(stream_name, hard_delete)
25
- headers = JSON_HEADERS.merge('ES-HardDelete' => hard_delete.to_s)
26
- make_request(:delete, "/streams/#{stream_name}", {}, headers)
18
+ headers = {
19
+ 'ES-HardDelete' => hard_delete.to_s
20
+ }.reject { |_key, val| val.empty? }
21
+
22
+ make_request(:delete, "/streams/#{stream_name}", body: {}, headers: headers)
27
23
  end
28
24
 
29
- def read(stream_name, direction: 'forward', start: 0, count: per_page)
30
- make_request(:get, "/streams/#{stream_name}/#{start}/#{direction}/#{count}")
25
+ def read(stream_name, direction: 'forward', start: 0, count: per_page, resolve_links: true)
26
+ headers = {
27
+ 'ES-ResolveLinkTos' => resolve_links.to_s,
28
+ 'Accept' => 'application/vnd.eventstore.atom+json'
29
+ }
30
+
31
+ make_request(
32
+ :get,
33
+ "/streams/#{stream_name}/#{start}/#{direction}/#{count}",
34
+ headers: headers
35
+ )
31
36
  end
32
37
 
33
38
  def subscribe_to_stream(
@@ -43,7 +48,7 @@ module EventStoreClient
43
48
  resolveLinkTos: true
44
49
  },
45
50
  headers: {
46
- "Content-Type" => "application/json"
51
+ 'Content-Type' => 'application/json'
47
52
  }
48
53
  )
49
54
  end
@@ -51,20 +56,29 @@ module EventStoreClient
51
56
  def consume_feed(
52
57
  stream_name,
53
58
  subscription_name,
54
- start: 0,
55
59
  count: 1,
56
- long_pool: 0
60
+ long_poll: 0
57
61
  )
58
- headers = long_pool > 0 ? { "ES-LongPoll" => "#{long_pool}" } : {}
62
+ headers = long_poll.positive? ? { 'ES-LongPoll' => long_poll.to_s } : {}
59
63
  headers['Content-Type'] = 'application/vnd.eventstore.competingatom+json'
60
64
  headers['Accept'] = 'application/vnd.eventstore.competingatom+json'
61
65
  make_request(
62
- :get,
66
+ :get,
63
67
  "/subscriptions/#{stream_name}/#{subscription_name}/#{count}",
64
68
  headers: headers
65
69
  )
66
70
  end
67
71
 
72
+ def link_to(stream_name, events)
73
+ data = build_linkig_data(events)
74
+
75
+ make_request(
76
+ :post,
77
+ "/streams/#{stream_name}",
78
+ body: data
79
+ )
80
+ end
81
+
68
82
  def ack(url)
69
83
  make_request(:post, url)
70
84
  end
@@ -78,6 +92,27 @@ module EventStoreClient
78
92
  @per_page = per_page
79
93
  end
80
94
 
95
+ def build_events_data(events)
96
+ [events].flatten.map do |event|
97
+ {
98
+ eventId: event.id,
99
+ eventType: event.type,
100
+ data: event.data,
101
+ metadata: event.metadata
102
+ }
103
+ end
104
+ end
105
+
106
+ def build_linkig_data(events)
107
+ [events].flatten.map do |event|
108
+ {
109
+ eventId: event.id,
110
+ eventType: '$>',
111
+ data: event.title,
112
+ }
113
+ end
114
+ end
115
+
81
116
  def make_request(method_name, path, body: {}, headers: {})
82
117
  method = RequestMethod.new(method_name)
83
118
  connection.send(method.to_s, path) do |req|
@@ -17,13 +17,13 @@ module EventStoreClient
17
17
 
18
18
  attr_reader :name
19
19
 
20
+ SUPPORTED_METHODS = %w[get post put delete].freeze
21
+
20
22
  def initialize(name)
21
- raise InvalidMethodError unless name.to_s.in?(SUPPORTED_METHODS)
23
+ raise InvalidMethodError unless SUPPORTED_METHODS.include?(name.to_s)
22
24
 
23
25
  @name = name.to_s
24
26
  end
25
-
26
- SUPPORTED_METHODS = %w[get post put].freeze
27
27
  end
28
28
  end
29
29
  end
@@ -3,9 +3,15 @@
3
3
  module EventStoreClient
4
4
  module StoreAdapter
5
5
  class InMemory
6
+ Response = Struct.new(:body, :status) do
7
+ def success?
8
+ status == 200
9
+ end
10
+ end
11
+
6
12
  attr_reader :event_store
7
13
 
8
- def append_to_stream(stream_name, events, expected_version: nil)
14
+ def append_to_stream(stream_name, events, expected_version: nil) # rubocop:disable Lint/UnusedMethodArgument,Metrics/LineLength
9
15
  event_store[stream_name] = [] unless event_store.key?(stream_name)
10
16
 
11
17
  [events].flatten.each do |event|
@@ -13,61 +19,77 @@ module EventStoreClient
13
19
  'eventId' => event.id,
14
20
  'data' => event.data,
15
21
  'eventType' => event.type,
16
- 'metadata' => event.metadata,
22
+ 'metaData' => event.metadata,
17
23
  'positionEventNumber' => event_store[stream_name].length
18
24
  )
19
25
  end
20
26
  end
21
27
 
22
- def delete_stream(stream_name, hard_delete: false)
28
+ def read(stream_name, direction: 'forward', start: 0, resolve_links: nil)
29
+ response =
30
+ if direction == 'forward'
31
+ read_stream_forward(stream_name, start: start)
32
+ else
33
+ read_stream_backward(stream_name, start: start)
34
+ end
35
+
36
+ Response.new(response.to_json, 200)
37
+ end
38
+
39
+ def delete_stream(stream_name, hard_delete: false) # rubocop:disable Lint/UnusedMethodArgument
23
40
  event_store.delete(stream_name)
24
41
  end
25
42
 
26
- def read_stream_backward(stream_name, start: 0, count: per_page)
43
+ def link_to(stream_name, events)
44
+ append_to_stream(stream_name, events)
45
+ end
46
+
47
+ private
48
+
49
+ attr_reader :endpoint, :per_page
50
+
51
+ def initialize(host:, port:, per_page: 20)
52
+ @endpoint = Endpoint.new(host: host, port: port)
53
+ @per_page = per_page
54
+ @event_store = {}
55
+ end
56
+
57
+ def read_stream_backward(stream_name, start: 0)
27
58
  return [] unless event_store.key?(stream_name)
28
59
 
29
- start = start == 0 ? event_store[stream_name].length - 1 : start
30
- last_index = start - count
60
+ start = start == 'head' ? event_store[stream_name].length - 1 : start
61
+ last_index = start - per_page
31
62
  entries = event_store[stream_name].select do |event|
32
63
  event['positionEventNumber'] > last_index &&
33
64
  event['positionEventNumber'] <= start
34
65
  end
35
66
  {
36
67
  'entries' => entries,
37
- 'links' => links(stream_name, last_index, 'next', entries, count)
68
+ 'links' => links(stream_name, last_index, 'next', entries, per_page)
38
69
  }
39
70
  end
40
71
 
41
- def read_stream_forward(stream_name, start: 0, count: per_page)
72
+ def read_stream_forward(stream_name, start: 0)
42
73
  return [] unless event_store.key?(stream_name)
43
74
 
44
- last_index = start + count
45
- entries = event_store[stream_name].reverse.select do |event|
75
+ last_index = start + per_page
76
+ entries = event_store[stream_name].select do |event|
46
77
  event['positionEventNumber'] < last_index &&
47
78
  event['positionEventNumber'] >= start
48
79
  end
49
80
  {
50
81
  'entries' => entries,
51
- 'links' => links(stream_name, last_index, 'previous', entries, count)
82
+ 'links' => links(stream_name, last_index, 'previous', entries, per_page)
52
83
  }
53
84
  end
54
85
 
55
- private
56
-
57
- attr_reader :endpoint, :per_page
58
-
59
- def initialize(host:, port:, per_page: 20)
60
- @endpoint = Endpoint.new(host: host, port: port)
61
- @per_page = per_page
62
- @event_store = {}
63
- end
64
-
65
86
  def links(stream_name, batch_size, direction, entries, count)
66
- if entries.empty? || batch_size < 0
87
+ if entries.empty? || batch_size.negative?
67
88
  []
68
89
  else
69
90
  [{
70
- 'uri' => "http://#{endpoint.url}/streams/#{stream_name}/#{batch_size}/#{direction}/#{count}",
91
+ 'uri' =>
92
+ "http://#{endpoint.url}/streams/#{stream_name}/#{batch_size}/#{direction}/#{count}",
71
93
  'relation' => direction
72
94
  }]
73
95
  end
@@ -6,6 +6,7 @@ module EventStoreClient
6
6
  attr_reader :stream, :name
7
7
 
8
8
  private
9
+
9
10
  def initialize(type:, name:)
10
11
  @name = name
11
12
  @subscribers = []
@@ -4,6 +4,12 @@ require 'dry-types'
4
4
 
5
5
  module EventStoreClient
6
6
  module Types
7
+ UUID_REGEXP = /\A[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}\z/i
8
+
7
9
  include Dry.Types()
10
+
11
+ UUID = Types::Strict::String.constrained(
12
+ format: UUID_REGEXP
13
+ )
8
14
  end
9
15
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module EventStoreClient
4
- VERSION = '0.1.0'
4
+ VERSION = '0.1.5'
5
5
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: event_store_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sebastian Wilgosz
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-12-02 00:00:00.000000000 Z
11
+ date: 2020-02-19 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: dry-schema
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 1.4.1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 1.4.1
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: dry-struct
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -66,6 +80,20 @@ dependencies:
66
80
  - - ">="
67
81
  - !ruby/object:Gem::Version
68
82
  version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: webmock
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
69
97
  description: Easy to use client for event-sources applications written in ruby
70
98
  email:
71
99
  - sebastian@driggl.com
@@ -81,6 +109,7 @@ files:
81
109
  - lib/event_store_client/client.rb
82
110
  - lib/event_store_client/configuration.rb
83
111
  - lib/event_store_client/connection.rb
112
+ - lib/event_store_client/deserialized_event.rb
84
113
  - lib/event_store_client/endpoint.rb
85
114
  - lib/event_store_client/event.rb
86
115
  - lib/event_store_client/mapper.rb
@@ -115,7 +144,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
115
144
  - !ruby/object:Gem::Version
116
145
  version: '0'
117
146
  requirements: []
118
- rubygems_version: 3.0.4
147
+ rubygems_version: 3.0.6
119
148
  signing_key:
120
149
  specification_version: 4
121
150
  summary: Ruby integration for https://eventstore.org