Skip to content

Commit

Permalink
fk: generalize using AlterTable and SchemaCreation.
Browse files Browse the repository at this point in the history
  • Loading branch information
senny committed Jun 26, 2014
1 parent 74b2fe4 commit 1c170fd
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 49 deletions.
Expand Up @@ -18,11 +18,25 @@ def visit_AddColumn(o)
add_column_options!(sql, column_options(o))
end

def visit_AddForeignKey(o)
<<-SQL
ADD CONSTRAINT #{quote_column_name(o.name)}
FOREIGN KEY (#{quote_column_name(o.column)})
REFERENCES #{quote_table_name(o.to_table)} (#{quote_column_name(o.primary_key)})
SQL
end

def visit_DropForeignKey(name)
"DROP CONSTRAINT #{name}"
end

private

def visit_AlterTable(o)
sql = "ALTER TABLE #{quote_table_name(o.name)} "
sql << o.adds.map { |col| visit_AddColumn col }.join(' ')
sql << o.foreign_key_adds.map { |fk| visit_AddForeignKey fk }.join(' ')
sql << o.foreign_key_drops.map { |fk| visit_DropForeignKey fk }.join(' ')
end

def visit_ColumnDefinition(o)
Expand Down
Expand Up @@ -317,14 +317,26 @@ def aliased_types

class AlterTable # :nodoc:
attr_reader :adds
attr_reader :foreign_key_adds
attr_reader :foreign_key_drops

def initialize(td)
@td = td
@adds = []
@foreign_key_adds = []
@foreign_key_drops = []
end

def name; @td.name; end

def add_foreign_key(to_table, options)
@foreign_key_adds << ForeignKeyDefinition.new(name, to_table, options)
end

def drop_foreign_key(name)
@foreign_key_drops << name
end

def add_column(name, type, options)
name = name.to_s
type = type.to_sym
Expand Down
Expand Up @@ -625,13 +625,6 @@ def add_reference(table_name, ref_name, options = {})
end
alias :add_belongs_to :add_reference

def foreign_key_name(table_name, options)
options.fetch(:name) do
column_name = options.fetch(:column)
"#{table_name}_#{column_name}_fk"
end
end

# Removes the reference(s). Also removes a +type+ column if one exists.
# <tt>remove_reference</tt>, <tt>remove_references</tt> and <tt>remove_belongs_to</tt> are acceptable.
#
Expand All @@ -649,6 +642,36 @@ def remove_reference(table_name, ref_name, options = {})
end
alias :remove_belongs_to :remove_reference

def foreign_keys(table_name)
raise NotImplementedError, "foreign_keys is not implemented"
end

def add_foreign_key(from_table, to_table, options = {})
options = {
column: options.fetch(:column),
primary_key: "id",
name: foreign_key_name(from_table, options)
}
at = create_alter_table from_table
at.add_foreign_key to_table, options

execute schema_creation.accept at
end

def remove_foreign_key(from_table, options = {})
at = create_alter_table from_table
at.drop_foreign_key foreign_key_name(from_table, options)

execute schema_creation.accept at
end

def foreign_key_name(table_name, options) # :nodoc:
options.fetch(:name) do
column_name = options.fetch(:column)
"#{table_name}_#{column_name}_fk"
end
end

def dump_schema_information #:nodoc:
sm_table = ActiveRecord::Migrator.schema_migrations_table_name

Expand Down
Expand Up @@ -10,6 +10,10 @@ def visit_AddColumn(o)
add_column_position!(super, column_options(o))
end

def visit_DropForeignKey(name)
"DROP FOREIGN KEY #{name}"
end

private

def visit_TableDefinition(o)
Expand Down Expand Up @@ -525,26 +529,6 @@ def foreign_keys(table_name)
end
end

def add_foreign_key(from_table, to_table, options = {})
foreign_key_column = options.fetch(:column)
referenced_column = "id"
foreign_key_name = foreign_key_name(from_table, options)
execute <<-SQL
ALTER TABLE #{quote_table_name(from_table)}
ADD CONSTRAINT #{foreign_key_name}
FOREIGN KEY (#{quote_column_name(foreign_key_column)})
REFERENCES #{quote_table_name(to_table)} (#{quote_column_name(referenced_column)})
SQL
end

def remove_foreign_key(from_table, options = {})
foreign_key_name = foreign_key_name(from_table, options)
execute <<-SQL
ALTER TABLE #{quote_table_name(from_table)}
DROP FOREIGN KEY #{foreign_key_name}
SQL
end

# Maps logical Rails types to MySQL-specific data types.
def type_to_sql(type, limit = nil, precision = nil, scale = nil)
case type.to_s
Expand Down
Expand Up @@ -472,26 +472,6 @@ def foreign_keys(table_name)
end
end

def add_foreign_key(from_table, to_table, options = {})
foreign_key_column = options.fetch(:column)
referenced_column = "id"
foreign_key_name = foreign_key_name(from_table, options)
execute <<-SQL
ALTER TABLE #{quote_table_name(from_table)}
ADD CONSTRAINT #{foreign_key_name}
FOREIGN KEY (#{quote_column_name(foreign_key_column)})
REFERENCES #{quote_table_name(to_table)} (#{quote_column_name(referenced_column)})
SQL
end

def remove_foreign_key(from_table, options = {})
foreign_key_name = foreign_key_name(from_table, options)
execute <<-SQL
ALTER TABLE #{quote_table_name(from_table)}
DROP CONSTRAINT #{foreign_key_name}
SQL
end

def index_name_length
63
end
Expand Down
6 changes: 4 additions & 2 deletions activerecord/test/cases/migration/foreign_key_test.rb
Expand Up @@ -23,8 +23,10 @@ class Astronaut < ActiveRecord::Base
end

teardown do
@connection.execute "DROP TABLE IF EXISTS astronauts"
@connection.execute "DROP TABLE IF EXISTS rockets"
if defined?(@connection)
@connection.execute "DROP TABLE IF EXISTS astronauts"
@connection.execute "DROP TABLE IF EXISTS rockets"
end
end

def test_foreign_keys
Expand Down

0 comments on commit 1c170fd

Please sign in to comment.