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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6df7059570ed2a75376a49b5568cde3dcda5abef
|
4
|
+
data.tar.gz: d0df6fa0c71d2388f31897fcb4c1918ecbe6bdd2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cff7f24db48fe2ec230c54526f3231fff0c2f7cd94ed12b585807cfa06084cba5a7c4d7d63b670816844ba8b5f6a3114a6d755bb0b16b6cb2e3336ea9c68236c
|
7
|
+
data.tar.gz: 2592b3457a5c030517d968302aa4c716af3cd58fa3080c1378960a066a40fbf28000e963ab22d75c0fbf600acd3b4f75799ceea63d3a01f1c7d90d59927b5ea4
|
data/.gitignore
CHANGED
data/Guardfile
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
module SandthornDriverSequel
|
2
|
+
class AggregateAccess < Access::Base
|
3
|
+
|
4
|
+
def find_or_register(aggregate_id, aggregate_type)
|
5
|
+
if aggregate = find_by_aggregate_id(aggregate_id)
|
6
|
+
aggregate
|
7
|
+
else
|
8
|
+
register_aggregate(aggregate_id, aggregate_type)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# Create a database row for an aggregate.
|
13
|
+
# Return the row.
|
14
|
+
def register_aggregate(aggregate_id, aggregate_type)
|
15
|
+
id = storage.aggregates.insert(aggregate_id: aggregate_id, aggregate_type: aggregate_type.to_s)
|
16
|
+
find(id)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Find by database table id.
|
20
|
+
def find(id)
|
21
|
+
storage.aggregates[id]
|
22
|
+
end
|
23
|
+
|
24
|
+
def find_by_aggregate_id(aggregate_id)
|
25
|
+
storage.aggregates.first(aggregate_id: aggregate_id)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Throws an error if the aggregate isn't registered.
|
29
|
+
def find_by_aggregate_id!(aggregate_id)
|
30
|
+
aggregate = find_by_aggregate_id(aggregate_id)
|
31
|
+
raise Errors::NoAggregateError, aggregate_id unless aggregate
|
32
|
+
aggregate
|
33
|
+
end
|
34
|
+
|
35
|
+
def aggregate_types
|
36
|
+
storage.aggregates.select(:aggregate_type).distinct.select_map(:aggregate_type)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Returns aggregate ids.
|
40
|
+
# @param aggregate_type, optional,
|
41
|
+
def aggregate_ids(aggregate_type: nil)
|
42
|
+
aggs = storage.aggregates
|
43
|
+
if aggregate_type
|
44
|
+
aggs = aggs.where(aggregate_type: aggregate_type.to_s)
|
45
|
+
end
|
46
|
+
aggs.order(:id).select_map(:aggregate_id)
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module SandthornDriverSequel
|
2
|
+
class EventAccess < Access::Base
|
3
|
+
# = EventAccess
|
4
|
+
# Reads and writes events.
|
5
|
+
|
6
|
+
def store_events(aggregate, events)
|
7
|
+
events = Utilities.array_wrap(events)
|
8
|
+
timestamp = Time.now.utc
|
9
|
+
events.each do |event|
|
10
|
+
store_event(aggregate, timestamp, event)
|
11
|
+
end
|
12
|
+
aggregate.save
|
13
|
+
end
|
14
|
+
|
15
|
+
def find_events_by_aggregate_id(aggregate_id)
|
16
|
+
aggregate_version = Sequel.qualify(storage.events_table_name, :aggregate_version)
|
17
|
+
wrap(storage.events
|
18
|
+
.join(storage.aggregates, id: :aggregate_table_id)
|
19
|
+
.where(aggregate_id: aggregate_id)
|
20
|
+
.select(
|
21
|
+
:sequence_number,
|
22
|
+
:aggregate_id,
|
23
|
+
:aggregate_table_id,
|
24
|
+
aggregate_version,
|
25
|
+
:event_name,
|
26
|
+
:event_data,
|
27
|
+
:timestamp)
|
28
|
+
.all)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Returns events that occurred after the given snapshot
|
32
|
+
def after_snapshot(snapshot)
|
33
|
+
_aggregate_version = snapshot.aggregate_version
|
34
|
+
aggregate_table_id = snapshot.aggregate_table_id
|
35
|
+
wrap(storage.events
|
36
|
+
.where(aggregate_table_id: aggregate_table_id)
|
37
|
+
.where { aggregate_version > _aggregate_version }.all)
|
38
|
+
end
|
39
|
+
|
40
|
+
def get_events(*args)
|
41
|
+
query_builder = EventQuery.new(storage)
|
42
|
+
query_builder.build(*args)
|
43
|
+
wrap(query_builder.events)
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def wrap(arg)
|
49
|
+
events = Utilities.array_wrap(arg)
|
50
|
+
events.map { |e| EventWrapper.new(e.values) }
|
51
|
+
end
|
52
|
+
|
53
|
+
def build_event_data(aggregate, timestamp, event)
|
54
|
+
{
|
55
|
+
aggregate_table_id: aggregate.id,
|
56
|
+
aggregate_version: event.aggregate_version,
|
57
|
+
event_name: event.event_name,
|
58
|
+
event_data: event.event_data,
|
59
|
+
timestamp: timestamp
|
60
|
+
}
|
61
|
+
end
|
62
|
+
|
63
|
+
def check_versions!(aggregate, event)
|
64
|
+
version = aggregate.aggregate_version
|
65
|
+
if version != event[:aggregate_version]
|
66
|
+
raise Errors::ConcurrencyError.new(event, aggregate)
|
67
|
+
end
|
68
|
+
rescue TypeError
|
69
|
+
raise Errors::EventFormatError, "Event has wrong format: #{event.inspect}"
|
70
|
+
end
|
71
|
+
|
72
|
+
def store_event(aggregate, timestamp, event)
|
73
|
+
event = EventWrapper.new(event)
|
74
|
+
aggregate.aggregate_version += 1
|
75
|
+
check_versions!(aggregate, event)
|
76
|
+
data = build_event_data(aggregate, timestamp, event)
|
77
|
+
storage.events.insert(data)
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module SandthornDriverSequel
|
2
|
+
class SnapshotAccess < Access::Base
|
3
|
+
|
4
|
+
def find_by_aggregate_id(aggregate_id)
|
5
|
+
aggregate = aggregates.find_by_aggregate_id(aggregate_id)
|
6
|
+
storage.snapshots.first(aggregate_table_id: aggregate.id)
|
7
|
+
end
|
8
|
+
|
9
|
+
def find(snapshot_id)
|
10
|
+
storage.snapshots[snapshot_id]
|
11
|
+
end
|
12
|
+
|
13
|
+
def record_snapshot(aggregate_id, snapshot_data)
|
14
|
+
aggregate = aggregates.find_by_aggregate_id!(aggregate_id)
|
15
|
+
previous_snapshot = find_by_aggregate_id(aggregate_id)
|
16
|
+
if perform_snapshot?(aggregate, previous_snapshot)
|
17
|
+
perform_snapshot(aggregate, previous_snapshot, snapshot_data)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def obsolete(aggregate_types: [], max_event_distance: 100)
|
22
|
+
aggregate_types.map!(&:to_s)
|
23
|
+
snapshot_version = Sequel.qualify(storage.snapshots_table_name, :aggregate_version)
|
24
|
+
aggregate_version = Sequel.qualify(storage.aggregates_table_name, :aggregate_version)
|
25
|
+
query = storage.aggregates.left_outer_join(storage.snapshots, aggregate_table_id: :id)
|
26
|
+
query = query.select { (aggregate_version - snapshot_version).as(distance) }
|
27
|
+
query = query.select_append(:aggregate_id, :aggregate_type)
|
28
|
+
query = query.where { (aggregate_version - coalesce(snapshot_version, 0)) > max_event_distance }
|
29
|
+
if aggregate_types.any?
|
30
|
+
query = query.where(aggregate_type: aggregate_types)
|
31
|
+
end
|
32
|
+
query.all
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def aggregates
|
38
|
+
@aggregates ||= AggregateAccess.new(storage)
|
39
|
+
end
|
40
|
+
|
41
|
+
def perform_snapshot?(aggregate, snapshot)
|
42
|
+
return true if snapshot.nil?
|
43
|
+
snapshot = SnapshotWrapper.new(snapshot)
|
44
|
+
aggregate.aggregate_version > snapshot.aggregate_version
|
45
|
+
end
|
46
|
+
|
47
|
+
def perform_snapshot(aggregate, snapshot, snapshot_data)
|
48
|
+
check_snapshot_version!(aggregate, snapshot_data)
|
49
|
+
if valid_snapshot?(snapshot)
|
50
|
+
update_snapshot(snapshot, snapshot_data)
|
51
|
+
else
|
52
|
+
insert_snapshot(aggregate, snapshot_data)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def insert_snapshot(aggregate, snapshot_data)
|
57
|
+
data = build_snapshot(snapshot_data)
|
58
|
+
data[:aggregate_table_id] = aggregate.id
|
59
|
+
storage.snapshots.insert(data)
|
60
|
+
end
|
61
|
+
|
62
|
+
def build_snapshot(snapshot_data)
|
63
|
+
snapshot_data = SnapshotWrapper.new(snapshot_data)
|
64
|
+
{
|
65
|
+
snapshot_data: snapshot_data.data,
|
66
|
+
aggregate_version: snapshot_data.aggregate_version
|
67
|
+
}
|
68
|
+
end
|
69
|
+
|
70
|
+
def valid_snapshot?(snapshot)
|
71
|
+
snapshot && snapshot[:snapshot_data]
|
72
|
+
end
|
73
|
+
|
74
|
+
def update_snapshot(snapshot, snapshot_data)
|
75
|
+
data = build_snapshot(snapshot_data)
|
76
|
+
storage.snapshots.where(id: snapshot.id).update(data)
|
77
|
+
end
|
78
|
+
|
79
|
+
def check_snapshot_version!(aggregate, snapshot_data)
|
80
|
+
snapshot = SnapshotWrapper.new(snapshot_data)
|
81
|
+
if aggregate.aggregate_version < snapshot.aggregate_version
|
82
|
+
raise Errors::WrongSnapshotVersionError.new(aggregate, snapshot.aggregate_version)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module SandthornDriverSequel
|
2
|
+
module Access
|
3
|
+
class Base
|
4
|
+
# = Access::Base
|
5
|
+
# Inheriting classes use +storage+ to provide access to a
|
6
|
+
# particular database model/table.
|
7
|
+
def initialize(storage)
|
8
|
+
@storage = storage
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
attr_reader :storage
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
require "sandthorn_driver_sequel/access/aggregate_access"
|
19
|
+
require "sandthorn_driver_sequel/access/event_access"
|
20
|
+
require "sandthorn_driver_sequel/access/snapshot_access"
|
@@ -1,7 +1,49 @@
|
|
1
1
|
module SandthornDriverSequel::Errors
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
2
|
+
Error = Class.new(StandardError)
|
3
|
+
InternalError = Class.new(Error)
|
4
|
+
NoAggregateError = Class.new(Error)
|
5
|
+
EventFormatError = Class.new(Error)
|
6
|
+
|
7
|
+
class ConcurrencyError < Error
|
8
|
+
attr_reader :event, :aggregate
|
9
|
+
def initialize(event, aggregate)
|
10
|
+
@event = event
|
11
|
+
@aggregate = aggregate
|
12
|
+
super(create_message)
|
13
|
+
end
|
14
|
+
|
15
|
+
def create_message
|
16
|
+
"#{aggregate.aggregate_type} with id #{aggregate.aggregate_id}: " +
|
17
|
+
"expected event with version #{aggregate.aggregate_version}, but got #{event.aggregate_version}"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class WrongAggregateVersionError < Error;
|
22
|
+
def initialize(aggregate, version)
|
23
|
+
@aggregate = aggregate
|
24
|
+
@version = version
|
25
|
+
super(create_message)
|
26
|
+
end
|
27
|
+
|
28
|
+
def create_message
|
29
|
+
"#{@aggregate[:aggregate_type]} with id #{@aggregate[:aggregate_id]}" +
|
30
|
+
" should be at version #{@version}" +
|
31
|
+
" but was #{@aggregate[:aggregate_version]} in the event store."
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class WrongSnapshotVersionError < Error
|
36
|
+
attr_reader :aggregate, :version
|
37
|
+
def initialize(aggregate, version)
|
38
|
+
@aggregate = aggregate
|
39
|
+
@version = version
|
40
|
+
super(create_message)
|
41
|
+
end
|
42
|
+
|
43
|
+
def create_message
|
44
|
+
"#{aggregate[:aggregate_type]} with id #{aggregate[:aggregate_id]}: tried to save snapshot with version "+
|
45
|
+
"#{version}, but current version is at #{aggregate[:aggregate_version]}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
7
49
|
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module SandthornDriverSequel
|
2
|
+
class EventQuery
|
3
|
+
def initialize(storage)
|
4
|
+
@storage = storage
|
5
|
+
end
|
6
|
+
|
7
|
+
def build(
|
8
|
+
aggregate_types: [],
|
9
|
+
take: 0,
|
10
|
+
after_sequence_number: 0,
|
11
|
+
include_events: [],
|
12
|
+
exclude_events: [])
|
13
|
+
|
14
|
+
aggregate_types.map!(&:to_s)
|
15
|
+
include_events.map!(&:to_s)
|
16
|
+
exclude_events.map!(&:to_s)
|
17
|
+
|
18
|
+
query = storage.events
|
19
|
+
query = add_aggregate_types(query, aggregate_types)
|
20
|
+
query = add_sequence_number(query, after_sequence_number)
|
21
|
+
query = add_included_events(query, include_events)
|
22
|
+
query = add_excluded_events(query, exclude_events)
|
23
|
+
query = add_select(query)
|
24
|
+
query = add_limit(query, take)
|
25
|
+
@query = query.order(:sequence_number)
|
26
|
+
end
|
27
|
+
|
28
|
+
def events
|
29
|
+
@query.all
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
attr_reader :storage
|
35
|
+
|
36
|
+
def add_limit(query, take)
|
37
|
+
if take > 0
|
38
|
+
query.limit(take)
|
39
|
+
else
|
40
|
+
query
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def add_select(query)
|
45
|
+
query.select(*select_columns)
|
46
|
+
end
|
47
|
+
|
48
|
+
def select_columns
|
49
|
+
rel = Sequel.qualify(storage.events_table_name, :aggregate_version)
|
50
|
+
[
|
51
|
+
:aggregate_type,
|
52
|
+
rel,
|
53
|
+
:aggregate_id,
|
54
|
+
:sequence_number,
|
55
|
+
:event_name,
|
56
|
+
:event_data,
|
57
|
+
:timestamp
|
58
|
+
]
|
59
|
+
end
|
60
|
+
|
61
|
+
def add_excluded_events(query, exclude_events)
|
62
|
+
if exclude_events.any?
|
63
|
+
query.exclude(event_name: exclude_events)
|
64
|
+
else
|
65
|
+
query
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def add_included_events(query, include_events)
|
70
|
+
if include_events.any?
|
71
|
+
query.where(event_name: include_events)
|
72
|
+
else
|
73
|
+
query
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def add_sequence_number(query, after_sequence_number)
|
78
|
+
query.where { sequence_number > after_sequence_number }
|
79
|
+
end
|
80
|
+
|
81
|
+
def add_aggregate_types(query, aggregate_types)
|
82
|
+
if aggregate_types.any?
|
83
|
+
query.join(storage.aggregates, id: :aggregate_table_id, aggregate_type: aggregate_types)
|
84
|
+
else
|
85
|
+
query.join(storage.aggregates, id: :aggregate_table_id)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
end
|
@@ -1,201 +1,138 @@
|
|
1
|
-
require 'sandthorn_driver_sequel/sequel_driver'
|
2
|
-
|
3
1
|
module SandthornDriverSequel
|
4
2
|
class EventStore
|
5
3
|
include EventStoreContext
|
4
|
+
|
6
5
|
attr_reader :driver, :context, :url
|
6
|
+
|
7
7
|
def initialize url: nil, context: nil
|
8
8
|
@driver = SequelDriver.new url: url
|
9
9
|
@context = context
|
10
10
|
@url = url
|
11
11
|
end
|
12
12
|
|
13
|
-
def save_events
|
14
|
-
current_aggregate_version = originating_aggregate_version
|
15
|
-
aggregate_type = class_name.first.to_s
|
13
|
+
def save_events events, aggregate_id, class_name
|
16
14
|
driver.execute_in_transaction do |db|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
timestamp = Time.now.utc
|
29
|
-
aggregate_events.each do |event|
|
30
|
-
current_aggregate_version += 1
|
31
|
-
if current_aggregate_version != event[:aggregate_version]
|
32
|
-
error_message = "#{aggregate_type} with id #{aggregate_id}: expected event with version #{current_aggregate_version}, but got #{event[:aggregate_version]}"
|
33
|
-
raise SandthornDriverSequel::Errors::ConcurrencyError.new(error_message)
|
34
|
-
end
|
35
|
-
to_insert = ({aggregate_table_id: pk_id, aggregate_version: event[:aggregate_version], event_name: event[:event_name], event_data: event[:event_data], timestamp: timestamp})
|
36
|
-
db[events_table_name].insert(to_insert)
|
37
|
-
end
|
38
|
-
db[aggregates_table_name].where(id: pk_id).update(aggregate_version: current_aggregate_version)
|
15
|
+
aggregates = get_aggregate_access(db)
|
16
|
+
event_access = get_event_access(db)
|
17
|
+
aggregate = aggregates.find_or_register(aggregate_id, class_name)
|
18
|
+
event_access.store_events(aggregate, events)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def get_aggregate_events(aggregate_id)
|
23
|
+
driver.execute do |db|
|
24
|
+
events = get_event_access(db)
|
25
|
+
events.find_events_by_aggregate_id(aggregate_id)
|
39
26
|
end
|
40
27
|
end
|
41
28
|
|
42
|
-
def save_snapshot aggregate_snapshot, aggregate_id
|
43
|
-
#ar_snapshot.event_name = snapshot[:event_name]
|
44
|
-
#ar_snapshot.event_data = snapshot[:event_data]
|
45
|
-
#ar_snapshot.aggregate_version = snapshot[:aggregate_version]
|
46
|
-
#ar_snapshot.aggregate_id = aggregate_id
|
29
|
+
def save_snapshot aggregate_snapshot, aggregate_id
|
47
30
|
driver.execute_in_transaction do |db|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
31
|
+
snapshot_access = get_snapshot_access(db)
|
32
|
+
snapshot_access.record_snapshot(aggregate_id, aggregate_snapshot)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# If the aggregate has a snapshot, return events starting from the snapshots.
|
37
|
+
# Otherwise, return all events.
|
38
|
+
# TODO: needs a better name
|
39
|
+
def get_aggregate_events_from_snapshot(aggregate_id)
|
40
|
+
driver.execute do |db|
|
41
|
+
snapshots = get_snapshot_access(db)
|
42
|
+
event_access = get_event_access(db)
|
43
|
+
snapshot = snapshots.find_by_aggregate_id(aggregate_id)
|
44
|
+
if snapshot
|
45
|
+
events = event_access.after_snapshot(snapshot)
|
46
|
+
snapshot_event = build_snapshot_event(snapshot)
|
47
|
+
events.unshift(snapshot_event)
|
60
48
|
else
|
61
|
-
|
62
|
-
db[snapshots_table_name].where(aggregate_table_id: pk_id).update(to_update)
|
49
|
+
event_access.find_events_by_aggregate_id(aggregate_id)
|
63
50
|
end
|
64
51
|
end
|
65
52
|
end
|
66
53
|
|
67
|
-
def
|
68
|
-
|
69
|
-
|
54
|
+
def build_snapshot_event(snapshot)
|
55
|
+
{
|
56
|
+
aggregate_version: snapshot[:aggregate_version],
|
57
|
+
event_data: snapshot[:snapshot_data],
|
58
|
+
event_name: "aggregate_set_from_snapshot"
|
59
|
+
}
|
70
60
|
end
|
71
61
|
|
72
62
|
def get_aggregate aggregate_id, *class_name
|
73
|
-
|
74
|
-
|
75
|
-
after_aggregate_version = snapshot[:aggregate_version] unless snapshot.nil?
|
76
|
-
events = aggregate_events after_aggregate_version: after_aggregate_version, aggregate_id: aggregate_id
|
77
|
-
unless snapshot.nil?
|
78
|
-
snap_event = snapshot
|
79
|
-
snap_event[:event_name] = "aggregate_set_from_snapshot"
|
80
|
-
events = events.unshift(snap_event)
|
81
|
-
end
|
82
|
-
events
|
63
|
+
warn(":get_aggregate is deprecated. Use :get_aggregate_events_from_snapshot")
|
64
|
+
get_aggregate_events_from_snapshot(aggregate_id)
|
83
65
|
end
|
84
|
-
|
85
|
-
|
66
|
+
|
67
|
+
def get_aggregate_ids(aggregate_type: nil)
|
86
68
|
driver.execute do |db|
|
87
|
-
|
69
|
+
access = get_aggregate_access(db)
|
70
|
+
access.aggregate_ids(aggregate_type: aggregate_type)
|
88
71
|
end
|
89
72
|
end
|
90
73
|
|
91
|
-
def
|
92
|
-
|
93
|
-
|
94
|
-
end
|
74
|
+
def get_aggregate_list_by_typename(type)
|
75
|
+
warn(":get_aggregate_list_by_typenames is deprecated. Use :get_aggregate_ids")
|
76
|
+
get_aggregate_ids(type: type)
|
95
77
|
end
|
96
78
|
|
97
|
-
def
|
98
|
-
aggregate_type = class_name.first.to_s
|
79
|
+
def get_all_types
|
99
80
|
driver.execute do |db|
|
100
|
-
|
101
|
-
|
102
|
-
return nil if snap.nil?
|
103
|
-
return {aggregate_version: snap[:aggregate_version], event_data: snap[:snapshot_data]}
|
81
|
+
access = get_aggregate_access(db)
|
82
|
+
access.aggregate_types
|
104
83
|
end
|
105
84
|
end
|
106
85
|
|
107
|
-
def
|
108
|
-
take = args.fetch(:take, 0)
|
109
|
-
aggregate_type = class_name.to_s
|
86
|
+
def get_snapshot aggregate_id
|
110
87
|
driver.execute do |db|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
query = query.select(:aggregate_type, rel, :aggregate_id, :sequence_number, :event_name, :event_data, :timestamp)
|
115
|
-
query = query.limit(take) if take > 0
|
116
|
-
return query.order(:sequence_number).all
|
88
|
+
snapshots = get_snapshot_access(db)
|
89
|
+
snapshot = snapshots.find_by_aggregate_id(aggregate_id)
|
90
|
+
transform_snapshot(snapshot)
|
117
91
|
end
|
118
92
|
end
|
119
|
-
|
120
|
-
|
121
|
-
exclude_events = exclude_events.map { |e| e.to_s }
|
122
|
-
aggregate_types = aggregate_types.map { |e| e.to_s }
|
93
|
+
|
94
|
+
def get_events(*args)
|
123
95
|
driver.execute do |db|
|
124
|
-
|
125
|
-
|
126
|
-
else
|
127
|
-
query = db[events_table_name].join(aggregates_table_name, id: :aggregate_table_id, aggregate_type: aggregate_types)
|
128
|
-
end
|
129
|
-
query = query.where{sequence_number > after_sequence_number}
|
130
|
-
unless include_events.empty?
|
131
|
-
query = query.where(event_name: include_events)
|
132
|
-
end
|
133
|
-
unless exclude_events.empty?
|
134
|
-
query = query.exclude(event_name: exclude_events)
|
135
|
-
end
|
136
|
-
rel = "#{events_table_name}__aggregate_version".to_sym
|
137
|
-
query = query.select(:aggregate_type, rel, :aggregate_id, :sequence_number, :event_name, :event_data, :timestamp)
|
138
|
-
query = query.limit(take) if take > 0
|
139
|
-
return query.order(:sequence_number).all
|
96
|
+
event_access = get_event_access(db)
|
97
|
+
event_access.get_events(*args)
|
140
98
|
end
|
141
99
|
end
|
142
|
-
|
100
|
+
|
101
|
+
def get_new_events_after_event_id_matching_classname event_id, class_name, take: 0
|
102
|
+
get_events(after_sequence_number: event_id, aggregate_types: Utilities.array_wrap(class_name), take: take)
|
103
|
+
end
|
104
|
+
|
105
|
+
def obsolete_snapshots(*args)
|
143
106
|
driver.execute do |db|
|
144
|
-
|
145
|
-
|
146
|
-
query_select = eval("lambda{(#{aggr_rel} - coalesce(#{rel},0)).as(distance)}")
|
147
|
-
query = db[aggregates_table_name].left_outer_join(snapshots_table_name, aggregate_table_id: :id)
|
148
|
-
query = query.select &query_select
|
149
|
-
query = query.select_append(:aggregate_id, :aggregate_type)
|
150
|
-
query_where = eval("lambda{(#{aggr_rel} - coalesce(#{rel},0)) > max_event_distance}")
|
151
|
-
query = query.where &query_where
|
152
|
-
unless class_names.empty?
|
153
|
-
class_names.map! {|c|c.to_s}
|
154
|
-
query = query.where(aggregate_type: class_names)
|
155
|
-
end
|
156
|
-
query.all
|
107
|
+
snapshots = get_snapshot_access(db)
|
108
|
+
snapshots.obsolete(*args)
|
157
109
|
end
|
158
110
|
end
|
111
|
+
|
159
112
|
private
|
160
113
|
|
161
|
-
def
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
# rel = "#{events_table_name}__aggregate_version".to_sym
|
175
|
-
# where_proc = eval("lambda{ #{rel} > after_aggregate_version }")
|
176
|
-
# driver.execute do |db|
|
177
|
-
# query = db[events_table_name].join(aggregates_table_name, id: :aggregate_table_id, aggregate_id: aggregate_id)
|
178
|
-
# query = query.where &where_proc
|
179
|
-
# result = query.select(rel, :aggregate_id, :sequence_number, :event_name, :event_data, :timestamp).order(:sequence_number).all
|
180
|
-
# end
|
181
|
-
# }
|
182
|
-
|
183
|
-
# end
|
184
|
-
# result
|
185
|
-
end
|
186
|
-
def get_current_aggregate_from_aggregates_table aggregate_id, aggregate_type, db
|
187
|
-
aggregate_type = aggregate_type.to_s
|
188
|
-
current_aggregate = db[aggregates_table_name].where(aggregate_id: aggregate_id)
|
189
|
-
if current_aggregate.empty?
|
190
|
-
error_message = "#{aggregate_type} with id #{aggregate_id} was not found in the eventstore."
|
191
|
-
raise SandthornDriverSequel::Errors::NoAggregateError.new(error_message)
|
192
|
-
end
|
193
|
-
current_aggregate.first
|
114
|
+
def transform_snapshot(snapshot)
|
115
|
+
{
|
116
|
+
aggregate_version: snapshot.aggregate_version,
|
117
|
+
event_data: snapshot.snapshot_data
|
118
|
+
}
|
119
|
+
end
|
120
|
+
|
121
|
+
def get_aggregate_access(db)
|
122
|
+
AggregateAccess.new(storage(db))
|
123
|
+
end
|
124
|
+
|
125
|
+
def get_event_access(db)
|
126
|
+
EventAccess.new(storage(db))
|
194
127
|
end
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
snap.first
|
128
|
+
|
129
|
+
def get_snapshot_access(db)
|
130
|
+
SnapshotAccess.new(storage(db))
|
199
131
|
end
|
132
|
+
|
133
|
+
def storage(db)
|
134
|
+
Storage.new(db, context)
|
135
|
+
end
|
136
|
+
|
200
137
|
end
|
201
|
-
end
|
138
|
+
end
|