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.
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