sandthorn_driver_sequel 1.1.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -1
- data/Guardfile +7 -0
- data/lib/sandthorn_driver_sequel/access/aggregate_access.rb +50 -0
- data/lib/sandthorn_driver_sequel/access/event_access.rb +81 -0
- data/lib/sandthorn_driver_sequel/access/snapshot_access.rb +87 -0
- data/lib/sandthorn_driver_sequel/access.rb +20 -0
- data/lib/sandthorn_driver_sequel/errors.rb +47 -5
- data/lib/sandthorn_driver_sequel/event_query.rb +90 -0
- data/lib/sandthorn_driver_sequel/event_store.rb +90 -153
- data/lib/sandthorn_driver_sequel/event_store_context.rb +1 -0
- data/lib/sandthorn_driver_sequel/migration.rb +9 -1
- data/lib/sandthorn_driver_sequel/old_event_store.rb +228 -0
- data/lib/sandthorn_driver_sequel/sequel_driver.rb +8 -25
- data/lib/sandthorn_driver_sequel/storage.rb +46 -0
- data/lib/sandthorn_driver_sequel/utilities/array.rb +13 -0
- data/lib/sandthorn_driver_sequel/utilities.rb +1 -0
- data/lib/sandthorn_driver_sequel/version.rb +1 -1
- data/lib/sandthorn_driver_sequel/wrappers/event_wrapper.rb +12 -0
- data/lib/sandthorn_driver_sequel/wrappers/snapshot_wrapper.rb +11 -0
- data/lib/sandthorn_driver_sequel/wrappers.rb +2 -0
- data/lib/sandthorn_driver_sequel.rb +5 -0
- data/sandthorn_driver_sequel.gemspec +2 -2
- data/spec/aggregate_access_spec.rb +97 -0
- data/spec/asking_for_aggregates_to_snapshot_spec.rb +7 -4
- data/spec/driver_interface_spec.rb +23 -40
- data/spec/event_access_spec.rb +96 -0
- data/spec/event_store_with_context_spec.rb +4 -4
- data/spec/get_events_spec.rb +20 -13
- data/spec/migration_specifying_domain_spec.rb +10 -10
- data/spec/saving_events_spec.rb +42 -39
- data/spec/saving_snapshot_spec.rb +7 -7
- data/spec/snapshot_access_spec.rb +119 -0
- data/spec/spec_helper.rb +0 -4
- data/spec/storage_spec.rb +66 -0
- metadata +39 -18
@@ -37,6 +37,15 @@ module SandthornDriverSequel
|
|
37
37
|
was_migrated aggr_migration_0, db
|
38
38
|
end
|
39
39
|
end
|
40
|
+
aggr_migration_1 = "#{aggregates_table_name}-20141024"
|
41
|
+
unless has_been_migrated?(aggr_migration_1)
|
42
|
+
driver.execute do |db|
|
43
|
+
db.alter_table(aggregates_table_name) do
|
44
|
+
set_column_default :aggregate_version, 0
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
40
49
|
end
|
41
50
|
def events
|
42
51
|
events_migration_0 = "#{events_table_name}-20130308"
|
@@ -95,7 +104,6 @@ module SandthornDriverSequel
|
|
95
104
|
String :migration_name, null: false
|
96
105
|
index [:migration_name], unique: true
|
97
106
|
DateTime :timestamp, :null=>false
|
98
|
-
index [:migration_name], unique: true
|
99
107
|
end
|
100
108
|
end
|
101
109
|
end
|
@@ -0,0 +1,228 @@
|
|
1
|
+
require 'sandthorn_driver_sequel/sequel_driver'
|
2
|
+
|
3
|
+
module SandthornDriverSequel
|
4
|
+
class OldEventStore
|
5
|
+
include EventStoreContext
|
6
|
+
attr_reader :driver, :context, :url
|
7
|
+
def initialize url: nil, context: nil
|
8
|
+
@driver = SequelDriver.new url: url
|
9
|
+
@context = context
|
10
|
+
@url = url
|
11
|
+
end
|
12
|
+
|
13
|
+
def save_events aggregate_events, originating_aggregate_version, aggregate_id, class_name
|
14
|
+
current_aggregate_version = originating_aggregate_version
|
15
|
+
aggregate_type = class_name.to_s
|
16
|
+
driver.execute_in_transaction do |db|
|
17
|
+
if current_aggregate_version == 0
|
18
|
+
pk_id = register_new_aggregate(aggregate_id, aggregate_type, db)
|
19
|
+
else
|
20
|
+
current_aggregate = get_current_aggregate_from_aggregates_table(aggregate_id, aggregate_type, db)
|
21
|
+
check_initial_aggregate_version!(current_aggregate, current_aggregate_version)
|
22
|
+
pk_id = current_aggregate[:id]
|
23
|
+
end
|
24
|
+
timestamp = Time.now.utc
|
25
|
+
aggregate_events.each do |event|
|
26
|
+
current_aggregate_version += 1
|
27
|
+
check_event_aggregate_version!(event, class_name, current_aggregate_version)
|
28
|
+
insert_event(db, event, pk_id, timestamp)
|
29
|
+
end
|
30
|
+
db[aggregates_table_name].where(id: pk_id).update(aggregate_version: current_aggregate_version)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def insert_event(db, event, pk_id, timestamp)
|
35
|
+
to_insert = {
|
36
|
+
aggregate_table_id: pk_id,
|
37
|
+
aggregate_version: event[:aggregate_version],
|
38
|
+
event_name: event[:event_name],
|
39
|
+
event_data: event[:event_data],
|
40
|
+
timestamp: timestamp
|
41
|
+
}
|
42
|
+
db[events_table_name].insert(to_insert)
|
43
|
+
end
|
44
|
+
|
45
|
+
def check_event_aggregate_version!(event, aggregate_type, current_aggregate_version)
|
46
|
+
if event[:aggregate_version] != current_aggregate_version
|
47
|
+
raise SandthornDriverSequel::Errors::ConcurrencyError, event, aggregate_type, current_aggregate_version
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def check_initial_aggregate_version!(aggregate, current_aggregate_version)
|
52
|
+
if aggregate[:aggregate_version] != current_aggregate_version
|
53
|
+
raise SandthornDriverSequel::Errors::WrongAggregateVersionError, aggregate, current_aggregate_version
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def register_new_aggregate(aggregate_id, aggregate_type, db)
|
58
|
+
to_insert = {
|
59
|
+
aggregate_id: aggregate_id,
|
60
|
+
aggregate_type: aggregate_type,
|
61
|
+
aggregate_version: 0
|
62
|
+
}
|
63
|
+
pk_id = db[aggregates_table_name].insert(to_insert)
|
64
|
+
end
|
65
|
+
|
66
|
+
def save_snapshot aggregate_snapshot, aggregate_id, class_name
|
67
|
+
driver.execute_in_transaction do |db|
|
68
|
+
current_aggregate = get_current_aggregate_from_aggregates_table aggregate_id, class_name, db
|
69
|
+
pk_id = current_aggregate[:id]
|
70
|
+
current_snapshot = get_current_snapshot pk_id, db
|
71
|
+
aggregate_version = aggregate_snapshot[:aggregate_version]
|
72
|
+
return if snapshot_fresh?(current_snapshot, aggregate_version)
|
73
|
+
check_snapshot_version!(current_aggregate, aggregate_version)
|
74
|
+
if current_snapshot.nil?
|
75
|
+
to_insert = {aggregate_version: aggregate_version, snapshot_data: aggregate_snapshot[:event_data], aggregate_table_id: pk_id }
|
76
|
+
db[snapshots_table_name].insert(to_insert)
|
77
|
+
else
|
78
|
+
to_update = {aggregate_version: aggregate_version, snapshot_data: aggregate_snapshot[:event_data] }
|
79
|
+
db[snapshots_table_name].where(aggregate_table_id: pk_id).update(to_update)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def snapshot_fresh?(current_snapshot, aggregate_version)
|
85
|
+
!current_snapshot.nil? && current_snapshot[:aggregate_version] == aggregate_version
|
86
|
+
end
|
87
|
+
|
88
|
+
def check_snapshot_version!(aggregate, aggregate_version)
|
89
|
+
if aggregate[:aggregate_version] < aggregate_version
|
90
|
+
raise SandthornDriverSequel::Errors::WrongSnapshotVersionError, aggregate, version
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def get_aggregate_events aggregate_id, *class_name
|
95
|
+
#aggregate_type = class_name.to_s unless class_name.nil?
|
96
|
+
return aggregate_events aggregate_id: aggregate_id
|
97
|
+
end
|
98
|
+
|
99
|
+
def get_aggregate aggregate_id, *class_name
|
100
|
+
snapshot = get_snapshot aggregate_id, class_name
|
101
|
+
after_aggregate_version = 0
|
102
|
+
after_aggregate_version = snapshot[:aggregate_version] unless snapshot.nil?
|
103
|
+
events = aggregate_events after_aggregate_version: after_aggregate_version, aggregate_id: aggregate_id
|
104
|
+
unless snapshot.nil?
|
105
|
+
snap_event = snapshot
|
106
|
+
snap_event[:event_name] = "aggregate_set_from_snapshot"
|
107
|
+
events = events.unshift(snap_event)
|
108
|
+
end
|
109
|
+
events
|
110
|
+
end
|
111
|
+
def get_aggregate_list_by_typename class_name
|
112
|
+
aggregate_type = class_name.to_s
|
113
|
+
driver.execute do |db|
|
114
|
+
db[aggregates_table_name].where(aggregate_type: aggregate_type).select(:aggregate_id).map { |e| e[:aggregate_id] }
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def get_all_typenames
|
119
|
+
driver.execute do |db|
|
120
|
+
db[aggregates_table_name].select(:aggregate_type).distinct.order(:aggregate_type).map{|e| e[:aggregate_type]}
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def get_snapshot aggregate_id, *class_name
|
125
|
+
aggregate_type = class_name.first.to_s
|
126
|
+
driver.execute do |db|
|
127
|
+
current_aggregate = get_current_aggregate_from_aggregates_table aggregate_id, aggregate_type, db
|
128
|
+
snap = get_current_snapshot current_aggregate[:id], db
|
129
|
+
return nil if snap.nil?
|
130
|
+
return {aggregate_version: snap[:aggregate_version], event_data: snap[:snapshot_data]}
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def get_new_events_after_event_id_matching_classname event_id, class_name, args = {}
|
135
|
+
take = args.fetch(:take, 0)
|
136
|
+
aggregate_type = class_name.to_s
|
137
|
+
driver.execute do |db|
|
138
|
+
query = db[events_table_name].join(aggregates_table_name, id: :aggregate_table_id, aggregate_type: aggregate_type)
|
139
|
+
query = query.where{sequence_number > event_id}
|
140
|
+
rel = "#{events_table_name}__aggregate_version".to_sym
|
141
|
+
query = query.select(:aggregate_type, rel, :aggregate_id, :sequence_number, :event_name, :event_data, :timestamp)
|
142
|
+
query = query.limit(take) if take > 0
|
143
|
+
return query.order(:sequence_number).all
|
144
|
+
end
|
145
|
+
end
|
146
|
+
def get_events aggregate_types: [], take: 0, after_sequence_number: 0, include_events: [], exclude_events: []
|
147
|
+
include_events = include_events.map { |e| e.to_s }
|
148
|
+
exclude_events = exclude_events.map { |e| e.to_s }
|
149
|
+
aggregate_types = aggregate_types.map { |e| e.to_s }
|
150
|
+
driver.execute do |db|
|
151
|
+
if aggregate_types.empty?
|
152
|
+
query = db[events_table_name].join(aggregates_table_name, id: :aggregate_table_id)
|
153
|
+
else
|
154
|
+
query = db[events_table_name].join(aggregates_table_name, id: :aggregate_table_id, aggregate_type: aggregate_types)
|
155
|
+
end
|
156
|
+
query = query.where{sequence_number > after_sequence_number}
|
157
|
+
unless include_events.empty?
|
158
|
+
query = query.where(event_name: include_events)
|
159
|
+
end
|
160
|
+
unless exclude_events.empty?
|
161
|
+
query = query.exclude(event_name: exclude_events)
|
162
|
+
end
|
163
|
+
rel = "#{events_table_name}__aggregate_version".to_sym
|
164
|
+
query = query.select(:aggregate_type, rel, :aggregate_id, :sequence_number, :event_name, :event_data, :timestamp)
|
165
|
+
query = query.limit(take) if take > 0
|
166
|
+
return query.order(:sequence_number).all
|
167
|
+
end
|
168
|
+
end
|
169
|
+
def obsolete_snapshots aggregate_types: [], max_event_distance: 100
|
170
|
+
driver.execute do |db|
|
171
|
+
rel = "#{snapshots_table_name}__aggregate_version".to_sym
|
172
|
+
aggr_rel = "#{aggregates_table_name}__aggregate_version".to_sym
|
173
|
+
query_select = eval("lambda{(#{aggr_rel} - coalesce(#{rel},0)).as(distance)}")
|
174
|
+
query = db[aggregates_table_name].left_outer_join(snapshots_table_name, aggregate_table_id: :id)
|
175
|
+
query = query.select &query_select
|
176
|
+
query = query.select_append(:aggregate_id, :aggregate_type)
|
177
|
+
query_where = eval("lambda{(#{aggr_rel} - coalesce(#{rel},0)) > max_event_distance}")
|
178
|
+
query = query.where &query_where
|
179
|
+
unless class_names.empty?
|
180
|
+
class_names.map! {|c|c.to_s}
|
181
|
+
query = query.where(aggregate_type: class_names)
|
182
|
+
end
|
183
|
+
query.all
|
184
|
+
end
|
185
|
+
end
|
186
|
+
private
|
187
|
+
|
188
|
+
def aggregate_events after_aggregate_version: 0, aggregate_id: nil
|
189
|
+
|
190
|
+
rel = "#{events_table_name}__aggregate_version".to_sym
|
191
|
+
where_proc = eval("lambda{ #{rel} > after_aggregate_version }")
|
192
|
+
driver.execute do |db|
|
193
|
+
query = db[events_table_name].join(aggregates_table_name, id: :aggregate_table_id, aggregate_id: aggregate_id)
|
194
|
+
query = query.where &where_proc
|
195
|
+
result = query.select(rel, :aggregate_id, :sequence_number, :event_name, :event_data, :timestamp).order(:sequence_number).all
|
196
|
+
end
|
197
|
+
|
198
|
+
# result = nil
|
199
|
+
# Benchmark.bm do |x|
|
200
|
+
# x.report("find") {
|
201
|
+
# rel = "#{events_table_name}__aggregate_version".to_sym
|
202
|
+
# where_proc = eval("lambda{ #{rel} > after_aggregate_version }")
|
203
|
+
# driver.execute do |db|
|
204
|
+
# query = db[events_table_name].join(aggregates_table_name, id: :aggregate_table_id, aggregate_id: aggregate_id)
|
205
|
+
# query = query.where &where_proc
|
206
|
+
# result = query.select(rel, :aggregate_id, :sequence_number, :event_name, :event_data, :timestamp).order(:sequence_number).all
|
207
|
+
# end
|
208
|
+
# }
|
209
|
+
|
210
|
+
# end
|
211
|
+
# result
|
212
|
+
end
|
213
|
+
def get_current_aggregate_from_aggregates_table aggregate_id, aggregate_type, db
|
214
|
+
aggregate_type = aggregate_type.to_s
|
215
|
+
current_aggregate = db[aggregates_table_name].where(aggregate_id: aggregate_id)
|
216
|
+
if current_aggregate.empty?
|
217
|
+
error_message = "#{aggregate_type} with id #{aggregate_id} was not found in the eventstore."
|
218
|
+
raise SandthornDriverSequel::Errors::NoAggregateError.new(error_message)
|
219
|
+
end
|
220
|
+
current_aggregate.first
|
221
|
+
end
|
222
|
+
def get_current_snapshot aggregate_table_id, db
|
223
|
+
snap = db[snapshots_table_name].where(aggregate_table_id: aggregate_table_id)
|
224
|
+
return nil if snap.empty?
|
225
|
+
snap.first
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
@@ -2,39 +2,22 @@ require 'sequel'
|
|
2
2
|
|
3
3
|
module SandthornDriverSequel
|
4
4
|
class SequelDriver
|
5
|
+
|
5
6
|
def initialize args = {}
|
6
7
|
@url = args.fetch(:url)
|
7
8
|
Sequel.default_timezone = :utc
|
8
9
|
@db = Sequel.connect(@url)
|
9
10
|
end
|
10
|
-
|
11
|
-
|
11
|
+
|
12
|
+
def execute
|
13
|
+
yield @db
|
12
14
|
end
|
15
|
+
|
13
16
|
def execute_in_transaction &block
|
14
|
-
@db.transaction
|
15
|
-
|
16
|
-
|
17
|
+
@db.transaction do
|
18
|
+
block.call(@db)
|
19
|
+
end
|
17
20
|
end
|
18
21
|
|
19
22
|
end
|
20
23
|
end
|
21
|
-
|
22
|
-
|
23
|
-
# module SandthornDriverSequel
|
24
|
-
# class SequelDriver
|
25
|
-
# def initialize args = {}
|
26
|
-
# @url = args.fetch(:url)
|
27
|
-
# Sequel.default_timezone = :utc
|
28
|
-
# end
|
29
|
-
# def execute &block
|
30
|
-
# Sequel.connect(@url) { |db| return block.call db}
|
31
|
-
# end
|
32
|
-
# def execute_in_transaction &block
|
33
|
-
# Sequel.connect(@url) do |db|
|
34
|
-
# db.transaction do
|
35
|
-
# return block.call db
|
36
|
-
# end
|
37
|
-
# end
|
38
|
-
# end
|
39
|
-
# end
|
40
|
-
# end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module SandthornDriverSequel
|
2
|
+
class Storage
|
3
|
+
# = Storage
|
4
|
+
# Abstracts access to contextualized database tables.
|
5
|
+
#
|
6
|
+
# == Rationale
|
7
|
+
# Provide object-oriented access to the different tables to other objects.
|
8
|
+
# Make it unnecessary for them to know about the current context.
|
9
|
+
include EventStoreContext
|
10
|
+
|
11
|
+
attr_reader :db
|
12
|
+
|
13
|
+
def initialize(db, context)
|
14
|
+
@db = db
|
15
|
+
@context = context
|
16
|
+
end
|
17
|
+
|
18
|
+
# Returns a Sequel::Model for accessing aggregates
|
19
|
+
def aggregates
|
20
|
+
Class.new(Sequel::Model(aggregates_table))
|
21
|
+
end
|
22
|
+
|
23
|
+
# Returns a Sequel::Model for accessing events
|
24
|
+
def events
|
25
|
+
Class.new(Sequel::Model(events_table))
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns a Sequel::Model for accessing snapshots
|
29
|
+
def snapshots
|
30
|
+
Class.new(Sequel::Model(snapshots_table))
|
31
|
+
end
|
32
|
+
|
33
|
+
def aggregates_table
|
34
|
+
db[aggregates_table_name]
|
35
|
+
end
|
36
|
+
|
37
|
+
def events_table
|
38
|
+
db[events_table_name]
|
39
|
+
end
|
40
|
+
|
41
|
+
def snapshots_table
|
42
|
+
db[snapshots_table_name]
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require "sandthorn_driver_sequel/utilities/array"
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'delegate'
|
2
|
+
module SandthornDriverSequel
|
3
|
+
class EventWrapper < SimpleDelegator
|
4
|
+
|
5
|
+
[:aggregate_version, :event_name, :event_data, :timestamp, :aggregate_table_id].each do |attribute|
|
6
|
+
define_method(attribute) do
|
7
|
+
fetch(attribute)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
end
|
@@ -1,5 +1,10 @@
|
|
1
1
|
require "sandthorn_driver_sequel/version"
|
2
|
+
require "sandthorn_driver_sequel/utilities"
|
3
|
+
require "sandthorn_driver_sequel/wrappers"
|
4
|
+
require "sandthorn_driver_sequel/event_query"
|
2
5
|
require "sandthorn_driver_sequel/event_store_context"
|
6
|
+
require "sandthorn_driver_sequel/access"
|
7
|
+
require "sandthorn_driver_sequel/storage"
|
3
8
|
require 'sandthorn_driver_sequel/event_store'
|
4
9
|
require 'sandthorn_driver_sequel/errors'
|
5
10
|
require 'sandthorn_driver_sequel/migration'
|
@@ -22,7 +22,6 @@ Gem::Specification.new do |spec|
|
|
22
22
|
spec.add_development_dependency "rake"
|
23
23
|
|
24
24
|
spec.add_development_dependency "rspec"
|
25
|
-
spec.add_development_dependency "coveralls"
|
26
25
|
spec.add_development_dependency "gem-release"
|
27
26
|
spec.add_development_dependency "sqlite3"
|
28
27
|
spec.add_development_dependency "pry"
|
@@ -33,7 +32,8 @@ Gem::Specification.new do |spec|
|
|
33
32
|
spec.add_development_dependency "ruby-beautify"
|
34
33
|
spec.add_development_dependency "msgpack"
|
35
34
|
spec.add_development_dependency "snappy"
|
35
|
+
spec.add_development_dependency "guard-rspec"
|
36
36
|
|
37
|
-
spec.add_runtime_dependency "sequel"
|
37
|
+
spec.add_runtime_dependency "sequel", "~> 4.17"
|
38
38
|
spec.add_runtime_dependency "pg"
|
39
39
|
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module SandthornDriverSequel
|
4
|
+
describe AggregateAccess do
|
5
|
+
include EventStoreContext
|
6
|
+
let(:context) { :test }
|
7
|
+
let(:db) { Sequel.connect(event_store_url)}
|
8
|
+
let(:aggregate_id) { generate_uuid }
|
9
|
+
let(:storage) { Storage.new(db, :test) }
|
10
|
+
let(:access) { AggregateAccess.new(storage) }
|
11
|
+
|
12
|
+
before { prepare_for_test }
|
13
|
+
|
14
|
+
describe "#find" do
|
15
|
+
it "finds by table id" do
|
16
|
+
aggregate = access.register_aggregate(aggregate_id, "boo")
|
17
|
+
aggregate = access.find(aggregate.id)
|
18
|
+
expect(aggregate.aggregate_id).to eq(aggregate_id)
|
19
|
+
expect(aggregate.aggregate_type).to eq("boo")
|
20
|
+
end
|
21
|
+
|
22
|
+
it "doesn't find by table id" do
|
23
|
+
access.register_aggregate(aggregate_id, "foo")
|
24
|
+
max_id = db[aggregates_table_name].max(:id)
|
25
|
+
expect(access.find(max_id + 1)).to be_nil
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "#find_by_aggregate_id" do
|
30
|
+
context "when the aggregate is registered" do
|
31
|
+
it "returns the aggregate" do
|
32
|
+
access.register_aggregate(aggregate_id, "bar")
|
33
|
+
aggregate = access.find_by_aggregate_id(aggregate_id)
|
34
|
+
expect(aggregate.aggregate_id).to eq(aggregate_id)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context "when the aggregate isn't registered" do
|
39
|
+
it "returns nil" do
|
40
|
+
expect(access.find_by_aggregate_id(aggregate_id)).to be_nil
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "#find_or_register" do
|
46
|
+
context "when the aggregate is registered" do
|
47
|
+
it "returns the aggregate" do
|
48
|
+
access.register_aggregate(aggregate_id, "baz")
|
49
|
+
aggregate = access.find_or_register(aggregate_id, "qux")
|
50
|
+
expect(aggregate.aggregate_id).to eq(aggregate_id)
|
51
|
+
expect(aggregate.aggregate_type).to eq("baz")
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe "#register_aggregate" do
|
57
|
+
it "returns the aggregate" do
|
58
|
+
aggregate = access.register_aggregate(aggregate_id, "bar")
|
59
|
+
expect(aggregate.aggregate_id).to eq(aggregate_id)
|
60
|
+
expect(aggregate.aggregate_type).to eq("bar")
|
61
|
+
expect(aggregate.id).to_not be_nil
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "#aggregate_types" do
|
66
|
+
it "returns all aggregate types in the event store" do
|
67
|
+
types = ["foo", "bar", "qux"]
|
68
|
+
types.each do |type|
|
69
|
+
access.register_aggregate(generate_uuid, type)
|
70
|
+
end
|
71
|
+
expect(access.aggregate_types).to eq(types.sort)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe "#aggregate_ids" do
|
76
|
+
context "when given no argument" do
|
77
|
+
it "returns all aggregate ids" do
|
78
|
+
aggregate_ids = 3.times.map { generate_uuid }
|
79
|
+
aggregate_ids.each { |id| access.register_aggregate(id, "foo") }
|
80
|
+
expect(access.aggregate_ids).to eq(aggregate_ids)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
context "when given an aggregate type" do
|
84
|
+
it "returns only aggregates of that type" do
|
85
|
+
foo_agg_id, bar_agg_id = generate_uuid, generate_uuid
|
86
|
+
access.register_aggregate(foo_agg_id, "foo")
|
87
|
+
access.register_aggregate(bar_agg_id, "bar")
|
88
|
+
expect(access.aggregate_ids(aggregate_type: "foo")).to eq([foo_agg_id])
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def generate_uuid
|
94
|
+
SecureRandom.uuid
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|