sandthorn 0.5.1 → 0.6.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
  SHA1:
3
- metadata.gz: 974b2f1521c09c03ea633790cdc1de37b47b46fb
4
- data.tar.gz: 782de64f891f07fc78aff62cd53ebd70b9f05846
3
+ metadata.gz: f39fd41916e13c8d9af482497da9774295644984
4
+ data.tar.gz: b3ae469f87f318a99d27f34049513cf35cae754d
5
5
  SHA512:
6
- metadata.gz: 9fc7334244668d45c4a39e730ab51dadb468267839638fe299b6c4ea131c964078d9dd2e73cfdd0fe23297ebfc257e7dfb6bab715f3a07996478c1d052f4de67
7
- data.tar.gz: 86b770a90624c2cfed0a1ae9cae04f07f569c7ed3fb75c297cd5a53a9573180d1888b7f57ea3b39754f5c448bb8da7752e411e6f60346d19a168dc72a79e3d78
6
+ metadata.gz: 2c3d769b134a6421cfe4164190726c9ce1448f06962ee24aee7aec32f14fc1cf7c4c6e5c2a6160c62a0c316f482e8d72709463c2ac3f0298e7584ab02f604011
7
+ data.tar.gz: d54a6d161c31dd38ff4bd03217035d35d2f445419d83c59caca649828b32543eaf9714ed8832b56f4262315fad95992936b778bdda52f602254103611067b6c2
data/.gitignore CHANGED
@@ -17,3 +17,4 @@ tmp
17
17
  .yardoc
18
18
  _yardoc
19
19
  doc/
20
+ .idea
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- sandthorn (0.5.1)
4
+ sandthorn (0.6.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -9,7 +9,7 @@ GEM
9
9
  autotest-standalone (4.5.11)
10
10
  awesome_print (1.2.0)
11
11
  coderay (1.1.0)
12
- coveralls (0.7.0)
12
+ coveralls (0.7.1)
13
13
  multi_json (~> 1.3)
14
14
  rest-client
15
15
  simplecov (>= 0.7)
@@ -19,11 +19,11 @@ GEM
19
19
  docile (1.1.5)
20
20
  gem-release (0.7.3)
21
21
  method_source (0.8.2)
22
- mime-types (2.3)
22
+ mime-types (2.4.3)
23
23
  multi_json (1.10.1)
24
- netrc (0.7.7)
24
+ netrc (0.8.0)
25
25
  pg (0.17.1)
26
- pry (0.10.0)
26
+ pry (0.10.1)
27
27
  coderay (~> 1.1.0)
28
28
  method_source (~> 0.8.1)
29
29
  slop (~> 3.4)
@@ -34,25 +34,25 @@ GEM
34
34
  rest-client (1.7.2)
35
35
  mime-types (>= 1.16, < 3.0)
36
36
  netrc (~> 0.7)
37
- rspec (3.0.0)
38
- rspec-core (~> 3.0.0)
39
- rspec-expectations (~> 3.0.0)
40
- rspec-mocks (~> 3.0.0)
41
- rspec-core (3.0.3)
42
- rspec-support (~> 3.0.0)
43
- rspec-expectations (3.0.3)
37
+ rspec (3.1.0)
38
+ rspec-core (~> 3.1.0)
39
+ rspec-expectations (~> 3.1.0)
40
+ rspec-mocks (~> 3.1.0)
41
+ rspec-core (3.1.7)
42
+ rspec-support (~> 3.1.0)
43
+ rspec-expectations (3.1.2)
44
44
  diff-lcs (>= 1.2.0, < 2.0)
45
- rspec-support (~> 3.0.0)
46
- rspec-mocks (3.0.3)
47
- rspec-support (~> 3.0.0)
48
- rspec-support (3.0.3)
45
+ rspec-support (~> 3.1.0)
46
+ rspec-mocks (3.1.3)
47
+ rspec-support (~> 3.1.0)
48
+ rspec-support (3.1.2)
49
49
  sandthorn_driver_sequel (1.1.0)
50
50
  pg
51
51
  sequel
52
- sequel (4.13.0)
53
- simplecov (0.9.0)
52
+ sequel (4.15.0)
53
+ simplecov (0.9.1)
54
54
  docile (~> 1.1.0)
55
- multi_json
55
+ multi_json (~> 1.0)
56
56
  simplecov-html (~> 0.8.0)
57
57
  simplecov-html (0.8.0)
58
58
  slop (3.6.0)
@@ -60,7 +60,7 @@ GEM
60
60
  term-ansicolor (1.3.0)
61
61
  tins (~> 1.0)
62
62
  thor (0.19.1)
63
- tins (1.3.0)
63
+ tins (1.3.3)
64
64
  yard (0.8.7.4)
65
65
 
66
66
  PLATFORMS
@@ -75,7 +75,7 @@ DEPENDENCIES
75
75
  pry
76
76
  pry-doc
77
77
  rake
78
- rspec
78
+ rspec (~> 3.0)
79
79
  sandthorn!
80
80
  sandthorn_driver_sequel (~> 1.1)
81
81
  sqlite3
data/README.md CHANGED
@@ -64,10 +64,30 @@ class Ship
64
64
  end
65
65
  end
66
66
 
67
- # Setup the framework with the sequel driver for persistance
67
+ # Configure a driver
68
68
  url = "sqlite://spec/db/sequel_driver.sqlite3"
69
- catch_all_config = [ { driver: SandthornDriverSequel.driver_from_url(url: url) } ]
70
- Sandthorn.configuration = catch_all_config
69
+ sql_event_store = SandthornDriverSequel.driver_from_url(url: url)
70
+ Sandthorn.configure do |c|
71
+ c.event_store = sql_event_store
72
+ end
73
+
74
+ # Or configure many drivers
75
+
76
+ Sandthorn.configure do |c|
77
+ c.event_stores = {
78
+ default: sql_event_store,
79
+ other_event_store: other_store
80
+ }
81
+ end
82
+
83
+ # Assign your aggregates to a named event store
84
+
85
+ class Boat
86
+ include Sandthorn::AggregateRoot
87
+ event_store :other_event_store
88
+ end
89
+
90
+ # Aggregates with no explicit event store will use the default event store
71
91
 
72
92
  # Migrate db schema for the sequel driver
73
93
  migrator = SandthornDriverSequel::Migration.new url: url
data/lib/sandthorn.rb CHANGED
@@ -1,16 +1,30 @@
1
1
  require "sandthorn/version"
2
2
  require "sandthorn/errors"
3
3
  require "sandthorn/aggregate_root"
4
+ require "sandthorn/event_stores"
4
5
  require 'yaml'
5
6
  require 'securerandom'
6
7
 
7
8
  module Sandthorn
8
9
  class << self
9
- def configuration= configuration
10
- @configuration = configuration
10
+ extend Forwardable
11
+
12
+ def_delegators :configuration, :event_stores
13
+
14
+ def default_event_store
15
+ event_stores.default_store
16
+ end
17
+
18
+ def default_event_store=(store)
19
+ event_stores.default_store = store
20
+ end
21
+
22
+ def configure
23
+ yield(configuration) if block_given?
11
24
  end
25
+
12
26
  def configuration
13
- @configuration ||= []
27
+ @configuration ||= Configuration.new
14
28
  end
15
29
 
16
30
  def serialize data
@@ -31,35 +45,29 @@ module Sandthorn
31
45
  SecureRandom.uuid
32
46
  end
33
47
 
34
- def get_aggregate_events aggregate_id, class_name
35
- driver_for(class_name).get_aggregate_events aggregate_id, class_name
48
+ def get_aggregate_events aggregate_id, aggregate_type
49
+ event_store_for(aggregate_type).get_aggregate_events aggregate_id, aggregate_type
36
50
  end
37
51
 
38
- def save_events aggregate_events, originating_aggregate_version, aggregate_id, class_name
39
- #begin
40
- driver_for(class_name).save_events aggregate_events, originating_aggregate_version, aggregate_id, *class_name
41
- #rescue UpptecEventSequelDriver::Errors::WrongAggregateVersionError => sequel_error
42
- # raise UpptecEventFramework::Errors::ConcurrencyError.new sequel_error.message
43
- #end
52
+ def save_events aggregate_events, originating_aggregate_version, aggregate_id, aggregate_type
53
+ event_store_for(aggregate_type).save_events aggregate_events, originating_aggregate_version, aggregate_id, *aggregate_type
44
54
  end
45
55
 
46
- def get_aggregate aggregate_id, class_name
47
- driver_for(class_name).get_aggregate aggregate_id, class_name
56
+ def get_aggregate aggregate_id, aggregate_type
57
+ event_store_for(aggregate_type).get_aggregate aggregate_id, aggregate_type
48
58
  end
49
59
 
50
- def save_snapshot aggregate_snapshot, aggregate_id, class_name
51
- driver_for(class_name).save_snapshot aggregate_snapshot, aggregate_id, class_name
60
+ def save_snapshot aggregate_snapshot, aggregate_id, aggregate_type
61
+ event_store_for(aggregate_type).save_snapshot aggregate_snapshot, aggregate_id, aggregate_type
52
62
  end
53
63
 
54
- def get_aggregate_list_by_typename class_name
55
- driver_for(class_name).get_aggregate_list_by_typename class_name
64
+ def get_aggregate_list_by_type aggregate_type
65
+ event_store_for(aggregate_type).get_aggregate_list_by_typename aggregate_type
56
66
  end
57
67
 
58
- def get_events aggregate_types: [], take: 0, after_sequence_number: 0
59
- drivers = drivers_for_aggregate_types type_names: aggregate_types
60
- raise Sandthorn::Errors::Error.new "Cannot get events from multiple contexts simultaneously, only one single context can be handled at a time." unless drivers.length == 1
61
- driver = drivers.first
62
- events = driver.get_events aggregate_types: aggregate_types, take: take, after_sequence_number: after_sequence_number
68
+ def get_events event_store: :default, aggregate_types: [], take: 0, after_sequence_number: 0
69
+ event_store = find_event_store(event_store)
70
+ events = event_store.get_events aggregate_types: aggregate_types, take: take, after_sequence_number: after_sequence_number
63
71
  events.each do |event|
64
72
  event[:event_args] = deserialize event[:event_data]
65
73
  event.delete(:event_data)
@@ -68,43 +76,44 @@ module Sandthorn
68
76
  end
69
77
 
70
78
  def obsolete_snapshots type_names: [], min_event_distance: 0
71
- drivers = drivers_for_aggregate_types type_names: type_names
72
- obsolete = drivers.flat_map { |driver| driver.obsolete_snapshots(class_names: type_names, max_event_distance: min_event_distance) }
73
- yielder = []
74
- obsolete.each do |single_obsolete|
75
- type = Kernel.const_get single_obsolete[:aggregate_type]
76
- aggregate = type.aggregate_find single_obsolete[:aggregate_id]
77
- if block_given?
78
- yield aggregate
79
- else
80
- yielder << aggregate
81
- end
79
+ obsolete = event_stores.flat_map { |event_store| event_store.obsolete_snapshots(class_names: type_names, max_event_distance: min_event_distance) }
80
+ obsolete.map do |single_obsolete|
81
+ type = Kernel.const_get single_obsolete[:aggregate_type]
82
+ aggregate = type.aggregate_find(single_obsolete[:aggregate_id]).tap do |agg|
83
+ yield agg if block_given?
84
+ end
82
85
  end
83
- yielder unless block_given?
86
+ end
87
+
88
+ def find_event_store(name)
89
+ event_stores.by_name(name)
84
90
  end
85
91
 
86
92
  private
87
- def driver_for class_name, &block
88
- driver = identify_driver_from_class class_name
89
- block.call(driver) if block_given?
90
- driver
91
- end
92
- def identify_driver_from_class class_name
93
- matches = configuration.select do |conf|
94
- r = Regexp.new "^#{conf[:aggregate_pattern]}"
95
- pattern = class_name.to_s
96
- conf[:aggregate_pattern].nil? || r.match(pattern)
93
+
94
+ def event_store_for(aggregate_type)
95
+ event_store = event_stores.by_name(aggregate_type.event_store).tap do |store|
96
+ yield(store) if block_given?
97
97
  end
98
- raise Sandthorn::Errors::ConfigurationError.new "Aggregate class #{class_name} is not configured for Sandthorn" if matches.empty?
99
- first_match = matches.first
100
- first_match[:driver]
101
98
  end
102
- def drivers_for_aggregate_types type_names: []
103
- return all_drivers if type_names.empty?
104
- type_names.map { |e| driver_for e }
105
- end
106
- def all_drivers
107
- configuration.map { |e| e[:driver] }
99
+
100
+ class Configuration
101
+ extend Forwardable
102
+
103
+ def_delegators :default_store, :event_stores, :default_store=
104
+
105
+ def initialize
106
+ yield(self) if block_given?
107
+ end
108
+
109
+ def event_stores
110
+ @event_stores ||= EventStores.new
111
+ end
112
+
113
+ def event_store=(store)
114
+ @event_stores = EventStores.new(store)
115
+ end
116
+ alias_method :event_stores=, :event_store=
108
117
  end
109
118
  end
110
119
  end
@@ -29,9 +29,8 @@ module Sandthorn
29
29
  aggregate_events,
30
30
  aggregate_originating_version,
31
31
  aggregate_id,
32
- self.class.name
32
+ self.class
33
33
  )
34
-
35
34
  @aggregate_events = []
36
35
  @aggregate_originating_version = @aggregate_current_event_version
37
36
  end
@@ -39,6 +38,10 @@ module Sandthorn
39
38
  self
40
39
  end
41
40
 
41
+ def ==(other)
42
+ other.respond_to?(:aggregate_id) && aggregate_id == other.aggregate_id
43
+ end
44
+
42
45
  def aggregate_trace args
43
46
  @aggregate_trace_information = args
44
47
  yield self if block_given?
@@ -83,8 +86,16 @@ module Sandthorn
83
86
  @@aggregate_trace_information = nil
84
87
  end
85
88
 
89
+ def event_store(event_store = nil)
90
+ if event_store
91
+ @event_store = event_store
92
+ else
93
+ @event_store
94
+ end
95
+ end
96
+
86
97
  def all
87
- aggregate_id_list = Sandthorn.get_aggregate_list_by_typename(self.name)
98
+ aggregate_id_list = Sandthorn.get_aggregate_list_by_type(self)
88
99
  find aggregate_id_list
89
100
  end
90
101
 
@@ -94,17 +105,13 @@ module Sandthorn
94
105
  end
95
106
 
96
107
  def aggregate_find aggregate_id
97
- class_name = self.respond_to?(:name) ? self.name : self.class # to be able to extend a string for example.
98
- events = Sandthorn.get_aggregate(aggregate_id, class_name)
99
-
100
- unless events and !events.empty?
108
+ events = Sandthorn.get_aggregate(aggregate_id, self)
109
+ unless events && !events.empty?
101
110
  raise Sandthorn::Errors::AggregateNotFound
102
111
  end
103
-
104
112
  transformed_events = events.map do |e|
105
113
  e.merge(event_args: Sandthorn.deserialize(e[:event_data]))
106
114
  end
107
-
108
115
  aggregate_build transformed_events
109
116
  end
110
117
 
@@ -128,7 +135,7 @@ module Sandthorn
128
135
  current_aggregate_version = aggregate.aggregate_originating_version
129
136
  events.shift
130
137
  else
131
- aggregate = start_build_from_new events
138
+ aggregate = create_new_empty_aggregate
132
139
  end
133
140
 
134
141
  attributes = build_instance_vars_from_events events
@@ -165,17 +172,8 @@ module Sandthorn
165
172
  snapshot = events.first[:event_args][0]
166
173
  end
167
174
 
168
- def start_build_from_new events
169
- new_args = events.first[:event_args][:method_args]
170
-
171
- if new_args.nil?
172
- aggregate = new
173
- else
174
- aggregate = new(*new_args)
175
- end
176
-
177
- aggregate.send :aggregate_clear_current_event_version!
178
- aggregate
175
+ def create_new_empty_aggregate
176
+ allocate
179
177
  end
180
178
  end
181
179
 
@@ -25,6 +25,20 @@ module Sandthorn
25
25
  unless aggregate_snapshot
26
26
  raise Errors::SnapshotError, "No snapshot has been created!"
27
27
  end
28
+ @aggregate_snapshot[:event_data] = Sandthorn.serialize @aggregate_snapshot[:event_args]
29
+ @aggregate_snapshot[:event_args] = nil
30
+ Sandthorn.save_snapshot @aggregate_snapshot, @aggregate_id, 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
28
42
 
29
43
  @aggregate_snapshot[:event_data] = Sandthorn
30
44
  .serialize aggregate_snapshot[:event_args]
@@ -0,0 +1,64 @@
1
+ require 'forwardable'
2
+
3
+ module Sandthorn
4
+ class EventStores
5
+ extend Forwardable
6
+ include Enumerable
7
+
8
+ def_delegators :stores, :each
9
+
10
+ def initialize(stores = nil)
11
+ @store_map = Hash.new
12
+ add_initial(stores)
13
+ end
14
+
15
+ def add(name, event_store)
16
+ store_map[name] = event_store
17
+ end
18
+ alias_method :[]=, :add
19
+
20
+ def add_many(stores)
21
+ stores.each_pair do |name, store|
22
+ add(name, store)
23
+ end
24
+ end
25
+
26
+ def by_name(name)
27
+ store_map[name] || default_store
28
+ end
29
+ alias_method :[], :by_name
30
+
31
+ def default_store
32
+ store_map.fetch(:default)
33
+ end
34
+
35
+ def default_store=(store)
36
+ store_map[:default] = store
37
+ end
38
+
39
+ def stores
40
+ store_map.values
41
+ end
42
+
43
+ private
44
+
45
+ attr_reader :store_map
46
+
47
+ def add_initial(store)
48
+ if is_event_store?(store)
49
+ self.default_store = store
50
+ elsif is_many_event_stores?(store)
51
+ add_many(store)
52
+ end
53
+ end
54
+
55
+ def is_many_event_stores?(store)
56
+ store.respond_to?(:each_pair)
57
+ end
58
+
59
+ def is_event_store?(store)
60
+ store.respond_to?(:get_events)
61
+ end
62
+
63
+ end
64
+ end
@@ -1,3 +1,3 @@
1
1
  module Sandthorn
2
- VERSION = "0.5.1"
2
+ VERSION = "0.6.0"
3
3
  end
data/sandthorn.gemspec CHANGED
@@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
21
21
 
22
22
  spec.add_development_dependency "bundler", "~> 1.3"
23
23
  spec.add_development_dependency "rake"
24
- spec.add_development_dependency "rspec"
24
+ spec.add_development_dependency "rspec", "~> 3.0"
25
25
  spec.add_development_dependency "gem-release"
26
26
  spec.add_development_dependency "pry"
27
27
  spec.add_development_dependency "pry-doc"
@@ -38,6 +38,17 @@ module Sandthorn
38
38
 
39
39
  end
40
40
 
41
+ describe "::event_store" do
42
+ let(:klass) { Class.new { include Sandthorn::AggregateRoot } }
43
+ it "is available as a class method" do
44
+ expect(klass).to respond_to(:event_store)
45
+ end
46
+ it "sets the event store as a class level variable and returns it" do
47
+ klass.event_store(:other)
48
+ expect(klass.event_store).to eq(:other)
49
+ end
50
+ end
51
+
41
52
  describe "when get all aggregates from DirtyClass" do
42
53
 
43
54
  before(:each) do
@@ -72,4 +72,4 @@ describe 'when using complex types in events' do
72
72
  builded = IAmComplex.aggregate_build aggr.aggregate_events
73
73
  expect(builded.hello.foo_bar).to eql "morgan"
74
74
  end
75
- end
75
+ end
@@ -0,0 +1,81 @@
1
+ require 'spec_helper'
2
+
3
+ module Sandthorn
4
+ describe EventStores do
5
+ let(:stores) { EventStores.new }
6
+
7
+ describe "#initialize" do
8
+ context "when given a single event_store" do
9
+ it "sets it as the default event store" do
10
+ store = double(get_events: true)
11
+ allow(store).to receive(:get_events)
12
+ stores = EventStores.new(store)
13
+ expect(stores.default_store).to eq(store)
14
+ end
15
+ end
16
+
17
+ context "when given number of stores" do
18
+ it "adds them all" do
19
+ stores = {
20
+ default: double,
21
+ other: double
22
+ }
23
+ repo = EventStores.new(stores)
24
+ expect(repo.by_name(:default)).to eq(stores[:default])
25
+ expect(repo.by_name(:other)).to eq(stores[:other])
26
+ end
27
+ end
28
+ end
29
+
30
+ describe "enumerable" do
31
+ let(:store) { double }
32
+ let(:other_store) { double }
33
+ it "should respond to each" do
34
+ expect(stores).to respond_to(:each)
35
+ end
36
+
37
+ it "should yield each store" do
38
+ stores.add_many(
39
+ foo: store,
40
+ bar: other_store
41
+ )
42
+ expect { |block| stores.each(&block) }.to yield_successive_args(store, other_store)
43
+ end
44
+ end
45
+
46
+ describe "#default_store=" do
47
+ it "sets the default" do
48
+ store = double
49
+ stores = EventStores.new
50
+ stores.default_store = store
51
+ expect(stores.default_store).to eq(store)
52
+ end
53
+ end
54
+
55
+ describe "#by_name" do
56
+ context "when the store exists" do
57
+ it "returns the store" do
58
+ store = double
59
+ stores.add(:foo, store)
60
+ expect(stores.by_name(:foo)).to eq(store)
61
+ end
62
+ end
63
+
64
+ context "when the store does not exist" do
65
+ it "returns the default store" do
66
+ store = double
67
+ stores.default_store = store
68
+ expect(stores.by_name(:unknown)).to eq(store)
69
+ end
70
+ end
71
+ end
72
+
73
+ describe "#add" do
74
+ it "adds the store under the given name" do
75
+ store = double
76
+ stores.add(:foo, store)
77
+ expect(stores[:foo]).to eq(store)
78
+ end
79
+ end
80
+ end
81
+ end
@@ -4,12 +4,70 @@ class AnAggregate
4
4
  include Sandthorn::AggregateRoot
5
5
  end
6
6
 
7
+ class AnotherAggregate
8
+ include Sandthorn::AggregateRoot
9
+ event_store :other
10
+ end
11
+
7
12
  describe Sandthorn do
8
- before(:each) { AnAggregate.new.save }
9
- let(:events) { Sandthorn.get_events aggregate_types: [AnAggregate] }
10
- context "when getting events using Sandthorn.get_events for an aggregate type" do
11
- it "should return raw events" do
12
- expect(events).to_not be_empty
13
- end
14
- end
13
+
14
+ describe "::get_events" do
15
+ context "when getting events using Sandthorn.get_events for an aggregate type" do
16
+ before do
17
+ AnAggregate.new.save
18
+ end
19
+ let(:events) { Sandthorn.get_events aggregate_types: [AnAggregate] }
20
+ it "should return events" do
21
+ expect(events).to_not be_empty
22
+ end
23
+ end
24
+
25
+ context "when there are many event stores configured" do
26
+ before do
27
+ setup_secondary_db
28
+ end
29
+
30
+ let!(:agg) do
31
+ AnAggregate.new.save
32
+ end
33
+
34
+ let!(:other_agg) do
35
+ AnotherAggregate.new.save
36
+ end
37
+
38
+ shared_examples(:default_event_store) do
39
+ it "returns events from the default event store" do
40
+ events = Sandthorn.get_events
41
+ expect(events).to all(have_aggregate_type("AnAggregate"))
42
+ end
43
+ end
44
+
45
+ context "when no explicit event store is used" do
46
+ it_behaves_like :default_event_store
47
+ end
48
+
49
+ context "when given an explicit event store" do
50
+ context "and that event store exists" do
51
+ it "returns events from the chosen event store" do
52
+ events = Sandthorn.get_events(event_store: :other)
53
+ expect(events).to all(have_aggregate_type("AnotherAggregate"))
54
+ end
55
+ end
56
+
57
+ context "and that event store does not exist" do
58
+ it_behaves_like :default_event_store
59
+ end
60
+ end
61
+
62
+ end
63
+ end
64
+
65
+ def setup_secondary_db
66
+ url = "sqlite://spec/db/other_db.sqlite3"
67
+ driver = SandthornDriverSequel.driver_from_url(url: url)
68
+ Sandthorn.event_stores.add(:other, driver)
69
+ migrator = SandthornDriverSequel::Migration.new url: url
70
+ SandthornDriverSequel.migrate_db url: url
71
+ migrator.send(:clear_for_test)
72
+ end
15
73
  end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ class InitChange
4
+ include Sandthorn::AggregateRoot
5
+ attr_reader :foo
6
+ def initialize foo: nil
7
+ @foo = foo
8
+ end
9
+ end
10
+ def change_init
11
+ InitChange.class_eval do
12
+ define_method :initialize, lambda { @foo = :foo }
13
+ end
14
+ end
15
+ describe "when the initialize-method changes" do
16
+ it "should be possible to replay anyway" do
17
+ aggregate = InitChange.new foo: :bar
18
+ events = aggregate.aggregate_events
19
+ change_init
20
+ with_change = InitChange.new
21
+ expect(with_change.foo).to eql :foo
22
+ replayed = InitChange.aggregate_build(events)
23
+ expect(replayed.foo).to eql :bar
24
+ end
25
+ end
@@ -2,14 +2,16 @@ require 'spec_helper'
2
2
 
3
3
  class AnAggregate
4
4
  include Sandthorn::AggregateRoot
5
- attr_accessor :test_block_count
6
- def initialize
7
- @test_block_count = false
8
- end
9
5
  def touch; touched; end
10
6
  def touched; commit; end
11
7
  end
12
8
 
9
+ module Outer
10
+ module Inner
11
+ class OtherAggregate < AnAggregate; end
12
+ end
13
+ end
14
+
13
15
  describe Sandthorn do
14
16
  before(:each) {
15
17
  @aggregate = AnAggregate.new
@@ -17,24 +19,37 @@ describe Sandthorn do
17
19
  @aggregate.save
18
20
  }
19
21
 
20
- context "when doing snapshots" do
22
+ describe "::obsolete_snapshot" do
21
23
  it "retrieves a list of obsolete snapshots" do
22
24
  obsolete_aggregates = Sandthorn.obsolete_snapshots type_names: [AnAggregate], min_event_distance: 0
23
25
  expect(obsolete_aggregates).to_not be_empty
24
26
  end
25
27
 
26
28
  it "accepts a block that is applied to each aggregate" do
27
- obsolete_aggregates = []
28
- Sandthorn.obsolete_snapshots type_names: [AnAggregate], min_event_distance: 0 do |aggr|
29
- aggr.test_block_count = true
30
- obsolete_aggregates << aggr
31
- end
32
- expect(obsolete_aggregates.all? { |aggregate| aggregate.test_block_count == true }).to be_truthy
29
+ obsolete_aggregates = Sandthorn.obsolete_snapshots type_names: [AnAggregate], min_event_distance: 0
30
+ expect do |block|
31
+ Sandthorn.obsolete_snapshots type_names: [AnAggregate], min_event_distance: 0, &block
32
+ end.to yield_successive_args(*obsolete_aggregates)
33
33
  end
34
34
 
35
35
  it "only retrieves aggregates older than min_event_distance" do
36
36
  obsolete_aggregates = Sandthorn.obsolete_snapshots type_names: [AnAggregate], min_event_distance: 10
37
37
  expect(obsolete_aggregates).to be_empty
38
38
  end
39
+
40
+ context "when the aggregate has been declared in a module" do
41
+
42
+ before do
43
+ Outer::Inner::OtherAggregate.new.tap do |agg|
44
+ agg.touch
45
+ agg.save
46
+ end
47
+ end
48
+
49
+ it "doesn't crash" do
50
+ obsolete_aggregates = Sandthorn.obsolete_snapshots type_names: [Outer::Inner::OtherAggregate], min_event_distance: 0
51
+ expect(obsolete_aggregates).to all(be_a_kind_of(Outer::Inner::OtherAggregate))
52
+ end
53
+ end
39
54
  end
40
55
  end
data/spec/spec_helper.rb CHANGED
@@ -5,12 +5,13 @@
5
5
  #
6
6
  # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
7
  require 'coveralls'
8
+ Coveralls.wear!
8
9
  require "ap"
9
10
  require "bundler"
10
11
  require "sandthorn_driver_sequel"
12
+ require "support/custom_matchers"
11
13
 
12
14
  Bundler.require
13
- Coveralls.wear!
14
15
 
15
16
  module Helpers
16
17
  def class_including(mod)
@@ -36,8 +37,10 @@ def spec_db
36
37
  end
37
38
  def sqlite_store_setup
38
39
  url = spec_db
39
- catch_all_config = [ { driver: SandthornDriverSequel.driver_from_url(url: url) } ]
40
- Sandthorn.configuration = catch_all_config
40
+ driver = SandthornDriverSequel.driver_from_url(url: url)
41
+ Sandthorn.configure do |c|
42
+ c.event_store = driver
43
+ end
41
44
  migrator = SandthornDriverSequel::Migration.new url: url
42
45
  SandthornDriverSequel.migrate_db url: url
43
46
  migrator.send(:clear_for_test)
@@ -0,0 +1,7 @@
1
+ require 'rspec/expectations'
2
+
3
+ RSpec::Matchers.define :have_aggregate_type do |expected|
4
+ match do |actual|
5
+ actual[:aggregate_type].to_s == expected.to_s
6
+ end
7
+ 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: 0.5.1
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lars Krantz
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-10-18 00:00:00.000000000 Z
12
+ date: 2015-03-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -43,16 +43,16 @@ dependencies:
43
43
  name: rspec
44
44
  requirement: !ruby/object:Gem::Requirement
45
45
  requirements:
46
- - - ">="
46
+ - - "~>"
47
47
  - !ruby/object:Gem::Version
48
- version: '0'
48
+ version: '3.0'
49
49
  type: :development
50
50
  prerelease: false
51
51
  version_requirements: !ruby/object:Gem::Requirement
52
52
  requirements:
53
- - - ">="
53
+ - - "~>"
54
54
  - !ruby/object:Gem::Version
55
- version: '0'
55
+ version: '3.0'
56
56
  - !ruby/object:Gem::Dependency
57
57
  name: gem-release
58
58
  requirement: !ruby/object:Gem::Requirement
@@ -193,6 +193,7 @@ files:
193
193
  - lib/sandthorn/aggregate_root_snapshot.rb
194
194
  - lib/sandthorn/errors.rb
195
195
  - lib/sandthorn/event_inspector.rb
196
+ - lib/sandthorn/event_stores.rb
196
197
  - lib/sandthorn/version.rb
197
198
  - sandthorn.gemspec
198
199
  - spec/aggregate_delta_spec.rb
@@ -203,9 +204,12 @@ files:
203
204
  - spec/db/sequel_driver.sqlite3_old
204
205
  - spec/different_driver_spec.rb
205
206
  - spec/event_inspector_spec.rb
207
+ - spec/event_stores_spec.rb
206
208
  - spec/get_events_spec.rb
209
+ - spec/initialize_signature_change_spec.rb
207
210
  - spec/sandthorn_spec.rb
208
211
  - spec/spec_helper.rb
212
+ - spec/support/custom_matchers.rb
209
213
  - spec/tracing_spec.rb
210
214
  homepage: ''
211
215
  licenses:
@@ -227,7 +231,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
227
231
  version: '0'
228
232
  requirements: []
229
233
  rubyforge_project:
230
- rubygems_version: 2.2.2
234
+ rubygems_version: 2.4.3
231
235
  signing_key:
232
236
  specification_version: 4
233
237
  summary: Event sourcing gem
@@ -240,8 +244,11 @@ test_files:
240
244
  - spec/db/sequel_driver.sqlite3_old
241
245
  - spec/different_driver_spec.rb
242
246
  - spec/event_inspector_spec.rb
247
+ - spec/event_stores_spec.rb
243
248
  - spec/get_events_spec.rb
249
+ - spec/initialize_signature_change_spec.rb
244
250
  - spec/sandthorn_spec.rb
245
251
  - spec/spec_helper.rb
252
+ - spec/support/custom_matchers.rb
246
253
  - spec/tracing_spec.rb
247
254
  has_rdoc: