diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb index 0cef541051dd..e37bb396dfe6 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb @@ -26,6 +26,7 @@ def visit_AlterTable(o) sql << o.foreign_key_drops.map { |fk| visit_DropForeignKey fk }.join(" ") sql << o.check_constraint_adds.map { |con| visit_AddCheckConstraint con }.join(" ") sql << o.check_constraint_drops.map { |con| visit_DropCheckConstraint con }.join(" ") + o.ddl = sql end def visit_ColumnDefinition(o) diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index 071d2a9ddf75..b0616f4824d2 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -580,6 +580,7 @@ class AlterTable # :nodoc: attr_reader :adds attr_reader :foreign_key_adds, :foreign_key_drops attr_reader :check_constraint_adds, :check_constraint_drops + attr_accessor :ddl def initialize(td) @td = td 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 7bfad2031907..36a69950a43c 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -599,6 +599,24 @@ def drop_table(table_name, **options) # # Ignores the method call if the column exists # add_column(:shapes, :triangle, 'polygon', if_not_exists: true) def add_column(table_name, column_name, type, **options) + add_column_def = build_add_column_definition(table_name, column_name, type, **options) + return unless add_column_def + + execute(add_column_def.ddl) + end + + def add_columns(table_name, *column_names, type:, **options) # :nodoc: + column_names.each do |column_name| + add_column(table_name, column_name, type, **options) + end + end + + # Builds an AlterTable object for adding a column to a table. + # + # This definition object contains information about the column that would be created + # if the same arguments were passed to #add_column. See #add_column for information about + # passing a +table_name+, +column_name+, +type+ and other options that can be passed. + def build_add_column_definition(table_name, column_name, type, **options) # :nodoc: return if options[:if_not_exists] == true && column_exists?(table_name, column_name) if supports_datetime_with_precision? @@ -607,15 +625,10 @@ def add_column(table_name, column_name, type, **options) end end - at = create_alter_table table_name - at.add_column(column_name, type, **options) - execute schema_creation.accept at - end - - def add_columns(table_name, *column_names, type:, **options) # :nodoc: - column_names.each do |column_name| - add_column(table_name, column_name, type, **options) - end + alter_table = create_alter_table(table_name) + alter_table.add_column(column_name, type, **options) + schema_creation.accept(alter_table) + alter_table end # Removes the given columns from the table definition. diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/schema_creation.rb b/activerecord/lib/active_record/connection_adapters/postgresql/schema_creation.rb index d44d07ec3487..4949c47fbb94 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_creation.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_creation.rb @@ -10,6 +10,7 @@ def visit_AlterTable(o) sql << o.constraint_validations.map { |fk| visit_ValidateConstraint fk }.join(" ") sql << o.exclusion_constraint_adds.map { |con| visit_AddExclusionConstraint con }.join(" ") sql << o.exclusion_constraint_drops.map { |con| visit_DropExclusionConstraint con }.join(" ") + o.ddl = sql end def visit_AddForeignKey(o) diff --git a/activerecord/test/cases/migration/schema_definitions_test.rb b/activerecord/test/cases/migration/schema_definitions_test.rb index 0f95a0399936..d9c18ca61b19 100644 --- a/activerecord/test/cases/migration/schema_definitions_test.rb +++ b/activerecord/test/cases/migration/schema_definitions_test.rb @@ -61,6 +61,23 @@ def test_build_create_index_definition_for_existing_index connection.drop_table(:test) if connection.table_exists?(:test) end end + + def test_build_add_column_definition + connection.create_table(:test) + add_col_td = connection.build_add_column_definition(:test, :foo, :string) + + assert_match "ALTER TABLE", add_col_td.ddl + + add_cols = add_col_td.adds + assert_equal 1, add_cols.size + + add_col = add_cols.first.column + assert_equal "foo", add_col.name + assert add_col.type + assert add_col.sql_type + ensure + connection.drop_table(:test) if connection.table_exists?(:test) + end end end end