simple_event_sourcing 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 +1 -0
- data/Gemfile.lock +1 -1
- data/README.md +88 -6
- data/lib/simple_event_sourcing.rb +3 -98
- data/lib/simple_event_sourcing/aggregate_root/aggregate_root.rb +59 -0
- data/lib/simple_event_sourcing/events/events.rb +48 -0
- data/lib/simple_event_sourcing/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8c8f96d29fae329c09e8001a2ce8ab34e725ba76095d61e7927acf42321be8c2
|
4
|
+
data.tar.gz: 69fc9bde337b95d771f4ca23a15f7eedc0b40d0e39df082b39272e96c4ecf88a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 48671ba2bc1b7b37e7130622f87f7d519bafa91f9e38e1f26f3b346d14f60354b92e9cabfe1c8005f309cde15204ded274095867470f3800b7298e5ee7ff7104
|
7
|
+
data.tar.gz: ca37c5f86523fb2d3e28a6eedbe9f3f9ea9999940cba3d05daf616c18e7178e985e97df83f88a3860a6d019a42b778753a23252e6ac91bbc1ae3f0e0a2b37358
|
data/.gitignore
CHANGED
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,8 +1,17 @@
|
|
1
1
|
# EventSourcing
|
2
2
|
|
3
|
-
|
3
|
+
The fundamental idea of Event Sourcing is that of ensuring every change to the state of an application is captured in an event object, and that these event objects are themselves stored in the sequence they were applied for the same lifetime as the application state itself.
|
4
4
|
|
5
|
-
|
5
|
+
Martin Fowler , https://martinfowler.com/eaaDev/EventSourcing.html
|
6
|
+
|
7
|
+
This gem provides a simple way for add events sourcing related behaviour to your models class.
|
8
|
+
|
9
|
+
Base classes
|
10
|
+
|
11
|
+
- AggregateRoot
|
12
|
+
- Event
|
13
|
+
- EventStream
|
14
|
+
- EventPublisher
|
6
15
|
|
7
16
|
## Installation
|
8
17
|
|
@@ -22,13 +31,86 @@ Or install it yourself as:
|
|
22
31
|
|
23
32
|
## Usage
|
24
33
|
|
25
|
-
|
34
|
+
Here an example of use:
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
class Employee
|
38
|
+
|
39
|
+
include SimpleEventSourcing::AggregateRoot
|
40
|
+
|
41
|
+
attr_reader :name, :title, :salary
|
42
|
+
|
43
|
+
def initialize(args = nil )
|
44
|
+
super
|
45
|
+
unless args.nil?
|
46
|
+
apply_record_event NewEmployeeIsHiredEvent.new(@aggregate_id, args[:name], args[:title], args[:salary] )
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def salary=(new_salary)
|
51
|
+
apply_record_event SalaryHasChangedEvent.new(@aggregate_id, new_salary)
|
52
|
+
end
|
53
|
+
|
54
|
+
def apply_new_employee_is_hired_event(event)
|
55
|
+
@name = event.name
|
56
|
+
@title = event.title
|
57
|
+
@salary = event.salary
|
58
|
+
end
|
59
|
+
|
60
|
+
def apply_salary_has_changed_event(event)
|
61
|
+
@salary = event.new_salary
|
62
|
+
end
|
63
|
+
|
64
|
+
def save
|
65
|
+
# Persist the entity
|
66
|
+
publish_events { |event| SimpleEventSourcing::EventPublisher.publish(event) }
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
```
|
71
|
+
|
72
|
+
Firts you mus add behaviour including the AggregateRoot module
|
73
|
+
|
74
|
+
```ruby
|
75
|
+
include SimpleEventSourcing::AggregateRoot
|
76
|
+
```
|
77
|
+
|
78
|
+
After that all domain event must be applied and recorded
|
79
|
+
|
80
|
+
```ruby
|
81
|
+
apply_record_event SalaryHasChangedEvent.new(@aggregate_id, new_salary)
|
82
|
+
```
|
83
|
+
|
84
|
+
You must create your own events and a event stream
|
26
85
|
|
27
|
-
|
86
|
+
```ruby
|
87
|
+
class EmployeeStreamEvents < SimpleEventSourcing::StreamEvents
|
88
|
+
def get_aggregate_class
|
89
|
+
Employee
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
class SalaryHasChangedEvent < SimpleEventSourcing::Event
|
94
|
+
attr_reader :aggregate_id, :new_salary
|
95
|
+
|
96
|
+
def initialize(aggregate_id, new_salary)
|
97
|
+
@aggregate_id = aggregate_id
|
98
|
+
@new_salary = new_salary
|
99
|
+
super()
|
100
|
+
end
|
101
|
+
end
|
102
|
+
```
|
28
103
|
|
29
|
-
|
104
|
+
Once you persist the entity you must publish all recorded events.
|
105
|
+
|
106
|
+
```ruby
|
107
|
+
def save
|
108
|
+
# Persist the entity
|
109
|
+
publish_events { |event| SimpleEventSourcing::EventPublisher.publish(event) }
|
110
|
+
end
|
111
|
+
```
|
30
112
|
|
31
|
-
|
113
|
+
Happy coding!
|
32
114
|
|
33
115
|
## Contributing
|
34
116
|
|
@@ -1,104 +1,9 @@
|
|
1
1
|
require 'simple_event_sourcing/version'
|
2
|
-
require 'securerandom'
|
3
|
-
require 'facets'
|
4
2
|
|
5
|
-
module SimpleEventSourcing
|
6
|
-
class Event
|
7
|
-
attr_reader :occurred_on
|
8
|
-
|
9
|
-
def initialize
|
10
|
-
@occurred_on ||= Time.new
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
class StreamEvents < Array
|
15
|
-
attr_reader :aggregate_id
|
16
|
-
|
17
|
-
def initialize(aggregate_id)
|
18
|
-
@aggregate_id = aggregate_id
|
19
|
-
end
|
20
|
-
|
21
|
-
def get_aggregate
|
22
|
-
aggregate = get_aggregate_class.create_from_agrregate_id @aggregate_id
|
23
|
-
each { |event| aggregate.apply_record_event event }
|
24
|
-
aggregate
|
25
|
-
end
|
26
|
-
|
27
|
-
def get_aggregate_class
|
28
|
-
raise StandardError('Method must be implemented')
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
module EventPublisher
|
33
|
-
@@subscribers = []
|
34
|
-
|
35
|
-
def self.add_subscriber(subscriber)
|
36
|
-
@@subscribers << subscriber
|
37
|
-
end
|
38
|
-
|
39
|
-
def self.delete_subscriber(subscriber)
|
40
|
-
@@subscribers.delete(subscriber)
|
41
|
-
end
|
42
|
-
|
43
|
-
def self.get_subscribers
|
44
|
-
@@subscribers
|
45
|
-
end
|
46
3
|
|
47
|
-
|
48
|
-
|
49
|
-
end
|
50
|
-
end
|
4
|
+
require_relative 'simple_event_sourcing/aggregate_root/aggregate_root'
|
5
|
+
require_relative 'simple_event_sourcing/events/events'
|
51
6
|
|
52
|
-
|
53
|
-
def self.included(o)
|
54
|
-
o.extend(ClassMethods)
|
55
|
-
end
|
56
|
-
|
57
|
-
attr_accessor :aggregate_id
|
58
|
-
attr_reader :events
|
59
|
-
|
60
|
-
def initialize(_args = nil)
|
61
|
-
@events = []
|
62
|
-
@aggregate_id ||= SecureRandom.uuid
|
63
|
-
end
|
64
|
-
|
65
|
-
def have_changed?
|
66
|
-
(@events.count > 0)
|
67
|
-
end
|
68
|
-
|
69
|
-
def publish_events
|
70
|
-
@events.each do |event|
|
71
|
-
yield(event)
|
72
|
-
end
|
73
|
-
clear_events
|
74
|
-
end
|
75
|
-
|
76
|
-
def apply_record_event(event)
|
77
|
-
apply_event event
|
78
|
-
record_event event
|
79
|
-
end
|
80
|
-
|
81
|
-
private
|
82
|
-
|
83
|
-
def record_event(event)
|
84
|
-
@events << event
|
85
|
-
end
|
86
|
-
|
87
|
-
def clear_events
|
88
|
-
@events = []
|
89
|
-
end
|
90
|
-
|
91
|
-
def apply_event(event)
|
92
|
-
method = 'apply_' + event.class.name.snakecase
|
93
|
-
send(method, event)
|
94
|
-
end
|
7
|
+
module SimpleEventSourcing
|
95
8
|
|
96
|
-
module ClassMethods
|
97
|
-
def create_from_agrregate_id(id)
|
98
|
-
aggregate = new
|
99
|
-
aggregate.aggregate_id = id
|
100
|
-
aggregate
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
104
9
|
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
require 'facets'
|
3
|
+
|
4
|
+
module SimpleEventSourcing
|
5
|
+
module AggregateRoot
|
6
|
+
|
7
|
+
attr_accessor :aggregate_id
|
8
|
+
attr_reader :events
|
9
|
+
|
10
|
+
def initialize(_args = nil)
|
11
|
+
@events = []
|
12
|
+
@aggregate_id ||= SecureRandom.uuid
|
13
|
+
end
|
14
|
+
|
15
|
+
def have_changed?
|
16
|
+
(@events.count > 0)
|
17
|
+
end
|
18
|
+
|
19
|
+
def publish_events
|
20
|
+
@events.each do |event|
|
21
|
+
yield(event)
|
22
|
+
end
|
23
|
+
clear_events
|
24
|
+
end
|
25
|
+
|
26
|
+
def apply_record_event(event)
|
27
|
+
apply_event event
|
28
|
+
record_event event
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.included(o)
|
32
|
+
o.extend(ClassMethods)
|
33
|
+
end
|
34
|
+
|
35
|
+
module ClassMethods
|
36
|
+
def create_from_agrregate_id(id)
|
37
|
+
aggregate = new
|
38
|
+
aggregate.aggregate_id = id
|
39
|
+
aggregate
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def record_event(event)
|
46
|
+
@events << event
|
47
|
+
end
|
48
|
+
|
49
|
+
def clear_events
|
50
|
+
@events = []
|
51
|
+
end
|
52
|
+
|
53
|
+
def apply_event(event)
|
54
|
+
method = 'apply_' + event.class.name.snakecase
|
55
|
+
send(method, event)
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module SimpleEventSourcing
|
2
|
+
|
3
|
+
class Event
|
4
|
+
attr_reader :occurred_on
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@occurred_on ||= Time.new
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class StreamEvents < Array
|
12
|
+
attr_reader :aggregate_id
|
13
|
+
|
14
|
+
def initialize(aggregate_id)
|
15
|
+
@aggregate_id = aggregate_id
|
16
|
+
end
|
17
|
+
|
18
|
+
def get_aggregate
|
19
|
+
aggregate = get_aggregate_class.create_from_agrregate_id @aggregate_id
|
20
|
+
each { |event| aggregate.apply_record_event event }
|
21
|
+
aggregate
|
22
|
+
end
|
23
|
+
|
24
|
+
def get_aggregate_class
|
25
|
+
raise StandardError('Method must be implemented')
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
module EventPublisher
|
30
|
+
@@subscribers = []
|
31
|
+
|
32
|
+
def self.add_subscriber(subscriber)
|
33
|
+
@@subscribers << subscriber
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.delete_subscriber(subscriber)
|
37
|
+
@@subscribers.delete(subscriber)
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.get_subscribers
|
41
|
+
@@subscribers
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.publish(event)
|
45
|
+
@@subscribers.each { |subscriber| subscriber.handle(event) if subscriber.is_subscribet_to? event }
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: simple_event_sourcing
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Manel
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-04-
|
11
|
+
date: 2018-04-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -106,6 +106,8 @@ files:
|
|
106
106
|
- example/employee_subscribers.rb
|
107
107
|
- example/main.rb
|
108
108
|
- lib/simple_event_sourcing.rb
|
109
|
+
- lib/simple_event_sourcing/aggregate_root/aggregate_root.rb
|
110
|
+
- lib/simple_event_sourcing/events/events.rb
|
109
111
|
- lib/simple_event_sourcing/version.rb
|
110
112
|
- run.sh
|
111
113
|
- simple_event_sourcing.gemspec
|