departure 8.0.0 → 8.2.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.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +41 -2
  3. data/.pryrc +6 -6
  4. data/.standard.yml +9 -0
  5. data/AGENTS.md +77 -0
  6. data/Appraisals +11 -8
  7. data/CHANGELOG.md +16 -0
  8. data/Gemfile +8 -9
  9. data/Gemfile.lock +25 -11
  10. data/README.md +26 -4
  11. data/RELEASING.md +5 -4
  12. data/Rakefile +10 -10
  13. data/configuration.rb +3 -3
  14. data/departure.gemspec +26 -29
  15. data/gemfiles/rails_7_2.gemfile +2 -2
  16. data/gemfiles/rails_7_2.gemfile.lock +28 -11
  17. data/gemfiles/rails_8_0.gemfile +2 -2
  18. data/gemfiles/rails_8_0.gemfile.lock +28 -11
  19. data/gemfiles/rails_8_1.gemfile +3 -3
  20. data/gemfiles/rails_8_1.gemfile.lock +27 -11
  21. data/lib/active_record/connection_adapters/departure_adapter_behavior.rb +88 -0
  22. data/lib/active_record/connection_adapters/for_alter.rb +4 -10
  23. data/lib/active_record/connection_adapters/patch_connection_handling.rb +7 -6
  24. data/lib/active_record/connection_adapters/rails_7_2_departure_adapter.rb +17 -58
  25. data/lib/active_record/connection_adapters/rails_7_2_trilogy_adapter.rb +53 -0
  26. data/lib/active_record/connection_adapters/rails_8_0_departure_adapter.rb +26 -66
  27. data/lib/active_record/connection_adapters/rails_8_0_trilogy_adapter.rb +21 -0
  28. data/lib/active_record/connection_adapters/rails_8_1_mysql2_adapter.rb +23 -0
  29. data/lib/active_record/connection_adapters/rails_8_1_trilogy_adapter.rb +21 -0
  30. data/lib/departure/alter_argument.rb +6 -6
  31. data/lib/departure/cli_generator.rb +12 -12
  32. data/lib/departure/command.rb +1 -1
  33. data/lib/departure/configuration.rb +3 -3
  34. data/lib/departure/connection_details.rb +7 -7
  35. data/lib/departure/db_client.rb +5 -5
  36. data/lib/departure/dsn.rb +2 -2
  37. data/lib/departure/errors.rb +2 -2
  38. data/lib/departure/log_sanitizers/password_sanitizer.rb +1 -1
  39. data/lib/departure/logger.rb +2 -2
  40. data/lib/departure/migration.rb +40 -10
  41. data/lib/departure/option.rb +4 -4
  42. data/lib/departure/rails_adapter.rb +145 -85
  43. data/lib/departure/rails_patches/active_record_migrator_with_advisory_lock_patch.rb +2 -2
  44. data/lib/departure/railtie.rb +7 -5
  45. data/lib/departure/runner.rb +3 -3
  46. data/lib/departure/user_options.rb +1 -1
  47. data/lib/departure/version.rb +1 -1
  48. data/lib/departure.rb +21 -23
  49. data/lib/lhm/adapter.rb +12 -12
  50. data/lib/lhm/column_with_sql.rb +8 -8
  51. data/lib/lhm.rb +1 -1
  52. data/test_database.rb +10 -10
  53. metadata +12 -4
  54. data/.rubocop.yml +0 -66
  55. data/.rubocop_todo.yml +0 -238
  56. data/lib/active_record/connection_adapters/rails_8_1_departure_adapter.rb +0 -83
@@ -1,16 +1,18 @@
1
- require 'active_record/connection_adapters/abstract_mysql_adapter'
2
- require 'active_record/connection_adapters/statement_pool'
3
- require 'active_record/connection_adapters/mysql2_adapter'
4
- require 'active_record/connection_adapters/mysql2/database_statements'
5
- require 'active_record/connection_adapters/patch_connection_handling'
6
- require 'active_support/core_ext/string/filters'
7
- require 'departure'
8
- require 'forwardable'
1
+ require "active_record/connection_adapters/abstract_mysql_adapter"
2
+ require "active_record/connection_adapters/statement_pool"
3
+ require "active_record/connection_adapters/mysql2_adapter"
4
+ require "active_record/connection_adapters/mysql2/database_statements"
5
+ require "active_record/connection_adapters/patch_connection_handling"
6
+ require "active_support/core_ext/string/filters"
7
+ require "departure"
8
+ require "forwardable"
9
+ require "active_record/connection_adapters/departure_adapter_behavior"
9
10
 
10
11
  module ActiveRecord
11
12
  module ConnectionAdapters
12
13
  class Rails80DepartureAdapter < AbstractMysqlAdapter
13
14
  include ActiveRecord::ConnectionAdapters::Mysql2::DatabaseStatements
15
+
14
16
  TYPE_MAP = Type::TypeMap.new.tap { |m| initialize_type_map(m) } if defined?(initialize_type_map)
15
17
 
16
18
  class Column < ActiveRecord::ConnectionAdapters::MySQL::Column
@@ -19,24 +21,11 @@ module ActiveRecord
19
21
  end
20
22
  end
21
23
 
22
- class SchemaCreation < ActiveRecord::ConnectionAdapters::MySQL::SchemaCreation
23
- def visit_DropForeignKey(name) # rubocop:disable Naming/MethodName
24
- fk_name =
25
- if name =~ /^__(.+)/
26
- Regexp.last_match(1)
27
- else
28
- "_#{name}"
29
- end
30
-
31
- "DROP FOREIGN KEY #{fk_name}"
32
- end
33
- end
34
-
35
24
  extend Forwardable
36
25
 
37
- include ForAlterStatements unless method_defined?(:change_column_for_alter)
26
+ include DepartureAdapterBehavior::SchemaStatements
38
27
 
39
- ADAPTER_NAME = 'Percona'.freeze
28
+ ADAPTER_NAME = "Percona".freeze
40
29
 
41
30
  def self.new_client(config)
42
31
  connection_details = Departure::ConnectionDetails.new(config)
@@ -47,7 +36,7 @@ module ActiveRecord
47
36
  percona_logger = Departure::LoggerFactory.build(sanitizers: sanitizers, verbose: verbose)
48
37
  cli_generator = Departure::CliGenerator.new(connection_details)
49
38
 
50
- mysql_adapter = ActiveRecord::ConnectionAdapters::Mysql2Adapter.new(config.merge(adapter: 'mysql2'))
39
+ mysql_adapter = ActiveRecord::ConnectionAdapters::Mysql2Adapter.new(config.merge(adapter: "mysql2"))
51
40
 
52
41
  Departure::Runner.new(
53
42
  percona_logger,
@@ -62,7 +51,7 @@ module ActiveRecord
62
51
  @config[:flags] ||= 0
63
52
 
64
53
  if @config[:flags].is_a? Array
65
- @config[:flags].push 'FOUND_ROWS'
54
+ @config[:flags].push "FOUND_ROWS"
66
55
  else
67
56
  @config[:flags] |= ::Mysql2::Client::FOUND_ROWS
68
57
  end
@@ -81,18 +70,18 @@ module ActiveRecord
81
70
 
82
71
  @raw_connection.affected_rows
83
72
  end
84
- alias exec_update exec_delete
73
+ alias_method :exec_update, :exec_delete
85
74
 
86
75
  def exec_insert(sql, name, binds, pky = nil, sequence_name = nil, returning: nil) # rubocop:disable Lint/UnusedMethodArgument, Metrics/ParameterLists
87
76
  execute(to_sql(sql, binds), name)
88
77
  end
89
78
 
90
- def internal_exec_query(sql, name = 'SQL', _binds = [], **_kwargs) # :nodoc:
79
+ def internal_exec_query(sql, name = "SQL", _binds = [], **_kwargs) # :nodoc:
91
80
  result = execute(sql, name)
92
81
  fields = result.fields if defined?(result.fields)
93
82
  ActiveRecord::Result.new(fields || [], result.to_a)
94
83
  end
95
- alias exec_query internal_exec_query
84
+ alias_method :exec_query, :internal_exec_query
96
85
 
97
86
  # Executes a SELECT query and returns an array of rows. Each row is an
98
87
  # array of field values.
@@ -116,35 +105,6 @@ module ActiveRecord
116
105
  Column.new(...)
117
106
  end
118
107
 
119
- # Adds a new index to the table
120
- #
121
- # @param table_name [String, Symbol]
122
- # @param column_name [String, Symbol]
123
- # @param options [Hash] optional
124
- def add_index(table_name, column_name, options = {})
125
- index_definition, = add_index_options(table_name, column_name, **options)
126
- execute <<-SQL.squish
127
- ALTER TABLE #{quote_table_name(index_definition.table)}
128
- ADD #{schema_creation.accept(index_definition)}
129
- SQL
130
- end
131
-
132
- # Remove the given index from the table.
133
- #
134
- # @param table_name [String, Symbol]
135
- # @param options [Hash] optional
136
- def remove_index(table_name, column_name = nil, **options)
137
- return if options[:if_exists] && !index_exists?(table_name, column_name, **options)
138
-
139
- index_name = index_name_for_remove(table_name, column_name, options)
140
-
141
- execute "ALTER TABLE #{quote_table_name(table_name)} DROP INDEX #{quote_column_name(index_name)}"
142
- end
143
-
144
- def schema_creation
145
- SchemaCreation.new(self)
146
- end
147
-
148
108
  def change_table(table_name, _options = {})
149
109
  recorder = ActiveRecord::Migration::CommandRecorder.new(self)
150
110
  yield update_table_definition(table_name, recorder)
@@ -183,21 +143,21 @@ module ActiveRecord
183
143
 
184
144
  # rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity, Metrics/ParameterLists
185
145
  def raw_execute(sql, name = nil, binds = [], prepare: false, async: false, allow_retry: false,
186
- materialize_transactions: true, batch: false)
146
+ materialize_transactions: true, batch: false)
187
147
  type_casted_binds = type_casted_binds(binds)
188
148
  log(sql, name, binds, type_casted_binds, async: async) do |notification_payload|
189
149
  with_raw_connection(allow_retry: allow_retry, materialize_transactions: materialize_transactions) do |conn|
190
150
  perform_query(conn, sql, binds, type_casted_binds, prepare: prepare,
191
- notification_payload: notification_payload, batch: batch)
151
+ notification_payload: notification_payload, batch: batch)
192
152
  end
193
153
  end
194
154
  end
195
155
 
196
156
  def perform_query(raw_connection, sql, binds, type_casted_binds, prepare:, notification_payload:, batch: false)
197
157
  reset_multi_statement = if batch && !multi_statements_enabled?
198
- raw_connection.set_server_option(::Mysql2::Client::OPTION_MULTI_STATEMENTS_ON)
199
- true
200
- end
158
+ raw_connection.set_server_option(::Mysql2::Client::OPTION_MULTI_STATEMENTS_ON)
159
+ true
160
+ end
201
161
 
202
162
  # Make sure we carry over any changes to ActiveRecord.default_timezone that have been
203
163
  # made since we established the connection
@@ -216,10 +176,10 @@ module ActiveRecord
216
176
  # THIS IS THE CORE CHANGES 1 related to size
217
177
  # We will sometimes have a process exit code instead of a result from executing
218
178
  @affected_rows_before_warnings = if result.is_a? Process::Status
219
- result.try(:size) || 0
220
- else
221
- result.try(:size) || raw_connection.affected_rows
222
- end
179
+ result.try(:size) || 0
180
+ else
181
+ result.try(:size) || raw_connection.affected_rows
182
+ end
223
183
  end
224
184
  elsif prepare
225
185
 
@@ -0,0 +1,21 @@
1
+ require "active_record/connection_adapters/abstract_mysql_adapter"
2
+ require "active_record/connection_adapters/trilogy_adapter"
3
+ require "active_record/connection_adapters/patch_connection_handling"
4
+ require "departure"
5
+ require "active_record/connection_adapters/departure_adapter_behavior"
6
+
7
+ module ActiveRecord
8
+ module ConnectionAdapters
9
+ class Rails80TrilogyAdapter < ActiveRecord::ConnectionAdapters::TrilogyAdapter
10
+ class Column < ActiveRecord::ConnectionAdapters::MySQL::Column
11
+ def adapter
12
+ Rails80TrilogyAdapter
13
+ end
14
+ end
15
+
16
+ ADAPTER_NAME = "Percona".freeze
17
+
18
+ include DepartureAdapterBehavior::Rails8
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,23 @@
1
+ require "active_record/connection_adapters/abstract_mysql_adapter"
2
+ require "active_record/connection_adapters/mysql2_adapter"
3
+ require "active_record/connection_adapters/patch_connection_handling"
4
+ require "departure"
5
+ require "active_record/connection_adapters/departure_adapter_behavior"
6
+
7
+ module ActiveRecord
8
+ module ConnectionAdapters
9
+ class Rails81Mysql2Adapter < ActiveRecord::ConnectionAdapters::Mysql2Adapter
10
+ TYPE_MAP = Type::TypeMap.new.tap { |m| initialize_type_map(m) } if defined?(initialize_type_map)
11
+
12
+ class Column < ActiveRecord::ConnectionAdapters::MySQL::Column
13
+ def adapter
14
+ Rails81Mysql2Adapter
15
+ end
16
+ end
17
+
18
+ ADAPTER_NAME = "Percona".freeze
19
+
20
+ include DepartureAdapterBehavior::Rails8
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,21 @@
1
+ require "active_record/connection_adapters/abstract_mysql_adapter"
2
+ require "active_record/connection_adapters/trilogy_adapter"
3
+ require "active_record/connection_adapters/patch_connection_handling"
4
+ require "departure"
5
+ require "active_record/connection_adapters/departure_adapter_behavior"
6
+
7
+ module ActiveRecord
8
+ module ConnectionAdapters
9
+ class Rails81TrilogyAdapter < ActiveRecord::ConnectionAdapters::TrilogyAdapter
10
+ class Column < ActiveRecord::ConnectionAdapters::MySQL::Column
11
+ def adapter
12
+ Rails81TrilogyAdapter
13
+ end
14
+ end
15
+
16
+ ADAPTER_NAME = "Percona".freeze
17
+
18
+ include DepartureAdapterBehavior::Rails8
19
+ end
20
+ end
21
+ end
@@ -4,7 +4,7 @@ module Departure
4
4
  # Represents the '--alter' argument of Percona's pt-online-schema-change
5
5
  # See https://www.percona.com/doc/percona-toolkit/2.0/pt-online-schema-change.html
6
6
  class AlterArgument
7
- ALTER_TABLE_REGEX = /\AALTER TABLE [^\s]*[\n]* /
7
+ ALTER_TABLE_REGEX = /\AALTER TABLE [^\s]*\n* /
8
8
 
9
9
  attr_reader :table_name
10
10
 
@@ -21,8 +21,8 @@ module Departure
21
21
  #
22
22
  # Removes the grave marks, if they are there, so we can get the table_name
23
23
  @table_name = String(match)
24
- .split(' ')[2]
25
- .delete('`')
24
+ .split(" ")[2]
25
+ .delete("`")
26
26
  end
27
27
 
28
28
  # Returns the '--alter' pt-online-schema-change argument as a string. See
@@ -40,9 +40,9 @@ module Departure
40
40
  # @return [String]
41
41
  def parsed_statement
42
42
  @parsed_statement ||= statement
43
- .gsub(ALTER_TABLE_REGEX, '')
44
- .gsub('`', '\\\`')
45
- .gsub(/\\n/, '')
43
+ .gsub(ALTER_TABLE_REGEX, "")
44
+ .gsub("`", '\\\`')
45
+ .gsub("\\n", "")
46
46
  .gsub('"', '\\\"')
47
47
  end
48
48
  end
@@ -1,24 +1,24 @@
1
- require 'departure/dsn'
2
- require 'departure/option'
3
- require 'departure/alter_argument'
4
- require 'departure/connection_details'
5
- require 'departure/user_options'
1
+ require "departure/dsn"
2
+ require "departure/option"
3
+ require "departure/alter_argument"
4
+ require "departure/connection_details"
5
+ require "departure/user_options"
6
6
 
7
7
  module Departure
8
8
  # Generates the equivalent Percona's pt-online-schema-change command to the
9
9
  # given SQL statement
10
10
  #
11
11
  # --no-check-alter is used to allow running CHANGE COLUMN statements. For more details, check:
12
- # www.percona.com/doc/percona-toolkit/2.2/pt-online-schema-change.html#cmdoption-pt-online-schema-change--[no]check-alter # rubocop:disable Metrics/LineLength
12
+ # www.percona.com/doc/percona-toolkit/2.2/pt-online-schema-change.html#cmdoption-pt-online-schema-change--[no]check-alter
13
13
  #
14
14
  class CliGenerator
15
- COMMAND_NAME = 'pt-online-schema-change'.freeze
15
+ COMMAND_NAME = "pt-online-schema-change".freeze
16
16
  DEFAULT_OPTIONS = Set.new(
17
17
  [
18
- Option.new('execute'),
19
- Option.new('statistics'),
20
- Option.new('alter-foreign-keys-method', 'auto'),
21
- Option.new('no-check-alter')
18
+ Option.new("execute"),
19
+ Option.new("statistics"),
20
+ Option.new("alter-foreign-keys-method", "auto"),
21
+ Option.new("no-check-alter")
22
22
  ]
23
23
  ).freeze
24
24
 
@@ -78,7 +78,7 @@ module Departure
78
78
  env_variable_options = UserOptions.new
79
79
  global_configuration_options = UserOptions.new(Departure.configuration.global_percona_args)
80
80
  options = env_variable_options.merge(global_configuration_options).merge(DEFAULT_OPTIONS)
81
- options.to_a.join(' ')
81
+ options.to_a.join(" ")
82
82
  end
83
83
  end
84
84
  end
@@ -86,7 +86,7 @@ module Departure
86
86
  if redirect_stderr
87
87
  File.read(error_log_path)
88
88
  else
89
- ''
89
+ ""
90
90
  end
91
91
  end
92
92
 
@@ -1,11 +1,11 @@
1
1
  module Departure
2
2
  class Configuration
3
3
  attr_accessor :tmp_path, :global_percona_args, :enabled_by_default, :redirect_stderr,
4
- :disable_rails_advisory_lock_patch
4
+ :disable_rails_advisory_lock_patch
5
5
 
6
6
  def initialize
7
- @tmp_path = '.'.freeze
8
- @error_log_filename = 'departure_error.log'.freeze
7
+ @tmp_path = ".".freeze
8
+ @error_log_filename = "departure_error.log".freeze
9
9
  @global_percona_args = nil
10
10
  @enabled_by_default = true
11
11
  @redirect_stderr = true
@@ -1,4 +1,4 @@
1
- require 'shellwords'
1
+ require "shellwords"
2
2
  module Departure
3
3
  # Holds the parameters of the DB connection and formats them to string
4
4
  class ConnectionDetails
@@ -26,7 +26,7 @@ module Departure
26
26
  #
27
27
  # @return [String]
28
28
  def database
29
- ENV.fetch('PERCONA_DB_NAME', connection_data[:database])
29
+ ENV.fetch("PERCONA_DB_NAME", connection_data[:database])
30
30
  end
31
31
 
32
32
  # Returns the password fragment of the details string if a password is passed
@@ -36,7 +36,7 @@ module Departure
36
36
  if password.present?
37
37
  %(--password #{Shellwords.escape(password)} )
38
38
  else
39
- ''
39
+ ""
40
40
  end
41
41
  end
42
42
 
@@ -77,7 +77,7 @@ module Departure
77
77
  #
78
78
  # @return [String]
79
79
  def host
80
- ENV.fetch('PERCONA_DB_HOST', connection_data[:host]) || 'localhost'
80
+ ENV.fetch("PERCONA_DB_HOST", connection_data[:host]) || "localhost"
81
81
  end
82
82
 
83
83
  # Returns the database user. If PERCONA_DB_USER is passed its value will be
@@ -85,7 +85,7 @@ module Departure
85
85
  #
86
86
  # @return [String]
87
87
  def user
88
- ENV.fetch('PERCONA_DB_USER', connection_data[:username])
88
+ ENV.fetch("PERCONA_DB_USER", connection_data[:username])
89
89
  end
90
90
 
91
91
  # Returns the database user's password. If PERCONA_DB_PASSWORD is passed its
@@ -93,7 +93,7 @@ module Departure
93
93
  #
94
94
  # @return [String]
95
95
  def password
96
- ENV.fetch('PERCONA_DB_PASSWORD', connection_data[:password])
96
+ ENV.fetch("PERCONA_DB_PASSWORD", connection_data[:password])
97
97
  end
98
98
 
99
99
  # Returns the database socket path. If PERCONA_DB_SOCKET is passed its value
@@ -101,7 +101,7 @@ module Departure
101
101
  #
102
102
  # @return [String]
103
103
  def socket
104
- ENV.fetch('PERCONA_DB_SOCKET', connection_data[:socket])
104
+ ENV.fetch("PERCONA_DB_SOCKET", connection_data[:socket])
105
105
  end
106
106
 
107
107
  # Returns the database's port.
@@ -1,6 +1,6 @@
1
- require 'open3'
1
+ require "open3"
2
2
 
3
- require 'forwardable'
3
+ require "forwardable"
4
4
 
5
5
  module Departure
6
6
  # It executes pt-online-schema-change commands in a new process and gets its
@@ -40,9 +40,9 @@ module Departure
40
40
  command_line = @cli_generator.parse_statement(raw_sql_string)
41
41
 
42
42
  Command.new(command_line,
43
- Departure.configuration.error_log_path,
44
- @logger,
45
- Departure.configuration.redirect_stderr).run
43
+ Departure.configuration.error_log_path,
44
+ @logger,
45
+ Departure.configuration.redirect_stderr).run
46
46
  end
47
47
 
48
48
  def alter_statement?(raw_sql_string)
data/lib/departure/dsn.rb CHANGED
@@ -9,13 +9,13 @@ module Departure
9
9
  def initialize(database, table_name)
10
10
  @database = database
11
11
  @table_name = table_name
12
- @suffix = ENV.fetch('PERCONA_DSN_SUFFIX', nil)
12
+ @suffix = ENV.fetch("PERCONA_DSN_SUFFIX", nil)
13
13
  end
14
14
 
15
15
  # Returns the pt-online-schema-change DSN string. See
16
16
  # https://www.percona.com/doc/percona-toolkit/2.0/pt-online-schema-change.html#dsn-options
17
17
  def to_s
18
- "D=#{database},t=#{table_name}#{suffix.nil? ? nil : ',' + suffix}"
18
+ "D=#{database},t=#{table_name}#{"," + suffix unless suffix.nil?}"
19
19
  end
20
20
 
21
21
  private
@@ -5,7 +5,7 @@ module Departure
5
5
  # status.
6
6
  class NoStatusError < Error
7
7
  def message
8
- 'Status could not be retrieved'.freeze
8
+ "Status could not be retrieved".freeze
9
9
  end
10
10
  end
11
11
 
@@ -29,7 +29,7 @@ module Departure
29
29
 
30
30
  class CommandNotFoundError < Error
31
31
  def message
32
- 'Please install pt-online-schema-change. Check: https://www.percona.com/doc/percona-toolkit for further details'
32
+ "Please install pt-online-schema-change. Check: https://www.percona.com/doc/percona-toolkit for further details"
33
33
  end
34
34
  end
35
35
 
@@ -1,7 +1,7 @@
1
1
  module Departure
2
2
  module LogSanitizers
3
3
  class PasswordSanitizer
4
- PASSWORD_REPLACEMENT = '[filtered_password]'.freeze
4
+ PASSWORD_REPLACEMENT = "[filtered_password]".freeze
5
5
 
6
6
  delegate :password_argument, to: :connection_details
7
7
 
@@ -14,13 +14,13 @@ module Departure
14
14
  # @param message [String]
15
15
  # @param subitem [Boolean] whether to show message as a nested log item
16
16
  def say(message, subitem = false)
17
- write "#{subitem ? ' ->' : '--'} #{message}"
17
+ write "#{subitem ? " ->" : "--"} #{message}"
18
18
  end
19
19
 
20
20
  # Outputs the text through the stdout adding a new line at the end
21
21
  #
22
22
  # @param text [String]
23
- def write(text = '')
23
+ def write(text = "")
24
24
  puts(sanitize(text))
25
25
  end
26
26
 
@@ -8,6 +8,8 @@ module Departure
8
8
  module Migration
9
9
  extend ActiveSupport::Concern
10
10
 
11
+ DEPARTURE_ADAPTERS = %w[percona percona_trilogy].freeze
12
+
11
13
  included do
12
14
  # Holds the name of the adapter that was configured by the app.
13
15
  mattr_accessor :original_adapter
@@ -53,11 +55,13 @@ module Departure
53
55
  # Migrate with or without Departure based on uses_departure class
54
56
  # attribute.
55
57
  def migrate(direction)
56
- if uses_departure?
57
- departure_migrate(direction)
58
- else
59
- reconnect_without_percona
60
- active_record_migrate(direction)
58
+ with_restored_connection_specification_name do
59
+ if uses_departure?
60
+ departure_migrate(direction)
61
+ else
62
+ reconnect_without_percona
63
+ active_record_migrate(direction)
64
+ end
61
65
  end
62
66
  end
63
67
 
@@ -73,15 +77,29 @@ module Departure
73
77
  # Make all connections in the connection pool to use PerconaAdapter
74
78
  # instead of the current adapter.
75
79
  def reconnect_with_percona
76
- return if connection_config[:adapter] == 'percona'
77
- Departure::ConnectionBase.establish_connection(connection_config.merge(adapter: 'percona'))
80
+ config = connection_config
81
+ return if departure_adapter_config?(config)
82
+
83
+ departure_adapter = Departure::RailsAdapter.for_current(db_connection_adapter: config[:adapter])
84
+ Departure::ConnectionBase.establish_connection(
85
+ config.merge(
86
+ adapter: departure_adapter.departure_adapter_name,
87
+ departure_original_adapter: config[:adapter]
88
+ )
89
+ )
78
90
  end
79
91
 
80
92
  # Reconnect without percona adapter when Departure is disabled but was
81
93
  # enabled in a previous migration.
82
94
  def reconnect_without_percona
83
- return unless connection_config[:adapter] == 'percona'
84
- Departure::OriginalAdapterConnection.establish_connection(connection_config.merge(adapter: original_adapter))
95
+ config = connection_config
96
+ return unless departure_adapter_config?(config)
97
+
98
+ Departure::OriginalAdapterConnection.establish_connection(
99
+ config
100
+ .except(:departure_original_adapter)
101
+ .merge(adapter: config[:departure_original_adapter] || original_adapter)
102
+ )
85
103
  end
86
104
 
87
105
  private
@@ -89,12 +107,24 @@ module Departure
89
107
  # Capture the type of the adapter configured by the app if not already set.
90
108
  def connection_config
91
109
  configuration_hash.tap do |config|
92
- self.class.original_adapter ||= config[:adapter]
110
+ self.class.original_adapter ||= config[:departure_original_adapter] || config[:adapter]
93
111
  end
94
112
  end
95
113
 
114
+ private def departure_adapter_config?(config)
115
+ DEPARTURE_ADAPTERS.include?(config[:adapter])
116
+ end
117
+
96
118
  private def configuration_hash
97
119
  ActiveRecord::Base.connection_db_config.configuration_hash
98
120
  end
121
+
122
+ private def with_restored_connection_specification_name
123
+ connection_specification_name = ActiveRecord::Base.connection_specification_name
124
+
125
+ yield
126
+ ensure
127
+ ActiveRecord::Base.connection_specification_name = connection_specification_name
128
+ end
99
129
  end
100
130
  end
@@ -27,7 +27,7 @@ module Departure
27
27
  def ==(other)
28
28
  name == other.name
29
29
  end
30
- alias eql? ==
30
+ alias_method :eql?, :==
31
31
 
32
32
  # Returns the option's hash
33
33
  #
@@ -50,7 +50,7 @@ module Departure
50
50
  #
51
51
  # @return [String]
52
52
  def normalize_option(name)
53
- if name.start_with?('-')
53
+ if name.start_with?("-")
54
54
  name
55
55
  elsif name.length == 1
56
56
  "-#{name}"
@@ -64,8 +64,8 @@ module Departure
64
64
  # @return [String]
65
65
  def value_as_string
66
66
  if value.nil?
67
- ''
68
- elsif value.include?('=')
67
+ ""
68
+ elsif value.include?("=")
69
69
  " #{value}"
70
70
  else
71
71
  "=#{value}"