sandthorn 0.10.3 → 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +1 -1
- data/README.md +11 -10
- data/lib/sandthorn.rb +3 -68
- data/lib/sandthorn/aggregate_root_base.rb +15 -34
- data/lib/sandthorn/aggregate_root_snapshot.rb +1 -30
- data/lib/sandthorn/version.rb +1 -1
- data/sandthorn.gemspec +1 -1
- data/spec/aggregate_root_spec.rb +4 -4
- data/spec/aggregate_snapshot_spec.rb +3 -12
- data/spec/spec_helper.rb +9 -6
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3a2f65aa6777c6570a39697fe0dd6edcbc5fe17d
|
4
|
+
data.tar.gz: 0a72c05d0fef7caf7c752bb24472a643b51b2854
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a3afc677df878cb3ae51f27e3b2beb37e82d549992a0915ffcedeccdcfcbe058780b525d4c593d508495063fa2e093e74d0252846bc3bcd7fd6ccb3e3236ea66
|
7
|
+
data.tar.gz: 3b6a3637a931aedab5c8b1a18f76100b945ee9e84fe8dc83a0f44322e8c91cb927b40d3335720a6b08fefab0465918c4be09304915fe641cef3843b2e64f37b5
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -182,20 +182,21 @@ Sandthorn.configure do |conf|
|
|
182
182
|
end
|
183
183
|
```
|
184
184
|
|
185
|
-
## Data serialization
|
185
|
+
## Data serialization
|
186
186
|
|
187
|
-
Its possible to configure how events and snapshots are serialized
|
187
|
+
Its possible to configure how events and snapshots are serialized. Since version `0.11.0` of Sandthorn the serialization of events and snapshots is the responsibility of the driver. This means drivers can have different serialization mechanism, independent of each other.
|
188
|
+
|
189
|
+
The default serializer of the Sequel driver is YAML.
|
190
|
+
|
191
|
+
Here's how to use the Oj gem to serialize data in the Sequel driver:
|
188
192
|
|
189
193
|
```ruby
|
190
|
-
|
191
|
-
conf.
|
192
|
-
conf.
|
193
|
-
|
194
|
-
conf.snapshot_deserializer = Proc.new { |data| Oj::load(data) }
|
195
|
-
end
|
194
|
+
oj_driver = SandthornDriverSequel.driver_from_connection(connection: Sequel.sqlite) { |conf|
|
195
|
+
conf.event_serializer = Proc.new { |data| Oj::dump(data) }
|
196
|
+
conf.event_deserializer = Proc.new { |data| Oj::load(data) }
|
197
|
+
}
|
196
198
|
```
|
197
199
|
|
198
|
-
|
199
200
|
# Usage
|
200
201
|
|
201
202
|
## Aggregate Root
|
@@ -238,7 +239,7 @@ end
|
|
238
239
|
|
239
240
|
Its possible to add a default_attributes method on an aggregate and set default values to new and already created aggregates.
|
240
241
|
|
241
|
-
The default_attributes method will be run before initialize on Class.new and before the events when an aggregate is rebuilt. This will make is possible to add default attributes to an aggregate during its hole life cycle.
|
242
|
+
The `default_attributes` method will be run before initialize on Class.new and before the events when an aggregate is rebuilt. This will make is possible to add default attributes to an aggregate during its hole life cycle.
|
242
243
|
|
243
244
|
```ruby
|
244
245
|
def default_attributes
|
data/lib/sandthorn.rb
CHANGED
@@ -10,7 +10,7 @@ module Sandthorn
|
|
10
10
|
class << self
|
11
11
|
extend Forwardable
|
12
12
|
|
13
|
-
def_delegators :configuration, :event_stores
|
13
|
+
def_delegators :configuration, :event_stores
|
14
14
|
|
15
15
|
def default_event_store
|
16
16
|
event_stores.default_store
|
@@ -28,8 +28,6 @@ module Sandthorn
|
|
28
28
|
@configuration ||= Configuration.new
|
29
29
|
end
|
30
30
|
|
31
|
-
|
32
|
-
|
33
31
|
def generate_aggregate_id
|
34
32
|
SecureRandom.uuid
|
35
33
|
end
|
@@ -46,12 +44,8 @@ module Sandthorn
|
|
46
44
|
event_store_for(aggregate_type).get_aggregate_events_from_snapshot aggregate_id
|
47
45
|
end
|
48
46
|
|
49
|
-
def save_snapshot(
|
50
|
-
|
51
|
-
aggregate_snapshot: missing_key(:aggregate_snapshot),
|
52
|
-
aggregate_id: missing_key(:aggregate_id)
|
53
|
-
)
|
54
|
-
event_store_for(aggregate_type).save_snapshot(aggregate_snapshot, aggregate_id)
|
47
|
+
def save_snapshot(aggregate)
|
48
|
+
event_store_for(aggregate.class).save_snapshot(aggregate)
|
55
49
|
end
|
56
50
|
|
57
51
|
def get_aggregate_list_by_type aggregate_type
|
@@ -62,8 +56,6 @@ module Sandthorn
|
|
62
56
|
event_store = find_event_store(event_store)
|
63
57
|
events = event_store.get_events aggregate_types: aggregate_types, take: take, after_sequence_number: after_sequence_number
|
64
58
|
events.map do |event|
|
65
|
-
event[:event_args] = deserialize event[:event_data]
|
66
|
-
event.delete(:event_data)
|
67
59
|
Event.new(event)
|
68
60
|
end
|
69
61
|
end
|
@@ -111,67 +103,10 @@ module Sandthorn
|
|
111
103
|
@event_stores = EventStores.new(store)
|
112
104
|
end
|
113
105
|
|
114
|
-
def serializer=(block)
|
115
|
-
@serializer = block if block.is_a? Proc
|
116
|
-
end
|
117
|
-
|
118
|
-
def deserializer=(block)
|
119
|
-
@deserializer = block if block.is_a? Proc
|
120
|
-
end
|
121
|
-
|
122
|
-
def serializer
|
123
|
-
@serializer || default_serializer
|
124
|
-
end
|
125
|
-
|
126
|
-
def deserializer
|
127
|
-
@deserializer || default_deserializer
|
128
|
-
end
|
129
|
-
|
130
|
-
def default_serializer
|
131
|
-
-> (data) { YAML.dump(data) }
|
132
|
-
end
|
133
|
-
|
134
|
-
def default_deserializer
|
135
|
-
-> (data) { YAML.load(data) }
|
136
|
-
end
|
137
|
-
|
138
|
-
def serialize(data)
|
139
|
-
serializer.call(data)
|
140
|
-
end
|
141
|
-
|
142
|
-
def deserialize(data)
|
143
|
-
deserializer.call(data)
|
144
|
-
end
|
145
|
-
|
146
|
-
def snapshot_serializer=(block)
|
147
|
-
@snapshot_serializer = block if block.is_a? Proc
|
148
|
-
end
|
149
|
-
|
150
|
-
def snapshot_deserializer=(block)
|
151
|
-
@snapshot_deserializer = block if block.is_a? Proc
|
152
|
-
end
|
153
|
-
|
154
|
-
def snapshot_serializer
|
155
|
-
@snapshot_serializer || default_serializer
|
156
|
-
end
|
157
|
-
|
158
|
-
def snapshot_deserializer
|
159
|
-
@snapshot_deserializer || default_deserializer
|
160
|
-
end
|
161
|
-
|
162
|
-
def serialize_snapshot(data)
|
163
|
-
snapshot_serializer.call(data)
|
164
|
-
end
|
165
|
-
|
166
|
-
def deserialize_snapshot data
|
167
|
-
snapshot_deserializer.call(data)
|
168
|
-
end
|
169
|
-
|
170
106
|
def map_types= data
|
171
107
|
@event_stores.map_types data
|
172
108
|
end
|
173
109
|
|
174
|
-
|
175
110
|
alias_method :event_stores=, :event_store=
|
176
111
|
end
|
177
112
|
end
|
@@ -10,6 +10,7 @@ module Sandthorn
|
|
10
10
|
attr_reader :aggregate_trace_information
|
11
11
|
|
12
12
|
alias :id :aggregate_id
|
13
|
+
alias :aggregate_version :aggregate_current_event_version
|
13
14
|
|
14
15
|
|
15
16
|
def aggregate_base_initialize
|
@@ -19,12 +20,7 @@ module Sandthorn
|
|
19
20
|
end
|
20
21
|
|
21
22
|
def save
|
22
|
-
aggregate_events.
|
23
|
-
event[:event_data] = Sandthorn.serialize event[:event_args]
|
24
|
-
event[:event_args] = nil #Not send extra data over the wire
|
25
|
-
end
|
26
|
-
|
27
|
-
unless aggregate_events.empty?
|
23
|
+
if aggregate_events.any?
|
28
24
|
Sandthorn.save_events(
|
29
25
|
aggregate_events,
|
30
26
|
aggregate_id,
|
@@ -90,26 +86,17 @@ module Sandthorn
|
|
90
86
|
unless events && !events.empty?
|
91
87
|
raise Sandthorn::Errors::AggregateNotFound
|
92
88
|
end
|
93
|
-
|
94
|
-
if first_event_snapshot?(events)
|
95
|
-
transformed_snapshot_event = events.first.merge(event_args: Sandthorn.deserialize_snapshot(events.first[:event_data]))
|
96
|
-
events.shift
|
97
|
-
end
|
98
89
|
|
99
|
-
|
100
|
-
e.merge(event_args: Sandthorn.deserialize(e[:event_data]))
|
101
|
-
end
|
102
|
-
aggregate_build ([transformed_snapshot_event] + transformed_events).compact
|
90
|
+
aggregate_build events
|
103
91
|
end
|
104
92
|
|
105
93
|
def new *args, &block
|
106
|
-
|
107
|
-
aggregate = allocate
|
94
|
+
aggregate = create_new_empty_aggregate()
|
108
95
|
aggregate.aggregate_base_initialize
|
109
96
|
aggregate.aggregate_initialize
|
110
97
|
|
111
98
|
aggregate.default_attributes
|
112
|
-
aggregate.send :initialize, *args, &block
|
99
|
+
aggregate.send :initialize, *args, &block
|
113
100
|
aggregate.send :set_aggregate_id, Sandthorn.generate_aggregate_id
|
114
101
|
|
115
102
|
aggregate.aggregate_trace @@aggregate_trace_information do |aggr|
|
@@ -119,27 +106,26 @@ module Sandthorn
|
|
119
106
|
|
120
107
|
end
|
121
108
|
|
122
|
-
|
123
|
-
|
124
109
|
def aggregate_build events
|
125
|
-
current_aggregate_version = 0
|
126
|
-
|
127
110
|
if first_event_snapshot?(events)
|
128
|
-
aggregate =
|
129
|
-
current_aggregate_version = aggregate.aggregate_originating_version
|
111
|
+
aggregate = events.first[:aggregate]
|
130
112
|
events.shift
|
131
113
|
else
|
132
114
|
aggregate = create_new_empty_aggregate
|
133
115
|
end
|
134
116
|
|
117
|
+
if events.any?
|
118
|
+
current_aggregate_version = events.last[:aggregate_version]
|
119
|
+
aggregate.send :set_orginating_aggregate_version!, current_aggregate_version
|
120
|
+
aggregate.send :set_current_aggregate_version!, current_aggregate_version
|
121
|
+
end
|
122
|
+
|
135
123
|
attributes = build_instance_vars_from_events events
|
136
|
-
current_aggregate_version = events.last[:aggregate_version] unless events.empty?
|
137
124
|
aggregate.send :clear_aggregate_events
|
125
|
+
|
138
126
|
aggregate.default_attributes
|
139
|
-
aggregate.send :set_orginating_aggregate_version!, current_aggregate_version
|
140
|
-
aggregate.send :set_current_aggregate_version!, current_aggregate_version
|
141
127
|
aggregate.send :aggregate_initialize
|
142
|
-
|
128
|
+
|
143
129
|
aggregate.send :set_instance_variables!, attributes
|
144
130
|
aggregate
|
145
131
|
end
|
@@ -159,7 +145,6 @@ module Sandthorn
|
|
159
145
|
def build_instance_vars_from_events events
|
160
146
|
events.each_with_object({}) do |event, instance_vars|
|
161
147
|
event_args = event[:event_args]
|
162
|
-
event_name = event[:event_name]
|
163
148
|
attribute_deltas = event_args[:attribute_deltas]
|
164
149
|
unless attribute_deltas.nil?
|
165
150
|
deltas = attribute_deltas.each_with_object({}) do |delta, acc|
|
@@ -171,11 +156,7 @@ module Sandthorn
|
|
171
156
|
end
|
172
157
|
|
173
158
|
def first_event_snapshot? events
|
174
|
-
events.first[:
|
175
|
-
end
|
176
|
-
|
177
|
-
def start_build_from_snapshot events
|
178
|
-
snapshot = events.first[:event_args][0]
|
159
|
+
events.first[:aggregate]
|
179
160
|
end
|
180
161
|
|
181
162
|
def create_new_empty_aggregate
|
@@ -13,39 +13,10 @@ module Sandthorn
|
|
13
13
|
raise Errors::SnapshotError,
|
14
14
|
"Can't take snapshot on object with unsaved events"
|
15
15
|
end
|
16
|
-
|
17
|
-
@aggregate_snapshot = {
|
18
|
-
event_name: "aggregate_set_from_snapshot",
|
19
|
-
event_args: [self],
|
20
|
-
aggregate_version: @aggregate_current_event_version
|
21
|
-
}
|
22
16
|
end
|
23
17
|
|
24
18
|
def save_snapshot
|
25
|
-
|
26
|
-
raise Errors::SnapshotError, "No snapshot has been created!"
|
27
|
-
end
|
28
|
-
@aggregate_snapshot[:event_data] = Sandthorn.serialize_snapshot @aggregate_snapshot[:event_args]
|
29
|
-
@aggregate_snapshot[:event_args] = nil
|
30
|
-
Sandthorn.save_snapshot(aggregate_snapshot: @aggregate_snapshot, aggregate_id: @aggregate_id, aggregate_type: self.class)
|
31
|
-
@aggregate_snapshot = nil
|
32
|
-
end
|
33
|
-
private
|
34
|
-
def aggregate_create_event_when_extended
|
35
|
-
self.aggregate_snapshot!
|
36
|
-
vars = extract_relevant_aggregate_instance_variables
|
37
|
-
vars.each do |var_name|
|
38
|
-
value = instance_variable_get var_name
|
39
|
-
dump = Marshal.dump(value)
|
40
|
-
store_aggregate_instance_variable var_name, dump
|
41
|
-
end
|
42
|
-
|
43
|
-
@aggregate_snapshot[:event_data] = Sandthorn
|
44
|
-
.serialize_snapshot aggregate_snapshot[:event_args]
|
45
|
-
|
46
|
-
@aggregate_snapshot[:event_args] = nil
|
47
|
-
Sandthorn.save_snapshot aggregate_snapshot, aggregate_id
|
48
|
-
@aggregate_snapshot = nil
|
19
|
+
Sandthorn.save_snapshot(self)
|
49
20
|
end
|
50
21
|
end
|
51
22
|
end
|
data/lib/sandthorn/version.rb
CHANGED
data/sandthorn.gemspec
CHANGED
@@ -30,5 +30,5 @@ Gem::Specification.new do |spec|
|
|
30
30
|
spec.add_development_dependency "autotest-standalone"
|
31
31
|
spec.add_development_dependency "sqlite3"
|
32
32
|
spec.add_development_dependency "coveralls"
|
33
|
-
spec.add_development_dependency "sandthorn_driver_sequel", "
|
33
|
+
spec.add_development_dependency "sandthorn_driver_sequel", ">= 3.0"
|
34
34
|
end
|
data/spec/aggregate_root_spec.rb
CHANGED
@@ -87,7 +87,7 @@ module Sandthorn
|
|
87
87
|
it "should set the values" do
|
88
88
|
expect(subject.name).to eql "Mogge"
|
89
89
|
expect(subject.sex).to eql "hen"
|
90
|
-
expect{subject.writer}.to raise_error
|
90
|
+
expect{subject.writer}.to raise_error NoMethodError
|
91
91
|
end
|
92
92
|
end
|
93
93
|
|
@@ -117,12 +117,12 @@ module Sandthorn
|
|
117
117
|
|
118
118
|
context "when changing writer (attr_writer)" do
|
119
119
|
it "should raise error" do
|
120
|
-
expect{dirty_object.change_writer "new_writer"}.to raise_error
|
120
|
+
expect{dirty_object.change_writer "new_writer"}.to raise_error NameError
|
121
121
|
end
|
122
122
|
end
|
123
123
|
|
124
124
|
context "save" do
|
125
|
-
it "should not have events on
|
125
|
+
it "should not have events on aggregate after save" do
|
126
126
|
expect(dirty_object.save.aggregate_events.length).to eql 0
|
127
127
|
end
|
128
128
|
|
@@ -147,7 +147,7 @@ module Sandthorn
|
|
147
147
|
end
|
148
148
|
|
149
149
|
it "should raise error if trying to find id that not exist" do
|
150
|
-
expect{DirtyClass.find("666")}.to raise_error
|
150
|
+
expect{DirtyClass.find("666")}.to raise_error Sandthorn::Errors::AggregateNotFound
|
151
151
|
end
|
152
152
|
end
|
153
153
|
|
@@ -185,17 +185,10 @@ describe 'when generating state on an aggregate root' do
|
|
185
185
|
expect(@account.unpaid_interest_balance).to be > 1000
|
186
186
|
end
|
187
187
|
|
188
|
-
it 'should store snapshot data in aggregate_snapshot' do
|
189
|
-
expect(@account.aggregate_snapshot).to be_a(Hash)
|
190
|
-
end
|
191
|
-
|
192
|
-
it 'should store aggregate_version in aggregate_snapshot' do
|
193
|
-
expect(@account.aggregate_snapshot[:aggregate_version]).to eql(@original_account.aggregate_current_event_version)
|
194
|
-
end
|
195
188
|
|
196
189
|
it 'should be able to load up from snapshot' do
|
197
190
|
|
198
|
-
events = [@account
|
191
|
+
events = [aggregate: @account]
|
199
192
|
loaded = BankAccount.aggregate_build events
|
200
193
|
|
201
194
|
expect(loaded.balance).to eql(@original_account.balance)
|
@@ -227,9 +220,7 @@ end
|
|
227
220
|
|
228
221
|
describe 'when saving to repository' do
|
229
222
|
let(:account) {a_test_account.extend Sandthorn::AggregateRootSnapshot}
|
230
|
-
|
231
|
-
expect(lambda {account.save_snapshot}).to raise_error (Sandthorn::Errors::SnapshotError)
|
232
|
-
end
|
223
|
+
|
233
224
|
it 'should not raise an error if snapshot was created' do
|
234
225
|
account.save
|
235
226
|
account.aggregate_snapshot!
|
@@ -243,7 +234,7 @@ describe 'when saving to repository' do
|
|
243
234
|
end
|
244
235
|
|
245
236
|
it 'should raise error if trying to create snapshot before events are saved on object' do
|
246
|
-
expect(lambda {account.aggregate_snapshot!}).to raise_error
|
237
|
+
expect(lambda {account.aggregate_snapshot!}).to raise_error Sandthorn::Errors::SnapshotError
|
247
238
|
end
|
248
239
|
|
249
240
|
it 'should not raise an error if trying to create snapshot on object when events are saved' do
|
data/spec/spec_helper.rb
CHANGED
@@ -40,14 +40,17 @@ def spec_db
|
|
40
40
|
"sqlite://spec/db/sequel_driver.sqlite3"
|
41
41
|
end
|
42
42
|
def sqlite_store_setup
|
43
|
-
url = spec_db
|
44
|
-
|
43
|
+
url = spec_db
|
44
|
+
|
45
|
+
driver = SandthornDriverSequel.driver_from_url(url: url) do |conf|
|
46
|
+
conf.event_serializer = Proc.new { |data| YAML::dump(data) }
|
47
|
+
conf.event_deserializer = Proc.new { |data| YAML::load(data) }
|
48
|
+
conf.snapshot_serializer = Proc.new { |data| YAML::dump(data) }
|
49
|
+
conf.snapshot_deserializer = Proc.new { |data| YAML::load(data) }
|
50
|
+
end
|
51
|
+
|
45
52
|
Sandthorn.configure do |c|
|
46
53
|
c.event_store = driver
|
47
|
-
c.serializer = Proc.new { |data| YAML::dump(data) }
|
48
|
-
c.deserializer = Proc.new { |data| YAML::load(data) }
|
49
|
-
c.snapshot_serializer = Proc.new { |data| YAML::dump(data) }
|
50
|
-
c.snapshot_deserializer = Proc.new { |data| YAML::load(data) }
|
51
54
|
end
|
52
55
|
migrator = SandthornDriverSequel::Migration.new url: url
|
53
56
|
SandthornDriverSequel.migrate_db url: url
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sandthorn
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.11.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lars Krantz
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2016-
|
13
|
+
date: 2016-02-11 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: bundler
|
@@ -156,16 +156,16 @@ dependencies:
|
|
156
156
|
name: sandthorn_driver_sequel
|
157
157
|
requirement: !ruby/object:Gem::Requirement
|
158
158
|
requirements:
|
159
|
-
- - "
|
159
|
+
- - ">="
|
160
160
|
- !ruby/object:Gem::Version
|
161
|
-
version: '
|
161
|
+
version: '3.0'
|
162
162
|
type: :development
|
163
163
|
prerelease: false
|
164
164
|
version_requirements: !ruby/object:Gem::Requirement
|
165
165
|
requirements:
|
166
|
-
- - "
|
166
|
+
- - ">="
|
167
167
|
- !ruby/object:Gem::Version
|
168
|
-
version: '
|
168
|
+
version: '3.0'
|
169
169
|
description: Event sourcing gem
|
170
170
|
email:
|
171
171
|
- lars.krantz@alaz.se
|