1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Handle up/down for multiple databases

This change adds the ability to run up/down for a database in a multi-db
environment.

If you have an app with a primary and animals database the following
tasks will be generated:

```
VERSION=123 rake db:migrate:up:primary
VERSION=123 rake db:migrate:up:primary

VERSION=123 rake db:migrate:down:primary
VERSION=123 rake db:migrate:up:animals
```

I didn't generate descriptions with them since we don't generate a
description for a single database application.

In addition to this change I've made it so if your application has
multiple databases Rails will raise if you try to run `up` or `down`
without a namespace. This is because we don't know which DB you want to
run `up` or `down` against unless the app tells us, so it's safer to
just block it and recommend using namespaced versions of up/down
respectively.

The output for the raise looks like:

```
You're using a multiple database application. To use `db:migrate:down`
you must run the namespaced task with a VERSION. Available tasks are
db:migrate:down:primary and db:migrate:down:animals.
```
This commit is contained in:
eileencodes 2019-04-08 15:44:51 -04:00
parent 1a5381ff0c
commit f9244c6585
3 changed files with 115 additions and 1 deletions

View file

@ -128,6 +128,8 @@ db_namespace = namespace :db do
# desc 'Runs the "up" for a given migration VERSION.'
task up: :load_config do
ActiveRecord::Tasks::DatabaseTasks.raise_for_multi_db(command: "db:migrate:up")
raise "VERSION is required" if !ENV["VERSION"] || ENV["VERSION"].empty?
ActiveRecord::Tasks::DatabaseTasks.check_target_version
@ -139,8 +141,30 @@ db_namespace = namespace :db do
db_namespace["_dump"].invoke
end
namespace :up do
ActiveRecord::Tasks::DatabaseTasks.for_each do |spec_name|
desc "up for #{spec_name}"
task spec_name => :load_config do
raise "VERSION is required" if !ENV["VERSION"] || ENV["VERSION"].empty?
db_config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, spec_name: spec_name)
ActiveRecord::Base.establish_connection(db_config.config)
ActiveRecord::Tasks::DatabaseTasks.check_target_version
ActiveRecord::Base.connection.migration_context.run(
:up,
ActiveRecord::Tasks::DatabaseTasks.target_version
)
db_namespace["_dump"].invoke
end
end
end
# desc 'Runs the "down" for a given migration VERSION.'
task down: :load_config do
ActiveRecord::Tasks::DatabaseTasks.raise_for_multi_db(command: "db:migrate:down")
raise "VERSION is required - To go down one migration, use db:rollback" if !ENV["VERSION"] || ENV["VERSION"].empty?
ActiveRecord::Tasks::DatabaseTasks.check_target_version
@ -152,6 +176,25 @@ db_namespace = namespace :db do
db_namespace["_dump"].invoke
end
namespace :down do
ActiveRecord::Tasks::DatabaseTasks.for_each do |spec_name|
task spec_name => :load_config do
raise "VERSION is required" if !ENV["VERSION"] || ENV["VERSION"].empty?
db_config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, spec_name: spec_name)
ActiveRecord::Base.establish_connection(db_config.config)
ActiveRecord::Tasks::DatabaseTasks.check_target_version
ActiveRecord::Base.connection.migration_context.run(
:down,
ActiveRecord::Tasks::DatabaseTasks.target_version
)
db_namespace["_dump"].invoke
end
end
end
desc "Display status of migrations"
task status: :load_config do
ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env).each do |db_config|

View file

@ -155,6 +155,20 @@ module ActiveRecord
end
end
def raise_for_multi_db(environment = env, command:)
db_configs = ActiveRecord::Base.configurations.configs_for(env_name: environment)
if db_configs.count > 1
dbs_list = []
db_configs.each do |db|
dbs_list << "#{command}:#{db.spec_name}"
end
raise "You're using a multiple database application. To use `#{command}` you must run the namespaced task with a VERSION. Available tasks are #{dbs_list.to_sentence}."
end
end
def create_current(environment = env)
each_current_configuration(environment) { |configuration|
create configuration

View file

@ -24,7 +24,6 @@ module ApplicationTests
assert_no_match(/already exists/, output)
assert File.exist?(expected_database)
output = rails("db:drop")
assert_match(/Dropped database/, output)
assert_match_namespace(namespace, output)
@ -137,6 +136,36 @@ module ApplicationTests
end
end
def db_up_and_down(version, namespace = nil)
Dir.chdir(app_path) do
generate_models_for_animals
rails("db:migrate")
if namespace
down_output = rails("db:migrate:down:#{namespace}", "VERSION=#{version}")
up_output = rails("db:migrate:up:#{namespace}", "VERSION=#{version}")
else
assert_raises RuntimeError, /You're using a multiple database application/ do
down_output = rails("db:migrate:down", "VERSION=#{version}")
end
assert_raises RuntimeError, /You're using a multiple database application/ do
up_output = rails("db:migrate:up", "VERSION=#{version}")
end
end
case namespace
when "primary"
assert_match(/OneMigration: reverting/, down_output)
assert_match(/OneMigration: migrated/, up_output)
when nil
else
assert_match(/TwoMigration: reverting/, down_output)
assert_match(/TwoMigration: migrated/, up_output)
end
end
end
def db_prepare
Dir.chdir(app_path) do
generate_models_for_animals
@ -219,6 +248,34 @@ module ApplicationTests
end
end
test "db:migrate:down and db:migrate:up without a namespace raises in a multi-db application" do
require "#{app_path}/config/environment"
app_file "db/migrate/01_one_migration.rb", <<-MIGRATION
class OneMigration < ActiveRecord::Migration::Current
end
MIGRATION
db_up_and_down "01"
end
test "db:migrate:down:namespace and db:migrate:up:namespace works" do
require "#{app_path}/config/environment"
app_file "db/migrate/01_one_migration.rb", <<-MIGRATION
class OneMigration < ActiveRecord::Migration::Current
end
MIGRATION
app_file "db/animals_migrate/02_two_migration.rb", <<-MIGRATION
class TwoMigration < ActiveRecord::Migration::Current
end
MIGRATION
db_up_and_down "01", "primary"
db_up_and_down "02", "animals"
end
test "db:migrate:status works on all databases" do
require "#{app_path}/config/environment"
db_migrate_and_migrate_status