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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: d4f14306b2c1c46da7b99ce8409f6e69dcddf050
4
- data.tar.gz: 87dc839602892021e7aa13b2830bedbb1cc90891
2
+ SHA256:
3
+ metadata.gz: eb2833dc0d8dfa96bc80089a176f2718040f1107f0305232840e3009232511bb
4
+ data.tar.gz: 1c57a94df6798dfa32a1050d105bec05ccf30e08876c0a50aa610e3f7be3ce11
5
5
  SHA512:
6
- metadata.gz: 627da016b372e4f64e452c7bd3a6a8b69412f11e43b2f885e46b1aff6593d4cc73db78521761d5ef2f670ff238836b17a9e25d36208db37830670b38b30fea41
7
- data.tar.gz: a6db0ce8921f77bfeccf4fca94ba3ba2228f5f00d73318c445d5b3a60f9b8d7df98e3bfca6475bc27df9ff60a5704d3e51a0f46afeb8094bb0087bcd5a2b697a
6
+ metadata.gz: f21f398f4bbfc6ed3e23be70e294f5fbabfec60d1ed69bb03b8efd0f047d2131d9d225f4dd9794a24d45661ad6200b85364b54c50590825f0fa4bf9eb1d6759d
7
+ data.tar.gz: 027501a879da6025ffd51511e88b8affb9eb21e2e493086e143cab1faaa50e462142771a423a1e93f0d7b31f81da381869f7cfbebe5caf8a82880863c9ac9b4d
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in sandthorn.gemspec
4
- gemspec
4
+ gemspec
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  [![Build Status](https://travis-ci.org/Sandthorn/sandthorn.svg?branch=master)](https://travis-ci.org/Sandthorn/sandthorn)
2
- [![Coverage Status](https://coveralls.io/repos/Sandthorn/sandthorn/badge.png?branch=master)](https://coveralls.io/r/Sandthorn/sandthorn?branch=master)
3
- [![Code Climate](https://codeclimate.com/github/Sandthorn/sandthorn.png)](https://codeclimate.com/github/Sandthorn/sandthorn)
4
- [![Gem Version](https://badge.fury.io/rb/sandthorn.png)](http://badge.fury.io/rb/sandthorn)
2
+ [![Coverage Status](https://coveralls.io/repos/Sandthorn/sandthorn/badge.svg?branch=master)](https://coveralls.io/r/Sandthorn/sandthorn?branch=master)
3
+ [![Code Climate](https://codeclimate.com/github/Sandthorn/sandthorn.svg)](https://codeclimate.com/github/Sandthorn/sandthorn)
4
+ [![Gem Version](https://badge.fury.io/rb/sandthorn.svg)](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
- contructor_events :board_created
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 attribute_deltas of the event.
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
 
@@ -1,6 +1,5 @@
1
1
  require "sandthorn/version"
2
2
  require "sandthorn/errors"
3
- require "sandthorn/event"
4
3
  require "sandthorn/aggregate_root"
5
4
  require "sandthorn/event_stores"
6
5
  require 'yaml'
@@ -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
- formated_attribute_deltas = args.first.map do |key, value|
175
- {
176
- attribute_name: key.to_s,
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: 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
- event_data = event[:event_data]
198
- attribute_deltas = event_data[:attribute_deltas]
192
+ attribute_deltas = event[:event_data]
199
193
  unless attribute_deltas.nil?
200
- deltas = attribute_deltas.each_with_object({}) do |delta, acc|
201
- acc[delta[:attribute_name]] = delta[:new_value]
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
- equals_aggregate_id = variable.to_s == "@aggregate_id"
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: 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
@@ -1,3 +1,3 @@
1
1
  module Sandthorn
2
- VERSION = "1.0.0"
2
+ VERSION = "1.1.0"
3
3
  end
@@ -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 eql("Klabbarparen")
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 eql(person.name)
55
- expect(builded.aggregate_id).to eql(person.aggregate_id)
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 eql("bar")
79
- expect(builded.my_hash[:bar]).to eql("foo")
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 eql("BAR")
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 eql "new name"
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][:attribute_deltas][0][:new_value]).to eql("new name")
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 eql("name_changed")
59
+ expect(subject.aggregate_events[1][:event_name]).to eq("name_changed")
60
60
  end
61
61
  end
62
62
 
@@ -5,12 +5,12 @@ module Sandthorn
5
5
  class DirtyClass
6
6
  include Sandthorn::AggregateRoot
7
7
  attr_reader :name, :age
8
- attr :sex
8
+ attr :age
9
9
  attr_writer :writer
10
10
 
11
11
  def initialize args = {}
12
12
  @name = args.fetch(:name, nil)
13
- @sex = args.fetch(:sex, nil)
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 change_sex value
25
- unless sex == value
26
- @sex = value
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 eql 3
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", sex: "hen", writer: true) }
86
+ let(:subject) { DirtyClass.new(name: "Mogge", age: 35, writer: true) }
87
87
  it "should set the values" do
88
- expect(subject.name).to eql "Mogge"
89
- expect(subject.sex).to eql "hen"
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 eql "new_name"
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 eql 1
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 eql 2
107
+ expect(dirty_object.aggregate_events.length).to eq(2)
108
108
  end
109
109
  end
110
110
 
111
- context "when changing sex (attr)" do
112
- it "should get new_sex" do
113
- dirty_object.change_sex "new_sex"
114
- expect(dirty_object.sex).to eql "new_sex"
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 eql 0
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 eql 0
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 eql 1
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 eql dirty_object.id
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 eql "morgan"
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", :sex => "hen"
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][:attribute_deltas].first[:old_value]).to eql "old_value"
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][:attribute_deltas].first[:old_value]).to eql "old_value"
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][:attribute_deltas].last[:attribute_name]).not_to eql "aggregate_id"
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 sex attribute if sex method is not runned" do
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][:attribute_deltas].each do |attribute_delta|
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 sex attribute if sex attribute is the same" do
197
- dirty_object.change_sex "hen"
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][:attribute_deltas].each do |attribute_delta|
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 sex change" do
206
- dirty_object.change_sex "shemale"
207
- expect(dirty_object.aggregate_events.last[:event_data][:attribute_deltas].first[:old_value]).to eql "hen"
208
- expect(dirty_object.aggregate_events.last[:event_data][:attribute_deltas].first[:new_value]).to eql "shemale"
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 eql("no_state_change_only_empty_event")
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 attribute_deltas set to empty array" do
225
- expect(dirty_object.aggregate_events.first[:event_data][:attribute_deltas]).to eql([])
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