Skip to content
Browse files

fk: `foreign_keys`, `add_foreign_key` and `remove_foreign_key` for MySQL

  • Loading branch information...
1 parent 09b3a28 commit 74b2fe4c0febe051cb48c7c25a565333ddf22bce @senny senny committed Jun 10, 2014
View
14 activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
@@ -25,6 +25,20 @@ def primary_key?
class ChangeColumnDefinition < Struct.new(:column, :type, :options) #:nodoc:
end
+ class ForeignKeyDefinition < Struct.new(:from_table, :to_table, :options)
+ def name
+ options[:name]
+ end
+
+ def column
+ options[:column]
+ end
+
+ def primary_key
+ options[:primary_key]
+ end
+ end
+
# Represents the schema of an SQL table in an abstract way. This class
# provides methods for manipulating the schema representation.
#
View
7 activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
@@ -625,6 +625,13 @@ 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.
#
View
44 activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
@@ -192,6 +192,10 @@ def supports_indexes_in_create?
true
end
+ def supports_foreign_keys?
+ true
+ end
+
def native_database_types
NATIVE_DATABASE_TYPES
end
@@ -501,6 +505,46 @@ def add_index(table_name, column_name, options = {}) #:nodoc:
execute "CREATE #{index_type} INDEX #{quote_column_name(index_name)} #{index_using} ON #{quote_table_name(table_name)} (#{index_columns})#{index_options} #{index_algorithm}"
end
+ def foreign_keys(table_name)
+ fk_info = select_all %{
+ SELECT fk.referenced_table_name as 'to_table'
+ ,fk.referenced_column_name as 'primary_key'
+ ,fk.column_name as 'column'
+ ,fk.constraint_name as 'name'
+ FROM information_schema.key_column_usage fk
+ WHERE fk.referenced_column_name is not null
+ AND fk.table_schema = '#{@config[:database]}'
+ AND fk.table_name = '#{table_name}'
+ }
+
+ create_table_info = select_one("SHOW CREATE TABLE #{quote_table_name(table_name)}")["Create Table"]
+
+ fk_info.map do |row|
+ options = {column: row['column'], name: row['name'], primary_key: row['primary_key']}
+ ForeignKeyDefinition.new(table_name, row['to_table'], options)
+ 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
View
14 activerecord/lib/active_record/connection_adapters/postgresql/schema_definitions.rb
@@ -89,20 +89,6 @@ class ColumnDefinition < ActiveRecord::ConnectionAdapters::ColumnDefinition
attr_accessor :array
end
- class ForeignKeyDefinition < Struct.new(:from_table, :to_table, :options)
- def name
- options[:name]
- end
-
- def column
- options[:column]
- end
-
- def primary_key
- options[:primary_key]
- end
- end
-
class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
include ColumnMethods
View
7 activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
@@ -492,13 +492,6 @@ def remove_foreign_key(from_table, options = {})
SQL
end
- def foreign_key_name(table_name, options)
- options.fetch(:name) do
- column_name = options.fetch(:column)
- "#{table_name}_#{column_name}_fk"
- end
- end
-
def index_name_length
63
end
View
5 activerecord/test/cases/migration/foreign_key_test.rb
@@ -22,6 +22,11 @@ class Astronaut < ActiveRecord::Base
end
end
+ teardown do
+ @connection.execute "DROP TABLE IF EXISTS astronauts"
+ @connection.execute "DROP TABLE IF EXISTS rockets"
+ end
+
def test_foreign_keys
foreign_keys = @connection.foreign_keys("fk_test_has_fk")
assert_equal 1, foreign_keys.size

0 comments on commit 74b2fe4

Please sign in to comment.
Something went wrong with that request. Please try again.