1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00
rails--rails/activerecord/test/cases/migration/columns_test.rb
Ryuta Kamizono ab2d859e6c Deprecate allowed_index_name_length in DatabaseLimits
`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.
2020-04-30 01:21:54 +09:00

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