mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
ab2d859e6c
`allowed_index_name_length` was used for internal temporary operations
in SQLite3, since index name in SQLite3 must be globally unique and
SQLite3 doesn't have ALTER TABLE feature (so it is emulated by creating
temporary table with prefix).
`allowed_index_name_length` was to reserve the margin for the prefix,
but actually SQLite3 doesn't have a limitation for identifier name
length, so the margin has removed at 36901e6
.
Now `allowed_index_name_length` is no longer relied on by any adapter,
so I'd like to remove the internal specific method which is no longer
used.
326 lines
13 KiB
Ruby
326 lines
13 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require "cases/migration/helper"
|
|
|
|
module ActiveRecord
|
|
class Migration
|
|
class ColumnsTest < ActiveRecord::TestCase
|
|
include ActiveRecord::Migration::TestHelper
|
|
|
|
self.use_transactional_tests = false
|
|
|
|
# FIXME: this is more of an integration test with AR::Base and the
|
|
# schema modifications. Maybe we should move this?
|
|
def test_add_rename
|
|
add_column "test_models", "girlfriend", :string
|
|
TestModel.reset_column_information
|
|
|
|
TestModel.create girlfriend: "bobette"
|
|
|
|
rename_column "test_models", "girlfriend", "exgirlfriend"
|
|
|
|
TestModel.reset_column_information
|
|
bob = TestModel.first
|
|
|
|
assert_equal "bobette", bob.exgirlfriend
|
|
end
|
|
|
|
# FIXME: another integration test. We should decouple this from the
|
|
# AR::Base implementation.
|
|
def test_rename_column_using_symbol_arguments
|
|
add_column :test_models, :first_name, :string
|
|
|
|
TestModel.create first_name: "foo"
|
|
|
|
rename_column :test_models, :first_name, :nick_name
|
|
TestModel.reset_column_information
|
|
assert_includes TestModel.column_names, "nick_name"
|
|
assert_equal ["foo"], TestModel.all.map(&:nick_name)
|
|
end
|
|
|
|
# FIXME: another integration test. We should decouple this from the
|
|
# AR::Base implementation.
|
|
def test_rename_column
|
|
add_column "test_models", "first_name", "string"
|
|
|
|
TestModel.create first_name: "foo"
|
|
|
|
rename_column "test_models", "first_name", "nick_name"
|
|
TestModel.reset_column_information
|
|
assert_includes TestModel.column_names, "nick_name"
|
|
assert_equal ["foo"], TestModel.all.map(&:nick_name)
|
|
end
|
|
|
|
def test_rename_column_preserves_default_value_not_null
|
|
add_column "test_models", "salary", :integer, default: 70000
|
|
|
|
default_before = connection.columns("test_models").find { |c| c.name == "salary" }.default
|
|
assert_equal "70000", default_before
|
|
|
|
rename_column "test_models", "salary", "annual_salary"
|
|
|
|
assert_includes TestModel.column_names, "annual_salary"
|
|
default_after = connection.columns("test_models").find { |c| c.name == "annual_salary" }.default
|
|
assert_equal "70000", default_after
|
|
end
|
|
|
|
if current_adapter?(:Mysql2Adapter)
|
|
def test_mysql_rename_column_preserves_auto_increment
|
|
rename_column "test_models", "id", "id_test"
|
|
assert_predicate connection.columns("test_models").find { |c| c.name == "id_test" }, :auto_increment?
|
|
TestModel.reset_column_information
|
|
ensure
|
|
rename_column "test_models", "id_test", "id"
|
|
end
|
|
end
|
|
|
|
def test_rename_nonexistent_column
|
|
exception = if current_adapter?(:PostgreSQLAdapter, :OracleAdapter)
|
|
ActiveRecord::StatementInvalid
|
|
else
|
|
ActiveRecord::ActiveRecordError
|
|
end
|
|
|
|
assert_raise(exception) do
|
|
rename_column "test_models", "nonexistent", "should_fail"
|
|
end
|
|
end
|
|
|
|
def test_rename_column_with_sql_reserved_word
|
|
add_column "test_models", "first_name", :string
|
|
rename_column "test_models", "first_name", "group"
|
|
|
|
assert_includes TestModel.column_names, "group"
|
|
end
|
|
|
|
def test_rename_column_with_an_index
|
|
add_column "test_models", :hat_name, :string
|
|
add_index :test_models, :hat_name
|
|
|
|
assert_equal 1, connection.indexes("test_models").size
|
|
rename_column "test_models", "hat_name", "name"
|
|
|
|
assert_equal ["index_test_models_on_name"], connection.indexes("test_models").map(&:name)
|
|
end
|
|
|
|
def test_rename_column_with_multi_column_index
|
|
add_column "test_models", :hat_size, :integer
|
|
add_column "test_models", :hat_style, :string, limit: 100
|
|
add_index "test_models", ["hat_style", "hat_size"], unique: true
|
|
|
|
rename_column "test_models", "hat_size", "size"
|
|
assert_equal ["index_test_models_on_hat_style_and_size"], connection.indexes("test_models").map(&:name)
|
|
|
|
rename_column "test_models", "hat_style", "style"
|
|
assert_equal ["index_test_models_on_style_and_size"], connection.indexes("test_models").map(&:name)
|
|
end
|
|
|
|
def test_rename_column_does_not_rename_custom_named_index
|
|
add_column "test_models", :hat_name, :string
|
|
add_index :test_models, :hat_name, name: "idx_hat_name"
|
|
|
|
assert_equal 1, connection.indexes("test_models").size
|
|
rename_column "test_models", "hat_name", "name"
|
|
assert_equal ["idx_hat_name"], connection.indexes("test_models").map(&:name)
|
|
end
|
|
|
|
def test_remove_column_with_index
|
|
add_column "test_models", :hat_name, :string
|
|
add_index :test_models, :hat_name
|
|
|
|
assert_equal 1, connection.indexes("test_models").size
|
|
remove_column("test_models", "hat_name")
|
|
assert_equal 0, connection.indexes("test_models").size
|
|
end
|
|
|
|
def test_remove_column_with_multi_column_index
|
|
# MariaDB starting with 10.2.8
|
|
# Dropping a column that is part of a multi-column UNIQUE constraint is not permitted.
|
|
skip if current_adapter?(:Mysql2Adapter) && connection.mariadb? && connection.database_version >= "10.2.8"
|
|
|
|
add_column "test_models", :hat_size, :integer
|
|
add_column "test_models", :hat_style, :string, limit: 100
|
|
add_index "test_models", ["hat_style", "hat_size"], unique: true
|
|
|
|
assert_equal 1, connection.indexes("test_models").size
|
|
remove_column("test_models", "hat_size")
|
|
|
|
# Every database and/or database adapter has their own behavior
|
|
# if it drops the multi-column index when any of the indexed columns dropped by remove_column.
|
|
if current_adapter?(:PostgreSQLAdapter, :OracleAdapter)
|
|
assert_equal [], connection.indexes("test_models").map(&:name)
|
|
else
|
|
assert_equal ["index_test_models_on_hat_style_and_hat_size"], connection.indexes("test_models").map(&:name)
|
|
end
|
|
end
|
|
|
|
def test_change_type_of_not_null_column
|
|
change_column "test_models", "updated_at", :datetime, null: false
|
|
change_column "test_models", "updated_at", :datetime, null: false
|
|
|
|
TestModel.reset_column_information
|
|
assert_equal false, TestModel.columns_hash["updated_at"].null
|
|
ensure
|
|
change_column "test_models", "updated_at", :datetime, null: true
|
|
end
|
|
|
|
def test_change_column_nullability
|
|
add_column "test_models", "funny", :boolean
|
|
assert TestModel.columns_hash["funny"].null, "Column 'funny' must initially allow nulls"
|
|
|
|
change_column "test_models", "funny", :boolean, null: false, default: true
|
|
|
|
TestModel.reset_column_information
|
|
assert_not TestModel.columns_hash["funny"].null, "Column 'funny' must *not* allow nulls at this point"
|
|
|
|
change_column "test_models", "funny", :boolean, null: true
|
|
TestModel.reset_column_information
|
|
assert TestModel.columns_hash["funny"].null, "Column 'funny' must allow nulls again at this point"
|
|
end
|
|
|
|
def test_change_column
|
|
add_column "test_models", "age", :integer
|
|
add_column "test_models", "approved", :boolean, default: true
|
|
|
|
old_columns = connection.columns(TestModel.table_name)
|
|
|
|
assert old_columns.find { |c| c.name == "age" && c.type == :integer }
|
|
|
|
change_column "test_models", "age", :string
|
|
|
|
new_columns = connection.columns(TestModel.table_name)
|
|
|
|
assert_not new_columns.find { |c| c.name == "age" && c.type == :integer }
|
|
assert new_columns.find { |c| c.name == "age" && c.type == :string }
|
|
|
|
old_columns = connection.columns(TestModel.table_name)
|
|
assert old_columns.find { |c|
|
|
default = connection.lookup_cast_type_from_column(c).deserialize(c.default)
|
|
c.name == "approved" && c.type == :boolean && default == true
|
|
}
|
|
|
|
change_column :test_models, :approved, :boolean, default: false
|
|
new_columns = connection.columns(TestModel.table_name)
|
|
|
|
assert_not new_columns.find { |c|
|
|
default = connection.lookup_cast_type_from_column(c).deserialize(c.default)
|
|
c.name == "approved" && c.type == :boolean && default == true
|
|
}
|
|
assert new_columns.find { |c|
|
|
default = connection.lookup_cast_type_from_column(c).deserialize(c.default)
|
|
c.name == "approved" && c.type == :boolean && default == false
|
|
}
|
|
change_column :test_models, :approved, :boolean, default: true
|
|
end
|
|
|
|
def test_change_column_with_nil_default
|
|
add_column "test_models", "contributor", :boolean, default: true
|
|
assert_predicate TestModel.new, :contributor?
|
|
|
|
change_column "test_models", "contributor", :boolean, default: nil
|
|
TestModel.reset_column_information
|
|
assert_not_predicate TestModel.new, :contributor?
|
|
assert_nil TestModel.new.contributor
|
|
end
|
|
|
|
def test_change_column_to_drop_default_with_null_false
|
|
add_column "test_models", "contributor", :boolean, default: true, null: false
|
|
assert_predicate TestModel.new, :contributor?
|
|
|
|
change_column "test_models", "contributor", :boolean, default: nil, null: false
|
|
TestModel.reset_column_information
|
|
assert_not_predicate TestModel.new, :contributor?
|
|
assert_nil TestModel.new.contributor
|
|
end
|
|
|
|
def test_change_column_with_new_default
|
|
add_column "test_models", "administrator", :boolean, default: true
|
|
assert_predicate TestModel.new, :administrator?
|
|
|
|
change_column "test_models", "administrator", :boolean, default: false
|
|
TestModel.reset_column_information
|
|
assert_not_predicate TestModel.new, :administrator?
|
|
end
|
|
|
|
def test_change_column_with_custom_index_name
|
|
add_column "test_models", "category", :string
|
|
add_index :test_models, :category, name: "test_models_categories_idx"
|
|
|
|
assert_equal ["test_models_categories_idx"], connection.indexes("test_models").map(&:name)
|
|
change_column "test_models", "category", :string, null: false, default: "article"
|
|
|
|
assert_equal ["test_models_categories_idx"], connection.indexes("test_models").map(&:name)
|
|
end
|
|
|
|
def test_change_column_with_long_index_name
|
|
table_name_prefix = "test_models_"
|
|
long_index_name = table_name_prefix + ("x" * (connection.index_name_length - table_name_prefix.length))
|
|
add_column "test_models", "category", :string
|
|
add_index :test_models, :category, name: long_index_name
|
|
|
|
change_column "test_models", "category", :string, null: false, default: "article"
|
|
|
|
assert_equal [long_index_name], connection.indexes("test_models").map(&:name)
|
|
end
|
|
|
|
def test_change_column_default
|
|
add_column "test_models", "first_name", :string
|
|
connection.change_column_default "test_models", "first_name", "Tester"
|
|
|
|
assert_equal "Tester", TestModel.new.first_name
|
|
end
|
|
|
|
def test_change_column_default_to_null
|
|
add_column "test_models", "first_name", :string
|
|
connection.change_column_default "test_models", "first_name", nil
|
|
assert_nil TestModel.new.first_name
|
|
end
|
|
|
|
def test_change_column_default_with_from_and_to
|
|
add_column "test_models", "first_name", :string
|
|
connection.change_column_default "test_models", "first_name", from: nil, to: "Tester"
|
|
|
|
assert_equal "Tester", TestModel.new.first_name
|
|
end
|
|
|
|
def test_remove_column_no_second_parameter_raises_exception
|
|
assert_raise(ArgumentError) { connection.remove_column("funny") }
|
|
end
|
|
|
|
def test_removing_and_renaming_column_preserves_custom_primary_key
|
|
connection.create_table "my_table", primary_key: "my_table_id", force: true do |t|
|
|
t.integer "col_one"
|
|
t.string "col_two", limit: 128, null: false
|
|
end
|
|
|
|
remove_column("my_table", "col_two")
|
|
rename_column("my_table", "col_one", "col_three")
|
|
|
|
assert_equal "my_table_id", connection.primary_key("my_table")
|
|
ensure
|
|
connection.drop_table(:my_table) rescue nil
|
|
end
|
|
|
|
def test_column_with_index
|
|
connection.create_table "my_table", force: true do |t|
|
|
t.string :item_number, index: true
|
|
end
|
|
|
|
assert connection.index_exists?("my_table", :item_number, name: :index_my_table_on_item_number)
|
|
ensure
|
|
connection.drop_table(:my_table) rescue nil
|
|
end
|
|
|
|
def test_add_column_without_column_name
|
|
e = assert_raise ArgumentError do
|
|
connection.create_table "my_table", force: true do |t|
|
|
t.timestamp
|
|
end
|
|
end
|
|
assert_equal "Missing column name(s) for timestamp", e.message
|
|
ensure
|
|
connection.drop_table :my_table, if_exists: true
|
|
end
|
|
end
|
|
end
|
|
end
|