sequent 3.3.1 → 4.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/sequent +31 -25
- data/lib/notices.rb +6 -0
- data/lib/sequent/application_record.rb +2 -0
- data/lib/sequent/configuration.rb +29 -29
- data/lib/sequent/core/aggregate_repository.rb +24 -14
- 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 +30 -11
- data/lib/sequent/core/command_record.rb +12 -4
- data/lib/sequent/core/command_service.rb +41 -25
- 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 +20 -15
- data/lib/sequent/core/event_record.rb +7 -7
- data/lib/sequent/core/event_store.rb +75 -49
- 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 +64 -33
- 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 -4
- 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 +7 -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 +6 -0
- data/lib/sequent/generator/project.rb +3 -1
- data/lib/sequent/generator/template_project/Gemfile +1 -1
- data/lib/sequent/generator/template_project/spec/app/projectors/post_projector_spec.rb +1 -1
- data/lib/sequent/generator/template_project/spec/lib/post/post_command_handler_spec.rb +1 -1
- data/lib/sequent/generator.rb +3 -4
- data/lib/sequent/migrations/executor.rb +30 -9
- 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 +93 -44
- data/lib/sequent/rake/migration_tasks.rb +59 -23
- data/lib/sequent/rake/tasks.rb +5 -2
- data/lib/sequent/sequent.rb +6 -1
- data/lib/sequent/support/database.rb +39 -17
- 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 +39 -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 +194 -0
- data/lib/sequent/util/printer.rb +6 -5
- data/lib/sequent/util/skip_if_already_processing.rb +21 -5
- data/lib/sequent/util/timer.rb +2 -0
- data/lib/sequent/util/util.rb +3 -0
- data/lib/sequent.rb +4 -0
- data/lib/version.rb +3 -1
- metadata +110 -59
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'active_record'
|
2
4
|
|
3
5
|
module Sequent
|
@@ -14,8 +16,7 @@ module Sequent
|
|
14
16
|
end
|
15
17
|
|
16
18
|
class StreamRecord < Sequent::ApplicationRecord
|
17
|
-
|
18
|
-
self.table_name = "stream_records"
|
19
|
+
self.table_name = 'stream_records'
|
19
20
|
|
20
21
|
validates_presence_of :aggregate_type, :aggregate_id
|
21
22
|
validates_numericality_of :snapshot_threshold, only_integer: true, greater_than: 0, allow_nil: true
|
@@ -23,7 +24,12 @@ module Sequent
|
|
23
24
|
has_many :event_records
|
24
25
|
|
25
26
|
def event_stream
|
26
|
-
EventStream.new(
|
27
|
+
EventStream.new(
|
28
|
+
aggregate_type: aggregate_type,
|
29
|
+
aggregate_id: aggregate_id,
|
30
|
+
snapshot_threshold: snapshot_threshold,
|
31
|
+
stream_record_id: id,
|
32
|
+
)
|
27
33
|
end
|
28
34
|
|
29
35
|
def event_stream=(data)
|
@@ -1,13 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Sequent
|
2
4
|
module Core
|
3
5
|
module Transactions
|
4
|
-
|
5
6
|
class ActiveRecordTransactionProvider
|
6
|
-
def transactional
|
7
|
-
Sequent::ApplicationRecord.transaction(requires_new: true)
|
8
|
-
|
9
|
-
end
|
10
|
-
after_commit_queue.each &:call
|
7
|
+
def transactional(&block)
|
8
|
+
Sequent::ApplicationRecord.transaction(requires_new: true, &block)
|
9
|
+
after_commit_queue.pop.call until after_commit_queue.empty?
|
11
10
|
ensure
|
12
11
|
clear_after_commit_queue
|
13
12
|
end
|
@@ -19,14 +18,13 @@ module Sequent
|
|
19
18
|
private
|
20
19
|
|
21
20
|
def after_commit_queue
|
22
|
-
Thread.current[:after_commit_queue] ||=
|
21
|
+
Thread.current[:after_commit_queue] ||= Queue.new
|
23
22
|
end
|
24
23
|
|
25
24
|
def clear_after_commit_queue
|
26
|
-
|
25
|
+
after_commit_queue.clear
|
27
26
|
end
|
28
27
|
end
|
29
|
-
|
30
28
|
end
|
31
29
|
end
|
32
30
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'active_model'
|
2
4
|
require_relative 'helpers/string_support'
|
3
5
|
require_relative 'helpers/equal_support'
|
@@ -6,7 +8,6 @@ require_relative 'helpers/attribute_support'
|
|
6
8
|
require_relative 'helpers/param_support'
|
7
9
|
|
8
10
|
module Sequent
|
9
|
-
|
10
11
|
module Core
|
11
12
|
#
|
12
13
|
# ValueObject is a container for data that belongs together but requires no identity
|
@@ -26,20 +27,17 @@ module Sequent
|
|
26
27
|
#
|
27
28
|
# This a deep clone of the address with the street attribute containing "New Street"
|
28
29
|
class ValueObject
|
29
|
-
include
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
30
|
+
include ActiveModel::Validations
|
31
|
+
include Sequent::Core::Helpers::ParamSupport
|
32
|
+
include Sequent::Core::Helpers::AttributeSupport
|
33
|
+
include Sequent::Core::Helpers::Copyable
|
34
|
+
include Sequent::Core::Helpers::EqualSupport
|
35
|
+
include Sequent::Core::Helpers::StringSupport
|
35
36
|
include Sequent::Core::Helpers::TypeConversionSupport
|
36
37
|
|
37
38
|
def initialize(args = {})
|
38
39
|
update_all_attributes args
|
39
40
|
end
|
40
|
-
|
41
41
|
end
|
42
|
-
|
43
42
|
end
|
44
43
|
end
|
45
|
-
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative 'helpers/message_handler'
|
2
4
|
require_relative 'current_event'
|
3
5
|
|
@@ -11,7 +13,7 @@ module Sequent
|
|
11
13
|
begin
|
12
14
|
old_event = CurrentEvent.current
|
13
15
|
CurrentEvent.current = event
|
14
|
-
|
16
|
+
instance_exec(event, &block)
|
15
17
|
ensure
|
16
18
|
CurrentEvent.current = old_event
|
17
19
|
end
|
@@ -31,12 +33,12 @@ module Sequent
|
|
31
33
|
# jobs processor is not using the same database connection
|
32
34
|
# to enqueue jobs.
|
33
35
|
def after_commit(ignore_errors: false, &block)
|
34
|
-
Sequent.configuration.transaction_provider.after_commit
|
35
|
-
rescue StandardError =>
|
36
|
+
Sequent.configuration.transaction_provider.after_commit(&block)
|
37
|
+
rescue StandardError => e
|
36
38
|
if ignore_errors
|
37
|
-
Sequent.logger.warn("An exception was raised in an after_commit hook: #{
|
39
|
+
Sequent.logger.warn("An exception was raised in an after_commit hook: #{e}, #{e.inspect}")
|
38
40
|
else
|
39
|
-
raise
|
41
|
+
raise e
|
40
42
|
end
|
41
43
|
end
|
42
44
|
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,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
|
@@ -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'
|
@@ -54,7 +56,7 @@ module Sequent
|
|
54
56
|
end
|
55
57
|
|
56
58
|
def name_camelized
|
57
|
-
@name_camelized ||= name.camelize
|
59
|
+
@name_camelized ||= name.gsub(/\W/, '_').squeeze('_').camelize
|
58
60
|
end
|
59
61
|
end
|
60
62
|
end
|
data/lib/sequent/generator.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require_relative './generator/
|
4
|
-
require_relative './generator/event'
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative './generator/generator'
|
@@ -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`.
|
@@ -21,10 +22,26 @@ module Sequent
|
|
21
22
|
end
|
22
23
|
end
|
23
24
|
|
25
|
+
def create_indexes_after_execute_online(plan)
|
26
|
+
plan.replay_tables.each do |migration|
|
27
|
+
table = migration.record_class
|
28
|
+
original_table_name = table.table_name.gsub("_#{migration.version}", '')
|
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}")
|
36
|
+
end
|
37
|
+
statements.each(&method(:exec_sql))
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
24
41
|
def execute_offline(plan, current_version)
|
25
42
|
plan.replay_tables.each do |migration|
|
26
43
|
table = migration.record_class
|
27
|
-
current_table_name = table.table_name.gsub("_#{migration.version}",
|
44
|
+
current_table_name = table.table_name.gsub("_#{migration.version}", '')
|
28
45
|
# 2 Rename old table
|
29
46
|
exec_sql("ALTER TABLE IF EXISTS #{current_table_name} RENAME TO #{current_table_name}_#{current_version}")
|
30
47
|
# 3 Rename new table
|
@@ -36,7 +53,9 @@ module Sequent
|
|
36
53
|
|
37
54
|
plan.alter_tables.each do |migration|
|
38
55
|
table = migration.record_class
|
39
|
-
sql_file =
|
56
|
+
sql_file = <<~EOS.chomp
|
57
|
+
#{Sequent.configuration.migration_sql_files_directory}/#{table.table_name}_#{migration.version}.sql
|
58
|
+
EOS
|
40
59
|
statements = sql_file_to_statements(sql_file)
|
41
60
|
statements.each(&method(:exec_sql))
|
42
61
|
end
|
@@ -45,7 +64,7 @@ module Sequent
|
|
45
64
|
def reset_table_names(plan)
|
46
65
|
plan.replay_tables.each do |migration|
|
47
66
|
table = migration.record_class
|
48
|
-
table.table_name = table.table_name.gsub("_#{migration.version}",
|
67
|
+
table.table_name = table.table_name.gsub("_#{migration.version}", '')
|
49
68
|
table.reset_column_information
|
50
69
|
end
|
51
70
|
end
|
@@ -53,14 +72,16 @@ module Sequent
|
|
53
72
|
def set_table_names_to_new_version(plan)
|
54
73
|
plan.replay_tables.each do |migration|
|
55
74
|
table = migration.record_class
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
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?"
|
60
82
|
end
|
61
83
|
end
|
62
84
|
end
|
63
|
-
|
64
85
|
end
|
65
86
|
end
|
66
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
|
|