Merge pull request #45324 from adrianna-chang-shopify/ac-migration-strategy-objects

Introduce "Execution Strategy" object for Migrations
This commit is contained in:
Eileen M. Uchitelle 2022-06-24 07:37:03 -04:00 committed by GitHub
commit d51b171849
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 81 additions and 2 deletions

View File

@ -1,3 +1,11 @@
* Introduce strategy pattern for executing migrations.
By default, migrations will use a strategy object that delegates the method
to the connection adapter. Consumers can implement custom strategy objects
to change how their migrations run.
*Adrianna Chang*
* Add adapter option disallowing foreign keys
This adds a new option to be added to `database.yml` which enables skipping

View File

@ -302,6 +302,12 @@ module ActiveRecord
singleton_class.attr_accessor :timestamped_migrations
self.timestamped_migrations = true
##
# :singleton-method:
# Specify strategy to use for executing migrations.
singleton_class.attr_accessor :migration_strategy
self.migration_strategy = Migration::DefaultStrategy
##
# :singleton-method:
# Specify whether schema dump should happen at the end of the

View File

@ -548,6 +548,8 @@ module ActiveRecord
autoload :CommandRecorder, "active_record/migration/command_recorder"
autoload :Compatibility, "active_record/migration/compatibility"
autoload :JoinTable, "active_record/migration/join_table"
autoload :ExecutionStrategy, "active_record/migration/execution_strategy"
autoload :DefaultStrategy, "active_record/migration/default_strategy"
# This must be defined before the inherited hook, below
class Current < Migration # :nodoc:
@ -694,6 +696,10 @@ module ActiveRecord
@connection = nil
end
def execution_strategy
@execution_strategy ||= ActiveRecord.migration_strategy.new(self)
end
self.verbose = true
# instantiate the delegate object after initialize is defined
self.delegate = new
@ -881,6 +887,7 @@ module ActiveRecord
end
ensure
@connection = nil
@execution_strategy = nil
end
def write(text = "")
@ -935,8 +942,8 @@ module ActiveRecord
end
end
end
return super unless connection.respond_to?(method)
connection.send(method, *arguments, &block)
return super unless execution_strategy.respond_to?(method)
execution_strategy.send(method, *arguments, &block)
end
end
ruby2_keywords(:method_missing)

View File

@ -0,0 +1,23 @@
# frozen_string_literal: true
module ActiveRecord
class Migration
# The default strategy for executing migrations. Delegates method calls
# to the connection adapter.
class DefaultStrategy < ExecutionStrategy # :nodoc:
private
def method_missing(method, *arguments, &block)
connection.send(method, *arguments, &block)
end
ruby2_keywords(:method_missing)
def respond_to_missing?(method, *)
connection.respond_to?(method) || super
end
def connection
migration.connection
end
end
end
end

View File

@ -0,0 +1,19 @@
# frozen_string_literal: true
module ActiveRecord
class Migration
# ExecutionStrategy is used by the migration to respond to any method calls
# that the migration class does not implement directly. This is the base strategy.
# All strategies should inherit from this class.
#
# The ExecutionStrategy receives the current +migration+ when initialized.
class ExecutionStrategy # :nodoc:
def initialize(migration)
@migration = migration
end
private
attr_reader :migration
end
end
end

View File

@ -767,6 +767,22 @@ Specifies if an error should be raised if the order of a query is ignored during
Controls whether migrations are numbered with serial integers or with timestamps. The default is `true`, to use timestamps, which are preferred if there are multiple developers working on the same application.
#### `config.active_record.migration_strategy`
Controls the strategy class used to perform schema statement methods in a migration. The default class
delegates to the connection adapter. Custom strategies should inherit from `ActiveRecord::Migration::ExecutionStrategy`,
or may inherit from `DefaultStrategy`, which will preserve the default behaviour for methods that aren't implemented:
```ruby
class CustomMigrationStrategy < ActiveRecord::Migration::DefaultStrategy
def drop_table(*)
raise "Dropping tables is not supported!"
end
end
config.active_record.migration_strategy = CustomMigrationStrategy
```
#### `config.active_record.lock_optimistically`
Controls whether Active Record will use optimistic locking and is `true` by default.