Skip to content

Commit

Permalink
Define #build_change_column_definition on connection adapters
Browse files Browse the repository at this point in the history
Define APIs on the MySQL and PostgreSQL connection adapters for building
ChangeColumnDefinition objects. These provide information on what a
column change would look like, when called with the same arguments as
would be passed to #change_column.
  • Loading branch information
adrianna-chang-shopify committed Jul 28, 2022
1 parent 6d100e5 commit c59cbb5
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 41 deletions.
Expand Up @@ -92,7 +92,7 @@ def aliased_types(name, fallback)

AddColumnDefinition = Struct.new(:column) # :nodoc:

ChangeColumnDefinition = Struct.new(:column, :name) # :nodoc:
ChangeColumnDefinition = Struct.new(:column, :name, :ddl) # :nodoc:

CreateIndexDefinition = Struct.new(:index, :algorithm, :if_not_exists, :ddl) # :nodoc:

Expand Down
Expand Up @@ -371,6 +371,39 @@ def change_column(table_name, column_name, type, **options) # :nodoc:
execute("ALTER TABLE #{quote_table_name(table_name)} #{change_column_for_alter(table_name, column_name, type, **options)}")
end

# Builds a ChangeColumnDefinition object.
#
# This definition object contains information about the column change that would occur
# if the same arguments were passed to #change_column. See #change_column for information about
# passing a +table_name+, +column_name+, +type+ and other options that can be passed.
def build_change_column_definition(table_name, column_name, type, **options) # :nodoc:
column = column_for(table_name, column_name)
type ||= column.sql_type

unless options.key?(:default)
options[:default] = column.default
end

unless options.key?(:null)
options[:null] = column.null
end

unless options.key?(:comment)
options[:comment] = column.comment
end

unless options.key?(:auto_increment)
options[:auto_increment] = column.auto_increment?
end

td = create_table_definition(table_name)
cd = td.new_column_definition(column.name, type, **options)
change_column_def = ChangeColumnDefinition.new(cd, column.name)
schema_creation.accept(change_column_def)

change_column_def
end

def rename_column(table_name, column_name, new_column_name) # :nodoc:
execute("ALTER TABLE #{quote_table_name(table_name)} #{rename_column_for_alter(table_name, column_name, new_column_name)}")
rename_column_indexes(table_name, column_name, new_column_name)
Expand Down Expand Up @@ -726,28 +759,8 @@ def translate_exception(exception, message:, sql:, binds:)
end

def change_column_for_alter(table_name, column_name, type, **options)
column = column_for(table_name, column_name)
type ||= column.sql_type

unless options.key?(:default)
options[:default] = column.default
end

unless options.key?(:null)
options[:null] = column.null
end

unless options.key?(:comment)
options[:comment] = column.comment
end

unless options.key?(:auto_increment)
options[:auto_increment] = column.auto_increment?
end

td = create_table_definition(table_name)
cd = td.new_column_definition(column.name, type, **options)
schema_creation.accept(ChangeColumnDefinition.new(cd, column.name))
cd = build_change_column_definition(table_name, column_name, type, **options)
cd.ddl
end

def rename_column_for_alter(table_name, column_name, new_column_name)
Expand Down
Expand Up @@ -21,7 +21,7 @@ def visit_AddColumnDefinition(o)

def visit_ChangeColumnDefinition(o)
change_column_sql = +"CHANGE #{quote_column_name(o.name)} #{accept(o.column)}"
add_column_position!(change_column_sql, column_options(o.column))
o.ddl = add_column_position!(change_column_sql, column_options(o.column))
end

def visit_CreateIndexDefinition(o)
Expand Down
Expand Up @@ -84,7 +84,7 @@ def visit_ChangeColumnDefinition(o)
change_column_sql << ", ALTER COLUMN #{quoted_column_name} #{options[:null] ? 'DROP' : 'SET'} NOT NULL"
end

change_column_sql
o.ddl = change_column_sql
end

def add_column_options!(sql, options)
Expand Down
Expand Up @@ -409,6 +409,20 @@ def change_column(table_name, column_name, type, **options) # :nodoc:
procs.each(&:call)
end

# Builds a ChangeColumnDefinition object.
#
# This definition object contains information about the column change that would occur
# if the same arguments were passed to #change_column. See #change_column for information about
# passing a +table_name+, +column_name+, +type+ and other options that can be passed.
def build_change_column_definition(table_name, column_name, type, **options) # :nodoc:
td = create_table_definition(table_name)
cd = td.new_column_definition(column_name, type, **options)
change_column_def = ChangeColumnDefinition.new(cd, column_name)
schema_creation.accept(change_column_def)

change_column_def
end

# Changes the default value of a table column.
def change_column_default(table_name, column_name, default_or_changes) # :nodoc:
execute "ALTER TABLE #{quote_table_name(table_name)} #{change_column_default_for_alter(table_name, column_name, default_or_changes)}"
Expand Down Expand Up @@ -835,9 +849,8 @@ def add_column_for_alter(table_name, column_name, type, **options)
end

def change_column_for_alter(table_name, column_name, type, **options)
td = create_table_definition(table_name)
cd = td.new_column_definition(column_name, type, **options)
sqls = [schema_creation.accept(ChangeColumnDefinition.new(cd, column_name))]
change_col_def = build_change_column_definition(table_name, column_name, type, **options)
sqls = [change_col_def.ddl]
sqls << Proc.new { change_column_comment(table_name, column_name, options[:comment]) } if options.key?(:comment)
sqls
end
Expand Down
27 changes: 14 additions & 13 deletions activerecord/test/cases/migration/schema_definitions_test.rb
Expand Up @@ -62,21 +62,22 @@ def test_build_create_index_definition_for_existing_index
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
unless current_adapter?(:SQLite3Adapter)
def test_build_change_column_definition
connection.create_table(:test) do |t|
t.column :foo, :string
end

add_cols = add_col_td.adds
assert_equal 1, add_cols.size
change_cd = connection.build_change_column_definition(:test, :foo, :integer)
assert change_cd.ddl

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)
change_col = change_cd.column
assert_equal "foo", change_col.name.to_s
assert change_col.type
assert change_col.sql_type
ensure
connection.drop_table(:test) if connection.table_exists?(:test)
end
end
end
end
Expand Down

0 comments on commit c59cbb5

Please sign in to comment.