sequent 4.0.0 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/bin/sequent +31 -25
- data/lib/notices.rb +2 -0
- data/lib/sequent/application_record.rb +2 -0
- data/lib/sequent/configuration.rb +24 -31
- data/lib/sequent/core/aggregate_repository.rb +17 -13
- data/lib/sequent/core/aggregate_root.rb +16 -7
- data/lib/sequent/core/aggregate_roots.rb +24 -0
- data/lib/sequent/core/aggregate_snapshotter.rb +8 -5
- data/lib/sequent/core/base_command_handler.rb +4 -2
- data/lib/sequent/core/command.rb +17 -9
- data/lib/sequent/core/command_record.rb +8 -3
- data/lib/sequent/core/command_service.rb +18 -18
- data/lib/sequent/core/core.rb +2 -0
- data/lib/sequent/core/current_event.rb +2 -0
- data/lib/sequent/core/event.rb +16 -11
- data/lib/sequent/core/event_publisher.rb +16 -15
- data/lib/sequent/core/event_record.rb +7 -7
- data/lib/sequent/core/event_store.rb +57 -50
- data/lib/sequent/core/ext/ext.rb +9 -1
- data/lib/sequent/core/helpers/array_with_type.rb +4 -1
- data/lib/sequent/core/helpers/association_validator.rb +9 -7
- data/lib/sequent/core/helpers/attribute_support.rb +45 -28
- data/lib/sequent/core/helpers/autoset_attributes.rb +4 -4
- data/lib/sequent/core/helpers/boolean_validator.rb +6 -1
- data/lib/sequent/core/helpers/copyable.rb +2 -2
- data/lib/sequent/core/helpers/date_time_validator.rb +4 -1
- data/lib/sequent/core/helpers/date_validator.rb +6 -1
- data/lib/sequent/core/helpers/default_validators.rb +12 -10
- data/lib/sequent/core/helpers/equal_support.rb +8 -6
- data/lib/sequent/core/helpers/helpers.rb +2 -0
- data/lib/sequent/core/helpers/mergable.rb +6 -5
- data/lib/sequent/core/helpers/message_handler.rb +3 -1
- data/lib/sequent/core/helpers/param_support.rb +19 -15
- data/lib/sequent/core/helpers/secret.rb +14 -12
- data/lib/sequent/core/helpers/string_support.rb +5 -4
- data/lib/sequent/core/helpers/string_to_value_parsers.rb +7 -2
- data/lib/sequent/core/helpers/string_validator.rb +6 -1
- data/lib/sequent/core/helpers/type_conversion_support.rb +5 -3
- data/lib/sequent/core/helpers/uuid_helper.rb +5 -2
- data/lib/sequent/core/helpers/value_validators.rb +23 -9
- data/lib/sequent/core/persistors/active_record_persistor.rb +19 -9
- data/lib/sequent/core/persistors/persistor.rb +16 -14
- data/lib/sequent/core/persistors/persistors.rb +2 -0
- data/lib/sequent/core/persistors/replay_optimized_postgres_persistor.rb +70 -47
- data/lib/sequent/core/projector.rb +25 -22
- data/lib/sequent/core/random_uuid_generator.rb +2 -0
- data/lib/sequent/core/sequent_oj.rb +2 -0
- data/lib/sequent/core/stream_record.rb +9 -3
- data/lib/sequent/core/transactions/active_record_transaction_provider.rb +5 -9
- data/lib/sequent/core/transactions/no_transactions.rb +2 -1
- data/lib/sequent/core/transactions/transactions.rb +2 -0
- data/lib/sequent/core/value_object.rb +8 -10
- data/lib/sequent/core/workflow.rb +7 -5
- data/lib/sequent/generator/aggregate.rb +16 -10
- data/lib/sequent/generator/command.rb +26 -19
- data/lib/sequent/generator/event.rb +19 -17
- data/lib/sequent/generator/generator.rb +2 -0
- data/lib/sequent/generator/project.rb +2 -0
- data/lib/sequent/generator/template_project/Gemfile +1 -1
- data/lib/sequent/generator.rb +2 -0
- data/lib/sequent/migrations/executor.rb +22 -13
- data/lib/sequent/migrations/functions.rb +5 -6
- data/lib/sequent/migrations/migrate_events.rb +12 -9
- data/lib/sequent/migrations/migrations.rb +2 -1
- data/lib/sequent/migrations/planner.rb +33 -23
- data/lib/sequent/migrations/projectors.rb +4 -3
- data/lib/sequent/migrations/sql.rb +2 -0
- data/lib/sequent/migrations/view_schema.rb +84 -45
- data/lib/sequent/rake/migration_tasks.rb +58 -22
- data/lib/sequent/rake/tasks.rb +5 -2
- data/lib/sequent/sequent.rb +2 -0
- data/lib/sequent/support/database.rb +30 -15
- data/lib/sequent/support/view_projection.rb +6 -3
- data/lib/sequent/support/view_schema.rb +2 -0
- data/lib/sequent/support.rb +2 -0
- data/lib/sequent/test/command_handler_helpers.rb +35 -17
- data/lib/sequent/test/event_handler_helpers.rb +10 -4
- data/lib/sequent/test/event_stream_helpers.rb +7 -3
- data/lib/sequent/test/time_comparison.rb +12 -5
- data/lib/sequent/test.rb +2 -0
- data/lib/sequent/util/dry_run.rb +11 -8
- data/lib/sequent/util/printer.rb +6 -5
- data/lib/sequent/util/skip_if_already_processing.rb +3 -1
- data/lib/sequent/util/timer.rb +2 -0
- data/lib/sequent/util/util.rb +2 -0
- data/lib/sequent.rb +2 -0
- data/lib/version.rb +3 -1
- metadata +81 -66
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'fileutils'
|
|
2
4
|
require 'active_support'
|
|
3
5
|
require 'active_support/core_ext/string'
|
|
@@ -7,8 +9,6 @@ class TargetAlreadyExists < StandardError; end
|
|
|
7
9
|
module Sequent
|
|
8
10
|
module Generator
|
|
9
11
|
class Aggregate
|
|
10
|
-
attr_reader :name
|
|
11
|
-
|
|
12
12
|
def initialize(name)
|
|
13
13
|
@name = name
|
|
14
14
|
end
|
|
@@ -20,6 +20,10 @@ module Sequent
|
|
|
20
20
|
replace_template_aggregate
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
+
def name
|
|
24
|
+
@name ||= File.basename(path)
|
|
25
|
+
end
|
|
26
|
+
|
|
23
27
|
private
|
|
24
28
|
|
|
25
29
|
def copy_files
|
|
@@ -30,8 +34,14 @@ module Sequent
|
|
|
30
34
|
FileUtils.mv("#{path}/template_aggregate.rb", "#{path}/#{name_underscored}.rb")
|
|
31
35
|
FileUtils.mv("#{path}/template_aggregate", "#{path}/#{name_underscored}")
|
|
32
36
|
|
|
33
|
-
FileUtils.mv(
|
|
34
|
-
|
|
37
|
+
FileUtils.mv(
|
|
38
|
+
"#{path}/#{name_underscored}/template_aggregate_command_handler.rb",
|
|
39
|
+
"#{path}/#{name_underscored}/#{name_underscored}_command_handler.rb",
|
|
40
|
+
)
|
|
41
|
+
FileUtils.mv(
|
|
42
|
+
"#{path}/#{name_underscored}/template_aggregate.rb",
|
|
43
|
+
"#{path}/#{name_underscored}/#{name_underscored}.rb",
|
|
44
|
+
)
|
|
35
45
|
end
|
|
36
46
|
|
|
37
47
|
def replace_template_aggregate
|
|
@@ -46,11 +56,7 @@ module Sequent
|
|
|
46
56
|
end
|
|
47
57
|
|
|
48
58
|
def path
|
|
49
|
-
@path ||= File.expand_path(
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def name
|
|
53
|
-
@name ||= File.basename(path)
|
|
59
|
+
@path ||= File.expand_path('lib')
|
|
54
60
|
end
|
|
55
61
|
|
|
56
62
|
def name_underscored
|
|
@@ -63,7 +69,7 @@ module Sequent
|
|
|
63
69
|
|
|
64
70
|
def ensure_not_used!
|
|
65
71
|
if File.directory?("#{path}/#{name_underscored}") || File.exist?("#{path}/#{name_underscored}.rb")
|
|
66
|
-
|
|
72
|
+
fail TargetAlreadyExists
|
|
67
73
|
end
|
|
68
74
|
end
|
|
69
75
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'fileutils'
|
|
2
4
|
require 'active_support'
|
|
3
5
|
require 'active_support/core_ext/string'
|
|
@@ -9,12 +11,12 @@ class NoAggregateFound < StandardError; end
|
|
|
9
11
|
module Sequent
|
|
10
12
|
module Generator
|
|
11
13
|
class Command
|
|
12
|
-
attr_reader :
|
|
14
|
+
attr_reader :command, :attrs
|
|
13
15
|
|
|
14
16
|
def initialize(name, command, attrs)
|
|
15
17
|
@name = name
|
|
16
18
|
@command = command
|
|
17
|
-
@attrs = attrs.map{|a| a.split(':')}
|
|
19
|
+
@attrs = attrs.map { |a| a.split(':') }
|
|
18
20
|
end
|
|
19
21
|
|
|
20
22
|
def execute
|
|
@@ -22,32 +24,39 @@ module Sequent
|
|
|
22
24
|
add_command_to_aggregate
|
|
23
25
|
end
|
|
24
26
|
|
|
27
|
+
def name
|
|
28
|
+
@name ||= File.basename(path)
|
|
29
|
+
end
|
|
30
|
+
|
|
25
31
|
private
|
|
32
|
+
|
|
26
33
|
def append_command_handler
|
|
27
34
|
ast = Parser::CurrentRuby.parse(File.read("#{path_to_dir}/#{name_underscored}_command_handler.rb"))
|
|
28
35
|
target_cursor_position = find_target_cursor_position(ast)
|
|
29
|
-
|
|
36
|
+
|
|
30
37
|
File.open("#{path_to_dir}/#{name_underscored}_command_handler.rb", 'r+') do |f|
|
|
31
38
|
f.seek(target_cursor_position, IO::SEEK_SET)
|
|
32
39
|
lines_to_be_overwritten = f.read
|
|
33
40
|
f.seek(target_cursor_position, IO::SEEK_SET)
|
|
34
|
-
f << command_handler_template.result(binding).gsub(/^.+(\s)$/) { |x| x.gsub!(
|
|
41
|
+
f << command_handler_template.result(binding).gsub(/^.+(\s)$/) { |x| x.gsub!(Regexp.last_match(1), '') }
|
|
35
42
|
f << lines_to_be_overwritten
|
|
36
43
|
end
|
|
37
44
|
end
|
|
38
45
|
|
|
39
46
|
def find_target_cursor_position(ast)
|
|
40
47
|
return unless ast.children.any?
|
|
48
|
+
return if ast.children.any? { |c| c.class.to_s != 'Parser::AST::Node' }
|
|
49
|
+
if (child = ast.children.find { |c| c.type.to_s == 'block' })
|
|
50
|
+
return child.loc.expression.end_pos
|
|
51
|
+
end
|
|
41
52
|
|
|
42
|
-
ast.children.map do |
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
find_target_cursor_position(child)
|
|
46
|
-
end.flatten.compact.max
|
|
53
|
+
ast.children.map do |c|
|
|
54
|
+
find_target_cursor_position(c)
|
|
55
|
+
end&.flatten&.compact&.max
|
|
47
56
|
end
|
|
48
57
|
|
|
49
58
|
def append_command
|
|
50
|
-
File.open("#{path_to_dir}/commands.rb",
|
|
59
|
+
File.open("#{path_to_dir}/commands.rb", 'a') { |f| f << command_template.result(binding) }
|
|
51
60
|
end
|
|
52
61
|
|
|
53
62
|
def add_command_to_aggregate
|
|
@@ -56,11 +65,7 @@ module Sequent
|
|
|
56
65
|
end
|
|
57
66
|
|
|
58
67
|
def path
|
|
59
|
-
@path ||= File.expand_path(
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
def name
|
|
63
|
-
@name ||= File.basename(path)
|
|
68
|
+
@path ||= File.expand_path('lib')
|
|
64
69
|
end
|
|
65
70
|
|
|
66
71
|
def name_underscored
|
|
@@ -72,17 +77,19 @@ module Sequent
|
|
|
72
77
|
end
|
|
73
78
|
|
|
74
79
|
def ensure_existing_aggregate!
|
|
75
|
-
if !File.directory?(path_to_dir) ||
|
|
76
|
-
|
|
80
|
+
if !File.directory?(path_to_dir) ||
|
|
81
|
+
!File.exist?("#{path_to_dir}/#{name_underscored}_command_handler.rb") ||
|
|
82
|
+
!File.exist?("#{path_to_dir}/commands.rb")
|
|
83
|
+
fail NoAggregateFound
|
|
77
84
|
end
|
|
78
85
|
end
|
|
79
86
|
|
|
80
87
|
def command_template
|
|
81
|
-
ERB.new(File.read(File.join(
|
|
88
|
+
ERB.new(File.read(File.join(File.dirname(__FILE__), 'template_command.erb')))
|
|
82
89
|
end
|
|
83
90
|
|
|
84
91
|
def command_handler_template
|
|
85
|
-
ERB.new(File.read(File.join(
|
|
92
|
+
ERB.new(File.read(File.join(File.dirname(__FILE__), 'template_command_handler.erb')))
|
|
86
93
|
end
|
|
87
94
|
end
|
|
88
95
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'fileutils'
|
|
2
4
|
require 'active_support'
|
|
3
5
|
require 'active_support/core_ext/string'
|
|
@@ -7,12 +9,16 @@ class NoAggregateFound < StandardError; end
|
|
|
7
9
|
module Sequent
|
|
8
10
|
module Generator
|
|
9
11
|
class Event
|
|
10
|
-
attr_reader :
|
|
12
|
+
attr_reader :event, :attrs
|
|
11
13
|
|
|
12
14
|
def initialize(name, event, attrs)
|
|
13
15
|
@name = name
|
|
14
16
|
@event = event
|
|
15
|
-
@attrs = attrs.map{|a| a.split(':')}
|
|
17
|
+
@attrs = attrs.map { |a| a.split(':') }
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def name
|
|
21
|
+
@name ||= File.basename(path)
|
|
16
22
|
end
|
|
17
23
|
|
|
18
24
|
def execute
|
|
@@ -23,29 +29,31 @@ module Sequent
|
|
|
23
29
|
private
|
|
24
30
|
|
|
25
31
|
def append_event
|
|
26
|
-
File.open("#{path_to_dir}/events.rb",
|
|
32
|
+
File.open("#{path_to_dir}/events.rb", 'a') { |f| f << event_template.result(binding) }
|
|
27
33
|
end
|
|
28
34
|
|
|
29
35
|
def append_event_to_domain
|
|
30
36
|
ast = Parser::CurrentRuby.parse(File.read("#{path_to_dir}/#{name_underscored}.rb"))
|
|
31
37
|
target_cursor_position = find_target_cursor_position(ast)
|
|
32
|
-
|
|
38
|
+
|
|
33
39
|
File.open("#{path_to_dir}/#{name_underscored}.rb", 'r+') do |f|
|
|
34
40
|
f.seek(target_cursor_position, IO::SEEK_SET)
|
|
35
41
|
lines_to_be_overwritten = f.read
|
|
36
42
|
f.seek(target_cursor_position, IO::SEEK_SET)
|
|
37
|
-
f << event_handler_template.result(binding).gsub(/^.+(\s)$/) { |x| x.gsub!(
|
|
43
|
+
f << event_handler_template.result(binding).gsub(/^.+(\s)$/) { |x| x.gsub!(Regexp.last_match(1), '') }
|
|
38
44
|
f << lines_to_be_overwritten
|
|
39
45
|
end
|
|
40
46
|
end
|
|
41
47
|
|
|
42
48
|
def find_target_cursor_position(ast)
|
|
43
49
|
return unless ast.children.any?
|
|
50
|
+
return if ast.children.any? { |c| c.class.to_s != 'Parser::AST::Node' }
|
|
51
|
+
if (child = ast.children.find { |c| c.type.to_s == 'block' })
|
|
52
|
+
return child.loc.expression.end_pos
|
|
53
|
+
end
|
|
44
54
|
|
|
45
|
-
ast.children.reverse.map do |
|
|
46
|
-
|
|
47
|
-
return child.loc.expression.end_pos if child.type.to_s == 'block'
|
|
48
|
-
find_target_cursor_position(child)
|
|
55
|
+
ast.children.reverse.map do |c|
|
|
56
|
+
find_target_cursor_position(c)
|
|
49
57
|
end.flatten.compact.max
|
|
50
58
|
end
|
|
51
59
|
|
|
@@ -55,11 +63,7 @@ module Sequent
|
|
|
55
63
|
end
|
|
56
64
|
|
|
57
65
|
def path
|
|
58
|
-
@path ||= File.expand_path(
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
def name
|
|
62
|
-
@name ||= File.basename(path)
|
|
66
|
+
@path ||= File.expand_path('lib')
|
|
63
67
|
end
|
|
64
68
|
|
|
65
69
|
def name_underscored
|
|
@@ -71,9 +75,7 @@ module Sequent
|
|
|
71
75
|
end
|
|
72
76
|
|
|
73
77
|
def ensure_existing_aggregate!
|
|
74
|
-
if !File.directory?(path_to_dir) || !File.exist?("#{path_to_dir}/#{name_underscored}.rb")
|
|
75
|
-
raise NoAggregateFound
|
|
76
|
-
end
|
|
78
|
+
fail NoAggregateFound if !File.directory?(path_to_dir) || !File.exist?("#{path_to_dir}/#{name_underscored}.rb")
|
|
77
79
|
end
|
|
78
80
|
|
|
79
81
|
def event_template
|
data/lib/sequent/generator.rb
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require_relative 'sql'
|
|
2
4
|
|
|
3
5
|
module Sequent
|
|
4
6
|
module Migrations
|
|
5
|
-
|
|
6
7
|
##
|
|
7
8
|
# The executor is the implementation of the 3-phase deploy in Sequent.
|
|
8
9
|
# is responsible for executing the `Planner::Plan`.
|
|
@@ -25,18 +26,22 @@ module Sequent
|
|
|
25
26
|
plan.replay_tables.each do |migration|
|
|
26
27
|
table = migration.record_class
|
|
27
28
|
original_table_name = table.table_name.gsub("_#{migration.version}", '')
|
|
28
|
-
indexes_file_name =
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
indexes_file_name = <<~EOS.chomp
|
|
30
|
+
#{Sequent.configuration.migration_sql_files_directory}/#{original_table_name}.indexes.sql
|
|
31
|
+
EOS
|
|
32
|
+
next unless File.exist?(indexes_file_name)
|
|
33
|
+
|
|
34
|
+
statements = sql_file_to_statements(indexes_file_name) do |raw_sql|
|
|
35
|
+
raw_sql.gsub('%SUFFIX%', "_#{migration.version}")
|
|
32
36
|
end
|
|
37
|
+
statements.each(&method(:exec_sql))
|
|
33
38
|
end
|
|
34
39
|
end
|
|
35
40
|
|
|
36
41
|
def execute_offline(plan, current_version)
|
|
37
42
|
plan.replay_tables.each do |migration|
|
|
38
43
|
table = migration.record_class
|
|
39
|
-
current_table_name = table.table_name.gsub("_#{migration.version}",
|
|
44
|
+
current_table_name = table.table_name.gsub("_#{migration.version}", '')
|
|
40
45
|
# 2 Rename old table
|
|
41
46
|
exec_sql("ALTER TABLE IF EXISTS #{current_table_name} RENAME TO #{current_table_name}_#{current_version}")
|
|
42
47
|
# 3 Rename new table
|
|
@@ -48,7 +53,9 @@ module Sequent
|
|
|
48
53
|
|
|
49
54
|
plan.alter_tables.each do |migration|
|
|
50
55
|
table = migration.record_class
|
|
51
|
-
sql_file =
|
|
56
|
+
sql_file = <<~EOS.chomp
|
|
57
|
+
#{Sequent.configuration.migration_sql_files_directory}/#{table.table_name}_#{migration.version}.sql
|
|
58
|
+
EOS
|
|
52
59
|
statements = sql_file_to_statements(sql_file)
|
|
53
60
|
statements.each(&method(:exec_sql))
|
|
54
61
|
end
|
|
@@ -57,7 +64,7 @@ module Sequent
|
|
|
57
64
|
def reset_table_names(plan)
|
|
58
65
|
plan.replay_tables.each do |migration|
|
|
59
66
|
table = migration.record_class
|
|
60
|
-
table.table_name = table.table_name.gsub("_#{migration.version}",
|
|
67
|
+
table.table_name = table.table_name.gsub("_#{migration.version}", '')
|
|
61
68
|
table.reset_column_information
|
|
62
69
|
end
|
|
63
70
|
end
|
|
@@ -65,14 +72,16 @@ module Sequent
|
|
|
65
72
|
def set_table_names_to_new_version(plan)
|
|
66
73
|
plan.replay_tables.each do |migration|
|
|
67
74
|
table = migration.record_class
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
75
|
+
next if table.table_name.end_with?("_#{migration.version}")
|
|
76
|
+
|
|
77
|
+
table.table_name = "#{table.table_name}_#{migration.version}"
|
|
78
|
+
table.reset_column_information
|
|
79
|
+
unless table.table_exists?
|
|
80
|
+
fail MigrationError,
|
|
81
|
+
"Table #{table.table_name} does not exist. Did you run ViewSchema.migrate_online first?"
|
|
72
82
|
end
|
|
73
83
|
end
|
|
74
84
|
end
|
|
75
|
-
|
|
76
85
|
end
|
|
77
86
|
end
|
|
78
87
|
end
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Sequent
|
|
2
4
|
module Migrations
|
|
3
5
|
class Migration
|
|
4
|
-
|
|
5
6
|
module ClassMethods
|
|
6
7
|
def create(record_class, version)
|
|
7
8
|
migration = new(record_class)
|
|
@@ -11,6 +12,7 @@ module Sequent
|
|
|
11
12
|
end
|
|
12
13
|
|
|
13
14
|
def self.inherited(child_class)
|
|
15
|
+
super
|
|
14
16
|
class << child_class
|
|
15
17
|
include ClassMethods
|
|
16
18
|
end
|
|
@@ -35,11 +37,11 @@ module Sequent
|
|
|
35
37
|
def ==(other)
|
|
36
38
|
return false unless other.class == self.class
|
|
37
39
|
|
|
38
|
-
|
|
40
|
+
table_name == other.table_name && version == other.version
|
|
39
41
|
end
|
|
40
42
|
|
|
41
43
|
def hash
|
|
42
|
-
|
|
44
|
+
table_name.hash + (version&.hash || 0)
|
|
43
45
|
end
|
|
44
46
|
end
|
|
45
47
|
|
|
@@ -48,7 +50,6 @@ module Sequent
|
|
|
48
50
|
class ReplayTable < Migration; end
|
|
49
51
|
|
|
50
52
|
module Functions
|
|
51
|
-
|
|
52
53
|
module ClassMethods
|
|
53
54
|
def alter_table(name)
|
|
54
55
|
AlterTable.new(name)
|
|
@@ -62,13 +63,11 @@ module Sequent
|
|
|
62
63
|
def all_projectors
|
|
63
64
|
Sequent::Core::Migratable.all
|
|
64
65
|
end
|
|
65
|
-
|
|
66
66
|
end
|
|
67
67
|
|
|
68
68
|
def self.included(base)
|
|
69
69
|
base.extend(ClassMethods)
|
|
70
70
|
end
|
|
71
|
-
|
|
72
71
|
end
|
|
73
72
|
|
|
74
73
|
include Functions
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
##
|
|
2
4
|
# When you need to upgrade the event store based on information of the previous schema version
|
|
3
5
|
# this is the place you need to implement a migration.
|
|
@@ -20,11 +22,12 @@
|
|
|
20
22
|
module Sequent
|
|
21
23
|
module Migrations
|
|
22
24
|
class MigrateEvents
|
|
23
|
-
|
|
24
25
|
##
|
|
25
26
|
# @param env The string representing the current environment. E.g. "development", "production"
|
|
26
27
|
def initialize(env)
|
|
27
|
-
warn
|
|
28
|
+
warn <<~EOS
|
|
29
|
+
[DEPRECATED] Use of MigrateEvents is deprecated and will be removed from future version. Please use Sequent::Migrations::ViewSchema instead. See the changelog on how to update.
|
|
30
|
+
EOS
|
|
28
31
|
@env = env
|
|
29
32
|
end
|
|
30
33
|
|
|
@@ -32,9 +35,10 @@ module Sequent
|
|
|
32
35
|
#
|
|
33
36
|
# @param current_version The current version of the application. E.g. 10
|
|
34
37
|
# @param new_version The version to migrate to. E.g. 11
|
|
35
|
-
# @param &after_migration_block an optional block (with the current upgrade version as param)
|
|
38
|
+
# @param &after_migration_block an optional block (with the current upgrade version as param)
|
|
39
|
+
# to run after the migrations run. E.g. close resources
|
|
36
40
|
#
|
|
37
|
-
def execute_migrations(current_version, new_version
|
|
41
|
+
def execute_migrations(current_version, new_version)
|
|
38
42
|
migrations(current_version, new_version).each do |migration_class|
|
|
39
43
|
migration = migration_class.new(@env)
|
|
40
44
|
begin
|
|
@@ -47,12 +51,11 @@ module Sequent
|
|
|
47
51
|
|
|
48
52
|
def migrations(current_version, new_version)
|
|
49
53
|
return [] if current_version == 0
|
|
54
|
+
|
|
50
55
|
((current_version + 1)..new_version).map do |upgrade_to_version|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
nil
|
|
55
|
-
end
|
|
56
|
+
Class.const_get("Database::MigrateToVersion#{upgrade_to_version}")
|
|
57
|
+
rescue NameError
|
|
58
|
+
nil
|
|
56
59
|
end.compact
|
|
57
60
|
end
|
|
58
61
|
|
|
@@ -1,13 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Sequent
|
|
2
4
|
module Migrations
|
|
3
5
|
class Planner
|
|
4
6
|
Plan = Struct.new(:projectors, :migrations) do
|
|
5
7
|
def replay_tables
|
|
6
|
-
migrations.select { |m| m.
|
|
8
|
+
migrations.select { |m| m.instance_of?(ReplayTable) }
|
|
7
9
|
end
|
|
8
10
|
|
|
9
11
|
def alter_tables
|
|
10
|
-
migrations.select { |m| m.
|
|
12
|
+
migrations.select { |m| m.instance_of?(AlterTable) }
|
|
11
13
|
end
|
|
12
14
|
|
|
13
15
|
def empty?
|
|
@@ -28,7 +30,7 @@ module Sequent
|
|
|
28
30
|
migrations.yield_self(&method(:select_projectors)),
|
|
29
31
|
migrations
|
|
30
32
|
.yield_self(&method(:create_migrations))
|
|
31
|
-
.yield_self(&method(:remove_redundant_migrations))
|
|
33
|
+
.yield_self(&method(:remove_redundant_migrations)),
|
|
32
34
|
)
|
|
33
35
|
end
|
|
34
36
|
|
|
@@ -43,11 +45,11 @@ module Sequent
|
|
|
43
45
|
|
|
44
46
|
def remove_redundant_migrations(migrations)
|
|
45
47
|
redundant_migrations = migrations
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
.yield_self(&method(:group_identical_migrations))
|
|
49
|
+
.yield_self(&method(:select_redundant_migrations))
|
|
50
|
+
.yield_self(&method(:remove_redundancy))
|
|
51
|
+
.values
|
|
52
|
+
.flatten
|
|
51
53
|
|
|
52
54
|
(migrations - redundant_migrations)
|
|
53
55
|
.yield_self(&method(:remove_alter_tables_before_replay_table))
|
|
@@ -64,21 +66,22 @@ module Sequent
|
|
|
64
66
|
|
|
65
67
|
def remove_alter_tables_before_replay_table(migrations)
|
|
66
68
|
migrations - migrations
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
69
|
+
.each_with_index
|
|
70
|
+
.select { |migration, _index| migration.instance_of?(AlterTable) }
|
|
71
|
+
.select do |migration, index|
|
|
72
|
+
migrations
|
|
73
|
+
.slice((index + 1)..-1)
|
|
74
|
+
.find { |m| m.instance_of?(ReplayTable) && m.record_class == migration.record_class }
|
|
75
|
+
end.map(&:first)
|
|
73
76
|
end
|
|
74
77
|
|
|
75
78
|
def remove_redundancy(grouped_migrations)
|
|
76
|
-
grouped_migrations.reduce({})
|
|
79
|
+
grouped_migrations.reduce({}) do |memo, (key, ms)|
|
|
77
80
|
memo[key] = ms
|
|
78
|
-
|
|
79
|
-
|
|
81
|
+
.yield_self(&method(:order_by_version_desc))
|
|
82
|
+
.slice(1..-1)
|
|
80
83
|
memo
|
|
81
|
-
|
|
84
|
+
end
|
|
82
85
|
end
|
|
83
86
|
|
|
84
87
|
def order_by_version_desc(migrations)
|
|
@@ -95,13 +98,20 @@ module Sequent
|
|
|
95
98
|
end
|
|
96
99
|
|
|
97
100
|
def map_to_migrations(migrations)
|
|
98
|
-
migrations.reduce({}) do |memo, (version,
|
|
99
|
-
|
|
101
|
+
migrations.reduce({}) do |memo, (version, ms)|
|
|
102
|
+
unless ms.is_a?(Array)
|
|
103
|
+
fail "Declared migrations for version #{version} must be an Array. For example: {'3' => [FooProjector]}"
|
|
104
|
+
end
|
|
100
105
|
|
|
101
|
-
memo[version] =
|
|
106
|
+
memo[version] = ms.flat_map do |migration|
|
|
102
107
|
if migration.is_a?(AlterTable)
|
|
103
|
-
alter_table_sql_file_name =
|
|
104
|
-
|
|
108
|
+
alter_table_sql_file_name = <<~EOS.chomp
|
|
109
|
+
#{Sequent.configuration.migration_sql_files_directory}/#{migration.table_name}_#{version}.sql
|
|
110
|
+
EOS
|
|
111
|
+
unless File.exist?(alter_table_sql_file_name)
|
|
112
|
+
fail "Missing file #{alter_table_sql_file_name} to apply for version #{version}"
|
|
113
|
+
end
|
|
114
|
+
|
|
105
115
|
migration.copy(version)
|
|
106
116
|
elsif migration < Sequent::Projector
|
|
107
117
|
migration.managed_tables.map { |table| ReplayTable.create(table, version) }
|
|
@@ -1,19 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require_relative 'planner'
|
|
2
4
|
module Sequent
|
|
3
5
|
module Migrations
|
|
4
6
|
class Projectors
|
|
5
7
|
def self.versions
|
|
6
|
-
fail
|
|
8
|
+
fail 'Define your own Sequent::Migrations::List class that extends this class and implements this method'
|
|
7
9
|
end
|
|
8
10
|
|
|
9
11
|
def self.version
|
|
10
|
-
fail
|
|
12
|
+
fail 'Define your own Sequent::Migrations::List class that extends this class and implements this method'
|
|
11
13
|
end
|
|
12
14
|
|
|
13
15
|
def self.migrations_between(old, new)
|
|
14
16
|
Planner.new(versions).plan(old, new)
|
|
15
17
|
end
|
|
16
18
|
end
|
|
17
|
-
|
|
18
19
|
end
|
|
19
20
|
end
|