dwilkie-foreigner 0.3 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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
- fk_options = options.delete(:foreign_key)
50
-
51
- if fk_options && !options[:polymorphic]
52
- fk_options = {} if fk_options == true
53
- args.each { |to_table| foreign_key(to_table, fk_options) }
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
- if @base.supports_foreign_keys?
71
- to_table = to_table.to_s.pluralize if ActiveRecord::Base.pluralize_table_names
72
- foreign_keys << ForeignKey.new(@base, to_table, options)
73
- end
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.each do |row|
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
- foreign_keys << ForeignKeyDefinition.new(table_name, row['to_table'], options)
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
- select tc.constraint_name as name
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
- from information_schema.table_constraints tc
15
- join information_schema.key_column_usage kcu
16
- using (constraint_catalog, constraint_schema, constraint_name)
17
- join information_schema.referential_constraints rc
18
- using (constraint_catalog, constraint_schema, constraint_name)
19
- join information_schema.constraint_column_usage ccu
20
- using (constraint_catalog, constraint_schema, constraint_name)
21
- where tc.constraint_type = 'FOREIGN KEY'
22
- and tc.constraint_catalog = '#{@config[:database]}'
23
- and tc.table_name = '#{table_name}'
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.inject([]) do |foreign_keys, row|
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
- foreign_keys << ForeignKeyDefinition.new(table_name, row['to_table'], options)
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
- foreign_key_definition(to_table, options)
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
- sql
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 ['MySQL', 'PostgreSQL', 'SQLite'].include? connection.adapter_name
17
- require "foreigner/connection_adapters/#{connection.adapter_name.downcase}_adapter"
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: "0.3"
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: 2009-09-16 00:00:00 -07:00
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: false
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