sequent 3.3.1 → 4.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. checksums.yaml +4 -4
  2. data/bin/sequent +31 -25
  3. data/lib/notices.rb +6 -0
  4. data/lib/sequent/application_record.rb +2 -0
  5. data/lib/sequent/configuration.rb +29 -29
  6. data/lib/sequent/core/aggregate_repository.rb +24 -14
  7. data/lib/sequent/core/aggregate_root.rb +16 -7
  8. data/lib/sequent/core/aggregate_roots.rb +24 -0
  9. data/lib/sequent/core/aggregate_snapshotter.rb +8 -5
  10. data/lib/sequent/core/base_command_handler.rb +4 -2
  11. data/lib/sequent/core/command.rb +30 -11
  12. data/lib/sequent/core/command_record.rb +12 -4
  13. data/lib/sequent/core/command_service.rb +41 -25
  14. data/lib/sequent/core/core.rb +2 -0
  15. data/lib/sequent/core/current_event.rb +2 -0
  16. data/lib/sequent/core/event.rb +16 -11
  17. data/lib/sequent/core/event_publisher.rb +20 -15
  18. data/lib/sequent/core/event_record.rb +7 -7
  19. data/lib/sequent/core/event_store.rb +75 -49
  20. data/lib/sequent/core/ext/ext.rb +9 -1
  21. data/lib/sequent/core/helpers/array_with_type.rb +4 -1
  22. data/lib/sequent/core/helpers/association_validator.rb +9 -7
  23. data/lib/sequent/core/helpers/attribute_support.rb +64 -33
  24. data/lib/sequent/core/helpers/autoset_attributes.rb +4 -4
  25. data/lib/sequent/core/helpers/boolean_validator.rb +6 -1
  26. data/lib/sequent/core/helpers/copyable.rb +2 -2
  27. data/lib/sequent/core/helpers/date_time_validator.rb +4 -1
  28. data/lib/sequent/core/helpers/date_validator.rb +6 -1
  29. data/lib/sequent/core/helpers/default_validators.rb +12 -10
  30. data/lib/sequent/core/helpers/equal_support.rb +8 -6
  31. data/lib/sequent/core/helpers/helpers.rb +2 -0
  32. data/lib/sequent/core/helpers/mergable.rb +6 -4
  33. data/lib/sequent/core/helpers/message_handler.rb +3 -1
  34. data/lib/sequent/core/helpers/param_support.rb +19 -15
  35. data/lib/sequent/core/helpers/secret.rb +14 -12
  36. data/lib/sequent/core/helpers/string_support.rb +5 -4
  37. data/lib/sequent/core/helpers/string_to_value_parsers.rb +7 -2
  38. data/lib/sequent/core/helpers/string_validator.rb +6 -1
  39. data/lib/sequent/core/helpers/type_conversion_support.rb +5 -3
  40. data/lib/sequent/core/helpers/uuid_helper.rb +5 -2
  41. data/lib/sequent/core/helpers/value_validators.rb +23 -9
  42. data/lib/sequent/core/persistors/active_record_persistor.rb +19 -9
  43. data/lib/sequent/core/persistors/persistor.rb +16 -14
  44. data/lib/sequent/core/persistors/persistors.rb +2 -0
  45. data/lib/sequent/core/persistors/replay_optimized_postgres_persistor.rb +70 -47
  46. data/lib/sequent/core/projector.rb +25 -22
  47. data/lib/sequent/core/random_uuid_generator.rb +2 -0
  48. data/lib/sequent/core/sequent_oj.rb +2 -0
  49. data/lib/sequent/core/stream_record.rb +9 -3
  50. data/lib/sequent/core/transactions/active_record_transaction_provider.rb +7 -9
  51. data/lib/sequent/core/transactions/no_transactions.rb +2 -1
  52. data/lib/sequent/core/transactions/transactions.rb +2 -0
  53. data/lib/sequent/core/value_object.rb +8 -10
  54. data/lib/sequent/core/workflow.rb +7 -5
  55. data/lib/sequent/generator/aggregate.rb +16 -10
  56. data/lib/sequent/generator/command.rb +26 -19
  57. data/lib/sequent/generator/event.rb +19 -17
  58. data/lib/sequent/generator/generator.rb +6 -0
  59. data/lib/sequent/generator/project.rb +3 -1
  60. data/lib/sequent/generator/template_project/Gemfile +1 -1
  61. data/lib/sequent/generator/template_project/spec/app/projectors/post_projector_spec.rb +1 -1
  62. data/lib/sequent/generator/template_project/spec/lib/post/post_command_handler_spec.rb +1 -1
  63. data/lib/sequent/generator.rb +3 -4
  64. data/lib/sequent/migrations/executor.rb +30 -9
  65. data/lib/sequent/migrations/functions.rb +5 -6
  66. data/lib/sequent/migrations/migrate_events.rb +12 -9
  67. data/lib/sequent/migrations/migrations.rb +2 -1
  68. data/lib/sequent/migrations/planner.rb +33 -23
  69. data/lib/sequent/migrations/projectors.rb +4 -3
  70. data/lib/sequent/migrations/sql.rb +2 -0
  71. data/lib/sequent/migrations/view_schema.rb +93 -44
  72. data/lib/sequent/rake/migration_tasks.rb +59 -23
  73. data/lib/sequent/rake/tasks.rb +5 -2
  74. data/lib/sequent/sequent.rb +6 -1
  75. data/lib/sequent/support/database.rb +39 -17
  76. data/lib/sequent/support/view_projection.rb +6 -3
  77. data/lib/sequent/support/view_schema.rb +2 -0
  78. data/lib/sequent/support.rb +2 -0
  79. data/lib/sequent/test/command_handler_helpers.rb +39 -17
  80. data/lib/sequent/test/event_handler_helpers.rb +10 -4
  81. data/lib/sequent/test/event_stream_helpers.rb +7 -3
  82. data/lib/sequent/test/time_comparison.rb +12 -5
  83. data/lib/sequent/test.rb +2 -0
  84. data/lib/sequent/util/dry_run.rb +194 -0
  85. data/lib/sequent/util/printer.rb +6 -5
  86. data/lib/sequent/util/skip_if_already_processing.rb +21 -5
  87. data/lib/sequent/util/timer.rb +2 -0
  88. data/lib/sequent/util/util.rb +3 -0
  89. data/lib/sequent.rb +4 -0
  90. data/lib/version.rb +3 -1
  91. metadata +110 -59
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'oj'
2
4
 
3
5
  module Sequent
@@ -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(aggregate_type: aggregate_type, aggregate_id: aggregate_id, snapshot_threshold: snapshot_threshold, stream_record_id: id)
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) do
8
- yield
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
- Thread.current[:after_commit_queue] = []
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
  module Sequent
2
4
  module Core
3
5
  module Transactions
@@ -11,7 +13,6 @@ module Sequent
11
13
  yield
12
14
  end
13
15
  end
14
-
15
16
  end
16
17
  end
17
18
  end
@@ -1,2 +1,4 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'active_record_transaction_provider'
2
4
  require_relative 'no_transactions'
@@ -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 Sequent::Core::Helpers::StringSupport,
30
- Sequent::Core::Helpers::EqualSupport,
31
- Sequent::Core::Helpers::Copyable,
32
- Sequent::Core::Helpers::AttributeSupport,
33
- Sequent::Core::Helpers::ParamSupport,
34
- ActiveModel::Validations
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
- self.instance_exec(event, &block)
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 &block
35
- rescue StandardError => error
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: #{error}, #{error.inspect}")
39
+ Sequent.logger.warn("An exception was raised in an after_commit hook: #{e}, #{e.inspect}")
38
40
  else
39
- raise error
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("#{path}/#{name_underscored}/template_aggregate_command_handler.rb", "#{path}/#{name_underscored}/#{name_underscored}_command_handler.rb")
34
- FileUtils.mv("#{path}/#{name_underscored}/template_aggregate.rb", "#{path}/#{name_underscored}/#{name_underscored}.rb")
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("lib")
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
- raise TargetAlreadyExists
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 :name, :command, :attrs
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!($1, '')}
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 |child|
43
- return if child.class.to_s != "Parser::AST::Node"
44
- return child.loc.expression.end_pos if child.type.to_s == 'block'
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", "a") { |f| f << command_template.result(binding) }
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("lib")
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) || !File.exist?("#{path_to_dir}/#{name_underscored}_command_handler.rb") || !File.exist?("#{path_to_dir}/commands.rb")
76
- raise NoAggregateFound
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( File.dirname(__FILE__), 'template_command.erb' )))
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( File.dirname(__FILE__), 'template_command_handler.erb' )))
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 :name, :event, :attrs
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", "a") { |f| f << event_template.result(binding) }
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!($1, '')}
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 |child|
46
- return if child.class.to_s != "Parser::AST::Node"
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("lib")
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
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'aggregate'
4
+ require_relative 'command'
5
+ require_relative 'project'
6
+ require_relative 'event'
@@ -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
@@ -1,5 +1,5 @@
1
1
  source "https://rubygems.org"
2
- ruby "2.5.1"
2
+ ruby "3.0.0"
3
3
 
4
4
  gem 'rake'
5
5
  # let's use the latest and greatest
@@ -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
@@ -1,4 +1,3 @@
1
- require_relative './generator/project'
2
- require_relative './generator/aggregate'
3
- require_relative './generator/command'
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 = "#{Sequent.configuration.migration_sql_files_directory}/#{table.table_name}_#{migration.version}.sql"
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
- unless table.table_name.end_with?("_#{migration.version}")
57
- table.table_name = "#{table.table_name}_#{migration.version}"
58
- table.reset_column_information
59
- fail MigrationError.new("Table #{table.table_name} does not exist. Did you run ViewSchema.migrate_online first?") unless table.table_exists?
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
- self.table_name == other.table_name && version == other.version
40
+ table_name == other.table_name && version == other.version
39
41
  end
40
42
 
41
43
  def hash
42
- self.table_name.hash + (version&.hash || 0)
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 '[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.'
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) to run after the migrations run. E.g. close resources
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, &after_migration_block)
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
- begin
52
- Class.const_get("Database::MigrateToVersion#{upgrade_to_version}")
53
- rescue NameError
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,6 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Sequent
2
4
  module Migrations
3
-
4
5
  end
5
6
  end
6
7