sequent 4.0.0 → 4.3.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 +33 -26
  3. data/lib/notices.rb +2 -0
  4. data/lib/sequent/application_record.rb +2 -0
  5. data/lib/sequent/configuration.rb +24 -31
  6. data/lib/sequent/core/aggregate_repository.rb +48 -13
  7. data/lib/sequent/core/aggregate_root.rb +36 -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 +17 -9
  12. data/lib/sequent/core/command_record.rb +8 -3
  13. data/lib/sequent/core/command_service.rb +18 -18
  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 +16 -15
  18. data/lib/sequent/core/event_record.rb +7 -7
  19. data/lib/sequent/core/event_store.rb +89 -51
  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 +45 -28
  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 -5
  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 +53 -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 +30 -9
  51. data/lib/sequent/core/transactions/no_transactions.rb +2 -1
  52. data/lib/sequent/core/transactions/read_only_active_record_transaction_provider.rb +46 -0
  53. data/lib/sequent/core/transactions/transactions.rb +3 -0
  54. data/lib/sequent/core/value_object.rb +8 -10
  55. data/lib/sequent/core/workflow.rb +35 -5
  56. data/lib/sequent/generator/aggregate.rb +16 -10
  57. data/lib/sequent/generator/command.rb +26 -19
  58. data/lib/sequent/generator/event.rb +19 -17
  59. data/lib/sequent/generator/generator.rb +2 -0
  60. data/lib/sequent/generator/project.rb +9 -0
  61. data/lib/sequent/generator/template_project/Gemfile +1 -1
  62. data/lib/sequent/generator/template_project/ruby-version +1 -0
  63. data/lib/sequent/generator.rb +2 -0
  64. data/lib/sequent/migrations/executor.rb +22 -13
  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 +84 -45
  72. data/lib/sequent/rake/migration_tasks.rb +58 -22
  73. data/lib/sequent/rake/tasks.rb +5 -2
  74. data/lib/sequent/sequent.rb +2 -0
  75. data/lib/sequent/support/database.rb +30 -15
  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 +35 -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 +28 -20
  85. data/lib/sequent/util/printer.rb +6 -5
  86. data/lib/sequent/util/skip_if_already_processing.rb +3 -1
  87. data/lib/sequent/util/timer.rb +2 -0
  88. data/lib/sequent/util/util.rb +2 -0
  89. data/lib/sequent.rb +2 -0
  90. data/lib/version.rb +3 -1
  91. metadata +84 -67
@@ -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,15 +1,37 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Sequent
2
4
  module Core
3
5
  module Transactions
4
-
6
+ ##
7
+ # Always require a new transaction.
8
+ #
9
+ # Read:
10
+ # http://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html
11
+ #
12
+ # Without this change, there is a potential bug:
13
+ #
14
+ # ```ruby
15
+ # ActiveRecord::Base.transaction do
16
+ # Sequent.configuration.command_service.execute_commands command
17
+ # end
18
+ #
19
+ # on Command do
20
+ # do.some.things
21
+ # fail ActiveRecord::Rollback
22
+ # end
23
+ # ```
24
+ #
25
+ # In this example, you might be surprised to find that `do.some.things`
26
+ # does not get rolled back! This is because AR doesn't automatically make
27
+ # a "savepoint" for us when we call `.transaction` in a nested manner. In
28
+ # order to enable this behaviour, we have to call `.transaction` like
29
+ # this: `.transaction(requires_new: true)`.
30
+ #
5
31
  class ActiveRecordTransactionProvider
6
- def transactional
7
- Sequent::ApplicationRecord.transaction(requires_new: true) do
8
- yield
9
- end
10
- while(!after_commit_queue.empty?) do
11
- after_commit_queue.pop.call
12
- end
32
+ def transactional(&block)
33
+ Sequent::ApplicationRecord.transaction(requires_new: true, &block)
34
+ after_commit_queue.pop.call until after_commit_queue.empty?
13
35
  ensure
14
36
  clear_after_commit_queue
15
37
  end
@@ -28,7 +50,6 @@ module Sequent
28
50
  after_commit_queue.clear
29
51
  end
30
52
  end
31
-
32
53
  end
33
54
  end
34
55
  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
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sequent
4
+ module Core
5
+ module Transactions
6
+ class ReadOnlyActiveRecordTransactionProvider
7
+ def initialize(transaction_provider)
8
+ @transaction_provider = transaction_provider
9
+ end
10
+
11
+ def transactional(&block)
12
+ register_call
13
+ @transaction_provider.transactional do
14
+ Sequent::ApplicationRecord.connection.execute('SET TRANSACTION READ ONLY')
15
+ block.call
16
+ rescue ActiveRecord::StatementInvalid
17
+ @skip_set_transaction = true
18
+ raise
19
+ ensure
20
+ deregister_call
21
+ reset_stack_size if stack_size == 0
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def stack_size
28
+ Thread.current[:read_only_active_record_transaction_provider_calls]
29
+ end
30
+
31
+ def register_call
32
+ Thread.current[:read_only_active_record_transaction_provider_calls] ||= 0
33
+ Thread.current[:read_only_active_record_transaction_provider_calls] += 1
34
+ end
35
+
36
+ def deregister_call
37
+ Thread.current[:read_only_active_record_transaction_provider_calls] -= 1
38
+ end
39
+
40
+ def reset_stack_size
41
+ Thread.current[:read_only_active_record_transaction_provider_calls] = nil
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -1,2 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'active_record_transaction_provider'
2
4
  require_relative 'no_transactions'
5
+ require_relative 'read_only_active_record_transaction_provider'
@@ -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
 
@@ -6,12 +8,17 @@ module Sequent
6
8
  class Workflow
7
9
  include Helpers::MessageHandler
8
10
 
11
+ def self.inherited(subclass)
12
+ super
13
+ Workflows << subclass
14
+ end
15
+
9
16
  def self.on(*message_classes, &block)
10
17
  decorated_block = ->(event) do
11
18
  begin
12
19
  old_event = CurrentEvent.current
13
20
  CurrentEvent.current = event
14
- self.instance_exec(event, &block)
21
+ instance_exec(event, &block)
15
22
  ensure
16
23
  CurrentEvent.current = old_event
17
24
  end
@@ -31,12 +38,35 @@ module Sequent
31
38
  # jobs processor is not using the same database connection
32
39
  # to enqueue jobs.
33
40
  def after_commit(ignore_errors: false, &block)
34
- Sequent.configuration.transaction_provider.after_commit &block
35
- rescue StandardError => error
41
+ Sequent.configuration.transaction_provider.after_commit(&block)
42
+ rescue StandardError => e
36
43
  if ignore_errors
37
- Sequent.logger.warn("An exception was raised in an after_commit hook: #{error}, #{error.inspect}")
44
+ Sequent.logger.warn("An exception was raised in an after_commit hook: #{e}, #{e.inspect}")
38
45
  else
39
- raise error
46
+ raise e
47
+ end
48
+ end
49
+ end
50
+
51
+ #
52
+ # Utility class containing all subclasses of Workflow
53
+ #
54
+ class Workflows
55
+ class << self
56
+ def workflows
57
+ @workflows ||= []
58
+ end
59
+
60
+ def all
61
+ workflows
62
+ end
63
+
64
+ def <<(workflow)
65
+ workflows << workflow
66
+ end
67
+
68
+ def find(workflow_name)
69
+ workflows.find { |c| c.name == workflow_name }
40
70
  end
41
71
  end
42
72
  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
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'aggregate'
2
4
  require_relative 'command'
3
5
  require_relative 'project'
@@ -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'
@@ -12,6 +14,7 @@ module Sequent
12
14
  def execute
13
15
  make_directory
14
16
  copy_files
17
+ rename_ruby_version
15
18
  rename_app_file
16
19
  replace_app_name
17
20
  end
@@ -26,6 +29,12 @@ module Sequent
26
29
  FileUtils.copy_entry(File.expand_path('template_project', __dir__), path)
27
30
  end
28
31
 
32
+ # Hidden files are by default excluded from gem build.
33
+ # Therefor we need to rename the ruby-version to .ruby-version.
34
+ def rename_ruby_version
35
+ FileUtils.mv("#{path}/ruby-version", "#{path}/.ruby-version")
36
+ end
37
+
29
38
  def rename_app_file
30
39
  FileUtils.mv("#{path}/my_app.rb", "#{path}/#{name_underscored}.rb")
31
40
  end
@@ -1,5 +1,5 @@
1
1
  source "https://rubygems.org"
2
- ruby "2.6.5"
2
+ ruby "3.0.0"
3
3
 
4
4
  gem 'rake'
5
5
  # let's use the latest and greatest
@@ -1 +1,3 @@
1
+ # frozen_string_literal: true
2
+
1
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`.
@@ -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 = "#{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))
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 = "#{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
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
- 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?
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