sandthorn 1.0.0 → 1.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 +5 -5
- data/Gemfile +1 -1
- data/README.md +5 -5
- data/lib/sandthorn.rb +0 -1
- data/lib/sandthorn/aggregate_root_base.rb +15 -27
- data/lib/sandthorn/aggregate_root_marshal.rb +4 -5
- data/lib/sandthorn/version.rb +1 -1
- data/sandthorn.gemspec +1 -1
- data/spec/aggregate_delta_spec.rb +6 -13
- data/spec/aggregate_events_spec.rb +3 -3
- data/spec/aggregate_root_spec.rb +37 -41
- data/spec/complex_aggregate_spec.rb +1 -1
- data/spec/constructor_events_spec.rb +5 -5
- data/spec/default_attributes_spec.rb +3 -3
- data/spec/initialize_signature_change_spec.rb +2 -2
- data/spec/stateless_events_spec.rb +11 -7
- data/spec/tracing_spec.rb +6 -6
- metadata +4 -13
- data/lib/sandthorn/event.rb +0 -61
- data/spec/aggregate_snapshot_spec.rb +0 -263
- data/spec/different_driver_spec.rb +0 -101
- data/spec/event_inspector_spec.rb +0 -152
- data/spec/event_spec.rb +0 -99
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: eb2833dc0d8dfa96bc80089a176f2718040f1107f0305232840e3009232511bb
|
4
|
+
data.tar.gz: 1c57a94df6798dfa32a1050d105bec05ccf30e08876c0a50aa610e3f7be3ce11
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f21f398f4bbfc6ed3e23be70e294f5fbabfec60d1ed69bb03b8efd0f047d2131d9d225f4dd9794a24d45661ad6200b85364b54c50590825f0fa4bf9eb1d6759d
|
7
|
+
data.tar.gz: 027501a879da6025ffd51511e88b8affb9eb21e2e493086e143cab1faaa50e462142771a423a1e93f0d7b31f81da381869f7cfbebe5caf8a82880863c9ac9b4d
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
[](https://travis-ci.org/Sandthorn/sandthorn)
|
2
|
-
[](https://coveralls.io/r/Sandthorn/sandthorn?branch=master)
|
3
|
+
[](https://codeclimate.com/github/Sandthorn/sandthorn)
|
4
|
+
[](http://badge.fury.io/rb/sandthorn)
|
5
5
|
|
6
6
|
# Sandthorn Event Sourcing
|
7
7
|
A ruby library for saving an object's state as a series of events.
|
@@ -124,7 +124,7 @@ class Board
|
|
124
124
|
include Sandthorn::AggregateRoot
|
125
125
|
|
126
126
|
# creates a private class method `board_created`
|
127
|
-
|
127
|
+
constructor_events :board_created
|
128
128
|
|
129
129
|
def self.create name
|
130
130
|
|
@@ -137,7 +137,7 @@ end
|
|
137
137
|
|
138
138
|
### `Sandthorn::AggregateRoot::stateless_events`
|
139
139
|
|
140
|
-
Calling `stateless_events` creates public class methods. The first argument is an `aggregate_id` and the second argument is optional but has to be a hash and is stored in the
|
140
|
+
Calling `stateless_events` creates public class methods. The first argument is an `aggregate_id` and the second argument is optional but has to be a hash and is stored in the event_data of the event.
|
141
141
|
|
142
142
|
When creating a stateless event, the corresponding aggregate is never loaded and the event is saved without calling the save method.
|
143
143
|
|
data/lib/sandthorn.rb
CHANGED
@@ -118,6 +118,7 @@ module Sandthorn
|
|
118
118
|
current_aggregate_version = events.last[:aggregate_version]
|
119
119
|
aggregate.send :set_orginating_aggregate_version!, current_aggregate_version
|
120
120
|
aggregate.send :set_current_aggregate_version!, current_aggregate_version
|
121
|
+
aggregate.send :set_aggregate_id, events.first.fetch(:aggregate_id)
|
121
122
|
end
|
122
123
|
attributes = build_instance_vars_from_events events
|
123
124
|
aggregate.send :clear_aggregate_events
|
@@ -132,7 +133,7 @@ module Sandthorn
|
|
132
133
|
def stateless_events(*event_names)
|
133
134
|
event_names.each do |name|
|
134
135
|
define_singleton_method name do |aggregate_id, *args|
|
135
|
-
event = build_stateless_event(name.to_s, args)
|
136
|
+
event = build_stateless_event(aggregate_id, name.to_s, args)
|
136
137
|
Sandthorn.save_events([event], aggregate_id, self)
|
137
138
|
return aggregate_id
|
138
139
|
end
|
@@ -169,24 +170,18 @@ module Sandthorn
|
|
169
170
|
|
170
171
|
private
|
171
172
|
|
172
|
-
def build_stateless_event name, args = []
|
173
|
+
def build_stateless_event aggregate_id, name, args = []
|
173
174
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
old_value: nil,
|
178
|
-
new_value: value
|
179
|
-
}
|
175
|
+
deltas = {}
|
176
|
+
args.first.each do |key, value|
|
177
|
+
deltas[key.to_sym] = { old_value: nil, new_value: value }
|
180
178
|
end unless args.empty?
|
181
179
|
|
182
|
-
data = {
|
183
|
-
attribute_deltas: formated_attribute_deltas
|
184
|
-
}
|
185
|
-
|
186
180
|
return {
|
187
181
|
aggregate_version: nil,
|
182
|
+
aggregate_id: aggregate_id,
|
188
183
|
event_name: name,
|
189
|
-
event_data:
|
184
|
+
event_data: deltas,
|
190
185
|
event_metadata: nil
|
191
186
|
}
|
192
187
|
|
@@ -194,11 +189,11 @@ module Sandthorn
|
|
194
189
|
|
195
190
|
def build_instance_vars_from_events events
|
196
191
|
events.each_with_object({}) do |event, instance_vars|
|
197
|
-
|
198
|
-
attribute_deltas = event_data[:attribute_deltas]
|
192
|
+
attribute_deltas = event[:event_data]
|
199
193
|
unless attribute_deltas.nil?
|
200
|
-
deltas =
|
201
|
-
|
194
|
+
deltas = {}
|
195
|
+
attribute_deltas.each do |key, value|
|
196
|
+
deltas[key] = value[:new_value]
|
202
197
|
end
|
203
198
|
instance_vars.merge! deltas
|
204
199
|
end
|
@@ -220,10 +215,7 @@ module Sandthorn
|
|
220
215
|
|
221
216
|
def extract_relevant_aggregate_instance_variables
|
222
217
|
instance_variables.select do |variable|
|
223
|
-
|
224
|
-
does_not_contain_aggregate = !variable.to_s.start_with?("@aggregate_")
|
225
|
-
|
226
|
-
equals_aggregate_id || does_not_contain_aggregate
|
218
|
+
!variable.to_s.start_with?("@aggregate_")
|
227
219
|
end
|
228
220
|
end
|
229
221
|
|
@@ -252,17 +244,13 @@ module Sandthorn
|
|
252
244
|
end
|
253
245
|
|
254
246
|
def commit_with_event_name(event_name)
|
255
|
-
aggregate_attribute_deltas = get_delta
|
256
|
-
|
257
247
|
increase_current_aggregate_version!
|
258
|
-
data = {
|
259
|
-
attribute_deltas: aggregate_attribute_deltas
|
260
|
-
}
|
261
248
|
|
262
249
|
@aggregate_events << ({
|
263
250
|
aggregate_version: @aggregate_current_event_version,
|
251
|
+
aggregate_id: @aggregate_id,
|
264
252
|
event_name: event_name,
|
265
|
-
event_data:
|
253
|
+
event_data: get_delta(),
|
266
254
|
event_metadata: @aggregate_trace_information
|
267
255
|
})
|
268
256
|
|
@@ -3,7 +3,7 @@ module Sandthorn
|
|
3
3
|
module Marshal
|
4
4
|
|
5
5
|
def aggregate_initialize *args
|
6
|
-
@aggregate_attribute_deltas =
|
6
|
+
@aggregate_attribute_deltas = {}
|
7
7
|
@aggregate_stored_instance_variables = {}
|
8
8
|
end
|
9
9
|
|
@@ -20,7 +20,7 @@ module Sandthorn
|
|
20
20
|
def get_delta
|
21
21
|
deltas = extract_relevant_aggregate_instance_variables
|
22
22
|
deltas.each { |d| delta_attribute(d) }
|
23
|
-
|
23
|
+
|
24
24
|
result = @aggregate_attribute_deltas
|
25
25
|
clear_aggregate_deltas
|
26
26
|
result
|
@@ -42,8 +42,7 @@ module Sandthorn
|
|
42
42
|
new_value_to_store = ::Marshal.load(new_dump)
|
43
43
|
old_value_to_store = old_dump ? ::Marshal.load(old_dump) : nil
|
44
44
|
|
45
|
-
@aggregate_attribute_deltas
|
46
|
-
attribute_name: attribute_name.to_s.delete("@"),
|
45
|
+
@aggregate_attribute_deltas[attribute_name.to_s.delete("@").to_sym] = {
|
47
46
|
old_value: old_value_to_store,
|
48
47
|
new_value: new_value_to_store
|
49
48
|
}
|
@@ -54,7 +53,7 @@ module Sandthorn
|
|
54
53
|
end
|
55
54
|
|
56
55
|
def clear_aggregate_deltas
|
57
|
-
@aggregate_attribute_deltas =
|
56
|
+
@aggregate_attribute_deltas = {}
|
58
57
|
end
|
59
58
|
end
|
60
59
|
end
|
data/lib/sandthorn/version.rb
CHANGED
data/sandthorn.gemspec
CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
|
|
10
10
|
spec.email = ["lars.krantz@alaz.se", "morgan.hallgren@gmail.com", "jesper.josefsson@gmail.com"]
|
11
11
|
spec.description = %q{Event sourcing gem}
|
12
12
|
spec.summary = %q{Event sourcing gem}
|
13
|
-
spec.homepage = ""
|
13
|
+
spec.homepage = "https://github.com/Sandthorn/sandthorn"
|
14
14
|
spec.license = "MIT"
|
15
15
|
|
16
16
|
spec.files = `git ls-files`.split($/)
|
@@ -1,7 +1,5 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
3
|
class PersonTest
|
6
4
|
include Sandthorn::AggregateRoot
|
7
5
|
attr_reader :name
|
@@ -44,15 +42,14 @@ describe 'Property Delta Event Sourcing' do
|
|
44
42
|
|
45
43
|
it 'should be able to set name' do
|
46
44
|
person.change_name "Klabbarparen"
|
47
|
-
expect(person.name).to
|
48
|
-
#puts person.aggregate_events
|
45
|
+
expect(person.name).to eq("Klabbarparen")
|
49
46
|
end
|
50
47
|
|
51
48
|
it 'should be able to build from events' do
|
52
49
|
person.change_name "Klabbarparen"
|
53
50
|
builded = PersonTest.aggregate_build person.aggregate_events
|
54
|
-
expect(builded.name).to
|
55
|
-
expect(builded.aggregate_id).to
|
51
|
+
expect(builded.name).to eq(person.name)
|
52
|
+
expect(builded.aggregate_id).to eq(person.aggregate_id)
|
56
53
|
end
|
57
54
|
|
58
55
|
it 'should not have any events when built up' do
|
@@ -75,16 +72,12 @@ describe 'Property Delta Event Sourcing' do
|
|
75
72
|
person.add_to_hash :bar, "foo"
|
76
73
|
|
77
74
|
builded = PersonTest.aggregate_build person.aggregate_events
|
78
|
-
expect(builded.my_hash[:foo]).to
|
79
|
-
expect(builded.my_hash[:bar]).to
|
75
|
+
expect(builded.my_hash[:foo]).to eq("bar")
|
76
|
+
expect(builded.my_hash[:bar]).to eq("foo")
|
80
77
|
|
81
78
|
person.add_to_hash :foo, "BAR"
|
82
79
|
|
83
|
-
#events = person.aggregate_events
|
84
|
-
#events << builded.aggregate_events
|
85
|
-
#puts events
|
86
|
-
|
87
80
|
builded2 = PersonTest.aggregate_build person.aggregate_events
|
88
|
-
expect(builded2.my_hash[:foo]).to
|
81
|
+
expect(builded2.my_hash[:foo]).to eq("BAR")
|
89
82
|
end
|
90
83
|
end
|
@@ -44,7 +44,7 @@ module Sandthorn
|
|
44
44
|
end
|
45
45
|
|
46
46
|
it "should set the name instance variable" do
|
47
|
-
expect(subject.name).to
|
47
|
+
expect(subject.name).to eq("new name")
|
48
48
|
end
|
49
49
|
|
50
50
|
it "should store the event params as methods args" do
|
@@ -52,11 +52,11 @@ module Sandthorn
|
|
52
52
|
end
|
53
53
|
|
54
54
|
it "should store the args to the event" do
|
55
|
-
expect(subject.aggregate_events[1][:event_data][:
|
55
|
+
expect(subject.aggregate_events[1][:event_data][:name][:new_value]).to eq("new name")
|
56
56
|
end
|
57
57
|
|
58
58
|
it "should store the event_name" do
|
59
|
-
expect(subject.aggregate_events[1][:event_name]).to
|
59
|
+
expect(subject.aggregate_events[1][:event_name]).to eq("name_changed")
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
data/spec/aggregate_root_spec.rb
CHANGED
@@ -5,12 +5,12 @@ module Sandthorn
|
|
5
5
|
class DirtyClass
|
6
6
|
include Sandthorn::AggregateRoot
|
7
7
|
attr_reader :name, :age
|
8
|
-
attr :
|
8
|
+
attr :age
|
9
9
|
attr_writer :writer
|
10
10
|
|
11
11
|
def initialize args = {}
|
12
12
|
@name = args.fetch(:name, nil)
|
13
|
-
@
|
13
|
+
@age = args.fetch(:age, nil)
|
14
14
|
@writer = args.fetch(:writer, nil)
|
15
15
|
end
|
16
16
|
|
@@ -21,9 +21,9 @@ module Sandthorn
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
-
def
|
25
|
-
unless
|
26
|
-
@
|
24
|
+
def change_age value
|
25
|
+
unless age == value
|
26
|
+
@age = value
|
27
27
|
commit
|
28
28
|
end
|
29
29
|
end
|
@@ -64,7 +64,7 @@ module Sandthorn
|
|
64
64
|
|
65
65
|
context "all" do
|
66
66
|
it "should all the aggregates" do
|
67
|
-
expect(subject.length).to
|
67
|
+
expect(subject.length).to eq(3)
|
68
68
|
end
|
69
69
|
|
70
70
|
it "should include correct aggregates" do
|
@@ -83,10 +83,10 @@ module Sandthorn
|
|
83
83
|
|
84
84
|
context "new with args" do
|
85
85
|
|
86
|
-
let(:subject) { DirtyClass.new(name: "Mogge",
|
86
|
+
let(:subject) { DirtyClass.new(name: "Mogge", age: 35, writer: true) }
|
87
87
|
it "should set the values" do
|
88
|
-
expect(subject.name).to
|
89
|
-
expect(subject.
|
88
|
+
expect(subject.name).to eq("Mogge")
|
89
|
+
expect(subject.age).to eq(35)
|
90
90
|
expect{subject.writer}.to raise_error NoMethodError
|
91
91
|
end
|
92
92
|
end
|
@@ -95,23 +95,23 @@ module Sandthorn
|
|
95
95
|
|
96
96
|
it "should get new_name" do
|
97
97
|
dirty_object.change_name "new_name"
|
98
|
-
expect(dirty_object.name).to
|
98
|
+
expect(dirty_object.name).to eq("new_name")
|
99
99
|
end
|
100
100
|
|
101
101
|
it "should generate one event on new" do
|
102
|
-
expect(dirty_object.aggregate_events.length).to
|
102
|
+
expect(dirty_object.aggregate_events.length).to eq(1)
|
103
103
|
end
|
104
104
|
|
105
105
|
it "should generate 2 events new and change_name" do
|
106
106
|
dirty_object.change_name "new_name"
|
107
|
-
expect(dirty_object.aggregate_events.length).to
|
107
|
+
expect(dirty_object.aggregate_events.length).to eq(2)
|
108
108
|
end
|
109
109
|
end
|
110
110
|
|
111
|
-
context "when changing
|
112
|
-
it "should get
|
113
|
-
dirty_object.
|
114
|
-
expect(dirty_object.
|
111
|
+
context "when changing age (attr)" do
|
112
|
+
it "should get new_age" do
|
113
|
+
dirty_object.change_age "new_age"
|
114
|
+
expect(dirty_object.age).to eq("new_age")
|
115
115
|
end
|
116
116
|
end
|
117
117
|
|
@@ -123,27 +123,27 @@ module Sandthorn
|
|
123
123
|
|
124
124
|
context "save" do
|
125
125
|
it "should not have events on aggregate after save" do
|
126
|
-
expect(dirty_object.save.aggregate_events.length).to
|
126
|
+
expect(dirty_object.save.aggregate_events.length).to eq(0)
|
127
127
|
end
|
128
128
|
|
129
129
|
it "should have aggregate_originating_version == 0 pre save" do
|
130
|
-
expect(dirty_object.aggregate_originating_version).to
|
130
|
+
expect(dirty_object.aggregate_originating_version).to eq(0)
|
131
131
|
end
|
132
132
|
|
133
133
|
it "should have aggregate_originating_version == 1 post save" do
|
134
|
-
expect(dirty_object.save.aggregate_originating_version).to
|
134
|
+
expect(dirty_object.save.aggregate_originating_version).to eq(1)
|
135
135
|
end
|
136
136
|
end
|
137
137
|
|
138
138
|
context "find" do
|
139
139
|
before(:each) { dirty_object.save }
|
140
140
|
it "should find by id" do
|
141
|
-
expect(DirtyClass.find(dirty_object.id).id).to
|
141
|
+
expect(DirtyClass.find(dirty_object.id).id).to eq(dirty_object.id)
|
142
142
|
end
|
143
143
|
|
144
144
|
it "should hold changed name" do
|
145
145
|
dirty_object.change_name("morgan").save
|
146
|
-
expect(DirtyClass.find(dirty_object.id).name).to
|
146
|
+
expect(DirtyClass.find(dirty_object.id).name).to eq("morgan")
|
147
147
|
end
|
148
148
|
|
149
149
|
it "should raise error if trying to find id that not exist" do
|
@@ -157,7 +157,7 @@ module Sandthorn
|
|
157
157
|
describe "event data" do
|
158
158
|
|
159
159
|
let(:dirty_object) {
|
160
|
-
o = DirtyClass.new :name => "old_value", :
|
160
|
+
o = DirtyClass.new :name => "old_value", :age => 35
|
161
161
|
o.save
|
162
162
|
}
|
163
163
|
|
@@ -167,7 +167,7 @@ module Sandthorn
|
|
167
167
|
|
168
168
|
it "should set the old_value on the event" do
|
169
169
|
dirty_object_after_find.change_name "new_name"
|
170
|
-
expect(dirty_object_after_find.aggregate_events.last[:event_data][:
|
170
|
+
expect(dirty_object_after_find.aggregate_events.last[:event_data][:name][:old_value]).to eq("old_value")
|
171
171
|
end
|
172
172
|
|
173
173
|
end
|
@@ -176,36 +176,32 @@ module Sandthorn
|
|
176
176
|
|
177
177
|
it "should set the old_value on the event" do
|
178
178
|
dirty_object.change_name "new_name"
|
179
|
-
expect(dirty_object.aggregate_events.last[:event_data][:
|
179
|
+
expect(dirty_object.aggregate_events.last[:event_data][:name][:old_value]).to eq("old_value")
|
180
180
|
end
|
181
181
|
|
182
182
|
it "should not change aggregate_id" do
|
183
183
|
dirty_object.change_name "new_name"
|
184
|
-
expect(dirty_object.aggregate_events.last[:event_data][
|
184
|
+
expect(dirty_object.aggregate_events.last[:event_data]["attribute_name"]).not_to eq("aggregate_id")
|
185
185
|
end
|
186
186
|
|
187
|
-
it "should not change
|
187
|
+
it "should not change age attribute if age method is not runned" do
|
188
188
|
dirty_object.change_name "new_name"
|
189
189
|
dirty_object.aggregate_events.each do |event|
|
190
|
-
event[:event_data][
|
191
|
-
expect(attribute_delta[:attribute_name]).not_to eql "sex"
|
192
|
-
end
|
190
|
+
expect(event[:event_data]["age"].nil?).to be_truthy
|
193
191
|
end
|
194
192
|
end
|
195
193
|
|
196
|
-
it "should not change
|
197
|
-
dirty_object.
|
194
|
+
it "should not change age attribute if age attribute is the same" do
|
195
|
+
dirty_object.change_age 35
|
198
196
|
dirty_object.aggregate_events.each do |event|
|
199
|
-
event[:event_data][
|
200
|
-
expect(attribute_delta[:attribute_name]).not_to eql "sex"
|
201
|
-
end
|
197
|
+
expect(event[:event_data]["age"].nil?).to be_truthy
|
202
198
|
end
|
203
199
|
end
|
204
200
|
|
205
|
-
it "should set old_value and new_value on
|
206
|
-
dirty_object.
|
207
|
-
expect(dirty_object.aggregate_events.last[:event_data][:
|
208
|
-
expect(dirty_object.aggregate_events.last[:event_data][:
|
201
|
+
it "should set old_value and new_value on age change" do
|
202
|
+
dirty_object.change_age 36
|
203
|
+
expect(dirty_object.aggregate_events.last[:event_data][:age][:old_value]).to eq(35)
|
204
|
+
expect(dirty_object.aggregate_events.last[:event_data][:age][:new_value]).to eq(36)
|
209
205
|
end
|
210
206
|
end
|
211
207
|
end
|
@@ -218,11 +214,11 @@ module Sandthorn
|
|
218
214
|
end
|
219
215
|
|
220
216
|
it "should have the event no_state_change_only_empty_event" do
|
221
|
-
expect(dirty_object.aggregate_events.first[:event_name]).to
|
217
|
+
expect(dirty_object.aggregate_events.first[:event_name]).to eq("no_state_change_only_empty_event")
|
222
218
|
end
|
223
219
|
|
224
|
-
it "should have
|
225
|
-
expect(dirty_object.aggregate_events.first[:event_data]
|
220
|
+
it "should have event_data set to empty hash" do
|
221
|
+
expect(dirty_object.aggregate_events.first[:event_data]).to eq({})
|
226
222
|
end
|
227
223
|
|
228
224
|
end
|