mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Support removing custom-names indexes when only specifying column names
This commit is contained in:
parent
9771f5e178
commit
8ceb883b06
6 changed files with 108 additions and 19 deletions
|
@ -699,15 +699,15 @@ module ActiveRecord
|
||||||
|
|
||||||
# Removes the given index from the table.
|
# Removes the given index from the table.
|
||||||
#
|
#
|
||||||
# Removes the +index_accounts_on_column+ in the +accounts+ table.
|
# Removes the index on +branch_id+ in the +accounts+ table if exactly one such index exists.
|
||||||
#
|
#
|
||||||
# remove_index :accounts, :branch_id
|
# remove_index :accounts, :branch_id
|
||||||
#
|
#
|
||||||
# Removes the index named +index_accounts_on_branch_id+ in the +accounts+ table.
|
# Removes the index on +branch_id+ in the +accounts+ table if exactly one such index exists.
|
||||||
#
|
#
|
||||||
# remove_index :accounts, column: :branch_id
|
# remove_index :accounts, column: :branch_id
|
||||||
#
|
#
|
||||||
# Removes the index named +index_accounts_on_branch_id_and_party_id+ in the +accounts+ table.
|
# Removes the index on +branch_id+ and +party_id+ in the +accounts+ table if exactly one such index exists.
|
||||||
#
|
#
|
||||||
# remove_index :accounts, column: [:branch_id, :party_id]
|
# remove_index :accounts, column: [:branch_id, :party_id]
|
||||||
#
|
#
|
||||||
|
@ -1126,21 +1126,35 @@ module ActiveRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def index_name_for_remove(table_name, options = {})
|
def index_name_for_remove(table_name, options = {})
|
||||||
index_name = index_name(table_name, options)
|
# if the adapter doesn't support the indexes call the best we can do
|
||||||
|
# is return the default index name for the options provided
|
||||||
|
return index_name(table_name, options) unless respond_to?(:indexes)
|
||||||
|
|
||||||
unless index_name_exists?(table_name, index_name, true)
|
checks = []
|
||||||
if options.is_a?(Hash) && options.has_key?(:name)
|
|
||||||
options_without_column = options.dup
|
|
||||||
options_without_column.delete :column
|
|
||||||
index_name_without_column = index_name(table_name, options_without_column)
|
|
||||||
|
|
||||||
return index_name_without_column if index_name_exists?(table_name, index_name_without_column, false)
|
if options.is_a?(Hash)
|
||||||
|
checks << lambda { |i| i.name == options[:name].to_s } if options.has_key?(:name)
|
||||||
|
column_names = Array(options[:column]).map(&:to_s)
|
||||||
|
else
|
||||||
|
column_names = Array(options).map(&:to_s)
|
||||||
end
|
end
|
||||||
|
|
||||||
raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' does not exist"
|
if column_names.any?
|
||||||
|
checks << lambda { |i| i.columns.join('_and_') == column_names.join('_and_') }
|
||||||
end
|
end
|
||||||
|
|
||||||
index_name
|
raise ArgumentError "No name or columns specified" if checks.none?
|
||||||
|
|
||||||
|
matching_indexes = indexes(table_name).select { |i| checks.all? { |check| check[i] } }
|
||||||
|
|
||||||
|
if matching_indexes.count > 1
|
||||||
|
raise ArgumentError, "Multiple indexes found on #{table_name} columns #{column_names}. " \
|
||||||
|
"Specify an index name from #{matching_indexes.map(&:name).join(', ')}"
|
||||||
|
elsif matching_indexes.none?
|
||||||
|
raise ArgumentError, "No indexes found on #{table_name} with the options provided."
|
||||||
|
else
|
||||||
|
matching_indexes.first.name
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def rename_table_indexes(table_name, new_name)
|
def rename_table_indexes(table_name, new_name)
|
||||||
|
|
|
@ -39,6 +39,31 @@ module ActiveRecord
|
||||||
end
|
end
|
||||||
super
|
super
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def remove_index(table_name, options = {})
|
||||||
|
index_name = index_name_for_remove(table_name, options)
|
||||||
|
execute "DROP INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)}"
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def index_name_for_remove(table_name, options = {})
|
||||||
|
index_name = index_name(table_name, options)
|
||||||
|
|
||||||
|
unless index_name_exists?(table_name, index_name, true)
|
||||||
|
if options.is_a?(Hash) && options.has_key?(:name)
|
||||||
|
options_without_column = options.dup
|
||||||
|
options_without_column.delete :column
|
||||||
|
index_name_without_column = index_name(table_name, options_without_column)
|
||||||
|
|
||||||
|
return index_name_without_column if index_name_exists?(table_name, index_name_without_column, false)
|
||||||
|
end
|
||||||
|
|
||||||
|
raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' does not exist"
|
||||||
|
end
|
||||||
|
|
||||||
|
index_name
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class V4_2 < V5_0
|
class V4_2 < V5_0
|
||||||
|
|
|
@ -54,8 +54,10 @@ class PostgresqlActiveSchemaTest < ActiveRecord::PostgreSQLTestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_remove_index
|
def test_remove_index
|
||||||
# remove_index calls index_name_exists? which can't work since execute is stubbed
|
# remove_index calls index_name_for_remove which can't work since execute is stubbed
|
||||||
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.send(:define_method, :index_name_exists?) { |*| true }
|
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.send(:define_method, :index_name_for_remove) do |*|
|
||||||
|
'index_people_on_last_name'
|
||||||
|
end
|
||||||
|
|
||||||
expected = %(DROP INDEX CONCURRENTLY "index_people_on_last_name")
|
expected = %(DROP INDEX CONCURRENTLY "index_people_on_last_name")
|
||||||
assert_equal expected, remove_index(:people, name: "index_people_on_last_name", algorithm: :concurrently)
|
assert_equal expected, remove_index(:people, name: "index_people_on_last_name", algorithm: :concurrently)
|
||||||
|
@ -64,7 +66,7 @@ class PostgresqlActiveSchemaTest < ActiveRecord::PostgreSQLTestCase
|
||||||
add_index(:people, :last_name, algorithm: :copy)
|
add_index(:people, :last_name, algorithm: :copy)
|
||||||
end
|
end
|
||||||
|
|
||||||
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.send :remove_method, :index_name_exists?
|
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.send :remove_method, :index_name_for_remove
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
|
@ -323,8 +323,6 @@ class SchemaTest < ActiveRecord::PostgreSQLTestCase
|
||||||
|
|
||||||
def test_with_uppercase_index_name
|
def test_with_uppercase_index_name
|
||||||
@connection.execute "CREATE INDEX \"things_Index\" ON #{SCHEMA_NAME}.things (name)"
|
@connection.execute "CREATE INDEX \"things_Index\" ON #{SCHEMA_NAME}.things (name)"
|
||||||
assert_nothing_raised { @connection.remove_index "things", name: "#{SCHEMA_NAME}.things_Index"}
|
|
||||||
@connection.execute "CREATE INDEX \"things_Index\" ON #{SCHEMA_NAME}.things (name)"
|
|
||||||
|
|
||||||
with_schema_search_path SCHEMA_NAME do
|
with_schema_search_path SCHEMA_NAME do
|
||||||
assert_nothing_raised { @connection.remove_index "things", name: "things_Index"}
|
assert_nothing_raised { @connection.remove_index "things", name: "things_Index"}
|
||||||
|
|
42
activerecord/test/cases/migration/compatibility_test.rb
Normal file
42
activerecord/test/cases/migration/compatibility_test.rb
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
require 'cases/helper'
|
||||||
|
|
||||||
|
module ActiveRecord
|
||||||
|
class Migration
|
||||||
|
class CompatibilityTest < ActiveRecord::TestCase
|
||||||
|
attr_reader :connection
|
||||||
|
self.use_transactional_tests = false
|
||||||
|
|
||||||
|
def setup
|
||||||
|
super
|
||||||
|
@connection = ActiveRecord::Base.connection
|
||||||
|
@verbose_was = ActiveRecord::Migration.verbose
|
||||||
|
ActiveRecord::Migration.verbose = false
|
||||||
|
|
||||||
|
connection.create_table :testings do |t|
|
||||||
|
t.column :foo, :string, :limit => 100
|
||||||
|
t.column :bar, :string, :limit => 100
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
teardown do
|
||||||
|
connection.drop_table :testings rescue nil
|
||||||
|
ActiveRecord::Migration.verbose = @verbose_was
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_migration_doesnt_remove_named_index
|
||||||
|
connection.add_index :testings, :foo, :name => "custom_index_name"
|
||||||
|
|
||||||
|
migration = Class.new(ActiveRecord::Migration[4.2]) {
|
||||||
|
def version; 101 end
|
||||||
|
def migrate(x)
|
||||||
|
remove_index :testings, :foo
|
||||||
|
end
|
||||||
|
}.new
|
||||||
|
|
||||||
|
assert connection.index_exists?(:testings, :foo, name: "custom_index_name")
|
||||||
|
assert_raise(StandardError) { ActiveRecord::Migrator.new(:up, [migration]).migrate }
|
||||||
|
assert connection.index_exists?(:testings, :foo, name: "custom_index_name")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -135,6 +135,14 @@ module ActiveRecord
|
||||||
assert !connection.index_exists?(:testings, :foo, :name => "other_index_name")
|
assert !connection.index_exists?(:testings, :foo, :name => "other_index_name")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_remove_named_index
|
||||||
|
connection.add_index :testings, :foo, :name => "custom_index_name"
|
||||||
|
|
||||||
|
assert connection.index_exists?(:testings, :foo)
|
||||||
|
connection.remove_index :testings, :foo
|
||||||
|
assert !connection.index_exists?(:testings, :foo)
|
||||||
|
end
|
||||||
|
|
||||||
def test_add_index_attribute_length_limit
|
def test_add_index_attribute_length_limit
|
||||||
connection.add_index :testings, [:foo, :bar], :length => {:foo => 10, :bar => nil}
|
connection.add_index :testings, [:foo, :bar], :length => {:foo => 10, :bar => nil}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue