dwilkie-foreigner 0.3 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +4 -1
- data/lib/foreigner/connection_adapters/abstract/schema_definitions.rb +13 -52
- data/lib/foreigner/connection_adapters/abstract/schema_statements.rb +3 -0
- data/lib/foreigner/connection_adapters/mysql_adapter.rb +15 -8
- data/lib/foreigner/connection_adapters/postgresql_adapter.rb +26 -16
- data/lib/foreigner/connection_adapters/sql_2003.rb +6 -20
- data/lib/foreigner/schema_dumper.rb +7 -1
- data/lib/foreigner.rb +8 -3
- metadata +5 -6
data/README
CHANGED
@@ -27,7 +27,10 @@ Install as a plugin:
|
|
27
27
|
|
28
28
|
Install as a gem by adding the following to environment.rb:
|
29
29
|
|
30
|
-
config.gem "dwilkie-foreigner", :lib => "foreigner"
|
30
|
+
config.gem "dwilkie-foreigner", :lib => "foreigner", :source => "http://gemcutter.org"
|
31
|
+
|
32
|
+
|
33
|
+
sudo rake gems:install
|
31
34
|
|
32
35
|
API
|
33
36
|
---
|
@@ -2,7 +2,7 @@ module Foreigner
|
|
2
2
|
module ConnectionAdapters
|
3
3
|
class ForeignKeyDefinition < Struct.new(:from_table, :to_table, :options) #:nodoc:
|
4
4
|
end
|
5
|
-
|
5
|
+
|
6
6
|
module SchemaDefinitions
|
7
7
|
def self.included(base)
|
8
8
|
base::TableDefinition.class_eval do
|
@@ -16,73 +16,32 @@ module Foreigner
|
|
16
16
|
end
|
17
17
|
|
18
18
|
module TableDefinition
|
19
|
-
class ForeignKey < Struct.new(:base, :to_table, :options)
|
20
|
-
def to_sql
|
21
|
-
base.foreign_key_definition(to_table, options)
|
22
|
-
end
|
23
|
-
alias to_s :to_sql
|
24
|
-
end
|
25
|
-
|
26
19
|
def self.included(base)
|
27
20
|
base.class_eval do
|
28
21
|
include InstanceMethods
|
29
22
|
alias_method_chain :references, :foreign_keys
|
30
|
-
alias_method_chain :to_sql, :foreign_keys
|
31
23
|
end
|
32
24
|
end
|
33
25
|
|
34
26
|
module InstanceMethods
|
35
|
-
# Adds a :foreign_key option to TableDefinition.references.
|
36
|
-
# If :foreign_key is true, a foreign key constraint is added to the table.
|
37
|
-
# You can also specify a hash, which is passed as foreign key options.
|
38
|
-
#
|
39
|
-
# ===== Examples
|
40
|
-
# ====== Add goat_id column and a foreign key to the goats table.
|
41
|
-
# t.references(:goat, :foreign_key => true)
|
42
|
-
# ====== Add goat_id column and a cascading foreign key to the goats table.
|
43
|
-
# t.references(:goat, :foreign_key => {:dependent => :delete})
|
44
|
-
#
|
45
|
-
# Note: No foreign key is created if :polymorphic => true is used.
|
46
|
-
# Note: If no name is specified, the database driver creates one for you!
|
47
27
|
def references_with_foreign_keys(*args)
|
48
28
|
options = args.extract_options!
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
29
|
+
if options[:foreign_key].present?
|
30
|
+
ActiveSupport::Deprecation.warn(
|
31
|
+
':foreign_key option is deprecated inside create_table. ' +
|
32
|
+
'to add a foreign key, use add_foreign_key', caller[0,10]
|
33
|
+
)
|
54
34
|
end
|
55
35
|
|
56
36
|
references_without_foreign_keys(*(args << options))
|
57
37
|
end
|
58
38
|
|
59
|
-
# Defines a foreign key for the table. +to_table+ can be a single Symbol, or
|
60
|
-
# an Array of Symbols. See SchemaStatements#add_foreign_key
|
61
|
-
#
|
62
|
-
# ===== Examples
|
63
|
-
# ====== Creating a simple foreign key
|
64
|
-
# t.foreign_key(:people)
|
65
|
-
# ====== Defining the column
|
66
|
-
# t.foreign_key(:people, :column => :sender_id)
|
67
|
-
# ====== Creating a named foreign key
|
68
|
-
# t.foreign_key(:people, :column => :sender_id, :name => 'sender_foreign_key')
|
69
39
|
def foreign_key(to_table, options = {})
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
end
|
75
|
-
|
76
|
-
def to_sql_with_foreign_keys
|
77
|
-
sql = to_sql_without_foreign_keys
|
78
|
-
sql << ', ' << (foreign_keys * ', ') if foreign_keys.present?
|
79
|
-
sql
|
40
|
+
ActiveSupport::Deprecation.warn(
|
41
|
+
'adding a foreign key inside create_table is deprecated. ' +
|
42
|
+
'to add a foreign key, use add_foreign_key', caller[0,10]
|
43
|
+
)
|
80
44
|
end
|
81
|
-
|
82
|
-
private
|
83
|
-
def foreign_keys
|
84
|
-
@foreign_keys ||= []
|
85
|
-
end
|
86
45
|
end
|
87
46
|
end
|
88
47
|
|
@@ -105,6 +64,8 @@ module Foreigner
|
|
105
64
|
# t.foreign_key(:people, :column => :sender_id)
|
106
65
|
# ====== Creating a named foreign key
|
107
66
|
# t.foreign_key(:people, :column => :sender_id, :name => 'sender_foreign_key')
|
67
|
+
# ====== Defining the column of the +to_table+.
|
68
|
+
# t.foreign_key(:people, :column => :sender_id, :primary_key => :person_id)
|
108
69
|
def foreign_key(to_table, options = {})
|
109
70
|
@base.add_foreign_key(@table_name, to_table, options)
|
110
71
|
end
|
@@ -138,7 +99,7 @@ module Foreigner
|
|
138
99
|
polymorphic = options[:polymorphic]
|
139
100
|
fk_options = options.delete(:foreign_key)
|
140
101
|
|
141
|
-
references_without_foreign_keys(*(args << options))
|
102
|
+
references_without_foreign_keys(*(args.dup << options))
|
142
103
|
|
143
104
|
if fk_options && !polymorphic
|
144
105
|
fk_options = {} if fk_options == true
|
@@ -43,6 +43,9 @@ module Foreigner
|
|
43
43
|
# Specify the column name on the from_table that references the to_table. By default this is guessed
|
44
44
|
# to be the singular name of the to_table with "_id" suffixed. So a to_table of :posts will use "post_id"
|
45
45
|
# as the default <tt>:column</tt>.
|
46
|
+
# [:primary_key]
|
47
|
+
# Specify the column name on the to_table that is referenced by this foreign key. By default this is
|
48
|
+
# assumed to be "id".
|
46
49
|
# [:name]
|
47
50
|
# Specify the name of the foreign key constraint. This defaults to use from_table and foreign key column.
|
48
51
|
# [:dependent]
|
@@ -1,14 +1,22 @@
|
|
1
|
-
require 'foreigner/connection_adapters/sql_2003'
|
2
|
-
|
3
1
|
module Foreigner
|
4
2
|
module ConnectionAdapters
|
5
3
|
module MysqlAdapter
|
6
4
|
include Foreigner::ConnectionAdapters::Sql2003
|
7
5
|
|
6
|
+
def remove_foreign_key(table, options)
|
7
|
+
if Hash === options
|
8
|
+
foreign_key_name = foreign_key_name(table, options[:column], options)
|
9
|
+
else
|
10
|
+
foreign_key_name = foreign_key_name(table, "#{options.to_s.singularize}_id")
|
11
|
+
end
|
12
|
+
|
13
|
+
execute "ALTER TABLE #{quote_table_name(table)} DROP FOREIGN KEY #{quote_column_name(foreign_key_name)}"
|
14
|
+
end
|
15
|
+
|
8
16
|
def foreign_keys(table_name)
|
9
|
-
foreign_keys = []
|
10
17
|
fk_info = select_all %{
|
11
18
|
SELECT fk.referenced_table_name as 'to_table'
|
19
|
+
,fk.referenced_column_name as 'primary_key'
|
12
20
|
,fk.column_name as 'column'
|
13
21
|
,fk.constraint_name as 'name'
|
14
22
|
FROM information_schema.key_column_usage fk
|
@@ -19,8 +27,9 @@ module Foreigner
|
|
19
27
|
|
20
28
|
create_table_info = select_one("SHOW CREATE TABLE #{quote_table_name(table_name)}")["Create Table"]
|
21
29
|
|
22
|
-
fk_info.
|
23
|
-
options = {:column => row['column'], :name => row['name']}
|
30
|
+
fk_info.map do |row|
|
31
|
+
options = {:column => row['column'], :name => row['name'], :primary_key => row['primary_key']}
|
32
|
+
|
24
33
|
if create_table_info =~ /CONSTRAINT #{quote_column_name(row['name'])} FOREIGN KEY .* REFERENCES .* ON DELETE (CASCADE|SET NULL)/
|
25
34
|
if $1 == 'CASCADE'
|
26
35
|
options[:dependent] = :delete
|
@@ -28,10 +37,8 @@ module Foreigner
|
|
28
37
|
options[:dependent] = :nullify
|
29
38
|
end
|
30
39
|
end
|
31
|
-
|
40
|
+
ForeignKeyDefinition.new(table_name, row['to_table'], options)
|
32
41
|
end
|
33
|
-
|
34
|
-
foreign_keys
|
35
42
|
end
|
36
43
|
end
|
37
44
|
end
|
@@ -1,36 +1,46 @@
|
|
1
|
-
require 'foreigner/connection_adapters/sql_2003'
|
2
|
-
|
3
1
|
module Foreigner
|
4
2
|
module ConnectionAdapters
|
5
3
|
module PostgreSQLAdapter
|
6
4
|
include Foreigner::ConnectionAdapters::Sql2003
|
5
|
+
|
6
|
+
def remove_foreign_key(table, options)
|
7
|
+
if Hash === options
|
8
|
+
foreign_key_name = foreign_key_name(table, options[:column], options)
|
9
|
+
else
|
10
|
+
foreign_key_name = foreign_key_name(table, "#{options.to_s.singularize}_id")
|
11
|
+
end
|
12
|
+
|
13
|
+
execute "ALTER TABLE #{quote_table_name(table)} DROP CONSTRAINT #{quote_column_name(foreign_key_name)}"
|
14
|
+
end
|
7
15
|
|
8
16
|
def foreign_keys(table_name)
|
9
17
|
fk_info = select_all %{
|
10
|
-
|
18
|
+
SELECT tc.constraint_name as name
|
11
19
|
,ccu.table_name as to_table
|
20
|
+
,ccu.column_name as primary_key
|
12
21
|
,kcu.column_name as column
|
13
22
|
,rc.delete_rule as dependency
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
23
|
+
FROM information_schema.table_constraints tc
|
24
|
+
JOIN information_schema.key_column_usage kcu
|
25
|
+
USING (constraint_catalog, constraint_schema, constraint_name)
|
26
|
+
JOIN information_schema.referential_constraints rc
|
27
|
+
USING (constraint_catalog, constraint_schema, constraint_name)
|
28
|
+
JOIN information_schema.constraint_column_usage ccu
|
29
|
+
USING (constraint_catalog, constraint_schema, constraint_name)
|
30
|
+
WHERE tc.constraint_type = 'FOREIGN KEY'
|
31
|
+
AND tc.constraint_catalog = '#{@config[:database]}'
|
32
|
+
AND tc.table_name = '#{table_name}'
|
24
33
|
}
|
25
34
|
|
26
|
-
fk_info.
|
27
|
-
options = {:column => row['column'], :name => row['name']}
|
35
|
+
fk_info.map do |row|
|
36
|
+
options = {:column => row['column'], :name => row['name'], :primary_key => row['primary_key']}
|
37
|
+
|
28
38
|
if row['dependency'] == 'CASCADE'
|
29
39
|
options[:dependent] = :delete
|
30
40
|
elsif row['dependency'] == 'SET NULL'
|
31
41
|
options[:dependent] = :nullify
|
32
42
|
end
|
33
|
-
|
43
|
+
ForeignKeyDefinition.new(table_name, row['to_table'], options)
|
34
44
|
end
|
35
45
|
end
|
36
46
|
end
|
@@ -8,34 +8,20 @@ module Foreigner
|
|
8
8
|
def add_foreign_key(from_table, to_table, options = {})
|
9
9
|
column = options[:column] || "#{to_table.to_s.singularize}_id"
|
10
10
|
foreign_key_name = foreign_key_name(from_table, column, options)
|
11
|
+
primary_key = options[:primary_key] || "id"
|
12
|
+
dependency = dependency_sql(options[:dependent])
|
11
13
|
|
12
14
|
sql =
|
13
15
|
"ALTER TABLE #{quote_table_name(from_table)} " +
|
14
16
|
"ADD CONSTRAINT #{quote_column_name(foreign_key_name)} " +
|
15
|
-
|
16
|
-
|
17
|
-
execute(sql)
|
18
|
-
end
|
19
|
-
|
20
|
-
def foreign_key_definition(to_table, options = {})
|
21
|
-
column = options[:column] || "#{to_table.to_s.singularize}_id"
|
22
|
-
dependency = dependency_sql(options[:dependent])
|
17
|
+
"FOREIGN KEY (#{quote_column_name(column)}) " +
|
18
|
+
"REFERENCES #{quote_table_name(ActiveRecord::Migrator.proper_table_name(to_table))}(#{primary_key})"
|
23
19
|
|
24
|
-
sql = "FOREIGN KEY (#{quote_column_name(column)}) REFERENCES #{quote_table_name(to_table)}(id)"
|
25
20
|
sql << " #{dependency}" unless dependency.blank?
|
26
|
-
|
21
|
+
|
22
|
+
execute(sql)
|
27
23
|
end
|
28
24
|
|
29
|
-
def remove_foreign_key(table, options)
|
30
|
-
if Hash === options
|
31
|
-
foreign_key_name = foreign_key_name(table, options[:column], options)
|
32
|
-
else
|
33
|
-
foreign_key_name = foreign_key_name(table, "#{options.to_s.singularize}_id")
|
34
|
-
end
|
35
|
-
|
36
|
-
execute "ALTER TABLE #{quote_table_name(table)} DROP FOREIGN KEY #{quote_column_name(foreign_key_name)}"
|
37
|
-
end
|
38
|
-
|
39
25
|
private
|
40
26
|
def foreign_key_name(table, column, options = {})
|
41
27
|
if options[:name]
|
@@ -33,8 +33,14 @@ module Foreigner
|
|
33
33
|
add_foreign_key_statements = foreign_keys.map do |foreign_key|
|
34
34
|
statement_parts = [ ('add_foreign_key ' + foreign_key.from_table.inspect) ]
|
35
35
|
statement_parts << foreign_key.to_table.inspect
|
36
|
-
statement_parts << (':column => ' + foreign_key.options[:column].inspect)
|
37
36
|
statement_parts << (':name => ' + foreign_key.options[:name].inspect)
|
37
|
+
|
38
|
+
if foreign_key.options[:column] != "#{foreign_key.to_table.singularize}_id"
|
39
|
+
statement_parts << (':column => ' + foreign_key.options[:column].inspect)
|
40
|
+
end
|
41
|
+
if foreign_key.options[:primary_key] != 'id'
|
42
|
+
statement_parts << (':primary_key => ' + foreign_key.options[:primary_key].inspect)
|
43
|
+
end
|
38
44
|
if foreign_key.options[:dependent].present?
|
39
45
|
statement_parts << (':dependent => ' + foreign_key.options[:dependent].inspect)
|
40
46
|
end
|
data/lib/foreigner.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'foreigner/connection_adapters/abstract/schema_statements'
|
2
2
|
require 'foreigner/connection_adapters/abstract/schema_definitions'
|
3
|
+
require 'foreigner/connection_adapters/sql_2003'
|
3
4
|
require 'foreigner/schema_dumper'
|
4
5
|
|
5
6
|
module ActiveRecord
|
@@ -13,8 +14,12 @@ module ActiveRecord
|
|
13
14
|
end
|
14
15
|
|
15
16
|
Base.class_eval do
|
16
|
-
if
|
17
|
-
require "foreigner/connection_adapters/#{
|
17
|
+
if %w(SQLite).include? connection.adapter_name
|
18
|
+
require "foreigner/connection_adapters/#{connection_adapter_name.downcase}_adapter"
|
19
|
+
end
|
20
|
+
if %w(mysql postgresql).include? connection_pool.spec.config[:adapter].downcase
|
21
|
+
require "foreigner/connection_adapters/#{connection_pool.spec.config[:adapter].downcase}_adapter"
|
18
22
|
end
|
19
23
|
end
|
20
|
-
end
|
24
|
+
end
|
25
|
+
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dwilkie-foreigner
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Wilkie
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date:
|
12
|
+
date: 2010-02-01 00:00:00 +07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -26,9 +26,7 @@ files:
|
|
26
26
|
- Rakefile
|
27
27
|
- README
|
28
28
|
- lib/foreigner.rb
|
29
|
-
- lib/foreigner
|
30
29
|
- lib/foreigner/schema_dumper.rb
|
31
|
-
- lib/foreigner/connection_adapters
|
32
30
|
- lib/foreigner/connection_adapters/sql_2003.rb
|
33
31
|
- lib/foreigner/connection_adapters/mysql_adapter.rb
|
34
32
|
- lib/foreigner/connection_adapters/postgresql_adapter.rb
|
@@ -37,9 +35,10 @@ files:
|
|
37
35
|
- lib/foreigner/connection_adapters/abstract/schema_statements.rb
|
38
36
|
- test/helper.rb
|
39
37
|
- test/mysql_adapter_test.rb
|
40
|
-
has_rdoc:
|
38
|
+
has_rdoc: true
|
41
39
|
homepage: http://github.com/dwilkie/foreigner/tree/master
|
42
|
-
licenses:
|
40
|
+
licenses: []
|
41
|
+
|
43
42
|
post_install_message:
|
44
43
|
rdoc_options:
|
45
44
|
- --line-numbers
|