From d055dde9514a604068f66fdcd7e004e376617953 Mon Sep 17 00:00:00 2001 From: Jack Dempsey Date: Thu, 8 Jan 2009 17:18:52 -0500 Subject: [PATCH] Add column_exists and index_exists methods for use in migrations. Sometimes databases are tinkered with, and then a migration is written to do things the right way. At this point though, if you're writing a migration to add a column and its already in the table, you need to do some manual work to figure out if it already exists (same goes for an index). So, I've wrapped up that logic in a couple helper methods, which should make it even easier to write less brittle migrations --- .../abstract/schema_statements.rb | 15 +++++++++++++ activerecord/test/cases/migration_test.rb | 23 ++++++++++++++++++++ 2 files changed, 38 insertions(+), 0 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb index c29c156..657e53d 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -215,6 +215,21 @@ module ActiveRecord raise NotImplementedError, "change_column is not implemented" end + # Determine if the specified index already exists on the given table + # ===== Examples + # add_index(:people, :related_id) unless column_exists(:people, :related_id) + def index_exists(table_name, simple_index_name) + # The index_name method translates :column into :index_table_name_on_column + indexes(table_name).any? {|index| index.name == index_name(table_name, simple_index_name)} + end + + # Determine if the specified column already exists on the given table + # ===== Examples + # add_column(:people, :nickname, :string) unless column_exists(:people, :nickname) + def column_exists(table_name, column_name) + columns(table_name).any? {|column| column.name == column_name.to_s} + end + # Sets a new default value for a column. If you want to set the default # value to +NULL+, you are out of luck. You need to # DatabaseStatements#execute the appropriate SQL statement yourself. diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb index ac44dd7..1a83694 100644 --- a/activerecord/test/cases/migration_test.rb +++ b/activerecord/test/cases/migration_test.rb @@ -733,6 +733,29 @@ if ActiveRecord::Base.connection.supports_migrations? Person.connection.drop_table :testings rescue nil end + def test_index_exists + Person.connection.create_table :index_exists_test do |t| + t.column :name, :string + end + Person.connection.add_index :index_exists_test, :name + + assert_raises(ActiveRecord::StatementInvalid) { Person.connection.add_index :index_exists_test, :name} + assert_nothing_raised { Person.connection.add_index(:index_exists_test, :name) unless Person.connection.index_exists(:index_exists_test, :name) } + ensure + Person.connection.drop_table :index_exists_test + end + + def test_column_exists + Person.connection.create_table :column_exists_test do |t| + t.column :name, :string + end + + assert_raises(ActiveRecord::StatementInvalid) { Person.connection.add_column :column_exists_test, :name, :string} + assert_nothing_raised { Person.connection.add_column(:column_exists_test, :name, :string) unless Person.connection.column_exists(:column_exists_test, :name) } + ensure + Person.connection.drop_table :column_exists_test + end + def test_keeping_default_and_notnull_constaint_on_change Person.connection.create_table :testings do |t| t.column :title, :string -- 1.5.3.7