ruby_event_store 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.travis.yml +9 -0
- data/Gemfile +4 -0
- data/README.md +1 -0
- data/Rakefile +2 -0
- data/lib/ruby_event_store.rb +11 -0
- data/lib/ruby_event_store/actions/append_event_to_stream.rb +33 -0
- data/lib/ruby_event_store/actions/delete_stream_events.rb +23 -0
- data/lib/ruby_event_store/actions/read_all_events.rb +22 -0
- data/lib/ruby_event_store/actions/read_all_streams.rb +21 -0
- data/lib/ruby_event_store/actions/read_events_batch.rb +29 -0
- data/lib/ruby_event_store/constants.rb +3 -0
- data/lib/ruby_event_store/errors.rb +7 -0
- data/lib/ruby_event_store/event.rb +37 -0
- data/lib/ruby_event_store/facade.rb +64 -0
- data/lib/ruby_event_store/pub_sub/broker.rb +45 -0
- data/lib/ruby_event_store/version.rb +3 -0
- data/ruby_event_store.gemspec +27 -0
- metadata +145 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b20c0b1993fd1f71772a7963b630a711184bdfe2
|
4
|
+
data.tar.gz: 76fbda0433d8411362b2bb7a9352bb2771662928
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 32aa8a98da6beb67d3c8e7814eb27d7460672db707ee71a5e85392e63a237ac149da7785692211b01ce66a84a78d3f562193c0bba7b842092ee4f9b65deed6f6
|
7
|
+
data.tar.gz: d29d1fc35b3fd86c1951aae3639bf946c59353d5646e2fe98945077aa101662cf171e0f2d665d24230ee758a04d9e05fd7f2a73d73c169b8ce62395c229cfce9
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
- 2.1.5
|
4
|
+
before_install: gem install bundler
|
5
|
+
gemfile: Gemfile
|
6
|
+
script: bundle exec mutant --include lib --require ruby_event_store --use rspec "RubyEventStore*"
|
7
|
+
notifications:
|
8
|
+
slack:
|
9
|
+
secure: qCcGv1MmryEhPoHzTvZvgSv21UcC7j2Cfq0b0hmQWuYHrHN+jhqjhg7PuElNyr0mk6N1acIcVqOAWpS20ZkG/mipW2RBBXVEc9zVR10pvJnlKDmGKd4Vmj394VgIknn8ciruglw1LoJManf1bV7/Wm4ITMt3zCQqTMGclRUqA0l/dzK2z9zU35cT4v38nTGnoGVrPQx29FvpU3J/h9qC6kGllw3Bkic2nmpFABYOI49LQFF3/vdrbnK3Zo1rudHMV0lNoPg5Ntrbd6XHXUKrBGBcZmGSh3wW/mfYf9Tcft+5MwtCu4b70KnFknx7oFmBlU8JFYg2x5f1xNSIoRkDmLI5/jNDWJ3oLAtYjgY5CdBMlxnhhfnCBmbaxEJhTuscm2sIp+S+4+ggm8x/daIK3BUaBAV5BT8An52BXhQ/F6cdnYiSVn+5lGap/1wF2TWwnN/oVc+JVfATouG9FCygzMekUaji94JMKBtS+QgoLdAE5ufEGBeDONJELRD8Lca1R4uWSg2snf93GWoONca9aJfkIfXj3m+VaoAM9Bq9DGcOXwZESkltE2E+31Fznh5qYCRH1zgtgB0Hx8x7sdaxNQyybvgNS1R0lGnIU/NrUmREcUi5BYEI5YqygBtkTZ7F/nlYQgydKjjHJ6FG3oLc3ggxffE8oAdpuxvlUQ8ZN6o=
|
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
# ruby_event_store
|
data/Rakefile
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'ruby_event_store/actions/append_event_to_stream'
|
2
|
+
require 'ruby_event_store/actions/read_all_events'
|
3
|
+
require 'ruby_event_store/actions/read_events_batch'
|
4
|
+
require 'ruby_event_store/actions/delete_stream_events'
|
5
|
+
require 'ruby_event_store/actions/read_all_streams'
|
6
|
+
require 'ruby_event_store/pub_sub/broker'
|
7
|
+
require 'ruby_event_store/errors'
|
8
|
+
require 'ruby_event_store/constants'
|
9
|
+
require 'ruby_event_store/facade'
|
10
|
+
require 'ruby_event_store/event'
|
11
|
+
require 'ruby_event_store/version'
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module RubyEventStore
|
2
|
+
module Actions
|
3
|
+
class AppendEventToStream
|
4
|
+
|
5
|
+
def initialize(repository)
|
6
|
+
@repository = repository
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(stream_name, event, expected_version)
|
10
|
+
raise WrongExpectedEventVersion if version_incorrect?(stream_name, expected_version)
|
11
|
+
save_event(event, stream_name)
|
12
|
+
event
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
attr_reader :repository
|
17
|
+
|
18
|
+
def version_incorrect?(stream_name, expected_version)
|
19
|
+
unless expected_version.nil?
|
20
|
+
find_last_event_version(stream_name) != expected_version
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def find_last_event_version(stream_name)
|
25
|
+
repository.last_stream_event(stream_name).event_id
|
26
|
+
end
|
27
|
+
|
28
|
+
def save_event(event, stream_name)
|
29
|
+
repository.create(event.to_h.merge!(stream: stream_name))
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module RubyEventStore
|
2
|
+
module Actions
|
3
|
+
class DeleteStreamEvents
|
4
|
+
|
5
|
+
def initialize(repository)
|
6
|
+
@repository = repository
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(stream_name)
|
10
|
+
raise IncorrectStreamData if stream_name.nil? || stream_name.empty?
|
11
|
+
delete_stream(stream_name)
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
attr_reader :repository
|
16
|
+
|
17
|
+
def delete_stream(stream_name)
|
18
|
+
repository.delete({stream: stream_name})
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module RubyEventStore
|
2
|
+
module Actions
|
3
|
+
class ReadAllEvents
|
4
|
+
|
5
|
+
def initialize(repository)
|
6
|
+
@repository = repository
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(stream_name)
|
10
|
+
raise IncorrectStreamData if stream_name.nil? || stream_name.empty?
|
11
|
+
get_all_events(stream_name)
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
attr_reader :repository
|
16
|
+
|
17
|
+
def get_all_events(stream_name)
|
18
|
+
repository.load_all_events_forward(stream_name)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module RubyEventStore
|
2
|
+
module Actions
|
3
|
+
class ReadAllStreams
|
4
|
+
|
5
|
+
def initialize(repository)
|
6
|
+
@repository = repository
|
7
|
+
end
|
8
|
+
|
9
|
+
def call
|
10
|
+
get_all_events.group_by { |event| event.stream }
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
attr_reader :repository
|
15
|
+
|
16
|
+
def get_all_events
|
17
|
+
repository.get_all_events
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module RubyEventStore
|
2
|
+
module Actions
|
3
|
+
class ReadEventsBatch
|
4
|
+
|
5
|
+
def initialize(repository)
|
6
|
+
@repository = repository
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(stream_name, start, count)
|
10
|
+
raise IncorrectStreamData if stream_name.nil? || stream_name.empty?
|
11
|
+
event = find_event(start)
|
12
|
+
get_events_batch(stream_name, event.id, count)
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
attr_reader :repository
|
17
|
+
|
18
|
+
def get_events_batch(stream_name, start, count)
|
19
|
+
repository.load_events_batch(stream_name, start, count)
|
20
|
+
end
|
21
|
+
|
22
|
+
def find_event(start)
|
23
|
+
event = repository.find({event_id: start})
|
24
|
+
raise EventNotFound if event.nil?
|
25
|
+
event
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
module RubyEventStore
|
2
|
+
WrongExpectedEventVersion = Class.new(StandardError)
|
3
|
+
IncorrectStreamData = Class.new(StandardError)
|
4
|
+
EventNotFound = Class.new(StandardError)
|
5
|
+
SubscriberNotExist = Class.new(StandardError)
|
6
|
+
MethodNotDefined = Class.new(StandardError)
|
7
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
|
3
|
+
module RubyEventStore
|
4
|
+
class Event
|
5
|
+
|
6
|
+
def initialize(event_data={})
|
7
|
+
@event_type = event_data.fetch(:event_type, event_name)
|
8
|
+
@event_id = event_data.fetch(:event_id, generate_id).to_s
|
9
|
+
@metadata = event_data.fetch(:metadata, {})
|
10
|
+
@data = event_data.fetch(:data, {})
|
11
|
+
end
|
12
|
+
attr_reader :event_type, :event_id, :metadata, :data
|
13
|
+
|
14
|
+
def to_h
|
15
|
+
{
|
16
|
+
event_type: event_type,
|
17
|
+
event_id: event_id,
|
18
|
+
metadata: metadata.merge!(publish_time),
|
19
|
+
data: data
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def publish_time
|
26
|
+
{ published_at: Time.now.utc }
|
27
|
+
end
|
28
|
+
|
29
|
+
def generate_id
|
30
|
+
SecureRandom.uuid
|
31
|
+
end
|
32
|
+
|
33
|
+
def event_name
|
34
|
+
self.class.name
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module RubyEventStore
|
2
|
+
class Facade
|
3
|
+
|
4
|
+
def initialize(repository)
|
5
|
+
@repository = repository
|
6
|
+
end
|
7
|
+
attr_reader :repository
|
8
|
+
|
9
|
+
def publish_event(event_data, stream_name = GLOBAL_STREAM, expected_version = nil)
|
10
|
+
append_event_to_stream(event_data, stream_name, expected_version)
|
11
|
+
end
|
12
|
+
|
13
|
+
def delete_stream(stream_name)
|
14
|
+
delete_stream_events(stream_name)
|
15
|
+
end
|
16
|
+
|
17
|
+
def read_events(stream_name, start, count)
|
18
|
+
read_events_batch(stream_name, start, count)
|
19
|
+
end
|
20
|
+
|
21
|
+
def read_all_events(stream_name)
|
22
|
+
read_all_stream_events(stream_name)
|
23
|
+
end
|
24
|
+
|
25
|
+
def read_all_streams
|
26
|
+
read_all_events_from_store
|
27
|
+
end
|
28
|
+
|
29
|
+
def subscribe(subscriber, event_types)
|
30
|
+
event_broker.add_subscriber(subscriber, event_types)
|
31
|
+
end
|
32
|
+
|
33
|
+
def subscribe_to_all_events(subscriber)
|
34
|
+
event_broker.add_global_subscriber(subscriber)
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def append_event_to_stream(event_data, stream_name, expected_version)
|
40
|
+
event = Actions::AppendEventToStream.new(repository).call(stream_name, event_data, expected_version)
|
41
|
+
event_broker.notify_subscribers(event)
|
42
|
+
end
|
43
|
+
|
44
|
+
def delete_stream_events(stream_name)
|
45
|
+
Actions::DeleteStreamEvents.new(repository).call(stream_name)
|
46
|
+
end
|
47
|
+
|
48
|
+
def read_events_batch(stream_name, start, count)
|
49
|
+
Actions::ReadEventsBatch.new(repository).call(stream_name, start, count)
|
50
|
+
end
|
51
|
+
|
52
|
+
def read_all_stream_events(stream_name)
|
53
|
+
Actions::ReadAllEvents.new(repository).call(stream_name)
|
54
|
+
end
|
55
|
+
|
56
|
+
def read_all_events_from_store
|
57
|
+
Actions::ReadAllStreams.new(repository).call
|
58
|
+
end
|
59
|
+
|
60
|
+
def event_broker
|
61
|
+
@event_broker ||= PubSub::Broker.new
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module RubyEventStore
|
2
|
+
module PubSub
|
3
|
+
class Broker
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@subscribers = Hash.new {|hsh, key| hsh[key] = [] }
|
7
|
+
@global_subscribers = []
|
8
|
+
end
|
9
|
+
|
10
|
+
def add_subscriber(subscriber, event_types)
|
11
|
+
verify_subscriber(subscriber)
|
12
|
+
subscribe(subscriber, event_types)
|
13
|
+
end
|
14
|
+
|
15
|
+
def add_global_subscriber(subscriber)
|
16
|
+
verify_subscriber(subscriber)
|
17
|
+
@global_subscribers << subscriber
|
18
|
+
end
|
19
|
+
|
20
|
+
def notify_subscribers(event)
|
21
|
+
all_subscribers_for(event.event_type).each do |subscriber|
|
22
|
+
subscriber.handle_event(event)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
attr_reader :subscribers
|
28
|
+
|
29
|
+
def verify_subscriber(subscriber)
|
30
|
+
raise SubscriberNotExist if subscriber.nil?
|
31
|
+
raise MethodNotDefined unless subscriber.methods.include? :handle_event
|
32
|
+
end
|
33
|
+
|
34
|
+
def subscribe(subscriber, event_types)
|
35
|
+
event_types.each do |type|
|
36
|
+
subscribers[type] << subscriber
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def all_subscribers_for(event_type)
|
41
|
+
subscribers[event_type] + @global_subscribers
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'ruby_event_store/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "ruby_event_store"
|
8
|
+
spec.version = RubyEventStore::VERSION
|
9
|
+
spec.authors = ["rybex"]
|
10
|
+
spec.email = ["tomek.rybka@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{Implementation of Event Store in Ruby}
|
13
|
+
spec.description = %q{Implementation of Event Store in Ruby}
|
14
|
+
spec.homepage = ''
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
17
|
+
spec.bindir = "exe"
|
18
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.8"
|
22
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
23
|
+
spec.add_development_dependency 'rspec'
|
24
|
+
spec.add_development_dependency 'pry'
|
25
|
+
spec.add_development_dependency 'mutant', '~> 0.7.8'
|
26
|
+
spec.add_development_dependency 'mutant-rspec', '~> 0.7.8'
|
27
|
+
end
|
metadata
ADDED
@@ -0,0 +1,145 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ruby_event_store
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- rybex
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-05-26 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.8'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.8'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: pry
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: mutant
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 0.7.8
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 0.7.8
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: mutant-rspec
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 0.7.8
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 0.7.8
|
97
|
+
description: Implementation of Event Store in Ruby
|
98
|
+
email:
|
99
|
+
- tomek.rybka@gmail.com
|
100
|
+
executables: []
|
101
|
+
extensions: []
|
102
|
+
extra_rdoc_files: []
|
103
|
+
files:
|
104
|
+
- ".gitignore"
|
105
|
+
- ".travis.yml"
|
106
|
+
- Gemfile
|
107
|
+
- README.md
|
108
|
+
- Rakefile
|
109
|
+
- lib/ruby_event_store.rb
|
110
|
+
- lib/ruby_event_store/actions/append_event_to_stream.rb
|
111
|
+
- lib/ruby_event_store/actions/delete_stream_events.rb
|
112
|
+
- lib/ruby_event_store/actions/read_all_events.rb
|
113
|
+
- lib/ruby_event_store/actions/read_all_streams.rb
|
114
|
+
- lib/ruby_event_store/actions/read_events_batch.rb
|
115
|
+
- lib/ruby_event_store/constants.rb
|
116
|
+
- lib/ruby_event_store/errors.rb
|
117
|
+
- lib/ruby_event_store/event.rb
|
118
|
+
- lib/ruby_event_store/facade.rb
|
119
|
+
- lib/ruby_event_store/pub_sub/broker.rb
|
120
|
+
- lib/ruby_event_store/version.rb
|
121
|
+
- ruby_event_store.gemspec
|
122
|
+
homepage: ''
|
123
|
+
licenses: []
|
124
|
+
metadata: {}
|
125
|
+
post_install_message:
|
126
|
+
rdoc_options: []
|
127
|
+
require_paths:
|
128
|
+
- lib
|
129
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
130
|
+
requirements:
|
131
|
+
- - ">="
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '0'
|
134
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
requirements: []
|
140
|
+
rubyforge_project:
|
141
|
+
rubygems_version: 2.4.3
|
142
|
+
signing_key:
|
143
|
+
specification_version: 4
|
144
|
+
summary: Implementation of Event Store in Ruby
|
145
|
+
test_files: []
|