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.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -1
  3. data/Guardfile +7 -0
  4. data/lib/sandthorn_driver_sequel/access/aggregate_access.rb +50 -0
  5. data/lib/sandthorn_driver_sequel/access/event_access.rb +81 -0
  6. data/lib/sandthorn_driver_sequel/access/snapshot_access.rb +87 -0
  7. data/lib/sandthorn_driver_sequel/access.rb +20 -0
  8. data/lib/sandthorn_driver_sequel/errors.rb +47 -5
  9. data/lib/sandthorn_driver_sequel/event_query.rb +90 -0
  10. data/lib/sandthorn_driver_sequel/event_store.rb +90 -153
  11. data/lib/sandthorn_driver_sequel/event_store_context.rb +1 -0
  12. data/lib/sandthorn_driver_sequel/migration.rb +9 -1
  13. data/lib/sandthorn_driver_sequel/old_event_store.rb +228 -0
  14. data/lib/sandthorn_driver_sequel/sequel_driver.rb +8 -25
  15. data/lib/sandthorn_driver_sequel/storage.rb +46 -0
  16. data/lib/sandthorn_driver_sequel/utilities/array.rb +13 -0
  17. data/lib/sandthorn_driver_sequel/utilities.rb +1 -0
  18. data/lib/sandthorn_driver_sequel/version.rb +1 -1
  19. data/lib/sandthorn_driver_sequel/wrappers/event_wrapper.rb +12 -0
  20. data/lib/sandthorn_driver_sequel/wrappers/snapshot_wrapper.rb +11 -0
  21. data/lib/sandthorn_driver_sequel/wrappers.rb +2 -0
  22. data/lib/sandthorn_driver_sequel.rb +5 -0
  23. data/sandthorn_driver_sequel.gemspec +2 -2
  24. data/spec/aggregate_access_spec.rb +97 -0
  25. data/spec/asking_for_aggregates_to_snapshot_spec.rb +7 -4
  26. data/spec/driver_interface_spec.rb +23 -40
  27. data/spec/event_access_spec.rb +96 -0
  28. data/spec/event_store_with_context_spec.rb +4 -4
  29. data/spec/get_events_spec.rb +20 -13
  30. data/spec/migration_specifying_domain_spec.rb +10 -10
  31. data/spec/saving_events_spec.rb +42 -39
  32. data/spec/saving_snapshot_spec.rb +7 -7
  33. data/spec/snapshot_access_spec.rb +119 -0
  34. data/spec/spec_helper.rb +0 -4
  35. data/spec/storage_spec.rb +66 -0
  36. metadata +39 -18
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ee9068238f286a01fb246ec4f23d62c335033aab
4
- data.tar.gz: b467b5e449080ab8476492fce07ebb96df1a9a2e
3
+ metadata.gz: 6df7059570ed2a75376a49b5568cde3dcda5abef
4
+ data.tar.gz: d0df6fa0c71d2388f31897fcb4c1918ecbe6bdd2
5
5
  SHA512:
6
- metadata.gz: 7eaf9662b2ad127ab2a55195e5cc2b846158cce9039bfa5f52c7cddedde310867edeb9bc907e3fa0cdd4f05b37258c19190e4b75c6d82788c12591ad7054b5bc
7
- data.tar.gz: a9837bfcee62c4324c54a849aecaf605ad9e20272b3a018369529b6959ecc14f9d23459798ff94e7197db517112b12964797ac494a01a0a9aa742865583fbca9
6
+ metadata.gz: cff7f24db48fe2ec230c54526f3231fff0c2f7cd94ed12b585807cfa06084cba5a7c4d7d63b670816844ba8b5f6a3114a6d755bb0b16b6cb2e3336ea9c68236c
7
+ data.tar.gz: 2592b3457a5c030517d968302aa4c716af3cd58fa3080c1378960a066a40fbf28000e963ab22d75c0fbf600acd3b4f75799ceea63d3a01f1c7d90d59927b5ea4
data/.gitignore CHANGED
@@ -15,4 +15,5 @@ spec/reports
15
15
  test/tmp
16
16
  test/version_tmp
17
17
  tmp
18
- *.sqlite3
18
+ *.sqlite3
19
+ .idea
data/Guardfile ADDED
@@ -0,0 +1,7 @@
1
+ interactor :simple
2
+ guard :rspec, cmd: 'bundle exec rspec' do
3
+ watch(%r{^spec/.+_spec\.rb$})
4
+ watch(%r{^lib/sandthorn_driver_sequel/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
5
+ watch('spec/spec_helper.rb') { "spec" }
6
+ end
7
+
@@ -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
- class Error < StandardError; end
3
- class ConcurrencyError < Error; end
4
- class InternalError < Error; end
5
- class NoAggregateError < Error; end
6
- class WrongAggregateVersionError < Error; end
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 aggregate_events, originating_aggregate_version, aggregate_id, *class_name
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
- if current_aggregate_version == 0
18
- to_insert = {aggregate_id: aggregate_id, aggregate_type: aggregate_type, aggregate_version: 0}
19
- pk_id = db[aggregates_table_name].insert(to_insert)
20
- else
21
- current_aggregate = get_current_aggregate_from_aggregates_table aggregate_id, aggregate_type, db
22
- pk_id = current_aggregate[:id]
23
- if current_aggregate[:aggregate_version] != current_aggregate_version
24
- error_message = "#{aggregate_type} with id #{aggregate_id} should be att version #{current_aggregate_version} but was #{current_aggregate[:aggregate_version]} in the event store."
25
- raise SandthornDriverSequel::Errors::WrongAggregateVersionError.new(error_message)
26
- end
27
- end
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, class_name
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
- current_aggregate = get_current_aggregate_from_aggregates_table aggregate_id, class_name, db
49
- pk_id = current_aggregate[:id]
50
- current_snapshot = get_current_snapshot pk_id, db
51
- aggregate_version = aggregate_snapshot[:aggregate_version]
52
- return if !current_snapshot.nil? && current_snapshot[:aggregate_version] == aggregate_version
53
- if current_aggregate[:aggregate_version] < aggregate_version
54
- error_message = "#{class_name} with id #{aggregate_id}: tried to save snapshot with version #{aggregate_version}, but current version is at #{current_aggregate[:aggregate_version]}"
55
- raise SandthornDriverSequel::Errors::WrongAggregateVersionError.new error_message
56
- end
57
- if current_snapshot.nil?
58
- to_insert = {aggregate_version: aggregate_version, snapshot_data: aggregate_snapshot[:event_data], aggregate_table_id: pk_id }
59
- db[snapshots_table_name].insert(to_insert)
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
- to_update = {aggregate_version: aggregate_version, snapshot_data: aggregate_snapshot[:event_data] }
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 get_aggregate_events aggregate_id, *class_name
68
- #aggregate_type = class_name.to_s unless class_name.nil?
69
- return aggregate_events aggregate_id: aggregate_id
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
- snapshot = get_snapshot aggregate_id, class_name
74
- after_aggregate_version = 0
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
- def get_aggregate_list_by_typename class_name
85
- aggregate_type = class_name.to_s
66
+
67
+ def get_aggregate_ids(aggregate_type: nil)
86
68
  driver.execute do |db|
87
- db[aggregates_table_name].where(aggregate_type: aggregate_type).select(:aggregate_id).map { |e| e[:aggregate_id] }
69
+ access = get_aggregate_access(db)
70
+ access.aggregate_ids(aggregate_type: aggregate_type)
88
71
  end
89
72
  end
90
73
 
91
- def get_all_typenames
92
- driver.execute do |db|
93
- db[aggregates_table_name].select(:aggregate_type).distinct.order(:aggregate_type).map{|e| e[:aggregate_type]}
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 get_snapshot aggregate_id, *class_name
98
- aggregate_type = class_name.first.to_s
79
+ def get_all_types
99
80
  driver.execute do |db|
100
- current_aggregate = get_current_aggregate_from_aggregates_table aggregate_id, aggregate_type, db
101
- snap = get_current_snapshot current_aggregate[:id], db
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 get_new_events_after_event_id_matching_classname event_id, class_name, args = {}
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
- query = db[events_table_name].join(aggregates_table_name, id: :aggregate_table_id, aggregate_type: aggregate_type)
112
- query = query.where{sequence_number > event_id}
113
- rel = "#{events_table_name}__aggregate_version".to_sym
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
- def get_events aggregate_types: [], take: 0, after_sequence_number: 0, include_events: [], exclude_events: []
120
- include_events = include_events.map { |e| e.to_s }
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
- if aggregate_types.empty?
125
- query = db[events_table_name].join(aggregates_table_name, id: :aggregate_table_id)
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
- def obsolete_snapshots class_names: [], max_event_distance: 100
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
- rel = "#{snapshots_table_name}__aggregate_version".to_sym
145
- aggr_rel = "#{aggregates_table_name}__aggregate_version".to_sym
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 aggregate_events after_aggregate_version: 0, aggregate_id: nil
162
-
163
- rel = "#{events_table_name}__aggregate_version".to_sym
164
- where_proc = eval("lambda{ #{rel} > after_aggregate_version }")
165
- driver.execute do |db|
166
- query = db[events_table_name].join(aggregates_table_name, id: :aggregate_table_id, aggregate_id: aggregate_id)
167
- query = query.where &where_proc
168
- result = query.select(rel, :aggregate_id, :sequence_number, :event_name, :event_data, :timestamp).order(:sequence_number).all
169
- end
170
-
171
- # result = nil
172
- # Benchmark.bm do |x|
173
- # x.report("find") {
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
- def get_current_snapshot aggregate_table_id, db
196
- snap = db[snapshots_table_name].where(aggregate_table_id: aggregate_table_id)
197
- return nil if snap.empty?
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