sandthorn_driver_sequel 1.1.0 → 2.0.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 +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
|