提交 d665c611 编写于 作者: A Andrew White 提交者: GitHub

Merge pull request #24743 from kamipo/sqlite_foreing_key_support

SQLite: Foreign Key Support
......@@ -15,9 +15,9 @@ def accept(o)
end
delegate :quote_column_name, :quote_table_name, :quote_default_expression, :type_to_sql,
:options_include_default?, :supports_indexes_in_create?, :supports_foreign_keys?, :foreign_key_options, to: :@conn
:options_include_default?, :supports_indexes_in_create?, :supports_foreign_keys_in_create?, :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?, :supports_foreign_keys?, :foreign_key_options
:options_include_default?, :supports_indexes_in_create?, :supports_foreign_keys_in_create?, :foreign_key_options
private
......@@ -49,7 +49,7 @@ def visit_TableDefinition(o)
statements.concat(o.indexes.map { |column_name, options| index_in_create(o.name, column_name, options) })
end
if supports_foreign_keys?
if supports_foreign_keys_in_create?
statements.concat(o.foreign_keys.map { |to_table, options| foreign_key_in_create(o.name, to_table, options) })
end
......
......@@ -310,6 +310,12 @@ def supports_foreign_keys?
false
end
# Does this adapter support creating foreign key constraints
# in the same statement as creating the table?
def supports_foreign_keys_in_create?
supports_foreign_keys?
end
# Does this adapter support views?
def supports_views?
false
......
......@@ -130,6 +130,10 @@ def requires_reloading?
true
end
def supports_foreign_keys_in_create?
sqlite_version >= "3.6.19"
end
def supports_views?
true
end
......@@ -439,6 +443,19 @@ def rename_column(table_name, column_name, new_column_name) #:nodoc:
rename_column_indexes(table_name, column.name, new_column_name)
end
def foreign_keys(table_name)
fk_info = select_all("PRAGMA foreign_key_list(#{quote(table_name)})", "SCHEMA")
fk_info.map do |row|
options = {
column: row["from"],
primary_key: row["to"],
on_delete: extract_foreign_key_action(row["on_delete"]),
on_update: extract_foreign_key_action(row["on_update"])
}
ForeignKeyDefinition.new(table_name, row["table"], options)
end
end
private
def table_structure(table_name)
......@@ -592,6 +609,14 @@ def create_table_definition(*args)
SQLite3::TableDefinition.new(*args)
end
def extract_foreign_key_action(specifier)
case specifier
when "CASCADE"; :cascade
when "SET NULL"; :nullify
when "RESTRICT"; :restrict
end
end
def configure_connection
execute("PRAGMA foreign_keys = ON", "SCHEMA")
end
......
......@@ -2,6 +2,26 @@
require "support/ddl_helper"
require "support/schema_dumping_helper"
if ActiveRecord::Base.connection.supports_foreign_keys_in_create?
module ActiveRecord
class Migration
class ForeignKeyInCreateTest < ActiveRecord::TestCase
def test_foreign_keys
foreign_keys = ActiveRecord::Base.connection.foreign_keys("fk_test_has_fk")
assert_equal 1, foreign_keys.size
fk = foreign_keys.first
assert_equal "fk_test_has_fk", fk.from_table
assert_equal "fk_test_has_pk", fk.to_table
assert_equal "fk_id", fk.column
assert_equal "pk_id", fk.primary_key
assert_equal "fk_name", fk.name unless current_adapter?(:SQLite3Adapter)
end
end
end
end
end
if ActiveRecord::Base.connection.supports_foreign_keys?
module ActiveRecord
class Migration
......@@ -29,10 +49,8 @@ class Astronaut < ActiveRecord::Base
end
teardown do
if defined?(@connection)
@connection.drop_table "astronauts", if_exists: true
@connection.drop_table "rockets", if_exists: true
end
@connection.drop_table "astronauts", if_exists: true
@connection.drop_table "rockets", if_exists: true
end
def test_foreign_keys
......@@ -305,9 +323,11 @@ def test_remove_foreign_key_should_be_noop
@connection.remove_foreign_key :clubs, :categories
end
def test_foreign_keys_should_raise_not_implemented
assert_raises NotImplementedError do
@connection.foreign_keys("clubs")
unless current_adapter?(:SQLite3Adapter)
def test_foreign_keys_should_raise_not_implemented
assert_raises NotImplementedError do
@connection.foreign_keys("clubs")
end
end
end
end
......
require "cases/helper"
if ActiveRecord::Base.connection.supports_foreign_keys?
if ActiveRecord::Base.connection.supports_foreign_keys_in_create?
module ActiveRecord
class Migration
class ReferencesForeignKeyTest < ActiveRecord::TestCase
class ReferencesForeignKeyInCreateTest < ActiveRecord::TestCase
setup do
@connection = ActiveRecord::Base.connection
@connection.create_table(:testing_parents, force: true)
......@@ -61,6 +61,24 @@ class ReferencesForeignKeyTest < ActiveRecord::TestCase
assert_equal([["testings", "testing_parents", "parent_id"]],
fks.map { |fk| [fk.from_table, fk.to_table, fk.column] })
end
end
end
end
end
if ActiveRecord::Base.connection.supports_foreign_keys?
module ActiveRecord
class Migration
class ReferencesForeignKeyTest < ActiveRecord::TestCase
setup do
@connection = ActiveRecord::Base.connection
@connection.create_table(:testing_parents, force: true)
end
teardown do
@connection.drop_table "testings", if_exists: true
@connection.drop_table "testing_parents", if_exists: true
end
test "foreign keys cannot be added to polymorphic relations when creating the table" do
@connection.create_table :testings do |t|
......
......@@ -343,7 +343,7 @@ def up
t.column :name, :string
t.column :owner_id, :bigint
t.index [:name]
t.foreign_key :dog_owners, column: "owner_id" if supports_foreign_keys?
t.foreign_key :dog_owners, column: "owner_id"
end
end
def down
......
......@@ -1005,16 +1005,14 @@
create_table :records, force: true do |t|
end
if supports_foreign_keys?
# fk_test_has_fk should be before fk_test_has_pk
create_table :fk_test_has_fk, force: true do |t|
t.bigint :fk_id, null: false
disable_referential_integrity do
create_table :fk_test_has_pk, primary_key: "pk_id", force: :cascade do |t|
end
create_table :fk_test_has_pk, force: true, primary_key: "pk_id" do |t|
create_table :fk_test_has_fk, force: true do |t|
t.references :fk, null: false
t.foreign_key :fk_test_has_pk, column: "fk_id", name: "fk_name", primary_key: "pk_id"
end
add_foreign_key :fk_test_has_fk, :fk_test_has_pk, column: "fk_id", name: "fk_name", primary_key: "pk_id"
end
create_table :overloaded_types, force: true do |t|
......
ActiveRecord::Schema.define do
execute "DROP TABLE fk_test_has_fk" rescue nil
execute "DROP TABLE fk_test_has_pk" rescue nil
execute <<_SQL
CREATE TABLE 'fk_test_has_pk' (
'pk_id' INTEGER NOT NULL PRIMARY KEY
);
_SQL
execute <<_SQL
CREATE TABLE 'fk_test_has_fk' (
'id' INTEGER NOT NULL PRIMARY KEY,
'fk_id' INTEGER NOT NULL,
FOREIGN KEY ('fk_id') REFERENCES 'fk_test_has_pk'('pk_id')
);
_SQL
end
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册