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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a0af077c1f7192128bfc81d95dd245712d44fa647465dd4dddc3cd0cc3849044
4
- data.tar.gz: c34c2358c240f4235be395afbc42373336278fc85bfbd0ba8b768e479f842c3b
3
+ metadata.gz: ae87508c0ddc3384c7f2011ea0b8ed3700620cadc889164ae06776cdaa79cb4d
4
+ data.tar.gz: e5a91b0012ee57ccb2451a229c38a0c45f10fe27c400ba7d8f53e616b4da794c
5
5
  SHA512:
6
- metadata.gz: a6a6dd3da4a2b9e489309d718371726fd00b841ab55fd5a9502b4ed3e1c0e69a38e11b0d21d25a11a7109adc98017376403e2a2e0ce59a8d5e1c6adccc3dc395
7
- data.tar.gz: 8316de28bec9dee0efe27e8f1e7a3089f594900e63b83b56dca9752396fbe159a622be9e40c96257aac7be6da6b0f0144fea5c30ff2d5ad2460b37a5f5df9568
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.7.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
- 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.
12
+ This gem provides a simple way of adding event sourcing behaviour to your models class.
10
13
 
11
- Martin Fowler , https://martinfowler.com/eaaDev/EventSourcing.html
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
- - UUID Id
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
- Here an example of use:
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
- First, you must add behaviour including the AggregateRoot module
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 < SimpleEventSourcing::Events::Event
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 must be applied and recorded
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
- apply_record_event SalaryHasChangedEvent , new_salary: new_salary
104
+ on SalaryHasChangedEvent do |event|
105
+ @salary = event.new_salary
106
+ end
121
107
  ```
122
108
 
123
- SimpleEventSourcing provides a DSL to handle the applied events. You must provide a handler for each event
109
+ Now you could apply and record events.
124
110
 
125
111
  ```ruby
126
- on SalaryHasChangedEvent do |event|
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
- def save
135
- # Persist the entity
136
- publish_events { |event| SimpleEventSourcing::EventDispatcher.publish(event) }
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
- You could see this example in https://github.com/malotor/simple_event_sourcing_example
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
 
@@ -16,10 +16,9 @@ module SimpleEventSourcing
16
16
  end
17
17
 
18
18
  def publish_events
19
- @events.each do |event|
20
- yield(event)
21
- end
19
+ published_events = @events
22
20
  clear_events
21
+ published_events
23
22
  end
24
23
 
25
24
  def handle_message(message)
@@ -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.new
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
- class EventStore
3
+ module EventStore
4
+ class EventStoreBase
4
5
 
5
- def commit(event)
6
- raise StandardError "This methid must be implemented"
7
- end
6
+ def commit(event)
7
+ raise StandardError "This methid must be implemented"
8
+ end
8
9
 
9
- def get_history(aggregate_id)
10
- raise StandardError "This methid must be implemented"
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
@@ -1,3 +1,5 @@
1
+ require 'json'
2
+
1
3
  module SimpleEventSourcing
2
4
  module Events
3
5
 
@@ -1,3 +1,3 @@
1
1
  module SimpleEventSourcing
2
- VERSION = "0.7.0"
2
+ VERSION = "0.8.0"
3
3
  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.7.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-26 00:00:00.000000000 Z
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