Skip to content

Commit 51aab54

Browse files
committed
Foreign Key Support Fixes #375.
1 parent e178bcb commit 51aab54

File tree

5 files changed

+70
-0
lines changed

5 files changed

+70
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
* New `SQLServer::Utils::Name` object for decomposing and quoting SQL Server names/identifiers.
99
* Support for most all SQL Server types in schema statements and dumping.
1010
* Support create table with query from relation or select statement.
11+
* Foreign Key Support Fixes #375.
1112

1213
#### Changed
1314

lib/active_record/connection_adapters/sqlserver/schema_creation.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,18 @@ def add_column_options!(sql, options)
3434
end
3535
end
3636

37+
def action_sql(action, dependency)
38+
case dependency
39+
when :restrict
40+
raise ArgumentError, <<-MSG.strip_heredoc
41+
'#{dependency}' is not supported for :on_update or :on_delete.
42+
Supported values are: :nullify, :cascade
43+
MSG
44+
else
45+
super
46+
end
47+
end
48+
3749
end
3850
end
3951
end

lib/active_record/connection_adapters/sqlserver/schema_statements.rb

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,30 @@ def remove_index!(table_name, index_name)
116116
do_execute "DROP INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)}"
117117
end
118118

119+
def foreign_keys(table_name)
120+
identifier = SQLServer::Utils.extract_identifiers(table_name)
121+
fk_info = execute_procedure :sp_fkeys, nil, identifier.schema, nil, identifier.object, identifier.schema
122+
fk_info.map do |row|
123+
from_table = identifier.object
124+
to_table = row['PKTABLE_NAME']
125+
options = {
126+
name: row['FK_NAME'],
127+
column: row['FKCOLUMN_NAME'],
128+
primary_key: row['PKCOLUMN_NAME'],
129+
on_update: extract_foreign_key_action('update', row['FK_NAME']),
130+
on_delete: extract_foreign_key_action('delete', row['FK_NAME'])
131+
}
132+
ForeignKeyDefinition.new from_table, to_table, options
133+
end
134+
end
135+
136+
def extract_foreign_key_action(action, fk_name)
137+
case select_value("SELECT #{action}_referential_action_desc FROM sys.foreign_keys WHERE name = '#{fk_name}'")
138+
when 'CASCADE' then :cascade
139+
when 'SET_NULL' then :nullify
140+
end
141+
end
142+
119143
def type_to_sql(type, limit = nil, precision = nil, scale = nil)
120144
type_limitable = %w(string integer float char nchar varchar nvarchar).include?(type.to_s)
121145
limit = nil unless type_limitable

lib/active_record/connection_adapters/sqlserver_adapter.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,10 @@ def supports_views?
111111
true
112112
end
113113

114+
def supports_foreign_keys?
115+
true
116+
end
117+
114118
def disable_referential_integrity
115119
do_execute "EXEC sp_MSforeachtable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL'"
116120
yield

test/cases/coerced_tests.rb

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,13 @@ class ChangeSchemaTest < ActiveRecord::TestCase
126126
coerce_tests! :test_create_table_with_bigint,
127127
:test_create_table_with_defaults
128128

129+
130+
end
131+
class ChangeSchemaWithDependentObjectsTest < ActiveRecord::TestCase
132+
133+
# In SQL Server you have to delete the tables yourself in the right order.
134+
coerce_tests! :test_create_table_with_force_cascade_drops_dependent_objects
135+
129136
end
130137
end
131138
end
@@ -302,6 +309,28 @@ def test_take_and_first_and_last_with_integer_should_use_sql_limit_coerced
302309

303310

304311

312+
module ActiveRecord
313+
class Migration
314+
class ForeignKeyTest < ActiveRecord::TestCase
315+
316+
# We do not support :restrict.
317+
coerce_tests! :test_add_on_delete_restrict_foreign_key
318+
def test_add_on_delete_restrict_foreign_key_coerced
319+
assert_raises ArgumentError do
320+
@connection.add_foreign_key :astronauts, :rockets, column: "rocket_id", on_delete: :restrict
321+
end
322+
assert_raises ArgumentError do
323+
@connection.add_foreign_key :astronauts, :rockets, column: "rocket_id", on_update: :restrict
324+
end
325+
end
326+
327+
end
328+
end
329+
end
330+
331+
332+
333+
305334
class HasOneAssociationsTest < ActiveRecord::TestCase
306335

307336
# We use OFFSET/FETCH vs TOP. So we always have an order.

0 commit comments

Comments
 (0)