sandthorn 0.8.1 → 0.9.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: a1a17a62b61cd04ee60ba16439ae0d5b93ffd179
4
- data.tar.gz: 7ee6bcb37e9016d254c2ed32dcefb45831e55f8b
3
+ metadata.gz: 738faf44676674ac1da5b4591cfa857fa39196d2
4
+ data.tar.gz: b908878bd176b73a8a7aa5bf42173af2b28cbe79
5
5
  SHA512:
6
- metadata.gz: 7b9bdd8af7ca4e12d2924786328675264f60411a066b069bab152ab0a54bdecf2db3ea3bb0e69a4419c9b0114782d3e3ba753fc48e020f8c0315ca2ec6168017
7
- data.tar.gz: 3584ac990d2df159a15ed211d43a7ef0c17abf966599efedbc27fbde9d5e727920e0c8bbc2add4f6b3f315fe398f068a94b4d7c3a2a327546f619bce55e240aa
6
+ metadata.gz: 6e8d654e0dad2df6b94227088dfdebabdebdd5ca3eebfd68dfbffc29a9d0d437d5b8edcddc2ef1d90e036bc9a2170cf3749df6b0c206535dfcea132b20e631b7
7
+ data.tar.gz: f35b3ccf742865f59a910475423e78c778b9db9c6ee4d976b22de9dd426040379a59d89b8f816b33245685da9124b3285d32467ebffabcf8ae95fca3bf5e442c
@@ -3,3 +3,4 @@ rvm:
3
3
  - 2.1.0
4
4
  - 2.1.1
5
5
  - 2.0.0
6
+ sudo: false
data/README.md CHANGED
@@ -23,7 +23,7 @@ If you have been following [Uncle Bob](http://blog.8thlight.com/uncle-bob/2014/0
23
23
  Check out examples of Sandthorn:
24
24
 
25
25
  * [Examples](https://github.com/Sandthorn/sandthorn_examples) including a product shop and TicTacToe game.
26
- * Live [demo](http://demo.sandthorn.org) comparing Active Record and Sandthorn.
26
+ * Live [demo](http://infinite-mesa-8629.herokuapp.com/) comparing Active Record and Sandthorn.
27
27
 
28
28
  ## How do I use Sandthorn?
29
29
 
@@ -119,12 +119,15 @@ Or install it yourself as:
119
119
 
120
120
  # Configuring Sandthorn
121
121
 
122
- Sandthorn relies on a driver is specific to the data storage that you are using. This means Sandthorn can be used with any data storage given that a driver exists.
122
+ ## Driver
123
+
124
+ Sandthorn relies on a driver that is specific to the data storage that you are using. This means Sandthorn can be used with any data storage given that a driver exists.
123
125
 
124
126
  To setup a driver you need to add it to your project's Gemfile and configure it in your application code.
125
127
 
126
128
  gem 'sandthorn_driver_sequel'
127
129
 
130
+
128
131
  The driver is configured when your application launches. Here's an example of how to do it using the Sequel driver and a sqlite3 database.
129
132
 
130
133
  ```ruby
@@ -147,6 +150,36 @@ SandthornDriverSequel.migrate_db url: url
147
150
 
148
151
  Optionally, when using Sandthorn in your tests you can configure it in a `spec_helper.rb` which is then required by your test suites [example](https://github.com/Sandthorn/sandthorn_examples/blob/master/sandthorn_tictactoe/spec/spec_helper.rb#L20-L30). Note that the Sequel driver accepts a special parameter to empty the database between each test.
149
152
 
153
+ The Sequel driver is the only production-ready driver to date.
154
+
155
+
156
+ ## Map aggregate types to event stores
157
+
158
+ Its possible to map aggregate_types to events stores from the configuration setup. This makes it possible to work with data from different stores that are using the same context, and will override any event_store setting within an aggregate.
159
+
160
+ ```ruby
161
+ url_foo = "sqlite://spec/db/sequel_driver_foo.sqlite3"
162
+ driver_foo = SandthornDriverSequel.driver_from_url(url: url_foo)
163
+
164
+ url_bar = "sqlite://spec/db/sequel_driver_bar.sqlite3"
165
+ driver_bar = SandthornDriverSequel.driver_from_url(url: url_bar)
166
+
167
+ class AnAggregate
168
+ Include Sandthorn::AggregateRoot
169
+ end
170
+
171
+ class AnOtherAggregate
172
+ Include Sandthorn::AggregateRoot
173
+ end
174
+
175
+ Sandthorn.configure do |conf|
176
+ conf.event_stores = { foo: driver_foo, bar: driver_bar }
177
+ conf.map_types = { foo: [AnAggregate], bar: [AnOtherAggregate] }
178
+ end
179
+ ```
180
+
181
+ ## Data serialization / deserialization
182
+
150
183
  Its possible to configure how events and snapshots are serialized / deserialized. The default are YAML but can be overloaded in the configure block.
151
184
 
152
185
  ```ruby
@@ -158,10 +191,11 @@ Sandthorn.configure do |conf|
158
191
  end
159
192
  ```
160
193
 
161
- The Sequel driver is the only production-ready driver to date.
162
194
 
163
195
  # Usage
164
196
 
197
+ ## Aggregate Root
198
+
165
199
  Any object that should have event sourcing capability must include the methods provided by `Sandthorn::AggregateRoot`. These make it possible to `commit` events and `save` changes to an aggregate. Use the `include` directive as follows:
166
200
 
167
201
  ```ruby
@@ -251,6 +285,30 @@ end
251
285
 
252
286
  In this case, the resulting events from the commands `new` and `mark` will have the trace `{ip: :127.0.0.1}` attached to them.
253
287
 
288
+ ## Bounded Context
289
+
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)
291
+
292
+ A module can include `Sandthorn::BoundedContext` and all aggregates within the module can be retreived via the ::aggregate_types method on the module. A use case is to use it when Sandthorn is configured and setup all aggregates in a bounded context to a driver.
293
+
294
+ ```ruby
295
+ require 'sandthorn/bounded_context'
296
+
297
+ module TicTacToe
298
+ include Sandthorn::BoundedContext
299
+
300
+ class Board
301
+ include Sandthorn::AggregateRoot
302
+ end
303
+ end
304
+
305
+ Sandthorn.configure do |conf|
306
+ conf.event_stores = { foo: driver_foo}
307
+ conf.map_types = { foo: TicTacToe.aggregate_types }
308
+ end
309
+
310
+ TicTacToe.aggregate_types -> [TicTacToy::Board]
311
+ ```
254
312
 
255
313
  # Development
256
314
 
@@ -0,0 +1,39 @@
1
+ module Sandthorn
2
+ module BoundedContext
3
+ module ClassMethods
4
+ def aggregate_types
5
+ @aggregate_list = p_aggregate_types(self)
6
+ end
7
+
8
+ private
9
+
10
+ def p_aggregate_types(bounded_context_module)
11
+ return [] unless bounded_context_module.respond_to?(:constants)
12
+
13
+ classes = classes_in(bounded_context_module)
14
+ aggregate_list = classes.select { |item| item.include?(Sandthorn::AggregateRoot) }
15
+ modules = modules_in(bounded_context_module, classes)
16
+
17
+ aggregate_list += modules.flat_map { |m| p_aggregate_types(m) }
18
+
19
+ aggregate_list
20
+ end
21
+
22
+ def classes_in(namespace)
23
+ namespace.constants.map(&namespace.method(:const_get)).grep(Class)
24
+ end
25
+
26
+ def modules_in(namespace, classes)
27
+ namespace.constants.map(&namespace.method(:const_get)).grep(Module).delete_if do |m|
28
+ classes.include?(m) || m == Sandthorn::BoundedContext::ClassMethods
29
+ end
30
+ end
31
+ end
32
+
33
+ extend ClassMethods
34
+
35
+ def self.included( other )
36
+ other.extend( ClassMethods )
37
+ end
38
+ end
39
+ end
@@ -40,6 +40,12 @@ module Sandthorn
40
40
  store_map.values
41
41
  end
42
42
 
43
+ def map_types(hash)
44
+ hash.each_pair do |event_store, aggregate_types|
45
+ map_aggregate_types_to_event_store(aggregate_types, event_store)
46
+ end
47
+ end
48
+
43
49
  private
44
50
 
45
51
  attr_reader :store_map
@@ -60,5 +66,15 @@ module Sandthorn
60
66
  store.respond_to?(:get_events)
61
67
  end
62
68
 
69
+ def map_aggregate_type_to_event_store(aggregate_type, event_store)
70
+ aggregate_type.event_store(event_store)
71
+ end
72
+
73
+ def map_aggregate_types_to_event_store(aggregate_types = [], event_store)
74
+ aggregate_types.each do |aggregate_type|
75
+ map_aggregate_type_to_event_store(aggregate_type, event_store)
76
+ end
77
+ end
78
+
63
79
  end
64
80
  end
@@ -1,3 +1,3 @@
1
1
  module Sandthorn
2
- VERSION = "0.8.1"
2
+ VERSION = "0.9.0"
3
3
  end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+ require 'sandthorn/bounded_context'
3
+
4
+ module Sandthorn
5
+ describe BoundedContext do
6
+ it 'should respond to `aggregate_types`' do
7
+ expect(BoundedContext).to respond_to(:aggregate_types)
8
+ end
9
+ end
10
+
11
+ describe "::aggregate_types" do
12
+ module TestModule
13
+ include Sandthorn::BoundedContext
14
+ class AnAggregate
15
+ include Sandthorn::AggregateRoot
16
+ end
17
+
18
+ class NotAnAggregate
19
+ end
20
+
21
+ module Deep
22
+ class DeepAggregate
23
+ include Sandthorn::AggregateRoot
24
+ end
25
+ end
26
+ end
27
+
28
+ it "aggregate_types should include AnAggregate" do
29
+ expect(TestModule.aggregate_types).to include(TestModule::AnAggregate)
30
+ end
31
+
32
+ it "aggregate_types should not include NotAnAggregate" do
33
+ expect(TestModule.aggregate_types).not_to include(TestModule::NotAnAggregate)
34
+ end
35
+
36
+ it "aggregate_types should include DeepAnAggregate in a nested Module" do
37
+ expect(TestModule.aggregate_types).to include(TestModule::Deep::DeepAggregate)
38
+ end
39
+ end
40
+ end
@@ -4,6 +4,13 @@ module Sandthorn
4
4
  describe EventStores do
5
5
  let(:stores) { EventStores.new }
6
6
 
7
+ before do
8
+ class AnAggregate
9
+ include Sandthorn::AggregateRoot
10
+ end
11
+ end
12
+
13
+
7
14
  describe "#initialize" do
8
15
  context "when given a single event_store" do
9
16
  it "sets it as the default event store" do
@@ -77,5 +84,35 @@ module Sandthorn
77
84
  expect(stores[:foo]).to eq(store)
78
85
  end
79
86
  end
87
+
88
+ describe "#map_types" do
89
+
90
+ context "map two events stores" do
91
+
92
+ class AnAggregate1
93
+ include Sandthorn::AggregateRoot
94
+ end
95
+
96
+ class AnAggregate2
97
+ include Sandthorn::AggregateRoot
98
+ end
99
+
100
+ before do
101
+ store = double
102
+ stores.add(:foo, store)
103
+ stores.add(:bar, store)
104
+ stores.map_types(foo: [AnAggregate1], bar: [AnAggregate2])
105
+ end
106
+
107
+ it "should map event_store foo to AnAggregate1" do
108
+ expect(AnAggregate1.event_store).to eq(:foo)
109
+ end
110
+
111
+ it "should map event_store bar to AnAggregate2" do
112
+ expect(AnAggregate2.event_store).to eq(:bar)
113
+ end
114
+ end
115
+ end
116
+
80
117
  end
81
118
  end
@@ -6,7 +6,7 @@ end
6
6
 
7
7
  class AnotherAggregate
8
8
  include Sandthorn::AggregateRoot
9
- event_store :other
9
+ event_store :should_override_this
10
10
  end
11
11
 
12
12
  describe Sandthorn do
@@ -66,6 +66,7 @@ describe Sandthorn do
66
66
  url = "sqlite://spec/db/other_db.sqlite3"
67
67
  driver = SandthornDriverSequel.driver_from_url(url: url)
68
68
  Sandthorn.event_stores.add(:other, driver)
69
+ Sandthorn.event_stores.map_types(other: [AnotherAggregate])
69
70
  migrator = SandthornDriverSequel::Migration.new url: url
70
71
  SandthornDriverSequel.migrate_db url: url
71
72
  migrator.send(:clear_for_test)
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.8.1
4
+ version: 0.9.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: 2015-09-10 00:00:00.000000000 Z
13
+ date: 2015-09-29 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: bundler
@@ -192,6 +192,7 @@ files:
192
192
  - lib/sandthorn/aggregate_root_base.rb
193
193
  - lib/sandthorn/aggregate_root_marshal.rb
194
194
  - lib/sandthorn/aggregate_root_snapshot.rb
195
+ - lib/sandthorn/bounded_context.rb
195
196
  - lib/sandthorn/errors.rb
196
197
  - lib/sandthorn/event.rb
197
198
  - lib/sandthorn/event_inspector.rb
@@ -202,6 +203,7 @@ files:
202
203
  - spec/aggregate_root_spec.rb
203
204
  - spec/aggregate_snapshot_spec.rb
204
205
  - spec/benchmark_spec.rb
206
+ - spec/bounded_context_spec.rb
205
207
  - spec/complex_aggregate_spec.rb
206
208
  - spec/db/sequel_driver.sqlite3_old
207
209
  - spec/different_driver_spec.rb
@@ -243,6 +245,7 @@ test_files:
243
245
  - spec/aggregate_root_spec.rb
244
246
  - spec/aggregate_snapshot_spec.rb
245
247
  - spec/benchmark_spec.rb
248
+ - spec/bounded_context_spec.rb
246
249
  - spec/complex_aggregate_spec.rb
247
250
  - spec/db/sequel_driver.sqlite3_old
248
251
  - spec/different_driver_spec.rb