simple_event_sourcing 0.7.0 → 0.8.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/Gemfile.lock +5 -1
- data/README.md +50 -51
- data/lib/simple_event_sourcing/aggregate_root/base.rb +2 -3
- data/lib/simple_event_sourcing/events/event.rb +11 -1
- data/lib/simple_event_sourcing/events/event_store/redis/redis_client.rb +66 -0
- data/lib/simple_event_sourcing/events/event_store/redis/redis_event_store.rb +43 -0
- data/lib/simple_event_sourcing/events/event_store.rb +8 -7
- data/lib/simple_event_sourcing/events/stored_event.rb +2 -0
- data/lib/simple_event_sourcing/version.rb +1 -1
- data/lib/simple_event_sourcing.rb +2 -0
- data/simple_event_sourcing.gemspec +2 -1
- metadata +32 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ae87508c0ddc3384c7f2011ea0b8ed3700620cadc889164ae06776cdaa79cb4d
|
4
|
+
data.tar.gz: e5a91b0012ee57ccb2451a229c38a0c45f10fe27c400ba7d8f53e616b4da794c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 42d2a999148a1211598af7b5e9a8361c5bd769e9e73529cb06a7c5ff94d6a3e3f16d896f39e6416c84dae67e49b02f223c1afd5e5d7742ade56d6e92f62db8a5
|
7
|
+
data.tar.gz: ef5175ce65a340e3008bd9b6bbb676a6f027073c0eb8cdd79d212092730f89ca3596b74f388bd65328e6d75c27e083fda7c941cad8d2ff3bf0ea25dd03c174bd
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
simple_event_sourcing (0.
|
4
|
+
simple_event_sourcing (0.8.0)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
@@ -11,6 +11,7 @@ GEM
|
|
11
11
|
facets (3.1.0)
|
12
12
|
json (2.1.0)
|
13
13
|
rake (10.5.0)
|
14
|
+
redis (4.0.1)
|
14
15
|
rspec (3.7.0)
|
15
16
|
rspec-core (~> 3.7.0)
|
16
17
|
rspec-expectations (~> 3.7.0)
|
@@ -29,6 +30,7 @@ GEM
|
|
29
30
|
json (>= 1.8, < 3)
|
30
31
|
simplecov-html (~> 0.10.0)
|
31
32
|
simplecov-html (0.10.2)
|
33
|
+
timecop (0.9.1)
|
32
34
|
|
33
35
|
PLATFORMS
|
34
36
|
ruby
|
@@ -37,9 +39,11 @@ DEPENDENCIES
|
|
37
39
|
bundler (~> 1.16)
|
38
40
|
facets
|
39
41
|
rake (~> 10.0)
|
42
|
+
redis
|
40
43
|
rspec (~> 3.0)
|
41
44
|
simple_event_sourcing!
|
42
45
|
simplecov
|
46
|
+
timecop
|
43
47
|
|
44
48
|
BUNDLED WITH
|
45
49
|
1.16.1
|
data/README.md
CHANGED
@@ -5,20 +5,22 @@ DISCLAIMER
|
|
5
5
|
|
6
6
|
This gem is under development. DO NOT USE IN PRODUCTION ENVIRONMENT!!!!
|
7
7
|
|
8
|
+
>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.
|
9
|
+
>
|
10
|
+
>Martin Fowler , [https://martinfowler.com/eaaDev/EventSourcing.html](https://martinfowler.com/eaaDev/EventSourcing.html)
|
8
11
|
|
9
|
-
|
12
|
+
This gem provides a simple way of adding event sourcing behaviour to your models class.
|
10
13
|
|
11
|
-
|
12
|
-
|
13
|
-
This gem provides a simple way for add events sourcing related behaviour to your models class.
|
14
|
-
|
15
|
-
Base classes
|
14
|
+
You could find this base classes:
|
16
15
|
|
17
16
|
- AggregateRoot
|
18
|
-
-
|
17
|
+
- Id
|
18
|
+
- History
|
19
19
|
- Event
|
20
|
-
- EventStream
|
21
20
|
- EventDispatcher
|
21
|
+
- EventSubscriber
|
22
|
+
- StoredEvent
|
23
|
+
- RedisEventStore
|
22
24
|
|
23
25
|
## Installation
|
24
26
|
|
@@ -38,7 +40,7 @@ Or install it yourself as:
|
|
38
40
|
|
39
41
|
## Usage
|
40
42
|
|
41
|
-
|
43
|
+
Firts of all, you must add "event sourcing" behaviour to your model including the AggregateRoot Base Module
|
42
44
|
|
43
45
|
```ruby
|
44
46
|
class Employee
|
@@ -58,6 +60,10 @@ class Employee
|
|
58
60
|
apply_record_event SalaryHasChangedEvent , new_salary: new_salary
|
59
61
|
end
|
60
62
|
|
63
|
+
def id
|
64
|
+
aggregate_id.to_s
|
65
|
+
end
|
66
|
+
|
61
67
|
on NewEmployeeIsHiredEvent do |event|
|
62
68
|
@name = event.name
|
63
69
|
@title = event.title
|
@@ -68,76 +74,69 @@ class Employee
|
|
68
74
|
@salary = event.new_salary
|
69
75
|
end
|
70
76
|
|
71
|
-
def save
|
72
|
-
# Persist the entity
|
73
|
-
publish_events { |event| SimpleEventSourcing::Events::EventDispatcher.publish(event) }
|
74
|
-
end
|
75
|
-
|
76
77
|
end
|
77
78
|
|
78
79
|
```
|
79
80
|
|
80
|
-
|
81
|
-
|
82
|
-
```ruby
|
83
|
-
include SimpleEventSourcing::AggregateRoot::Base
|
84
|
-
```
|
85
|
-
|
86
|
-
You must create your own domain events and a event stream
|
81
|
+
You must create your own domain events
|
87
82
|
|
88
83
|
```ruby
|
89
|
-
class EmployeeStreamEvents < SimpleEventSourcing::AggregateRoot::History
|
90
|
-
def get_aggregate_class
|
91
|
-
Employee
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
|
96
|
-
class NewEmployeeIsHiredEvent < SimpleEventSourcing::Events::Event
|
97
|
-
attr_reader :name, :title,:salary
|
98
|
-
|
99
|
-
def initialize(args)
|
100
|
-
@name = args[:name]
|
101
|
-
@title = args[:title]
|
102
|
-
@salary = args[:salary]
|
103
|
-
super(args)
|
104
|
-
end
|
105
|
-
end
|
106
84
|
|
107
|
-
class SalaryHasChangedEvent
|
85
|
+
class SalaryHasChangedEvent < SimpleEventSourcing::Events::Event
|
108
86
|
attr_reader :new_salary
|
109
87
|
|
110
88
|
def initialize(args)
|
111
89
|
@new_salary = args[:new_salary]
|
112
90
|
super(args)
|
113
91
|
end
|
92
|
+
|
93
|
+
def serialize
|
94
|
+
super.merge("new_salary" => new_salary)
|
95
|
+
end
|
96
|
+
|
114
97
|
end
|
98
|
+
|
115
99
|
```
|
116
100
|
|
117
|
-
After that all domain event
|
101
|
+
After that, we must provide a handle in the out model for all domain event. SimpleEventSourcing provides a DSL to handle the applied events. You must provide a handler for each event
|
118
102
|
|
119
103
|
```ruby
|
120
|
-
|
104
|
+
on SalaryHasChangedEvent do |event|
|
105
|
+
@salary = event.new_salary
|
106
|
+
end
|
121
107
|
```
|
122
108
|
|
123
|
-
|
109
|
+
Now you could apply and record events.
|
124
110
|
|
125
111
|
```ruby
|
126
|
-
|
127
|
-
@salary = event.new_salary
|
128
|
-
end
|
112
|
+
apply_record_event SalaryHasChangedEvent , new_salary: new_salary
|
129
113
|
```
|
130
114
|
|
131
|
-
Once you persist the entity you must publish all recorded events.
|
132
|
-
|
115
|
+
Once you persist the entity you must store and publish all recorded events.
|
133
116
|
```ruby
|
134
|
-
|
135
|
-
|
136
|
-
|
117
|
+
class EmployeeRepository
|
118
|
+
def initialize(event_store)
|
119
|
+
@event_store = event_store
|
137
120
|
end
|
121
|
+
|
122
|
+
def save(employee)
|
123
|
+
employee.events.each do |event|
|
124
|
+
@event_store.commit event
|
125
|
+
SimpleEventSourcing::Events::EventDispatcher.publish(event)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def findById(id)
|
130
|
+
history = @event_store.get_history id
|
131
|
+
return Employee.create_from_history history
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
138
135
|
```
|
139
136
|
|
140
|
-
|
137
|
+
This gem provides a Redis Event Store or if you want, you could create your own usign "EventStoreBase" interface.
|
138
|
+
|
139
|
+
You could see this example running in https://github.com/malotor/simple_event_sourcing_example
|
141
140
|
|
142
141
|
Happy coding!
|
143
142
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
1
3
|
module SimpleEventSourcing
|
2
4
|
module Events
|
3
5
|
|
@@ -6,7 +8,15 @@ module SimpleEventSourcing
|
|
6
8
|
|
7
9
|
def initialize(args)
|
8
10
|
@aggregate_id = args[:aggregate_id]
|
9
|
-
@occurred_on ||= Time.
|
11
|
+
@occurred_on ||= Time.now.getlocal("+02:00").to_i
|
12
|
+
end
|
13
|
+
|
14
|
+
def serialize
|
15
|
+
{"aggregate_id" => aggregate_id.to_s, "occurred_on" => occurred_on }
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_json(*a)
|
19
|
+
serialize.to_json(*a)
|
10
20
|
end
|
11
21
|
end
|
12
22
|
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'redis'
|
2
|
+
|
3
|
+
module SimpleEventSourcing
|
4
|
+
module Events
|
5
|
+
module EventStore
|
6
|
+
|
7
|
+
module RedisClient
|
8
|
+
class << self
|
9
|
+
attr_writer :configuration
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.configuration
|
13
|
+
@configuration ||= Configuration.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.reset
|
17
|
+
@configuration = Configuration.new
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.configure
|
21
|
+
yield(configuration)
|
22
|
+
end
|
23
|
+
|
24
|
+
class Configuration
|
25
|
+
attr_accessor :host,:port,:mock
|
26
|
+
|
27
|
+
def initialize
|
28
|
+
@host ='localhost'
|
29
|
+
@port = 6379
|
30
|
+
@mock = false
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
def self.get_client
|
36
|
+
if @configuration.mock
|
37
|
+
return RedisClientMock.new
|
38
|
+
else
|
39
|
+
return Redis.new(
|
40
|
+
host: @configuration.host,
|
41
|
+
port: @configuration.port
|
42
|
+
)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
class RedisClientMock
|
49
|
+
attr_reader :entries
|
50
|
+
|
51
|
+
def initialize
|
52
|
+
@entries = Hash.new()
|
53
|
+
end
|
54
|
+
def rpush(key, value)
|
55
|
+
@entries[key] ||= []
|
56
|
+
@entries[key] << value
|
57
|
+
end
|
58
|
+
def lrange(key,inf,max)
|
59
|
+
@entries[key] ||= []
|
60
|
+
return @entries[key]
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module SimpleEventSourcing
|
4
|
+
module Events
|
5
|
+
module EventStore
|
6
|
+
class RedisEventStore < SimpleEventSourcing::Events::EventStore::EventStoreBase
|
7
|
+
|
8
|
+
def initialize(client)
|
9
|
+
@redis = client
|
10
|
+
end
|
11
|
+
|
12
|
+
def commit(event)
|
13
|
+
|
14
|
+
stored_event = SimpleEventSourcing::Events::StoredEvent.new(
|
15
|
+
aggregate_id: event.aggregate_id.to_s,
|
16
|
+
occurred_on: Time.now.getlocal("+02:00").to_i,
|
17
|
+
event_type: event.class.name,
|
18
|
+
event_data: event.to_json
|
19
|
+
)
|
20
|
+
|
21
|
+
@redis.rpush(event.aggregate_id.to_s, stored_event.to_json )
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
def get_history(aggregate_id)
|
26
|
+
stored_events_json = @redis.lrange( aggregate_id, 0, -1 )
|
27
|
+
history = SimpleEventSourcing::AggregateRoot::History.new(aggregate_id)
|
28
|
+
stored_events_json.each do |stored_event_json|
|
29
|
+
stored_event = SimpleEventSourcing::Events::StoredEvent.create_from_json stored_event_json
|
30
|
+
event = Object.const_get(stored_event.event_type)
|
31
|
+
args = JSON.parse(stored_event.event_data)
|
32
|
+
args.keys.each do |key|
|
33
|
+
args[(key.to_sym rescue key) || key] = args.delete(key)
|
34
|
+
end
|
35
|
+
recovered_event = event.new(args)
|
36
|
+
history << recovered_event
|
37
|
+
end
|
38
|
+
history
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -1,15 +1,16 @@
|
|
1
1
|
module SimpleEventSourcing
|
2
2
|
module Events
|
3
|
-
|
3
|
+
module EventStore
|
4
|
+
class EventStoreBase
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
6
|
+
def commit(event)
|
7
|
+
raise StandardError "This methid must be implemented"
|
8
|
+
end
|
8
9
|
|
9
|
-
|
10
|
-
|
10
|
+
def get_history(aggregate_id)
|
11
|
+
raise StandardError "This methid must be implemented"
|
12
|
+
end
|
11
13
|
end
|
12
14
|
end
|
13
|
-
|
14
15
|
end
|
15
16
|
end
|
@@ -9,3 +9,5 @@ require 'simple_event_sourcing/events/event_dispatcher'
|
|
9
9
|
require 'simple_event_sourcing/events/event_subscriber'
|
10
10
|
require 'simple_event_sourcing/events/stored_event'
|
11
11
|
require 'simple_event_sourcing/events/event_store'
|
12
|
+
require 'simple_event_sourcing/events/event_store/redis/redis_client'
|
13
|
+
require 'simple_event_sourcing/events/event_store/redis/redis_event_store'
|
@@ -35,5 +35,6 @@ Gem::Specification.new do |spec|
|
|
35
35
|
spec.add_development_dependency "rspec", "~> 3.0"
|
36
36
|
spec.add_development_dependency "facets"
|
37
37
|
spec.add_development_dependency "simplecov"
|
38
|
-
|
38
|
+
spec.add_development_dependency "timecop"
|
39
|
+
spec.add_development_dependency "redis"
|
39
40
|
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.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Manuel López Torrent
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-04-
|
11
|
+
date: 2018-04-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -80,6 +80,34 @@ dependencies:
|
|
80
80
|
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: timecop
|
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: redis
|
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'
|
83
111
|
description: This gem provides a simple way for add events sourcing related behaviour
|
84
112
|
to your models class
|
85
113
|
email:
|
@@ -109,6 +137,8 @@ files:
|
|
109
137
|
- lib/simple_event_sourcing/events/event.rb
|
110
138
|
- lib/simple_event_sourcing/events/event_dispatcher.rb
|
111
139
|
- lib/simple_event_sourcing/events/event_store.rb
|
140
|
+
- lib/simple_event_sourcing/events/event_store/redis/redis_client.rb
|
141
|
+
- lib/simple_event_sourcing/events/event_store/redis/redis_event_store.rb
|
112
142
|
- lib/simple_event_sourcing/events/event_subscriber.rb
|
113
143
|
- lib/simple_event_sourcing/events/stored_event.rb
|
114
144
|
- lib/simple_event_sourcing/version.rb
|