sandthorn 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA256:
3
- metadata.gz: eb2833dc0d8dfa96bc80089a176f2718040f1107f0305232840e3009232511bb
4
- data.tar.gz: 1c57a94df6798dfa32a1050d105bec05ccf30e08876c0a50aa610e3f7be3ce11
2
+ SHA1:
3
+ metadata.gz: 6972dfa7eb47e800f74d28d1680403c805bb8f81
4
+ data.tar.gz: 5ff2d842c430fb11fe405f071698053163e943c6
5
5
  SHA512:
6
- metadata.gz: f21f398f4bbfc6ed3e23be70e294f5fbabfec60d1ed69bb03b8efd0f047d2131d9d225f4dd9794a24d45661ad6200b85364b54c50590825f0fa4bf9eb1d6759d
7
- data.tar.gz: 027501a879da6025ffd51511e88b8affb9eb21e2e493086e143cab1faaa50e462142771a423a1e93f0d7b31f81da381869f7cfbebe5caf8a82880863c9ac9b4d
6
+ metadata.gz: be7b451226e349e592599358cec26170fa32651b7b9cc27044a083a017b901ef5fe977b5c8e0673be89a167e99871538da1c4b90df32d088444e0f878f75bc5d
7
+ data.tar.gz: f3d545cd1be566ec4870e625ef99cdaa95a78d986308339a329fb251c504399349da9867ba073518e1c83996cea7947cdc10d22c05e5d8b573f4d63fac895650
data/.travis.yml CHANGED
@@ -2,7 +2,5 @@ language: ruby
2
2
  rvm:
3
3
  - 2.4.1
4
4
  - 2.3.4
5
- - 2.2.6
6
- - 2.1.10
7
- - 2.0.0
5
+ - 2.2.7
8
6
  sudo: false
data/README.md CHANGED
@@ -241,6 +241,50 @@ end
241
241
 
242
242
  In this case, the resulting events from the commands `new` and `mark` will have the trace `{ip: :127.0.0.1}` attached to them.
243
243
 
244
+ ### `Sandthorn::AggregateRoot.unsaved_events?`
245
+
246
+ Check if there are unsaved events attached to the aggregate.
247
+
248
+ ```ruby
249
+ board = Board.new
250
+ board.mark :o, 0, 1
251
+ board.unsaved_events?
252
+ => true
253
+ ```
254
+
255
+ ## Snapshot
256
+
257
+ If there is a lot of events saved to an aggregate it can take some time to reload the current state of the aggregate via the `.find` method. This is because all events belonging to the aggregate has to be fetched and iterated one by one to build its current state. The snapshot functionality makes it possible to store the current aggregate state and re-use it when loading the aggregate. The snapshot is used as a cache where only the events that has occurred after the snapshot has to be fetched and used to build the current state of the aggregate.
258
+
259
+ There is one global snapshot store where all snapshots are stored independent on aggregate_type. To enable snapshot on a aggregate_type the Class has to be added to the `snapshot_types` Array when configuring Sandthorn. The aggregate will now be stored to the snapshot_store on every `.save` and when using `.find` it will look for a snapshot of the requested aggregate.
260
+
261
+ Currently its only possible to store the snapshots in memory, so be careful not draining your applications memory space.
262
+
263
+
264
+ ```ruby
265
+
266
+ class Board
267
+ include Sandthorn::AggregateRoot
268
+ end
269
+
270
+ Sandthorn.configure do |c|
271
+ c.snapshot_types = [Board]
272
+ end
273
+ ```
274
+
275
+ Its also possible to take manual snapshots without enabling snapshots on the aggregate_type.
276
+
277
+ ```ruby
278
+ board = Board.new
279
+ board.save
280
+
281
+ # Save snapshot of the board aggregate
282
+ Sandthorn.save_snapshot board
283
+
284
+ # Get snapshot
285
+ snapshot = Sandthorn.find_snapshot board.aggregate_id
286
+ ```
287
+
244
288
  ## Bounded Context
245
289
 
246
290
  A bounded context is a system divider that split large systems into smaller parts. [Bounded Context by Martin Fowler](http://martinfowler.com/bliki/BoundedContext.html)
data/lib/sandthorn.rb CHANGED
@@ -2,6 +2,7 @@ require "sandthorn/version"
2
2
  require "sandthorn/errors"
3
3
  require "sandthorn/aggregate_root"
4
4
  require "sandthorn/event_stores"
5
+ require "sandthorn/snapshot_store"
5
6
  require 'yaml'
6
7
  require 'securerandom'
7
8
 
@@ -10,6 +11,7 @@ module Sandthorn
10
11
  extend Forwardable
11
12
 
12
13
  def_delegators :configuration, :event_stores
14
+ def_delegators :configuration, :snapshot_store
13
15
 
14
16
  def default_event_store
15
17
  event_stores.default_store
@@ -39,12 +41,17 @@ module Sandthorn
39
41
  event_store_for(aggregate_type).all(aggregate_type)
40
42
  end
41
43
 
42
- def find aggregate_id, aggregate_type
43
- event_store_for(aggregate_type).find(aggregate_id, aggregate_type)
44
+ def find aggregate_id, aggregate_type, after_aggregate_version = 0
45
+ event_store_for(aggregate_type).find(aggregate_id, aggregate_type, after_aggregate_version)
44
46
  end
45
47
 
46
- def save_snapshot(aggregate)
47
- raise "Not Implemented"
48
+ def save_snapshot aggregate
49
+ raise Errors::SnapshotError, "Can't take snapshot on object with unsaved events" if aggregate.unsaved_events?
50
+ snapshot_store.save aggregate.aggregate_id, aggregate
51
+ end
52
+
53
+ def find_snapshot aggregate_id
54
+ return snapshot_store.find aggregate_id
48
55
  end
49
56
 
50
57
  def find_event_store(name)
@@ -84,6 +91,16 @@ module Sandthorn
84
91
  @event_stores.map_types data
85
92
  end
86
93
 
94
+ def snapshot_store
95
+ @snapshot_store ||= SnapshotStore.new
96
+ end
97
+
98
+ def snapshot_types= aggregate_types
99
+ aggregate_types.each do |aggregate_type|
100
+ aggregate_type.snapshot(true)
101
+ end
102
+ end
103
+
87
104
  alias_method :event_stores=, :event_store=
88
105
  end
89
106
  end
@@ -29,6 +29,8 @@ module Sandthorn
29
29
  @aggregate_originating_version = @aggregate_current_event_version
30
30
  end
31
31
 
32
+ Sandthorn.save_snapshot self if self.class.snapshot
33
+
32
34
  self
33
35
  end
34
36
 
@@ -36,6 +38,10 @@ module Sandthorn
36
38
  other.respond_to?(:aggregate_id) && aggregate_id == other.aggregate_id
37
39
  end
38
40
 
41
+ def unsaved_events?
42
+ aggregate_events.any?
43
+ end
44
+
39
45
  def aggregate_trace args
40
46
  @aggregate_trace_information = args
41
47
  yield self if block_given?
@@ -70,9 +76,17 @@ module Sandthorn
70
76
  end
71
77
  end
72
78
 
79
+ def snapshot(value = nil)
80
+ if value
81
+ @snapshot = value
82
+ else
83
+ @snapshot
84
+ end
85
+ end
86
+
73
87
  def all
74
88
  Sandthorn.all(self).map { |events|
75
- aggregate_build events
89
+ aggregate_build events, nil
76
90
  }
77
91
  end
78
92
 
@@ -83,12 +97,14 @@ module Sandthorn
83
97
 
84
98
  def aggregate_find aggregate_id
85
99
  begin
86
- events = Sandthorn.find(aggregate_id, self)
87
- unless events && !events.empty?
100
+ aggregate_from_snapshot = Sandthorn.find_snapshot(aggregate_id) if self.snapshot
101
+ current_aggregate_version = aggregate_from_snapshot.nil? ? 0 : aggregate_from_snapshot.aggregate_current_event_version
102
+ events = Sandthorn.find(aggregate_id, self, current_aggregate_version)
103
+ if aggregate_from_snapshot.nil? && events.empty?
88
104
  raise Errors::AggregateNotFound
89
105
  end
90
106
 
91
- return aggregate_build events
107
+ return aggregate_build events, aggregate_from_snapshot
92
108
  rescue Exception
93
109
  raise Errors::AggregateNotFound
94
110
  end
@@ -111,8 +127,8 @@ module Sandthorn
111
127
 
112
128
  end
113
129
 
114
- def aggregate_build events
115
- aggregate = create_new_empty_aggregate
130
+ def aggregate_build events, aggregate_from_snapshot = nil
131
+ aggregate = aggregate_from_snapshot || create_new_empty_aggregate
116
132
 
117
133
  if events.any?
118
134
  current_aggregate_version = events.last[:aggregate_version]
@@ -0,0 +1,17 @@
1
+ module Sandthorn
2
+ class SnapshotStore
3
+ def initialize
4
+ @store = Hash.new
5
+ end
6
+
7
+ attr_reader :store
8
+
9
+ def save key, value
10
+ @store[key] = value
11
+ end
12
+
13
+ def find key
14
+ @store[key]
15
+ end
16
+ end
17
+ end
@@ -1,3 +1,3 @@
1
1
  module Sandthorn
2
- VERSION = "1.1.0"
2
+ VERSION = "1.2.0"
3
3
  end
data/sandthorn.gemspec CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |spec|
8
8
  spec.version = Sandthorn::VERSION
9
9
  spec.authors = ["Lars Krantz", "Morgan Hallgren", "Jesper Josefsson"]
10
10
  spec.email = ["lars.krantz@alaz.se", "morgan.hallgren@gmail.com", "jesper.josefsson@gmail.com"]
11
- spec.description = %q{Event sourcing gem}
11
+ spec.description = %q{Event sourcing}
12
12
  spec.summary = %q{Event sourcing gem}
13
13
  spec.homepage = "https://github.com/Sandthorn/sandthorn"
14
14
  spec.license = "MIT"
@@ -51,6 +51,17 @@ module Sandthorn
51
51
  end
52
52
  end
53
53
 
54
+ describe "::snapshot" do
55
+ let(:klass) { Class.new { include Sandthorn::AggregateRoot } }
56
+ it "is available as a class method" do
57
+ expect(klass).to respond_to(:snapshot)
58
+ end
59
+ it "sets the snapshot to true and returns it" do
60
+ klass.snapshot(true)
61
+ expect(klass.snapshot).to eq(true)
62
+ end
63
+ end
64
+
54
65
  describe "when get all aggregates from DirtyClass" do
55
66
 
56
67
  before(:each) do
@@ -0,0 +1,68 @@
1
+ require 'spec_helper'
2
+
3
+ module Sandthorn
4
+ module Snapshot
5
+ class KlassOne
6
+ include Sandthorn::AggregateRoot
7
+ snapshot true
8
+ end
9
+
10
+ class KlassTwo
11
+ include Sandthorn::AggregateRoot
12
+ end
13
+
14
+ class KlassThree
15
+ include Sandthorn::AggregateRoot
16
+ end
17
+
18
+ describe "::snapshot" do
19
+ before do
20
+ Sandthorn.configure do |c|
21
+ c.snapshot_types = [KlassTwo]
22
+ end
23
+ end
24
+ it "snapshot should be enabled on KlassOne and KlassTwo but not KlassThree" do
25
+ expect(KlassOne.snapshot).to be_truthy
26
+ expect(KlassTwo.snapshot).to be_truthy
27
+ expect(KlassThree.snapshot).not_to be_truthy
28
+ end
29
+ end
30
+
31
+ describe "find snapshot on snapshot enabled aggregate" do
32
+ let(:klass) { KlassOne.new.save }
33
+
34
+ it "should find on snapshot enabled Class" do
35
+ copy = KlassOne.find klass.aggregate_id
36
+ expect(copy.aggregate_version).to eql(klass.aggregate_version)
37
+ end
38
+
39
+ it "should get saved snapshot" do
40
+ copy = Sandthorn.find_snapshot klass.aggregate_id
41
+ expect(copy.aggregate_version).to eql(klass.aggregate_version)
42
+ end
43
+
44
+ end
45
+
46
+ describe "save and find snapshot on snapshot disabled aggregate" do
47
+ let(:klass) { KlassThree.new.save }
48
+
49
+ it "should not find snapshot" do
50
+ snapshot = Sandthorn.find_snapshot klass.aggregate_id
51
+ expect(snapshot).to be_nil
52
+ end
53
+
54
+ it "should save and get saved snapshot" do
55
+ Sandthorn.save_snapshot klass
56
+ snapshot = Sandthorn.find_snapshot klass.aggregate_id
57
+ expect(snapshot).not_to be_nil
58
+
59
+ #Check by key on the snapshot_store hash
60
+ expect(Sandthorn.snapshot_store.store.has_key?(klass.aggregate_id)).to be_truthy
61
+
62
+ end
63
+
64
+ end
65
+
66
+ end
67
+ end
68
+
data/spec/spec_helper.rb CHANGED
@@ -45,17 +45,13 @@ end
45
45
  def url
46
46
  "sqlite://spec/db/sequel_driver.sqlite3"
47
47
  end
48
+
48
49
  def sqlite_store_setup
49
50
 
50
51
  SandthornDriverSequel.migrate_db url: url
51
-
52
- driver = SandthornDriverSequel.driver_from_url(url: url) do |conf|
53
- conf.event_serializer = Proc.new { |data| YAML::dump(data) }
54
- conf.event_deserializer = Proc.new { |data| YAML::load(data) }
55
- end
56
52
 
57
53
  Sandthorn.configure do |c|
58
- c.event_store = driver
54
+ c.event_store = SandthornDriverSequel.driver_from_url(url: url)
59
55
  end
60
56
 
61
57
  end
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: 1.1.0
4
+ version: 1.2.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: 2018-05-25 00:00:00.000000000 Z
13
+ date: 2018-06-14 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: bundler
@@ -166,7 +166,7 @@ dependencies:
166
166
  - - ">="
167
167
  - !ruby/object:Gem::Version
168
168
  version: '4.0'
169
- description: Event sourcing gem
169
+ description: Event sourcing
170
170
  email:
171
171
  - lars.krantz@alaz.se
172
172
  - morgan.hallgren@gmail.com
@@ -182,20 +182,18 @@ files:
182
182
  - ".ruby-version"
183
183
  - ".travis.yml"
184
184
  - Gemfile
185
- - Gemfile.lock.old
186
185
  - LICENSE
187
- - LICENSE.txt
188
186
  - README.md
189
187
  - Rakefile
190
188
  - lib/sandthorn.rb
191
189
  - lib/sandthorn/aggregate_root.rb
192
190
  - lib/sandthorn/aggregate_root_base.rb
193
191
  - lib/sandthorn/aggregate_root_marshal.rb
194
- - lib/sandthorn/aggregate_root_snapshot.rb
195
192
  - lib/sandthorn/bounded_context.rb
196
193
  - lib/sandthorn/errors.rb
197
194
  - lib/sandthorn/event_inspector.rb
198
195
  - lib/sandthorn/event_stores.rb
196
+ - lib/sandthorn/snapshot_store.rb
199
197
  - lib/sandthorn/version.rb
200
198
  - sandthorn.gemspec
201
199
  - spec/aggregate_delta_spec.rb
@@ -209,6 +207,7 @@ files:
209
207
  - spec/default_attributes_spec.rb
210
208
  - spec/event_stores_spec.rb
211
209
  - spec/initialize_signature_change_spec.rb
210
+ - spec/snapshot_spec.rb
212
211
  - spec/spec_helper.rb
213
212
  - spec/stateless_events_spec.rb
214
213
  - spec/support/custom_matchers.rb
@@ -233,7 +232,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
233
232
  version: '0'
234
233
  requirements: []
235
234
  rubyforge_project:
236
- rubygems_version: 2.7.6
235
+ rubygems_version: 2.6.14
237
236
  signing_key:
238
237
  specification_version: 4
239
238
  summary: Event sourcing gem
@@ -249,6 +248,7 @@ test_files:
249
248
  - spec/default_attributes_spec.rb
250
249
  - spec/event_stores_spec.rb
251
250
  - spec/initialize_signature_change_spec.rb
251
+ - spec/snapshot_spec.rb
252
252
  - spec/spec_helper.rb
253
253
  - spec/stateless_events_spec.rb
254
254
  - spec/support/custom_matchers.rb
data/Gemfile.lock.old DELETED
@@ -1,54 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- sandthorn (0.0.1)
5
- upptec_event_sequel_driver (~> 1.2)
6
-
7
- GEM
8
- remote: https://rubygems.org/
9
- specs:
10
- autotest-standalone (4.5.11)
11
- awesome_print (1.2.0)
12
- coderay (1.1.0)
13
- diff-lcs (1.2.5)
14
- gem-release (0.7.1)
15
- method_source (0.8.2)
16
- pg (0.17.1)
17
- pry (0.9.12.6)
18
- coderay (~> 1.0)
19
- method_source (~> 0.8)
20
- slop (~> 3.4)
21
- pry-doc (0.5.1)
22
- pry (>= 0.9)
23
- yard (>= 0.8)
24
- rake (10.1.1)
25
- rspec (2.14.1)
26
- rspec-core (~> 2.14.0)
27
- rspec-expectations (~> 2.14.0)
28
- rspec-mocks (~> 2.14.0)
29
- rspec-core (2.14.8)
30
- rspec-expectations (2.14.5)
31
- diff-lcs (>= 1.1.3, < 2.0)
32
- rspec-mocks (2.14.6)
33
- sequel (4.7.0)
34
- slop (3.4.7)
35
- sqlite3 (1.3.9)
36
- upptec_event_sequel_driver (1.2.2)
37
- pg
38
- sequel
39
- yard (0.8.7.3)
40
-
41
- PLATFORMS
42
- ruby
43
-
44
- DEPENDENCIES
45
- autotest-standalone
46
- awesome_print
47
- bundler (~> 1.3)
48
- gem-release
49
- pry
50
- pry-doc
51
- rake
52
- rspec
53
- sandthorn!
54
- sqlite3
data/LICENSE.txt DELETED
@@ -1,22 +0,0 @@
1
- Copyright (c) 2013 Lars Krantz
2
-
3
- MIT License
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining
6
- a copy of this software and associated documentation files (the
7
- "Software"), to deal in the Software without restriction, including
8
- without limitation the rights to use, copy, modify, merge, publish,
9
- distribute, sublicense, and/or sell copies of the Software, and to
10
- permit persons to whom the Software is furnished to do so, subject to
11
- the following conditions:
12
-
13
- The above copyright notice and this permission notice shall be
14
- included in all copies or substantial portions of the Software.
15
-
16
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -1,22 +0,0 @@
1
- module Sandthorn
2
- module AggregateRootSnapshot
3
- attr_reader :aggregate_snapshot
4
-
5
- def snapshot
6
- aggregate_snapshot!
7
- save_snapshot
8
- self
9
- end
10
-
11
- def aggregate_snapshot!
12
- if @aggregate_events.count > 0
13
- raise Errors::SnapshotError,
14
- "Can't take snapshot on object with unsaved events"
15
- end
16
- end
17
-
18
- def save_snapshot
19
- Sandthorn.save_snapshot(self)
20
- end
21
- end
22
- end