mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Support for foreign keys in create table
If foreign keys specified in create table, generated SQL is slightly more efficient. Definition: ``` create_table :testings do |t| t.references :testing_parent, foreign_key: true end ``` Before: ``` CREATE TABLE "testings" ("id" serial primary key, "testing_parent_id" integer); ALTER TABLE "testings" ADD CONSTRAINT "fk_rails_a196c353b2" FOREIGN KEY ("testing_parent_id") REFERENCES "testing_parents" ("id"); ``` After: ``` CREATE TABLE "testings" ("id" serial primary key, "testing_parent_id" integer, CONSTRAINT "fk_rails_a196c353b2" FOREIGN KEY ("testing_parent_id") REFERENCES "testing_parents" ("id")); ```
This commit is contained in:
parent
26aa1b58b0
commit
fdf371ab06
3 changed files with 33 additions and 17 deletions
|
@ -15,9 +15,9 @@ module ActiveRecord
|
|||
end
|
||||
|
||||
delegate :quote_column_name, :quote_table_name, :quote_default_expression, :type_to_sql,
|
||||
:options_include_default?, :supports_indexes_in_create?, to: :@conn
|
||||
:options_include_default?, :supports_indexes_in_create?, :supports_foreign_keys?, :foreign_key_options, to: :@conn
|
||||
private :quote_column_name, :quote_table_name, :quote_default_expression, :type_to_sql,
|
||||
:options_include_default?, :supports_indexes_in_create?
|
||||
:options_include_default?, :supports_indexes_in_create?, :supports_foreign_keys?, :foreign_key_options
|
||||
|
||||
private
|
||||
|
||||
|
@ -49,6 +49,10 @@ module ActiveRecord
|
|||
statements.concat(o.indexes.map { |column_name, options| index_in_create(o.name, column_name, options) })
|
||||
end
|
||||
|
||||
if supports_foreign_keys?
|
||||
statements.concat(o.foreign_keys.map { |to_table, options| foreign_key_in_create(o.name, to_table, options) })
|
||||
end
|
||||
|
||||
create_sql << "(#{statements.join(', ')}) " if statements.present?
|
||||
create_sql << "#{o.options}"
|
||||
create_sql << " AS #{@conn.to_sql(o.as)}" if o.as
|
||||
|
@ -59,9 +63,9 @@ module ActiveRecord
|
|||
"PRIMARY KEY (#{o.name.join(', ')})"
|
||||
end
|
||||
|
||||
def visit_AddForeignKey(o)
|
||||
def visit_ForeignKeyDefinition(o)
|
||||
sql = <<-SQL.strip_heredoc
|
||||
ADD CONSTRAINT #{quote_column_name(o.name)}
|
||||
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
|
||||
|
@ -70,6 +74,10 @@ module ActiveRecord
|
|||
sql
|
||||
end
|
||||
|
||||
def visit_AddForeignKey(o)
|
||||
"ADD #{accept(o)}"
|
||||
end
|
||||
|
||||
def visit_DropForeignKey(name)
|
||||
"DROP CONSTRAINT #{quote_column_name(name)}"
|
||||
end
|
||||
|
@ -102,6 +110,11 @@ module ActiveRecord
|
|||
sql
|
||||
end
|
||||
|
||||
def foreign_key_in_create(from_table, to_table, options)
|
||||
options = foreign_key_options(from_table, to_table, options)
|
||||
accept ForeignKeyDefinition.new(from_table, to_table, options)
|
||||
end
|
||||
|
||||
def action_sql(action, dependency)
|
||||
case dependency
|
||||
when :nullify then "ON #{action} SET NULL"
|
||||
|
|
|
@ -260,10 +260,6 @@ module ActiveRecord
|
|||
end
|
||||
end
|
||||
|
||||
td.foreign_keys.each_pair do |other_table_name, foreign_key_options|
|
||||
add_foreign_key(table_name, other_table_name, foreign_key_options)
|
||||
end
|
||||
|
||||
result
|
||||
end
|
||||
|
||||
|
@ -792,15 +788,7 @@ module ActiveRecord
|
|||
def add_foreign_key(from_table, to_table, options = {})
|
||||
return unless supports_foreign_keys?
|
||||
|
||||
options[:column] ||= foreign_key_column_for(to_table)
|
||||
|
||||
options = {
|
||||
column: options[:column],
|
||||
primary_key: options[:primary_key],
|
||||
name: foreign_key_name(from_table, options),
|
||||
on_delete: options[:on_delete],
|
||||
on_update: options[:on_update]
|
||||
}
|
||||
options = foreign_key_options(from_table, to_table, options)
|
||||
at = create_alter_table from_table
|
||||
at.add_foreign_key to_table, options
|
||||
|
||||
|
@ -868,6 +856,13 @@ module ActiveRecord
|
|||
"#{name.singularize}_id"
|
||||
end
|
||||
|
||||
def foreign_key_options(from_table, to_table, options) # :nodoc:
|
||||
options = options.dup
|
||||
options[:column] ||= foreign_key_column_for(to_table)
|
||||
options[:name] ||= foreign_key_name(from_table, options)
|
||||
options
|
||||
end
|
||||
|
||||
def dump_schema_information #:nodoc:
|
||||
sm_table = ActiveRecord::Migrator.schema_migrations_table_name
|
||||
|
||||
|
|
|
@ -32,6 +32,14 @@ module ActiveRecord
|
|||
assert_equal [], @connection.foreign_keys("testings")
|
||||
end
|
||||
|
||||
test "foreign keys can be created in one query" do
|
||||
assert_queries(1) do
|
||||
@connection.create_table :testings do |t|
|
||||
t.references :testing_parent, foreign_key: true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
test "options hash can be passed" do
|
||||
@connection.change_table :testing_parents do |t|
|
||||
t.integer :other_id
|
||||
|
|
Loading…
Reference in a new issue