foreigner 0.9.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.
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 [name of plugin creator]
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,92 @@
1
+ = Foreigner
2
+
3
+ Rails does not come with methods to add foreign keys. Foreigner introduces a few
4
+ methods to your migrations for adding and removing foreign key constraints.
5
+
6
+ Since each adapter implements the API, migrations using Foreigner will continue to
7
+ work on databases that do not support foreign keys, such as sqlite3.
8
+
9
+ == Installation
10
+
11
+ In Rails 2, install as a gem by adding the following to config/environment.rb:
12
+
13
+ config.gem 'foreigner'
14
+
15
+ In Rails 3, install as a gem by adding the following to your Gemfile:
16
+
17
+ gem 'foreigner'
18
+
19
+ == API
20
+
21
+ An adapter implementing the Foreigner API implements three methods.
22
+ (Options are documented in connection_adapters/abstract/schema_definitions.rb):
23
+
24
+ add_foreign_key(from_table, to_table, options)
25
+ remove_foreign_key(from_table, options)
26
+ foreign_keys(table_name)
27
+
28
+ == Example
29
+
30
+ The most common use of foreign keys is to reference a table that a model belongs to.
31
+ For example, given the following model:
32
+
33
+ class Comment < ActiveRecord::Base
34
+ belongs_to :post
35
+ end
36
+
37
+ class Post < ActiveRecord::Base
38
+ has_many :comments, :dependent => :delete_all
39
+ end
40
+
41
+ You should add a foreign key in your migration:
42
+
43
+ add_foreign_key(:comments, :posts)
44
+
45
+ The :dependent option can be moved from the has_many definition to the foreign key:
46
+
47
+ add_foreign_key(:comments, :posts, :dependent => :delete)
48
+
49
+ If the column is named article_id instead of post_id, use the :column option:
50
+
51
+ add_foreign_key(:comments, :posts, :column => 'article_id')
52
+
53
+ Lastly, a name can be specified for the foreign key constraint:
54
+
55
+ add_foreign_key(:comments, :posts, :name => 'comment_article_foreign_key')
56
+
57
+ == Create/Change Table Shorthand
58
+
59
+ Foreigner adds extra behavior to change_table, which lets you define foreign keys using shorthand.
60
+
61
+ Add a missing foreign key to comments:
62
+
63
+ change_table :comments do |t|
64
+ t.foreign_key :posts, :dependent => :delete
65
+ end
66
+
67
+ t.foreign_key accepts the same options as add_foreign_key.
68
+
69
+
70
+ == Additional t.references option
71
+
72
+ Foreigner extends table.references with the :foreign_key option. Pass true, and the default
73
+ foreign key options are used:
74
+
75
+ change_table :comments do |t|
76
+ t.references :post, :foreign_key => true
77
+ end
78
+
79
+ An options hash can also be passed. It accepts the same options as add_foreign_key:
80
+
81
+ change_table :comments do |t|
82
+ t.references :author, :foreign_key => {:dependent => :restrict}
83
+ end
84
+
85
+ By default, t.references will not generate a foreign key.
86
+
87
+ == schema.rb
88
+
89
+ Similar to indexes, the foreign keys in your database are automatically dumped to schema.rb.
90
+ This allows you to use foreign keys without switching to the :sql schema.
91
+
92
+ Copyright (c) 2009 Matthew Higgins, released under the MIT license
@@ -0,0 +1,23 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ desc 'Default: run unit tests.'
6
+ task :default => :test
7
+
8
+ desc 'Test the foreigner plugin.'
9
+ Rake::TestTask.new(:test) do |t|
10
+ t.libs << 'lib'
11
+ t.libs << 'test'
12
+ t.pattern = 'test/**/*_test.rb'
13
+ t.verbose = true
14
+ end
15
+
16
+ desc 'Generate documentation for the foreigner plugin.'
17
+ Rake::RDocTask.new(:rdoc) do |rdoc|
18
+ rdoc.rdoc_dir = 'rdoc'
19
+ rdoc.title = 'Foreigner'
20
+ rdoc.options << '--line-numbers' << '--inline-source'
21
+ rdoc.rdoc_files.include('README')
22
+ rdoc.rdoc_files.include('lib/**/*.rb')
23
+ end
@@ -0,0 +1,53 @@
1
+ require 'foreigner/connection_adapters/abstract/schema_statements'
2
+ require 'foreigner/connection_adapters/abstract/schema_definitions'
3
+ require 'foreigner/connection_adapters/sql_2003'
4
+ require 'foreigner/schema_dumper'
5
+
6
+ module Foreigner
7
+ class << self
8
+ def adapters
9
+ @@adapters ||= {}
10
+ end
11
+
12
+ def register(adapter_name, file_name)
13
+ adapters[adapter_name] = file_name
14
+ end
15
+
16
+ def load_adapter!
17
+ ActiveRecord::ConnectionAdapters.module_eval do
18
+ include Foreigner::ConnectionAdapters::SchemaStatements
19
+ include Foreigner::ConnectionAdapters::SchemaDefinitions
20
+ end
21
+
22
+ ActiveRecord::SchemaDumper.class_eval do
23
+ include Foreigner::SchemaDumper
24
+ end
25
+
26
+ if adapters.key?(configured_adapter)
27
+ require adapters[configured_adapter]
28
+ end
29
+ end
30
+
31
+ def configured_adapter
32
+ ActiveRecord::Base.connection_pool.spec.config[:adapter]
33
+ end
34
+ end
35
+ end
36
+
37
+ Foreigner.register 'mysql', 'foreigner/connection_adapters/mysql_adapter'
38
+ Foreigner.register 'mysql2', 'foreigner/connection_adapters/mysql_adapter'
39
+ Foreigner.register 'postgresql', 'foreigner/connection_adapters/postgresql_adapter'
40
+
41
+ if defined?(Rails::Railtie)
42
+ module Foreigner
43
+ class Railtie < Rails::Railtie
44
+ initializer 'foreigner.load_adapter' do
45
+ ActiveSupport.on_load :active_record do
46
+ Foreigner.load_adapter!
47
+ end
48
+ end
49
+ end
50
+ end
51
+ else
52
+ Foreigner.load_adapter!
53
+ end
@@ -0,0 +1,78 @@
1
+ module Foreigner
2
+ module ConnectionAdapters
3
+ class ForeignKeyDefinition < Struct.new(:from_table, :to_table, :options) #:nodoc:
4
+ end
5
+
6
+ module SchemaDefinitions
7
+ def self.included(base)
8
+ base::Table.class_eval do
9
+ include Foreigner::ConnectionAdapters::Table
10
+ end
11
+ end
12
+ end
13
+
14
+ module Table
15
+ def self.included(base)
16
+ base.class_eval do
17
+ include InstanceMethods
18
+ alias_method_chain :references, :foreign_keys
19
+ end
20
+ end
21
+
22
+ module InstanceMethods
23
+ # Adds a new foreign key to the table. +to_table+ can be a single Symbol, or
24
+ # an Array of Symbols. See SchemaStatements#add_foreign_key
25
+ #
26
+ # ===== Examples
27
+ # ====== Creating a simple foreign key
28
+ # t.foreign_key(:people)
29
+ # ====== Defining the column
30
+ # t.foreign_key(:people, :column => :sender_id)
31
+ # ====== Creating a named foreign key
32
+ # t.foreign_key(:people, :column => :sender_id, :name => 'sender_foreign_key')
33
+ # ====== Defining the column of the +to_table+.
34
+ # t.foreign_key(:people, :column => :sender_id, :primary_key => :person_id)
35
+ def foreign_key(to_table, options = {})
36
+ @base.add_foreign_key(@table_name, to_table, options)
37
+ end
38
+
39
+ # Remove the given foreign key from the table.
40
+ #
41
+ # ===== Examples
42
+ # ====== Remove the suppliers_company_id_fk in the suppliers table.
43
+ # t.remove_foreign_key :companies
44
+ # ====== Remove the foreign key named accounts_branch_id_fk in the accounts table.
45
+ # remove_foreign_key :column => :branch_id
46
+ # ====== Remove the foreign key named party_foreign_key in the accounts table.
47
+ # remove_index :name => :party_foreign_key
48
+ def remove_foreign_key(options = {})
49
+ @base.remove_foreign_key(@table_name, options)
50
+ end
51
+
52
+ # Adds a :foreign_key option to Table.references.
53
+ # If :foreign_key is true, a foreign key constraint is added to the table.
54
+ # You can also specify a hash, which is passed as foreign key options.
55
+ #
56
+ # ===== Examples
57
+ # ====== Add goat_id column and a foreign key to the goats table.
58
+ # t.references(:goat, :foreign_key => true)
59
+ # ====== Add goat_id column and a cascading foreign key to the goats table.
60
+ # t.references(:goat, :foreign_key => {:dependent => :delete})
61
+ #
62
+ # Note: No foreign key is created if :polymorphic => true is used.
63
+ def references_with_foreign_keys(*args)
64
+ options = args.extract_options!
65
+ polymorphic = options[:polymorphic]
66
+ fk_options = options.delete(:foreign_key)
67
+
68
+ references_without_foreign_keys(*(args.dup << options))
69
+
70
+ if fk_options && !polymorphic
71
+ fk_options = {} if fk_options == true
72
+ args.each { |to_table| foreign_key(to_table, fk_options) }
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,75 @@
1
+ module Foreigner
2
+ module ConnectionAdapters
3
+ module SchemaStatements
4
+ def self.included(base)
5
+ base::AbstractAdapter.class_eval do
6
+ include Foreigner::ConnectionAdapters::AbstractAdapter
7
+ end
8
+ end
9
+ end
10
+
11
+ module AbstractAdapter
12
+ def supports_foreign_keys?
13
+ false
14
+ end
15
+
16
+ # Adds a new foreign key to the +from_table+, referencing the primary key of +to_table+
17
+ #
18
+ # The foreign key will be named after the from and to tables unless you pass
19
+ # <tt>:name</tt> as an option.
20
+ #
21
+ # ===== Examples
22
+ # ====== Creating a foreign key
23
+ # add_foreign_key(:comments, :posts)
24
+ # generates
25
+ # ALTER TABLE `comments` ADD CONSTRAINT
26
+ # `comments_post_id_fk` FOREIGN KEY (`post_id`) REFERENCES `posts` (`id`)
27
+ #
28
+ # ====== Creating a named foreign key
29
+ # add_foreign_key(:comments, :posts, :name => 'comments_belongs_to_posts')
30
+ # generates
31
+ # ALTER TABLE `comments` ADD CONSTRAINT
32
+ # `comments_belongs_to_posts` FOREIGN KEY (`post_id`) REFERENCES `posts` (`id`)
33
+ #
34
+ # ====== Creating a cascading foreign_key on a custom column
35
+ # add_foreign_key(:people, :people, :column => 'best_friend_id', :dependent => :nullify)
36
+ # generates
37
+ # ALTER TABLE `people` ADD CONSTRAINT
38
+ # `people_best_friend_id_fk` FOREIGN KEY (`best_friend_id`) REFERENCES `people` (`id`)
39
+ # ON DELETE SET NULL
40
+ #
41
+ # === Supported options
42
+ # [:column]
43
+ # Specify the column name on the from_table that references the to_table. By default this is guessed
44
+ # to be the singular name of the to_table with "_id" suffixed. So a to_table of :posts will use "post_id"
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".
49
+ # [:name]
50
+ # Specify the name of the foreign key constraint. This defaults to use from_table and foreign key column.
51
+ # [:dependent]
52
+ # If set to <tt>:delete</tt>, the associated records in from_table are deleted when records in to_table table are deleted.
53
+ # If set to <tt>:nullify</tt>, the foreign key column is set to +NULL+.
54
+ def add_foreign_key(from_table, to_table, options = {})
55
+ end
56
+
57
+ # Remove the given foreign key from the table.
58
+ #
59
+ # ===== Examples
60
+ # ====== Remove the suppliers_company_id_fk in the suppliers table.
61
+ # remove_foreign_key :suppliers, :companies
62
+ # ====== Remove the foreign key named accounts_branch_id_fk in the accounts table.
63
+ # remove_foreign_key :accounts, :column => :branch_id
64
+ # ====== Remove the foreign key named party_foreign_key in the accounts table.
65
+ # remove_foreign_key :accounts, :name => :party_foreign_key
66
+ def remove_foreign_key(from_table, options)
67
+ end
68
+
69
+ # Return the foreign keys for the schema_dumper
70
+ def foreign_keys(table_name)
71
+ []
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,54 @@
1
+ module Foreigner
2
+ module ConnectionAdapters
3
+ module MysqlAdapter
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 FOREIGN KEY #{quote_column_name(foreign_key_name)}"
14
+ end
15
+
16
+ def foreign_keys(table_name)
17
+ fk_info = select_all %{
18
+ SELECT fk.referenced_table_name as 'to_table'
19
+ ,fk.referenced_column_name as 'primary_key'
20
+ ,fk.column_name as 'column'
21
+ ,fk.constraint_name as 'name'
22
+ FROM information_schema.key_column_usage fk
23
+ WHERE fk.referenced_column_name is not null
24
+ AND fk.table_schema = '#{@config[:database]}'
25
+ AND fk.table_name = '#{table_name}'
26
+ }
27
+
28
+ create_table_info = select_one("SHOW CREATE TABLE #{quote_table_name(table_name)}")["Create Table"]
29
+
30
+ fk_info.map do |row|
31
+ options = {:column => row['column'], :name => row['name'], :primary_key => row['primary_key']}
32
+
33
+ if create_table_info =~ /CONSTRAINT #{quote_column_name(row['name'])} FOREIGN KEY .* REFERENCES .* ON DELETE (CASCADE|SET NULL|RESTRICT)/
34
+ options[:dependent] = case $1
35
+ when 'CASCADE' then :delete
36
+ when 'SET NULL' then :nullify
37
+ when 'RESTRICT' then :restrict
38
+ end
39
+ end
40
+ ForeignKeyDefinition.new(table_name, row['to_table'], options)
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+ [:MysqlAdapter, :Mysql2Adapter, :JdbcAdapter].each do |adapter|
48
+ begin
49
+ ActiveRecord::ConnectionAdapters.const_get(adapter).class_eval do
50
+ include Foreigner::ConnectionAdapters::MysqlAdapter
51
+ end
52
+ rescue
53
+ end
54
+ end
@@ -0,0 +1,58 @@
1
+ module Foreigner
2
+ module ConnectionAdapters
3
+ module PostgreSQLAdapter
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
15
+
16
+ def foreign_keys(table_name)
17
+ fk_info = select_all %{
18
+ SELECT tc.constraint_name as name
19
+ ,ccu.table_name as to_table
20
+ ,ccu.column_name as primary_key
21
+ ,kcu.column_name as column
22
+ ,rc.delete_rule as dependency
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}'
33
+ }
34
+
35
+ fk_info.map do |row|
36
+ options = {:column => row['column'], :name => row['name'], :primary_key => row['primary_key']}
37
+
38
+ options[:dependent] = case row['dependency']
39
+ when 'CASCADE' then :delete
40
+ when 'SET NULL' then :nullify
41
+ when 'RESTRICT' then :restrict
42
+ end
43
+
44
+ ForeignKeyDefinition.new(table_name, row['to_table'], options)
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+
51
+ [:PostgreSQLAdapter, :JdbcAdapter].each do |adapter|
52
+ begin
53
+ ActiveRecord::ConnectionAdapters.const_get(adapter).class_eval do
54
+ include Foreigner::ConnectionAdapters::PostgreSQLAdapter
55
+ end
56
+ rescue
57
+ end
58
+ end
@@ -0,0 +1,43 @@
1
+ module Foreigner
2
+ module ConnectionAdapters
3
+ module Sql2003
4
+ def supports_foreign_keys?
5
+ true
6
+ end
7
+
8
+ def add_foreign_key(from_table, to_table, options = {})
9
+ column = options[:column] || "#{to_table.to_s.singularize}_id"
10
+ foreign_key_name = foreign_key_name(from_table, column, options)
11
+ primary_key = options[:primary_key] || "id"
12
+ dependency = dependency_sql(options[:dependent])
13
+
14
+ sql =
15
+ "ALTER TABLE #{quote_table_name(from_table)} " +
16
+ "ADD CONSTRAINT #{quote_column_name(foreign_key_name)} " +
17
+ "FOREIGN KEY (#{quote_column_name(column)}) " +
18
+ "REFERENCES #{quote_table_name(ActiveRecord::Migrator.proper_table_name(to_table))}(#{primary_key})"
19
+ sql << " #{dependency}" if dependency.present?
20
+
21
+ execute(sql)
22
+ end
23
+
24
+ private
25
+ def foreign_key_name(table, column, options = {})
26
+ if options[:name]
27
+ options[:name]
28
+ else
29
+ "#{table}_#{column}_fk"
30
+ end
31
+ end
32
+
33
+ def dependency_sql(dependency)
34
+ case dependency
35
+ when :nullify then "ON DELETE SET NULL"
36
+ when :delete then "ON DELETE CASCADE"
37
+ when :restrict then "ON DELETE RESTRICT"
38
+ else ""
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,45 @@
1
+ module Foreigner
2
+ module SchemaDumper
3
+ def self.included(base)
4
+ base.class_eval do
5
+ include InstanceMethods
6
+ alias_method_chain :tables, :foreign_keys
7
+ end
8
+ end
9
+
10
+ module InstanceMethods
11
+ def tables_with_foreign_keys(stream)
12
+ tables_without_foreign_keys(stream)
13
+ @connection.tables.sort.each do |table|
14
+ foreign_keys(table, stream)
15
+ end
16
+ end
17
+
18
+ private
19
+ def foreign_keys(table_name, stream)
20
+ if (foreign_keys = @connection.foreign_keys(table_name)).any?
21
+ add_foreign_key_statements = foreign_keys.map do |foreign_key|
22
+ statement_parts = [ ('add_foreign_key ' + foreign_key.from_table.inspect) ]
23
+ statement_parts << foreign_key.to_table.inspect
24
+ statement_parts << (':name => ' + foreign_key.options[:name].inspect)
25
+
26
+ if foreign_key.options[:column] != "#{foreign_key.to_table.singularize}_id"
27
+ statement_parts << (':column => ' + foreign_key.options[:column].inspect)
28
+ end
29
+ if foreign_key.options[:primary_key] != 'id'
30
+ statement_parts << (':primary_key => ' + foreign_key.options[:primary_key].inspect)
31
+ end
32
+ if foreign_key.options[:dependent].present?
33
+ statement_parts << (':dependent => ' + foreign_key.options[:dependent].inspect)
34
+ end
35
+
36
+ ' ' + statement_parts.join(', ')
37
+ end
38
+
39
+ stream.puts add_foreign_key_statements.sort.join("\n")
40
+ stream.puts
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,8 @@
1
+ require 'test/unit'
2
+ require 'rubygems'
3
+ require 'active_support'
4
+ require 'active_support/test_case'
5
+ require 'active_record'
6
+ require 'active_record/test_case'
7
+ require 'active_record/connection_adapters/mysql_adapter'
8
+ require 'foreigner'
@@ -0,0 +1,91 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class MysqlAdapterTest < ActiveRecord::TestCase
4
+ include Foreigner::MysqlAdapter
5
+
6
+ def test_add_without_options
7
+ assert_equal(
8
+ "ALTER TABLE `employees` ADD CONSTRAINT `employees_company_id_fk` FOREIGN KEY (`company_id`) REFERENCES `companies`(id)",
9
+ add_foreign_key(:employees, :companies)
10
+ )
11
+ end
12
+
13
+ def test_add_with_name
14
+ assert_equal(
15
+ "ALTER TABLE `employees` ADD CONSTRAINT `favorite_company_fk` FOREIGN KEY (`company_id`) REFERENCES `companies`(id)",
16
+ add_foreign_key(:employees, :companies, :name => 'favorite_company_fk')
17
+ )
18
+ end
19
+
20
+ def test_add_with_column
21
+ assert_equal(
22
+ "ALTER TABLE `employees` ADD CONSTRAINT `employees_last_employer_id_fk` FOREIGN KEY (`last_employer_id`) REFERENCES `companies`(id)",
23
+ add_foreign_key(:employees, :companies, :column => 'last_employer_id')
24
+ )
25
+ end
26
+
27
+ def test_add_with_column_and_name
28
+ assert_equal(
29
+ "ALTER TABLE `employees` ADD CONSTRAINT `favorite_company_fk` FOREIGN KEY (`last_employer_id`) REFERENCES `companies`(id)",
30
+ add_foreign_key(:employees, :companies, :column => 'last_employer_id', :name => 'favorite_company_fk')
31
+ )
32
+ end
33
+
34
+ def test_add_with_delete_dependency
35
+ assert_equal(
36
+ "ALTER TABLE `employees` ADD CONSTRAINT `employees_company_id_fk` FOREIGN KEY (`company_id`) REFERENCES `companies`(id) " +
37
+ "ON DELETE CASCADE",
38
+ add_foreign_key(:employees, :companies, :dependent => :delete)
39
+ )
40
+ end
41
+
42
+ def test_add_with_nullify_dependency
43
+ assert_equal(
44
+ "ALTER TABLE `employees` ADD CONSTRAINT `employees_company_id_fk` FOREIGN KEY (`company_id`) REFERENCES `companies`(id) " +
45
+ "ON DELETE SET NULL",
46
+ add_foreign_key(:employees, :companies, :dependent => :nullify)
47
+ )
48
+ end
49
+
50
+ def test_add_with_restrict_dependency
51
+ assert_equal(
52
+ "ALTER TABLE `employees` ADD CONSTRAINT `employees_company_id_fk` FOREIGN KEY (`company_id`) REFERENCES `companies`(id) " +
53
+ "ON DELETE RESTRICT",
54
+ add_foreign_key(:employees, :companies, :dependent => :restrict)
55
+ )
56
+ end
57
+
58
+ def test_remove_by_table
59
+ assert_equal(
60
+ "ALTER TABLE `suppliers` DROP FOREIGN KEY `suppliers_company_id_fk`",
61
+ remove_foreign_key(:suppliers, :companies)
62
+ )
63
+ end
64
+
65
+ def test_remove_by_name
66
+ assert_equal(
67
+ "ALTER TABLE `suppliers` DROP FOREIGN KEY `belongs_to_supplier`",
68
+ remove_foreign_key(:suppliers, :name => "belongs_to_supplier")
69
+ )
70
+ end
71
+
72
+ def test_remove_by_column
73
+ assert_equal(
74
+ "ALTER TABLE `suppliers` DROP FOREIGN KEY `suppliers_ship_to_id_fk`",
75
+ remove_foreign_key(:suppliers, :column => "ship_to_id")
76
+ )
77
+ end
78
+
79
+ private
80
+ def execute(sql, name = nil)
81
+ sql
82
+ end
83
+
84
+ def quote_column_name(name)
85
+ "`#{name}`"
86
+ end
87
+
88
+ def quote_table_name(name)
89
+ quote_column_name(name).gsub('.', '`.`')
90
+ end
91
+ end
metadata ADDED
@@ -0,0 +1,82 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: foreigner
3
+ version: !ruby/object:Gem::Version
4
+ hash: 59
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 9
9
+ - 0
10
+ version: 0.9.0
11
+ platform: ruby
12
+ authors:
13
+ - Matthew Higgins
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-09-21 00:00:00 -07:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: Adds helpers to migrations and correctly dumps foreign keys to schema.rb
23
+ email: developer@matthewhiggins.com
24
+ executables: []
25
+
26
+ extensions: []
27
+
28
+ extra_rdoc_files:
29
+ - README.rdoc
30
+ files:
31
+ - MIT-LICENSE
32
+ - Rakefile
33
+ - README.rdoc
34
+ - lib/foreigner/connection_adapters/abstract/schema_definitions.rb
35
+ - lib/foreigner/connection_adapters/abstract/schema_statements.rb
36
+ - lib/foreigner/connection_adapters/mysql_adapter.rb
37
+ - lib/foreigner/connection_adapters/postgresql_adapter.rb
38
+ - lib/foreigner/connection_adapters/sql_2003.rb
39
+ - lib/foreigner/schema_dumper.rb
40
+ - lib/foreigner.rb
41
+ - test/helper.rb
42
+ - test/mysql_adapter_test.rb
43
+ has_rdoc: true
44
+ homepage: http://github.com/matthuhiggins/foreigner
45
+ licenses: []
46
+
47
+ post_install_message:
48
+ rdoc_options: []
49
+
50
+ require_paths:
51
+ - lib
52
+ required_ruby_version: !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ hash: 59
58
+ segments:
59
+ - 1
60
+ - 8
61
+ - 6
62
+ version: 1.8.6
63
+ required_rubygems_version: !ruby/object:Gem::Requirement
64
+ none: false
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ hash: 17
69
+ segments:
70
+ - 1
71
+ - 3
72
+ - 5
73
+ version: 1.3.5
74
+ requirements: []
75
+
76
+ rubyforge_project: foreigner
77
+ rubygems_version: 1.3.7
78
+ signing_key:
79
+ specification_version: 3
80
+ summary: Foreign keys for Rails
81
+ test_files: []
82
+