evey 0.1.0 → 0.2.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 +4 -4
- data/.gitignore +2 -0
- data/CITATIONS.txt +22 -0
- data/Gemfile.lock +221 -0
- data/LICENSE.txt +1 -1
- data/README.md +3 -5
- data/evey.gemspec +15 -0
- data/lib/evey.rb +21 -4
- data/lib/evey/dispatcher.rb +96 -0
- data/lib/evey/event.rb +151 -0
- data/lib/evey/event_serializer.rb +10 -0
- data/lib/evey/reactor.rb +14 -0
- data/lib/evey/reactor_job.rb +7 -0
- data/lib/evey/types.rb +2 -0
- data/lib/evey/types/association.rb +31 -0
- data/lib/evey/version.rb +1 -1
- data/lib/generators/evey/install_generator.rb +10 -0
- data/lib/generators/evey/migration.erb +16 -0
- metadata +185 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ea6cdb42a613f053cf4f4d08b8ecbd8c0648f72d69ea70054a8f5f7072c0c1f9
|
|
4
|
+
data.tar.gz: 3e07e0a600b608e2568050d46415b8713657637e768665a0c35ce7a46280389e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fd266ca53d16aa50fa25fbba1333c350619f1b1d40aeb9de3491686227e7a271f2c082ae2db259dfb8b6abe92b631cb942c41f736ff82f46a8774ee0dc5e1acb
|
|
7
|
+
data.tar.gz: '008745e3ac4fb77c091d9d6d55a5258fc786d9a9c89c9a795a0abc2f27c32338d9d27a645f1499ebcda4433392f38e0219fc7c258c0a10ce5006f02e92c64cce'
|
data/.gitignore
CHANGED
data/CITATIONS.txt
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
https://github.com/kickstarter/event-sourcing-rails-todo-app-demo
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2017 Kickstarter, PBC
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
+
a copy of this software and associated documentation files (the
|
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
11
|
+
the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be
|
|
14
|
+
included in all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
evey (0.1.0)
|
|
5
|
+
activejob
|
|
6
|
+
activerecord
|
|
7
|
+
activesupport
|
|
8
|
+
kix
|
|
9
|
+
|
|
10
|
+
GEM
|
|
11
|
+
remote: https://rubygems.org/
|
|
12
|
+
specs:
|
|
13
|
+
actioncable (6.1.3.1)
|
|
14
|
+
actionpack (= 6.1.3.1)
|
|
15
|
+
activesupport (= 6.1.3.1)
|
|
16
|
+
nio4r (~> 2.0)
|
|
17
|
+
websocket-driver (>= 0.6.1)
|
|
18
|
+
actionmailbox (6.1.3.1)
|
|
19
|
+
actionpack (= 6.1.3.1)
|
|
20
|
+
activejob (= 6.1.3.1)
|
|
21
|
+
activerecord (= 6.1.3.1)
|
|
22
|
+
activestorage (= 6.1.3.1)
|
|
23
|
+
activesupport (= 6.1.3.1)
|
|
24
|
+
mail (>= 2.7.1)
|
|
25
|
+
actionmailer (6.1.3.1)
|
|
26
|
+
actionpack (= 6.1.3.1)
|
|
27
|
+
actionview (= 6.1.3.1)
|
|
28
|
+
activejob (= 6.1.3.1)
|
|
29
|
+
activesupport (= 6.1.3.1)
|
|
30
|
+
mail (~> 2.5, >= 2.5.4)
|
|
31
|
+
rails-dom-testing (~> 2.0)
|
|
32
|
+
actionpack (6.1.3.1)
|
|
33
|
+
actionview (= 6.1.3.1)
|
|
34
|
+
activesupport (= 6.1.3.1)
|
|
35
|
+
rack (~> 2.0, >= 2.0.9)
|
|
36
|
+
rack-test (>= 0.6.3)
|
|
37
|
+
rails-dom-testing (~> 2.0)
|
|
38
|
+
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
|
39
|
+
actiontext (6.1.3.1)
|
|
40
|
+
actionpack (= 6.1.3.1)
|
|
41
|
+
activerecord (= 6.1.3.1)
|
|
42
|
+
activestorage (= 6.1.3.1)
|
|
43
|
+
activesupport (= 6.1.3.1)
|
|
44
|
+
nokogiri (>= 1.8.5)
|
|
45
|
+
actionview (6.1.3.1)
|
|
46
|
+
activesupport (= 6.1.3.1)
|
|
47
|
+
builder (~> 3.1)
|
|
48
|
+
erubi (~> 1.4)
|
|
49
|
+
rails-dom-testing (~> 2.0)
|
|
50
|
+
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
|
51
|
+
activejob (6.1.3.1)
|
|
52
|
+
activesupport (= 6.1.3.1)
|
|
53
|
+
globalid (>= 0.3.6)
|
|
54
|
+
activemodel (6.1.3.1)
|
|
55
|
+
activesupport (= 6.1.3.1)
|
|
56
|
+
activerecord (6.1.3.1)
|
|
57
|
+
activemodel (= 6.1.3.1)
|
|
58
|
+
activesupport (= 6.1.3.1)
|
|
59
|
+
activestorage (6.1.3.1)
|
|
60
|
+
actionpack (= 6.1.3.1)
|
|
61
|
+
activejob (= 6.1.3.1)
|
|
62
|
+
activerecord (= 6.1.3.1)
|
|
63
|
+
activesupport (= 6.1.3.1)
|
|
64
|
+
marcel (~> 1.0.0)
|
|
65
|
+
mini_mime (~> 1.0.2)
|
|
66
|
+
activesupport (6.1.3.1)
|
|
67
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
|
68
|
+
i18n (>= 1.6, < 2)
|
|
69
|
+
minitest (>= 5.1)
|
|
70
|
+
tzinfo (~> 2.0)
|
|
71
|
+
zeitwerk (~> 2.3)
|
|
72
|
+
ast (2.4.2)
|
|
73
|
+
builder (3.2.4)
|
|
74
|
+
coderay (1.1.3)
|
|
75
|
+
concurrent-ruby (1.1.8)
|
|
76
|
+
crass (1.0.6)
|
|
77
|
+
diff-lcs (1.4.4)
|
|
78
|
+
docile (1.3.5)
|
|
79
|
+
erubi (1.10.0)
|
|
80
|
+
factory_bot (6.1.0)
|
|
81
|
+
activesupport (>= 5.0.0)
|
|
82
|
+
factory_bot_rails (6.1.0)
|
|
83
|
+
factory_bot (~> 6.1.0)
|
|
84
|
+
railties (>= 5.0.0)
|
|
85
|
+
globalid (0.4.2)
|
|
86
|
+
activesupport (>= 4.2.0)
|
|
87
|
+
i18n (1.8.10)
|
|
88
|
+
concurrent-ruby (~> 1.0)
|
|
89
|
+
kix (1.0.0)
|
|
90
|
+
activesupport
|
|
91
|
+
loofah (2.9.1)
|
|
92
|
+
crass (~> 1.0.2)
|
|
93
|
+
nokogiri (>= 1.5.9)
|
|
94
|
+
mail (2.7.1)
|
|
95
|
+
mini_mime (>= 0.1.1)
|
|
96
|
+
marcel (1.0.1)
|
|
97
|
+
method_source (1.0.0)
|
|
98
|
+
mini_mime (1.0.3)
|
|
99
|
+
minitest (5.14.4)
|
|
100
|
+
nio4r (2.5.7)
|
|
101
|
+
nokogiri (1.11.3-x86_64-linux)
|
|
102
|
+
racc (~> 1.4)
|
|
103
|
+
parallel (1.20.1)
|
|
104
|
+
parser (3.0.1.0)
|
|
105
|
+
ast (~> 2.4.1)
|
|
106
|
+
pg (1.2.3)
|
|
107
|
+
pry (0.14.1)
|
|
108
|
+
coderay (~> 1.1)
|
|
109
|
+
method_source (~> 1.0)
|
|
110
|
+
racc (1.5.2)
|
|
111
|
+
rack (2.2.3)
|
|
112
|
+
rack-test (1.1.0)
|
|
113
|
+
rack (>= 1.0, < 3)
|
|
114
|
+
rails (6.1.3.1)
|
|
115
|
+
actioncable (= 6.1.3.1)
|
|
116
|
+
actionmailbox (= 6.1.3.1)
|
|
117
|
+
actionmailer (= 6.1.3.1)
|
|
118
|
+
actionpack (= 6.1.3.1)
|
|
119
|
+
actiontext (= 6.1.3.1)
|
|
120
|
+
actionview (= 6.1.3.1)
|
|
121
|
+
activejob (= 6.1.3.1)
|
|
122
|
+
activemodel (= 6.1.3.1)
|
|
123
|
+
activerecord (= 6.1.3.1)
|
|
124
|
+
activestorage (= 6.1.3.1)
|
|
125
|
+
activesupport (= 6.1.3.1)
|
|
126
|
+
bundler (>= 1.15.0)
|
|
127
|
+
railties (= 6.1.3.1)
|
|
128
|
+
sprockets-rails (>= 2.0.0)
|
|
129
|
+
rails-dom-testing (2.0.3)
|
|
130
|
+
activesupport (>= 4.2.0)
|
|
131
|
+
nokogiri (>= 1.6)
|
|
132
|
+
rails-html-sanitizer (1.3.0)
|
|
133
|
+
loofah (~> 2.3)
|
|
134
|
+
railties (6.1.3.1)
|
|
135
|
+
actionpack (= 6.1.3.1)
|
|
136
|
+
activesupport (= 6.1.3.1)
|
|
137
|
+
method_source
|
|
138
|
+
rake (>= 0.8.7)
|
|
139
|
+
thor (~> 1.0)
|
|
140
|
+
rainbow (3.0.0)
|
|
141
|
+
rake (12.3.3)
|
|
142
|
+
regexp_parser (2.1.1)
|
|
143
|
+
rexml (3.2.5)
|
|
144
|
+
rspec (3.10.0)
|
|
145
|
+
rspec-core (~> 3.10.0)
|
|
146
|
+
rspec-expectations (~> 3.10.0)
|
|
147
|
+
rspec-mocks (~> 3.10.0)
|
|
148
|
+
rspec-core (3.10.1)
|
|
149
|
+
rspec-support (~> 3.10.0)
|
|
150
|
+
rspec-expectations (3.10.1)
|
|
151
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
152
|
+
rspec-support (~> 3.10.0)
|
|
153
|
+
rspec-mocks (3.10.2)
|
|
154
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
155
|
+
rspec-support (~> 3.10.0)
|
|
156
|
+
rspec-rails (5.0.1)
|
|
157
|
+
actionpack (>= 5.2)
|
|
158
|
+
activesupport (>= 5.2)
|
|
159
|
+
railties (>= 5.2)
|
|
160
|
+
rspec-core (~> 3.10)
|
|
161
|
+
rspec-expectations (~> 3.10)
|
|
162
|
+
rspec-mocks (~> 3.10)
|
|
163
|
+
rspec-support (~> 3.10)
|
|
164
|
+
rspec-support (3.10.2)
|
|
165
|
+
rubocop (1.12.1)
|
|
166
|
+
parallel (~> 1.10)
|
|
167
|
+
parser (>= 3.0.0.0)
|
|
168
|
+
rainbow (>= 2.2.2, < 4.0)
|
|
169
|
+
regexp_parser (>= 1.8, < 3.0)
|
|
170
|
+
rexml
|
|
171
|
+
rubocop-ast (>= 1.2.0, < 2.0)
|
|
172
|
+
ruby-progressbar (~> 1.7)
|
|
173
|
+
unicode-display_width (>= 1.4.0, < 3.0)
|
|
174
|
+
rubocop-ast (1.4.1)
|
|
175
|
+
parser (>= 2.7.1.5)
|
|
176
|
+
rubocop-performance (1.10.1)
|
|
177
|
+
rubocop (>= 0.90.0, < 2.0)
|
|
178
|
+
rubocop-ast (>= 0.4.0)
|
|
179
|
+
ruby-progressbar (1.11.0)
|
|
180
|
+
simplecov (0.21.2)
|
|
181
|
+
docile (~> 1.1)
|
|
182
|
+
simplecov-html (~> 0.11)
|
|
183
|
+
simplecov_json_formatter (~> 0.1)
|
|
184
|
+
simplecov-html (0.12.3)
|
|
185
|
+
simplecov_json_formatter (0.1.2)
|
|
186
|
+
sprockets (4.0.2)
|
|
187
|
+
concurrent-ruby (~> 1.0)
|
|
188
|
+
rack (> 1, < 3)
|
|
189
|
+
sprockets-rails (3.2.2)
|
|
190
|
+
actionpack (>= 4.0)
|
|
191
|
+
activesupport (>= 4.0)
|
|
192
|
+
sprockets (>= 3.0.0)
|
|
193
|
+
standard (1.0.5)
|
|
194
|
+
rubocop (= 1.12.1)
|
|
195
|
+
rubocop-performance (= 1.10.1)
|
|
196
|
+
thor (1.1.0)
|
|
197
|
+
tzinfo (2.0.4)
|
|
198
|
+
concurrent-ruby (~> 1.0)
|
|
199
|
+
unicode-display_width (2.0.0)
|
|
200
|
+
websocket-driver (0.7.3)
|
|
201
|
+
websocket-extensions (>= 0.1.0)
|
|
202
|
+
websocket-extensions (0.1.5)
|
|
203
|
+
zeitwerk (2.4.2)
|
|
204
|
+
|
|
205
|
+
PLATFORMS
|
|
206
|
+
x86_64-linux
|
|
207
|
+
|
|
208
|
+
DEPENDENCIES
|
|
209
|
+
evey!
|
|
210
|
+
factory_bot_rails
|
|
211
|
+
pg
|
|
212
|
+
pry
|
|
213
|
+
rails
|
|
214
|
+
rake (~> 12.0)
|
|
215
|
+
rspec (~> 3.0)
|
|
216
|
+
rspec-rails
|
|
217
|
+
simplecov
|
|
218
|
+
standard
|
|
219
|
+
|
|
220
|
+
BUNDLED WITH
|
|
221
|
+
2.2.15
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
# Evey
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
TODO: Delete this and the text above, and describe your gem
|
|
3
|
+
Rails event sourcing made simple.
|
|
6
4
|
|
|
7
5
|
## Installation
|
|
8
6
|
|
|
@@ -22,7 +20,7 @@ Or install it yourself as:
|
|
|
22
20
|
|
|
23
21
|
## Usage
|
|
24
22
|
|
|
25
|
-
|
|
23
|
+
Probably don't.
|
|
26
24
|
|
|
27
25
|
## Development
|
|
28
26
|
|
|
@@ -32,7 +30,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
|
32
30
|
|
|
33
31
|
## Contributing
|
|
34
32
|
|
|
35
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
|
33
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/thomas07vt/evey.
|
|
36
34
|
|
|
37
35
|
|
|
38
36
|
## License
|
data/evey.gemspec
CHANGED
|
@@ -9,6 +9,7 @@ Gem::Specification.new do |spec|
|
|
|
9
9
|
spec.summary = %q{Simple Event sourcing coming soon.}
|
|
10
10
|
spec.description = %q{Simple event sourcing.}
|
|
11
11
|
spec.homepage = "https://github.com"
|
|
12
|
+
spec.homepage = "https://github.com/thomas07vt/serializable_rails"
|
|
12
13
|
spec.license = "MIT"
|
|
13
14
|
spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
|
|
14
15
|
|
|
@@ -23,4 +24,18 @@ Gem::Specification.new do |spec|
|
|
|
23
24
|
spec.bindir = "exe"
|
|
24
25
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
25
26
|
spec.require_paths = ["lib"]
|
|
27
|
+
|
|
28
|
+
spec.add_dependency "kix"
|
|
29
|
+
spec.add_dependency "activejob"
|
|
30
|
+
spec.add_dependency "activerecord"
|
|
31
|
+
spec.add_dependency "activesupport"
|
|
32
|
+
|
|
33
|
+
spec.add_development_dependency "pry"
|
|
34
|
+
spec.add_development_dependency "rails"
|
|
35
|
+
spec.add_development_dependency "rspec"
|
|
36
|
+
spec.add_development_dependency "rspec-rails"
|
|
37
|
+
spec.add_development_dependency "simplecov"
|
|
38
|
+
spec.add_development_dependency "standard"
|
|
39
|
+
spec.add_development_dependency "pg"
|
|
40
|
+
spec.add_development_dependency "factory_bot_rails"
|
|
26
41
|
end
|
data/lib/evey.rb
CHANGED
|
@@ -1,6 +1,23 @@
|
|
|
1
|
-
require "evey/version"
|
|
2
|
-
|
|
3
1
|
module Evey
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
def self.table_name_prefix
|
|
3
|
+
"evey_"
|
|
4
|
+
end
|
|
6
5
|
end
|
|
6
|
+
|
|
7
|
+
require "kix"
|
|
8
|
+
require "active_job"
|
|
9
|
+
require "active_record"
|
|
10
|
+
require "active_support"
|
|
11
|
+
require "active_support/core_ext/object/json.rb"
|
|
12
|
+
|
|
13
|
+
require "rails/generators"
|
|
14
|
+
require "rails/generators/migration"
|
|
15
|
+
|
|
16
|
+
require "evey/types.rb"
|
|
17
|
+
require "evey/types/association.rb"
|
|
18
|
+
require "evey/event_serializer.rb"
|
|
19
|
+
require "evey/event.rb"
|
|
20
|
+
require "evey/version.rb"
|
|
21
|
+
require "evey/reactor.rb"
|
|
22
|
+
require "evey/dispatcher.rb"
|
|
23
|
+
require "evey/reactor_job.rb"
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
class Evey::Dispatcher
|
|
2
|
+
def self.enable!
|
|
3
|
+
@disabled = false
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
def self.disable!
|
|
7
|
+
@disabled = true
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def self.enabled?
|
|
11
|
+
@disabled != true
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.configure
|
|
15
|
+
if block_given?
|
|
16
|
+
@rules = nil
|
|
17
|
+
yield self
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Register Reactors to Events.
|
|
22
|
+
# * Reactors registered with `sync` will be triggered synchronously
|
|
23
|
+
# * Reactors registered with `async` will be triggered asynchronously via a Sidekiq Job
|
|
24
|
+
#
|
|
25
|
+
# Example:
|
|
26
|
+
#
|
|
27
|
+
# on BaseEvent, sync: LogEvent, async: TrackEvent
|
|
28
|
+
# on PledgeCancelled, PaymentFailed, async: [NotifyAdmin, CreateTask]
|
|
29
|
+
# on [PledgeCancelled, PaymentFailed], async: [NotifyAdmin, CreateTask]
|
|
30
|
+
#
|
|
31
|
+
def self.on(*events, sync: [], async: [])
|
|
32
|
+
rules.register(events: events.flatten, sync: Array(sync), async: Array(async))
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Dispatches events to matching Reactors once.
|
|
36
|
+
# Called by all events after they are created.
|
|
37
|
+
def self.dispatch(event)
|
|
38
|
+
return unless enabled?
|
|
39
|
+
|
|
40
|
+
reactors = rules.for(event)
|
|
41
|
+
reactors.sync.each { |reactor| reactor.call(event) }
|
|
42
|
+
reactors.async.each { |reactor| Evey::ReactorJob.perform_later(event, reactor.to_s) }
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def self.rules
|
|
46
|
+
@rules ||= RuleSet.new
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
class RuleSet
|
|
50
|
+
def initialize
|
|
51
|
+
@rules ||= Hash.new { |h, k| h[k] = ReactorSet.new }
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Register events with their sync and async Reactors
|
|
55
|
+
def register(events:, sync:, async:)
|
|
56
|
+
events.each do |event|
|
|
57
|
+
@rules[event].add_sync sync
|
|
58
|
+
@rules[event].add_async async
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Return a ReactorSet containing all Reactors matching an Event
|
|
63
|
+
def for(event)
|
|
64
|
+
reactors = ReactorSet.new
|
|
65
|
+
|
|
66
|
+
@rules.each do |event_class, rule|
|
|
67
|
+
if event.class == event_class
|
|
68
|
+
reactors.add_sync rule.sync
|
|
69
|
+
reactors.add_async rule.async
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
reactors
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Contains sync and async reactors. Used to:
|
|
78
|
+
# * store reactors via Rules#register
|
|
79
|
+
# * return a set of matching reactors with Rules#for
|
|
80
|
+
class ReactorSet
|
|
81
|
+
attr_reader :sync, :async
|
|
82
|
+
|
|
83
|
+
def initialize
|
|
84
|
+
@sync = Set.new
|
|
85
|
+
@async = Set.new
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def add_sync(reactors)
|
|
89
|
+
@sync += reactors
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def add_async(reactors)
|
|
93
|
+
@async += reactors
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
data/lib/evey/event.rb
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
class Evey::Event < ActiveRecord::Base
|
|
2
|
+
include Kix::Serializable
|
|
3
|
+
|
|
4
|
+
belongs_to :user, optional: true
|
|
5
|
+
|
|
6
|
+
before_create :apply_and_persist
|
|
7
|
+
after_create_commit :dispatch
|
|
8
|
+
|
|
9
|
+
attribute :aggregates, Evey::Types::Association.new
|
|
10
|
+
attribute :associations, Evey::Types::Association.new
|
|
11
|
+
|
|
12
|
+
class << self
|
|
13
|
+
def registered_events
|
|
14
|
+
@registered_events ||= {}
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def inherited(klass)
|
|
18
|
+
super
|
|
19
|
+
::Evey::Event.registered_events[klass.event_name] = klass
|
|
20
|
+
klass.request_hook(&@request_hook) if @request_hook
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def aggregates(*ags)
|
|
24
|
+
@aggregates ||= []
|
|
25
|
+
|
|
26
|
+
ags.map(&:to_s).each do |ag|
|
|
27
|
+
next if @aggregates.include?(ag)
|
|
28
|
+
|
|
29
|
+
@aggregates << ag
|
|
30
|
+
|
|
31
|
+
define_method ag do
|
|
32
|
+
self.aggregates ||= {}
|
|
33
|
+
self.aggregates[ag]
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
define_method "#{ag}=" do |arg|
|
|
37
|
+
self.aggregates ||= {}
|
|
38
|
+
self.aggregates[ag] = arg
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
@aggregates
|
|
43
|
+
end
|
|
44
|
+
alias_method :aggregate, :aggregates
|
|
45
|
+
|
|
46
|
+
def associations(*assoces)
|
|
47
|
+
@associations ||= []
|
|
48
|
+
|
|
49
|
+
assoces.map(&:to_s).each do |assoc|
|
|
50
|
+
next if @associations.include?(assoc)
|
|
51
|
+
|
|
52
|
+
@associations << assoc
|
|
53
|
+
|
|
54
|
+
define_method assoc do
|
|
55
|
+
self.associations ||= {}
|
|
56
|
+
self.associations[assoc]
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
define_method "#{assoc}=" do |arg|
|
|
60
|
+
self.associations ||= {}
|
|
61
|
+
self.associations[assoc] = arg
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
@associations
|
|
66
|
+
end
|
|
67
|
+
alias_method :association, :associations
|
|
68
|
+
|
|
69
|
+
def data_attributes(*attrs)
|
|
70
|
+
@data_attributes ||= []
|
|
71
|
+
|
|
72
|
+
attrs.map(&:to_s).each do |attr|
|
|
73
|
+
@data_attributes << attr unless @data_attributes.include?(attr)
|
|
74
|
+
|
|
75
|
+
define_method attr do
|
|
76
|
+
self.data ||= {}
|
|
77
|
+
self.data[attr]
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
define_method "#{attr}=" do |arg|
|
|
81
|
+
self.data ||= {}
|
|
82
|
+
self.data[attr] = arg
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
define_method "#{attr}_was_set?" do
|
|
86
|
+
self.data ||= {}
|
|
87
|
+
self.data.key?(attr)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
@data_attributes
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def request_hook(&block)
|
|
95
|
+
@request_hook = block if block.present?
|
|
96
|
+
@request_hook
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Underscored class name by default. ex: "post/updated"
|
|
100
|
+
# Used when sending events to the data pipeline
|
|
101
|
+
def event_name
|
|
102
|
+
name.underscore
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
delegate :event_name, to: :class
|
|
107
|
+
|
|
108
|
+
after_initialize do
|
|
109
|
+
self.data ||= {}
|
|
110
|
+
self.associations ||= {}
|
|
111
|
+
self.aggregates ||= {}
|
|
112
|
+
self.metadata ||= {}
|
|
113
|
+
self.type ||= self.class.name
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def apply
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def request_hook
|
|
120
|
+
self.class.request_hook
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def errors_as_json
|
|
124
|
+
return {} if errors.blank?
|
|
125
|
+
|
|
126
|
+
errors.as_json.merge(aggregate_errors_as_json)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
private
|
|
130
|
+
|
|
131
|
+
def apply_and_persist
|
|
132
|
+
aggregates.values.map(&:lock!)
|
|
133
|
+
apply
|
|
134
|
+
aggregates.map do |name, aggregate|
|
|
135
|
+
errors.add(name, 'is invalid') unless aggregate.save
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
throw :abort if errors.any?
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def dispatch
|
|
142
|
+
Evey::Dispatcher.dispatch(self)
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def aggregate_errors_as_json
|
|
146
|
+
aggregates.each_with_object({}) do |array, hash|
|
|
147
|
+
name, aggregate = array
|
|
148
|
+
hash[name.to_sym] = aggregate.errors.as_json if aggregate.errors.present?
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
data/lib/evey/reactor.rb
ADDED
data/lib/evey/types.rb
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
class Evey::Types::Association < ActiveRecord::Type::Value
|
|
2
|
+
def type
|
|
3
|
+
:json
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
def cast(hash)
|
|
7
|
+
return if hash.nil?
|
|
8
|
+
|
|
9
|
+
hash.transform_values { |v| GlobalID::Locator.locate(v) }
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def deserialize(hash)
|
|
13
|
+
return cast(hash) unless hash.is_a?(::String)
|
|
14
|
+
|
|
15
|
+
cast(decode_value(hash))
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def serialize(hash)
|
|
19
|
+
return if hash.nil?
|
|
20
|
+
|
|
21
|
+
::ActiveSupport::JSON.encode(hash.transform_values { |v| v.to_global_id.to_s })
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def decode_value(value)
|
|
27
|
+
::ActiveSupport::JSON.decode(value)
|
|
28
|
+
rescue StandardError
|
|
29
|
+
nil
|
|
30
|
+
end
|
|
31
|
+
end
|
data/lib/evey/version.rb
CHANGED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
class CreateEveyEvents < ActiveRecord::Migration::Current
|
|
2
|
+
def change
|
|
3
|
+
create_table :evey_events do |t|
|
|
4
|
+
t.string :type, null: false
|
|
5
|
+
t.bigint :user_id
|
|
6
|
+
t.jsonb :data
|
|
7
|
+
t.jsonb :metadata
|
|
8
|
+
t.jsonb :aggregates
|
|
9
|
+
t.jsonb :associations
|
|
10
|
+
|
|
11
|
+
t.timestamps
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
add_index :evey_events, :user_id
|
|
15
|
+
end
|
|
16
|
+
end
|
metadata
CHANGED
|
@@ -1,15 +1,183 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: evey
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- John Thomas
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2021-
|
|
12
|
-
dependencies:
|
|
11
|
+
date: 2021-04-24 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: kix
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ">="
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '0'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ">="
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '0'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: activejob
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - ">="
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '0'
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - ">="
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: activerecord
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - ">="
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '0'
|
|
48
|
+
type: :runtime
|
|
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: activesupport
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - ">="
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '0'
|
|
62
|
+
type: :runtime
|
|
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: pry
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - ">="
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: '0'
|
|
76
|
+
type: :development
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - ">="
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '0'
|
|
83
|
+
- !ruby/object:Gem::Dependency
|
|
84
|
+
name: rails
|
|
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'
|
|
97
|
+
- !ruby/object:Gem::Dependency
|
|
98
|
+
name: rspec
|
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
|
100
|
+
requirements:
|
|
101
|
+
- - ">="
|
|
102
|
+
- !ruby/object:Gem::Version
|
|
103
|
+
version: '0'
|
|
104
|
+
type: :development
|
|
105
|
+
prerelease: false
|
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
107
|
+
requirements:
|
|
108
|
+
- - ">="
|
|
109
|
+
- !ruby/object:Gem::Version
|
|
110
|
+
version: '0'
|
|
111
|
+
- !ruby/object:Gem::Dependency
|
|
112
|
+
name: rspec-rails
|
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
|
114
|
+
requirements:
|
|
115
|
+
- - ">="
|
|
116
|
+
- !ruby/object:Gem::Version
|
|
117
|
+
version: '0'
|
|
118
|
+
type: :development
|
|
119
|
+
prerelease: false
|
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
121
|
+
requirements:
|
|
122
|
+
- - ">="
|
|
123
|
+
- !ruby/object:Gem::Version
|
|
124
|
+
version: '0'
|
|
125
|
+
- !ruby/object:Gem::Dependency
|
|
126
|
+
name: simplecov
|
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
|
128
|
+
requirements:
|
|
129
|
+
- - ">="
|
|
130
|
+
- !ruby/object:Gem::Version
|
|
131
|
+
version: '0'
|
|
132
|
+
type: :development
|
|
133
|
+
prerelease: false
|
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
135
|
+
requirements:
|
|
136
|
+
- - ">="
|
|
137
|
+
- !ruby/object:Gem::Version
|
|
138
|
+
version: '0'
|
|
139
|
+
- !ruby/object:Gem::Dependency
|
|
140
|
+
name: standard
|
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
|
142
|
+
requirements:
|
|
143
|
+
- - ">="
|
|
144
|
+
- !ruby/object:Gem::Version
|
|
145
|
+
version: '0'
|
|
146
|
+
type: :development
|
|
147
|
+
prerelease: false
|
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
149
|
+
requirements:
|
|
150
|
+
- - ">="
|
|
151
|
+
- !ruby/object:Gem::Version
|
|
152
|
+
version: '0'
|
|
153
|
+
- !ruby/object:Gem::Dependency
|
|
154
|
+
name: pg
|
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
|
156
|
+
requirements:
|
|
157
|
+
- - ">="
|
|
158
|
+
- !ruby/object:Gem::Version
|
|
159
|
+
version: '0'
|
|
160
|
+
type: :development
|
|
161
|
+
prerelease: false
|
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
163
|
+
requirements:
|
|
164
|
+
- - ">="
|
|
165
|
+
- !ruby/object:Gem::Version
|
|
166
|
+
version: '0'
|
|
167
|
+
- !ruby/object:Gem::Dependency
|
|
168
|
+
name: factory_bot_rails
|
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
|
170
|
+
requirements:
|
|
171
|
+
- - ">="
|
|
172
|
+
- !ruby/object:Gem::Version
|
|
173
|
+
version: '0'
|
|
174
|
+
type: :development
|
|
175
|
+
prerelease: false
|
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
177
|
+
requirements:
|
|
178
|
+
- - ">="
|
|
179
|
+
- !ruby/object:Gem::Version
|
|
180
|
+
version: '0'
|
|
13
181
|
description: Simple event sourcing.
|
|
14
182
|
email:
|
|
15
183
|
- thomas07@vt.edu
|
|
@@ -20,7 +188,9 @@ files:
|
|
|
20
188
|
- ".gitignore"
|
|
21
189
|
- ".rspec"
|
|
22
190
|
- ".travis.yml"
|
|
191
|
+
- CITATIONS.txt
|
|
23
192
|
- Gemfile
|
|
193
|
+
- Gemfile.lock
|
|
24
194
|
- LICENSE.txt
|
|
25
195
|
- README.md
|
|
26
196
|
- Rakefile
|
|
@@ -28,12 +198,21 @@ files:
|
|
|
28
198
|
- bin/setup
|
|
29
199
|
- evey.gemspec
|
|
30
200
|
- lib/evey.rb
|
|
201
|
+
- lib/evey/dispatcher.rb
|
|
202
|
+
- lib/evey/event.rb
|
|
203
|
+
- lib/evey/event_serializer.rb
|
|
204
|
+
- lib/evey/reactor.rb
|
|
205
|
+
- lib/evey/reactor_job.rb
|
|
206
|
+
- lib/evey/types.rb
|
|
207
|
+
- lib/evey/types/association.rb
|
|
31
208
|
- lib/evey/version.rb
|
|
32
|
-
|
|
209
|
+
- lib/generators/evey/install_generator.rb
|
|
210
|
+
- lib/generators/evey/migration.erb
|
|
211
|
+
homepage: https://github.com/thomas07vt/serializable_rails
|
|
33
212
|
licenses:
|
|
34
213
|
- MIT
|
|
35
214
|
metadata:
|
|
36
|
-
homepage_uri: https://github.com
|
|
215
|
+
homepage_uri: https://github.com/thomas07vt/serializable_rails
|
|
37
216
|
source_code_uri: https://github.com
|
|
38
217
|
post_install_message:
|
|
39
218
|
rdoc_options: []
|
|
@@ -50,7 +229,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
50
229
|
- !ruby/object:Gem::Version
|
|
51
230
|
version: '0'
|
|
52
231
|
requirements: []
|
|
53
|
-
rubygems_version: 3.
|
|
232
|
+
rubygems_version: 3.2.15
|
|
54
233
|
signing_key:
|
|
55
234
|
specification_version: 4
|
|
56
235
|
summary: Simple Event sourcing coming soon.
|