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 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