sequent 3.2.2 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/lib/notices.rb +4 -0
  3. data/lib/sequent.rb +3 -0
  4. data/lib/sequent/application_record.rb +7 -0
  5. data/lib/sequent/configuration.rb +13 -0
  6. data/lib/sequent/core/aggregate_repository.rb +7 -1
  7. data/lib/sequent/core/command.rb +13 -2
  8. data/lib/sequent/core/command_record.rb +5 -2
  9. data/lib/sequent/core/command_service.rb +28 -12
  10. data/lib/sequent/core/event_publisher.rb +4 -0
  11. data/lib/sequent/core/event_record.rb +2 -1
  12. data/lib/sequent/core/event_store.rb +23 -4
  13. data/lib/sequent/core/helpers/attribute_support.rb +28 -7
  14. data/lib/sequent/core/helpers/mergable.rb +1 -0
  15. data/lib/sequent/core/persistors/active_record_persistor.rb +1 -1
  16. data/lib/sequent/core/persistors/replay_optimized_postgres_persistor.rb +2 -2
  17. data/lib/sequent/core/projector.rb +23 -1
  18. data/lib/sequent/core/stream_record.rb +1 -1
  19. data/lib/sequent/core/transactions/active_record_transaction_provider.rb +6 -4
  20. data/lib/sequent/generator.rb +1 -4
  21. data/lib/sequent/generator/generator.rb +4 -0
  22. data/lib/sequent/generator/project.rb +1 -1
  23. data/lib/sequent/generator/template_project/Gemfile +1 -1
  24. data/lib/sequent/generator/template_project/app/records/post_record.rb +1 -1
  25. data/lib/sequent/generator/template_project/spec/app/projectors/post_projector_spec.rb +1 -1
  26. data/lib/sequent/generator/template_project/spec/lib/post/post_command_handler_spec.rb +1 -1
  27. data/lib/sequent/migrations/executor.rb +78 -0
  28. data/lib/sequent/migrations/functions.rb +76 -0
  29. data/lib/sequent/migrations/migrations.rb +1 -0
  30. data/lib/sequent/migrations/planner.rb +118 -0
  31. data/lib/sequent/migrations/projectors.rb +6 -5
  32. data/lib/sequent/migrations/sql.rb +17 -0
  33. data/lib/sequent/migrations/view_schema.rb +74 -73
  34. data/lib/sequent/rake/migration_tasks.rb +2 -2
  35. data/lib/sequent/rake/tasks.rb +1 -1
  36. data/lib/sequent/sequent.rb +5 -1
  37. data/lib/sequent/support/database.rb +11 -6
  38. data/lib/sequent/test/command_handler_helpers.rb +4 -0
  39. data/lib/sequent/util/dry_run.rb +191 -0
  40. data/lib/sequent/util/skip_if_already_processing.rb +19 -5
  41. data/lib/sequent/util/util.rb +1 -0
  42. data/lib/version.rb +1 -1
  43. metadata +77 -36
@@ -13,7 +13,7 @@ module Sequent
13
13
  end
14
14
  end
15
15
 
16
- class StreamRecord < ActiveRecord::Base
16
+ class StreamRecord < Sequent::ApplicationRecord
17
17
 
18
18
  self.table_name = "stream_records"
19
19
 
@@ -4,10 +4,12 @@ module Sequent
4
4
 
5
5
  class ActiveRecordTransactionProvider
6
6
  def transactional
7
- ActiveRecord::Base.transaction(requires_new: true) do
7
+ Sequent::ApplicationRecord.transaction(requires_new: true) do
8
8
  yield
9
9
  end
10
- after_commit_queue.each &:call
10
+ while(!after_commit_queue.empty?) do
11
+ after_commit_queue.pop.call
12
+ end
11
13
  ensure
12
14
  clear_after_commit_queue
13
15
  end
@@ -19,11 +21,11 @@ module Sequent
19
21
  private
20
22
 
21
23
  def after_commit_queue
22
- Thread.current[:after_commit_queue] ||= []
24
+ Thread.current[:after_commit_queue] ||= Queue.new
23
25
  end
24
26
 
25
27
  def clear_after_commit_queue
26
- Thread.current[:after_commit_queue] = []
28
+ after_commit_queue.clear
27
29
  end
28
30
  end
29
31
 
@@ -1,4 +1 @@
1
- require_relative './generator/project'
2
- require_relative './generator/aggregate'
3
- require_relative './generator/command'
4
- require_relative './generator/event'
1
+ require_relative './generator/generator'
@@ -0,0 +1,4 @@
1
+ require_relative 'aggregate'
2
+ require_relative 'command'
3
+ require_relative 'project'
4
+ require_relative 'event'
@@ -54,7 +54,7 @@ module Sequent
54
54
  end
55
55
 
56
56
  def name_camelized
57
- @name_camelized ||= name.camelize
57
+ @name_camelized ||= name.gsub(/\W/, '_').squeeze('_').camelize
58
58
  end
59
59
  end
60
60
  end
@@ -1,5 +1,5 @@
1
1
  source "https://rubygems.org"
2
- ruby "2.5.1"
2
+ ruby "2.6.5"
3
3
 
4
4
  gem 'rake'
5
5
  # let's use the latest and greatest
@@ -1,2 +1,2 @@
1
- class PostRecord < ActiveRecord::Base
1
+ class PostRecord < Sequent::ApplicationRecord
2
2
  end
@@ -1,4 +1,4 @@
1
- require_relative '../../spec_helper'
1
+ require 'spec_helper'
2
2
  require_relative '../../../app/projectors/post_projector'
3
3
 
4
4
  describe PostProjector do
@@ -1,4 +1,4 @@
1
- require_relative '../../spec_helper'
1
+ require 'spec_helper'
2
2
  require_relative '../../../lib/post'
3
3
 
4
4
  describe PostCommandHandler do
@@ -0,0 +1,78 @@
1
+ require_relative 'sql'
2
+
3
+ module Sequent
4
+ module Migrations
5
+
6
+ ##
7
+ # The executor is the implementation of the 3-phase deploy in Sequent.
8
+ # is responsible for executing the `Planner::Plan`.
9
+ #
10
+ class Executor
11
+ include Sql
12
+
13
+ def execute_online(plan)
14
+ plan.replay_tables.each do |migration|
15
+ table = migration.record_class
16
+ sql_file = "#{Sequent.configuration.migration_sql_files_directory}/#{table.table_name}.sql"
17
+ statements = sql_file_to_statements(sql_file) { |raw_sql| raw_sql.gsub('%SUFFIX%', "_#{migration.version}") }
18
+ statements.each(&method(:exec_sql))
19
+ table.table_name = "#{table.table_name}_#{migration.version}"
20
+ table.reset_column_information
21
+ end
22
+ end
23
+
24
+ def create_indexes_after_execute_online(plan)
25
+ plan.replay_tables.each do |migration|
26
+ table = migration.record_class
27
+ original_table_name = table.table_name.gsub("_#{migration.version}", '')
28
+ indexes_file_name = "#{Sequent.configuration.migration_sql_files_directory}/#{original_table_name}.indexes.sql"
29
+ if File.exist?(indexes_file_name)
30
+ statements = sql_file_to_statements(indexes_file_name) { |raw_sql| raw_sql.gsub('%SUFFIX%', "_#{migration.version}") }
31
+ statements.each(&method(:exec_sql))
32
+ end
33
+ end
34
+ end
35
+
36
+ def execute_offline(plan, current_version)
37
+ plan.replay_tables.each do |migration|
38
+ table = migration.record_class
39
+ current_table_name = table.table_name.gsub("_#{migration.version}", "")
40
+ # 2 Rename old table
41
+ exec_sql("ALTER TABLE IF EXISTS #{current_table_name} RENAME TO #{current_table_name}_#{current_version}")
42
+ # 3 Rename new table
43
+ exec_sql("ALTER TABLE #{table.table_name} RENAME TO #{current_table_name}")
44
+ # Use new table from now on
45
+ table.table_name = current_table_name
46
+ table.reset_column_information
47
+ end
48
+
49
+ plan.alter_tables.each do |migration|
50
+ table = migration.record_class
51
+ sql_file = "#{Sequent.configuration.migration_sql_files_directory}/#{table.table_name}_#{migration.version}.sql"
52
+ statements = sql_file_to_statements(sql_file)
53
+ statements.each(&method(:exec_sql))
54
+ end
55
+ end
56
+
57
+ def reset_table_names(plan)
58
+ plan.replay_tables.each do |migration|
59
+ table = migration.record_class
60
+ table.table_name = table.table_name.gsub("_#{migration.version}", "")
61
+ table.reset_column_information
62
+ end
63
+ end
64
+
65
+ def set_table_names_to_new_version(plan)
66
+ plan.replay_tables.each do |migration|
67
+ table = migration.record_class
68
+ unless table.table_name.end_with?("_#{migration.version}")
69
+ table.table_name = "#{table.table_name}_#{migration.version}"
70
+ table.reset_column_information
71
+ fail MigrationError.new("Table #{table.table_name} does not exist. Did you run ViewSchema.migrate_online first?") unless table.table_exists?
72
+ end
73
+ end
74
+ end
75
+
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,76 @@
1
+ module Sequent
2
+ module Migrations
3
+ class Migration
4
+
5
+ module ClassMethods
6
+ def create(record_class, version)
7
+ migration = new(record_class)
8
+ migration.version = version
9
+ migration
10
+ end
11
+ end
12
+
13
+ def self.inherited(child_class)
14
+ class << child_class
15
+ include ClassMethods
16
+ end
17
+ end
18
+
19
+ attr_reader :record_class
20
+ attr_accessor :version
21
+
22
+ def initialize(record_class)
23
+ @record_class = record_class
24
+ @version = nil
25
+ end
26
+
27
+ def table_name
28
+ @record_class.table_name
29
+ end
30
+
31
+ def copy(with_version)
32
+ self.class.create(record_class, with_version)
33
+ end
34
+
35
+ def ==(other)
36
+ return false unless other.class == self.class
37
+
38
+ self.table_name == other.table_name && version == other.version
39
+ end
40
+
41
+ def hash
42
+ self.table_name.hash + (version&.hash || 0)
43
+ end
44
+ end
45
+
46
+ class AlterTable < Migration; end
47
+
48
+ class ReplayTable < Migration; end
49
+
50
+ module Functions
51
+
52
+ module ClassMethods
53
+ def alter_table(name)
54
+ AlterTable.new(name)
55
+ end
56
+
57
+ def replay_table(name)
58
+ ReplayTable.new(name)
59
+ end
60
+
61
+ # Short hand for Sequent::Core::Migratable.all
62
+ def all_projectors
63
+ Sequent::Core::Migratable.all
64
+ end
65
+
66
+ end
67
+
68
+ def self.included(base)
69
+ base.extend(ClassMethods)
70
+ end
71
+
72
+ end
73
+
74
+ include Functions
75
+ end
76
+ end
@@ -7,3 +7,4 @@ end
7
7
  require_relative 'migrate_events'
8
8
  require_relative 'projectors'
9
9
  require_relative 'view_schema'
10
+ require_relative 'functions'
@@ -0,0 +1,118 @@
1
+ module Sequent
2
+ module Migrations
3
+ class Planner
4
+ Plan = Struct.new(:projectors, :migrations) do
5
+ def replay_tables
6
+ migrations.select { |m| m.class == ReplayTable }
7
+ end
8
+
9
+ def alter_tables
10
+ migrations.select { |m| m.class == AlterTable }
11
+ end
12
+
13
+ def empty?
14
+ migrations.empty?
15
+ end
16
+ end
17
+
18
+ attr_reader :versions
19
+
20
+ def initialize(versions)
21
+ @versions = versions
22
+ end
23
+
24
+ def plan(old, new)
25
+ migrations = versions.slice(*Range.new(old + 1, new).to_a.map(&:to_s))
26
+
27
+ Plan.new(
28
+ migrations.yield_self(&method(:select_projectors)),
29
+ migrations
30
+ .yield_self(&method(:create_migrations))
31
+ .yield_self(&method(:remove_redundant_migrations))
32
+ )
33
+ end
34
+
35
+ private
36
+
37
+ def select_projectors(migrations)
38
+ migrations
39
+ .values
40
+ .flatten
41
+ .select { |v| v.is_a?(Class) && v < Sequent::Projector }.uniq
42
+ end
43
+
44
+ def remove_redundant_migrations(migrations)
45
+ redundant_migrations = migrations
46
+ .yield_self(&method(:group_identical_migrations))
47
+ .yield_self(&method(:select_redundant_migrations))
48
+ .yield_self(&method(:remove_redundancy))
49
+ .values
50
+ .flatten
51
+
52
+ (migrations - redundant_migrations)
53
+ .yield_self(&method(:remove_alter_tables_before_replay_table))
54
+ end
55
+
56
+ def group_identical_migrations(migrations)
57
+ migrations
58
+ .group_by { |migration| {migration_type: migration.class, record_class: migration.record_class} }
59
+ end
60
+
61
+ def select_redundant_migrations(grouped_migrations)
62
+ grouped_migrations.select { |type, ms| type[:migration_type] == ReplayTable && ms.length > 1 }
63
+ end
64
+
65
+ def remove_alter_tables_before_replay_table(migrations)
66
+ migrations - migrations
67
+ .each_with_index
68
+ .select { |migration, _index| migration.class == AlterTable }
69
+ .select { |migration, index| migrations
70
+ .slice((index + 1)..-1)
71
+ .find { |m| m.class == ReplayTable && m.record_class == migration.record_class }
72
+ }.map(&:first)
73
+ end
74
+
75
+ def remove_redundancy(grouped_migrations)
76
+ grouped_migrations.reduce({}) { |memo, (key, ms)|
77
+ memo[key] = ms
78
+ .yield_self(&method(:order_by_version_desc))
79
+ .slice(1..-1)
80
+ memo
81
+ }
82
+ end
83
+
84
+ def order_by_version_desc(migrations)
85
+ migrations.sort_by { |m| m.version.to_i }
86
+ .reverse
87
+ end
88
+
89
+ def create_migrations(migrations)
90
+ migrations
91
+ .yield_self(&method(:map_to_migrations))
92
+ .values
93
+ .compact
94
+ .flatten
95
+ end
96
+
97
+ def map_to_migrations(migrations)
98
+ migrations.reduce({}) do |memo, (version, _migrations)|
99
+ fail "Declared migrations for version #{version} must be an Array. For example: {'3' => [FooProjector]}" unless _migrations.is_a?(Array)
100
+
101
+ memo[version] = _migrations.flat_map do |migration|
102
+ if migration.is_a?(AlterTable)
103
+ alter_table_sql_file_name = "#{Sequent.configuration.migration_sql_files_directory}/#{migration.table_name}_#{version}.sql"
104
+ fail "Missing file #{alter_table_sql_file_name} to apply for version #{version}" unless File.exist?(alter_table_sql_file_name)
105
+ migration.copy(version)
106
+ elsif migration < Sequent::Projector
107
+ migration.managed_tables.map { |table| ReplayTable.create(table, version) }
108
+ else
109
+ fail "Unknown Migration #{migration}"
110
+ end
111
+ end
112
+
113
+ memo
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
@@ -1,18 +1,19 @@
1
+ require_relative 'planner'
1
2
  module Sequent
2
3
  module Migrations
3
4
  class Projectors
4
5
  def self.versions
5
- fail "Define your own Sequent::Migrations::Projectors class that extends this class and implements this method"
6
+ fail "Define your own Sequent::Migrations::List class that extends this class and implements this method"
6
7
  end
7
8
 
8
9
  def self.version
9
- fail "Define your own Sequent::Migrations::Projectors class that extends this class and implements this method"
10
+ fail "Define your own Sequent::Migrations::List class that extends this class and implements this method"
10
11
  end
11
12
 
12
- def self.projectors_between(old, new)
13
- versions.values_at(*Range.new(old + 1, new).to_a.map(&:to_s)).compact.flatten.uniq
13
+ def self.migrations_between(old, new)
14
+ Planner.new(versions).plan(old, new)
14
15
  end
15
16
  end
17
+
16
18
  end
17
19
  end
18
-
@@ -0,0 +1,17 @@
1
+ require_relative '../application_record'
2
+
3
+ module Sequent
4
+ module Migrations
5
+ module Sql
6
+ def sql_file_to_statements(file_location)
7
+ sql_string = File.read(file_location, encoding: 'bom|utf-8')
8
+ sql_string = yield(sql_string) if block_given?
9
+ sql_string.split(/;$/).reject { |statement| statement.remove("\n").blank? }
10
+ end
11
+
12
+ def exec_sql(sql)
13
+ Sequent::ApplicationRecord.connection.execute(sql)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -6,30 +6,56 @@ require_relative '../sequent'
6
6
  require_relative '../util/timer'
7
7
  require_relative '../util/printer'
8
8
  require_relative './projectors'
9
+ require_relative 'planner'
10
+ require_relative 'executor'
11
+ require_relative 'sql'
9
12
 
10
13
  module Sequent
11
14
  module Migrations
12
15
  class MigrationError < RuntimeError; end
13
16
 
14
-
15
17
  ##
16
- # Responsible for migration of Projectors between view schema versions.
18
+ # ViewSchema is used for migration of you view_schema. For instance
19
+ # when you create new Projectors or change existing Projectors.
17
20
  #
18
- # A Projector needs migration when for instance:
21
+ # The following migrations are supported:
19
22
  #
20
- # - New columns are added
21
- # - Structure is changed
23
+ # - ReplayTable (Projector migrations)
24
+ # - AlterTable (For instance if you introduce a new column)
22
25
  #
23
26
  # To maintain your migrations you need to:
24
27
  # 1. Create a class that extends `Sequent::Migrations::Projectors` and specify in `Sequent.configuration.migrations_class_name`
25
- # 2. Define per version which Projectors you want to migrate
28
+ # 2. Define per version which migrations you want to execute
26
29
  # See the definition of `Sequent::Migrations::Projectors.versions` and `Sequent::Migrations::Projectors.version`
27
30
  # 3. Specify in Sequent where your sql files reside (Sequent.configuration.migration_sql_files_directory)
28
31
  # 4. Ensure that you add %SUFFIX% to each name that needs to be unique in postgres (like TABLE names, INDEX names, PRIMARY KEYS)
29
32
  # E.g. `create table foo%SUFFIX% (id serial NOT NULL, CONSTRAINT foo_pkey%SUFFIX% PRIMARY KEY (id))`
33
+ # 5. If you want to run an `alter_table` migration ensure that
34
+ # a sql file named `table_name_VERSION.sql` exists.
35
+ #
36
+ # Example:
37
+ #
38
+ # class AppMigrations < Sequent::Migrations::Projectors
39
+ # def self.version
40
+ # '3'
41
+ # end
42
+ #
43
+ # def self.versions
44
+ # {
45
+ # '1' => [Sequent.all_projectors],
46
+ # '2' => [
47
+ # UserProjector,
48
+ # InvoiceProjector,
49
+ # ],
50
+ # '3' => [
51
+ # Sequent::Migrations.alter_table(UserRecord)
52
+ # ]
53
+ #
54
+ # }
55
+ # end
30
56
  #
57
+ # end
31
58
  class ViewSchema
32
-
33
59
  # Corresponds with the index on aggregate_id column in the event_records table
34
60
  #
35
61
  # Since we replay in batches of the first 3 chars of the uuid we created an index on
@@ -42,9 +68,10 @@ module Sequent
42
68
 
43
69
  include Sequent::Util::Timer
44
70
  include Sequent::Util::Printer
71
+ include Sql
45
72
 
46
- class Versions < ActiveRecord::Base; end
47
- class ReplayedIds < ActiveRecord::Base; end
73
+ class Versions < Sequent::ApplicationRecord; end
74
+ class ReplayedIds < Sequent::ApplicationRecord; end
48
75
 
49
76
  attr_reader :view_schema, :db_config, :logger
50
77
 
@@ -71,6 +98,12 @@ module Sequent
71
98
  Sequent::Core::Migratable.all.flat_map(&:managed_tables).each do |table|
72
99
  statements = sql_file_to_statements("#{Sequent.configuration.migration_sql_files_directory}/#{table.table_name}.sql") { |raw_sql| raw_sql.remove('%SUFFIX%') }
73
100
  statements.each { |statement| exec_sql(statement) }
101
+
102
+ indexes_file_name = "#{Sequent.configuration.migration_sql_files_directory}/#{table.table_name}.indexes.sql"
103
+ if File.exist?(indexes_file_name)
104
+ statements = sql_file_to_statements(indexes_file_name) { |raw_sql| raw_sql.remove('%SUFFIX%') }
105
+ statements.each(&method(:exec_sql))
106
+ end
74
107
  end
75
108
  end
76
109
  end
@@ -80,7 +113,7 @@ module Sequent
80
113
  #
81
114
  # This method is mainly useful in test scenario's or development tasks
82
115
  def replay_all!
83
- replay!(Sequent::Core::Migratable.all, Sequent.configuration.online_replay_persistor_class.new)
116
+ replay!(Sequent.configuration.online_replay_persistor_class.new)
84
117
  end
85
118
 
86
119
  ##
@@ -95,6 +128,14 @@ module Sequent
95
128
  end
96
129
  end
97
130
 
131
+ def plan
132
+ @plan ||= Planner.new(Sequent.migration_class.versions).plan(current_version, Sequent.new_version)
133
+ end
134
+
135
+ def executor
136
+ @executor ||= Executor.new
137
+ end
138
+
98
139
  ##
99
140
  # First part of a view schema migration
100
141
  #
@@ -118,14 +159,16 @@ module Sequent
118
159
  truncate_replay_ids_table!
119
160
 
120
161
  drop_old_tables(Sequent.new_version)
121
- for_each_table_to_migrate do |table|
122
- statements = sql_file_to_statements("#{Sequent.configuration.migration_sql_files_directory}/#{table.table_name}.sql") { |raw_sql| raw_sql.gsub('%SUFFIX%', "_#{Sequent.new_version}") }
123
- statements.each { |statement| exec_sql(statement) }
124
- table.table_name = "#{table.table_name}_#{Sequent.new_version}"
125
- table.reset_column_information
126
- end
162
+ executor.execute_online(plan)
163
+ end
164
+
165
+ if plan.projectors.any?
166
+ replay!(Sequent.configuration.online_replay_persistor_class.new)
167
+ end
168
+
169
+ in_view_schema do
170
+ executor.create_indexes_after_execute_online(plan)
127
171
  end
128
- replay!(projectors_to_migrate, Sequent.configuration.online_replay_persistor_class.new)
129
172
  rescue Exception => e
130
173
  rollback_migration
131
174
  raise e
@@ -155,28 +198,20 @@ module Sequent
155
198
 
156
199
  ensure_version_correct!
157
200
 
158
- set_table_names_to_new_version
201
+ executor.set_table_names_to_new_version(plan)
159
202
 
160
203
  # 1 replay events not yet replayed
161
- replay!(projectors_to_migrate, Sequent.configuration.offline_replay_persistor_class.new, exclude_ids: true, group_exponent: 1)
204
+ replay!(Sequent.configuration.offline_replay_persistor_class.new, exclude_ids: true, group_exponent: 1) if plan.projectors.any?
162
205
 
163
206
  in_view_schema do
164
- ActiveRecord::Base.transaction do
165
- for_each_table_to_migrate do |table|
166
- current_table_name = table.table_name.gsub("_#{Sequent.new_version}", "")
167
- # 2 Rename old table
168
- exec_sql("ALTER TABLE IF EXISTS #{current_table_name} RENAME TO #{current_table_name}_#{current_version}")
169
- # 3 Rename new table
170
- exec_sql("ALTER TABLE #{table.table_name} RENAME TO #{current_table_name}")
171
- # Use new table from now on
172
- table.table_name = current_table_name
173
- table.reset_column_information
174
- end
175
- # 4. Create migration record
207
+ Sequent::ApplicationRecord.transaction do
208
+ # 2.1, 2.2
209
+ executor.execute_offline(plan, current_version)
210
+ # 2.3 Create migration record
176
211
  Versions.create!(version: Sequent.new_version)
177
212
  end
178
213
 
179
- # 5. Truncate replayed ids
214
+ # 3. Truncate replayed ids
180
215
  truncate_replay_ids_table!
181
216
  end
182
217
  logger.info "Migrated to version #{Sequent.new_version}"
@@ -186,41 +221,27 @@ module Sequent
186
221
  end
187
222
 
188
223
  private
189
- def set_table_names_to_new_version
190
- for_each_table_to_migrate do |table|
191
- unless table.table_name.end_with?("_#{Sequent.new_version}")
192
- table.table_name = "#{table.table_name}_#{Sequent.new_version}"
193
- table.reset_column_information
194
- fail MigrationError.new("Table #{table.table_name} does not exist. Did you run migrate_online first?") unless table.table_exists?
195
- end
196
- end
197
- end
198
224
 
199
- def reset_table_names
200
- for_each_table_to_migrate do |table|
201
- table.table_name = table.table_name.gsub("_#{Sequent.new_version}", "")
202
- table.reset_column_information
203
- end
204
- end
205
225
 
206
226
  def ensure_version_correct!
207
227
  create_view_schema_if_not_exists
208
228
  new_version = Sequent.new_version
209
229
 
210
230
  fail ArgumentError.new("new_version [#{new_version}] must be greater or equal to current_version [#{current_version}]") if new_version < current_version
231
+
211
232
  end
212
233
 
213
- def replay!(projectors, replay_persistor, exclude_ids: false, group_exponent: 3)
234
+ def replay!(replay_persistor, projectors: plan.projectors, exclude_ids: false, group_exponent: 3)
214
235
  logger.info "group_exponent: #{group_exponent.inspect}"
215
236
 
216
237
  with_sequent_config(replay_persistor, projectors) do
217
238
  logger.info "Start replaying events"
218
239
 
219
- time("#{16**group_exponent} groups replayed") do
240
+ time("#{16 ** group_exponent} groups replayed") do
220
241
  event_types = projectors.flat_map { |projector| projector.message_mapping.keys }.uniq.map(&:name)
221
242
  disconnect!
222
243
 
223
- number_of_groups = 16**group_exponent
244
+ number_of_groups = 16 ** group_exponent
224
245
  groups = groups_of_aggregate_id_prefixes(number_of_groups)
225
246
 
226
247
  @connected = false
@@ -264,7 +285,7 @@ module Sequent
264
285
  drop_old_tables(Sequent.new_version)
265
286
 
266
287
  truncate_replay_ids_table!
267
- reset_table_names
288
+ executor.reset_table_names(plan)
268
289
  end
269
290
 
270
291
  def truncate_replay_ids_table!
@@ -272,7 +293,7 @@ module Sequent
272
293
  end
273
294
 
274
295
  def groups_of_aggregate_id_prefixes(number_of_groups)
275
- all_prefixes = (0...16**LENGTH_OF_SUBSTRING_INDEX_ON_AGGREGATE_ID_IN_EVENT_STORE).to_a.map { |i| i.to_s(16) } # first x digits of hex
296
+ all_prefixes = (0...16 ** LENGTH_OF_SUBSTRING_INDEX_ON_AGGREGATE_ID_IN_EVENT_STORE).to_a.map { |i| i.to_s(16) } # first x digits of hex
276
297
  all_prefixes = all_prefixes.map { |s| s.length == 3 ? s : "#{"0" * (3 - s.length)}#{s}" }
277
298
 
278
299
  logger.info "Number of groups #{number_of_groups}"
@@ -280,17 +301,7 @@ module Sequent
280
301
  logger.debug "Prefixes: #{all_prefixes.length}"
281
302
  fail "Can not have more groups #{number_of_groups} than number of prefixes #{all_prefixes.length}" if number_of_groups > all_prefixes.length
282
303
 
283
- all_prefixes.each_slice(all_prefixes.length/number_of_groups).to_a
284
- end
285
-
286
- def for_each_table_to_migrate
287
- projectors_to_migrate.flat_map(&:managed_tables).each do |managed_table|
288
- yield(managed_table)
289
- end
290
- end
291
-
292
- def projectors_to_migrate
293
- Sequent.migration_class.projectors_between(current_version, Sequent.new_version)
304
+ all_prefixes.each_slice(all_prefixes.length / number_of_groups).to_a
294
305
  end
295
306
 
296
307
  def in_view_schema
@@ -299,12 +310,6 @@ module Sequent
299
310
  end
300
311
  end
301
312
 
302
- def sql_file_to_statements(file_location)
303
- raw_sql_string = File.read(file_location, encoding: 'bom|utf-8')
304
- sql_string = yield(raw_sql_string)
305
- sql_string.split(/;$/).reject { |statement| statement.remove("\n").blank? }
306
- end
307
-
308
313
  def drop_old_tables(new_version)
309
314
  versions_to_check = (current_version - 10)..new_version
310
315
  old_tables = versions_to_check.flat_map do |old_version|
@@ -358,10 +363,6 @@ module Sequent
358
363
  def establish_connection
359
364
  Sequent::Support::Database.establish_connection(db_config)
360
365
  end
361
-
362
- def exec_sql(sql)
363
- ActiveRecord::Base.connection.execute(sql)
364
- end
365
366
  end
366
367
  end
367
368
  end