ws-foreigner 1.2.2

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/MIT-LICENSE ADDED
@@ -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.
data/README.rdoc ADDED
@@ -0,0 +1,70 @@
1
+ = Foreigner
2
+
3
+ Foreigner introduces a few methods to your migrations for adding and removing foreign key constraints. It also dumps foreign keys to schema.rb.
4
+
5
+ The following adapters are supported:
6
+
7
+ * mysql2
8
+ * postgres
9
+ * sqlite (foreign key methods are a no-op)
10
+
11
+ == Installation
12
+
13
+ Add the following to your Gemfile:
14
+
15
+ gem 'foreigner'
16
+
17
+ == API Examples
18
+
19
+ Foreigner adds two methods to migrations.
20
+
21
+ * add_foreign_key(from_table, to_table, options)
22
+ * remove_foreign_key(from_table, options)
23
+
24
+ (Options are documented in connection_adapters/abstract/schema_definitions.rb):
25
+
26
+ For example, given the following model:
27
+
28
+ class Comment < ActiveRecord::Base
29
+ belongs_to :post
30
+ end
31
+
32
+ class Post < ActiveRecord::Base
33
+ has_many :comments, :dependent => :delete_all
34
+ end
35
+
36
+ You should add a foreign key in your migration:
37
+
38
+ add_foreign_key(:comments, :posts)
39
+
40
+ The :dependent option can be moved from the has_many definition to the foreign key:
41
+
42
+ add_foreign_key(:comments, :posts, :dependent => :delete)
43
+
44
+ If the column is named article_id instead of post_id, use the :column option:
45
+
46
+ add_foreign_key(:comments, :posts, :column => 'article_id')
47
+
48
+ A name can be specified for the foreign key constraint:
49
+
50
+ add_foreign_key(:comments, :posts, :name => 'comment_article_foreign_key')
51
+
52
+ == Change Table Methods
53
+
54
+ Foreigner adds extra methods to change_table.
55
+
56
+ Add a missing foreign key to comments:
57
+
58
+ change_table :comments do |t|
59
+ t.foreign_key :posts, :dependent => :delete
60
+ end
61
+
62
+ Remove an unwanted foreign key:
63
+
64
+ change_table :comments do |t|
65
+ t.remove_foreign_key :users
66
+ end
67
+
68
+ == License
69
+
70
+ Copyright (c) 2011 Matthew Higgins, released under the MIT license
data/Rakefile ADDED
@@ -0,0 +1,18 @@
1
+ require 'rake'
2
+ # begin
3
+ # require 'bundler/setup'
4
+ # rescue LoadError
5
+ # puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ # end
7
+
8
+ desc 'Default: run unit tests.'
9
+ task :default => :test
10
+
11
+ require 'rake/testtask'
12
+ desc 'Test the foreigner plugin.'
13
+ Rake::TestTask.new(:test) do |t|
14
+ t.libs << 'lib'
15
+ t.libs << 'test'
16
+ t.pattern = 'test/**/*_test.rb'
17
+ t.verbose = true
18
+ end
data/lib/foreigner.rb ADDED
@@ -0,0 +1,28 @@
1
+ require 'active_support/all'
2
+
3
+ module Foreigner
4
+ extend ActiveSupport::Autoload
5
+ autoload :Adapter
6
+ autoload :SchemaDumper
7
+
8
+ module ConnectionAdapters
9
+ extend ActiveSupport::Autoload
10
+ autoload :Sql2003
11
+
12
+ autoload_under 'abstract' do
13
+ autoload :SchemaDefinitions
14
+ autoload :SchemaStatements
15
+ end
16
+ end
17
+
18
+ module Migration
19
+ autoload :CommandRecorder, 'foreigner/migration/command_recorder'
20
+ end
21
+ end
22
+
23
+ Foreigner::Adapter.register 'mysql', 'foreigner/connection_adapters/mysql_adapter'
24
+ Foreigner::Adapter.register 'mysql2', 'foreigner/connection_adapters/mysql2_adapter'
25
+ Foreigner::Adapter.register 'jdbcmysql', 'foreigner/connection_adapters/mysql2_adapter'
26
+ Foreigner::Adapter.register 'postgresql', 'foreigner/connection_adapters/postgresql_adapter'
27
+
28
+ require 'foreigner/railtie' if defined?(Rails)
@@ -0,0 +1,22 @@
1
+ module Foreigner
2
+ class Adapter
3
+ class_attribute :registered
4
+ self.registered = {}
5
+
6
+ class << self
7
+ def register(adapter_name, file_name)
8
+ registered[adapter_name] = file_name
9
+ end
10
+
11
+ def load!
12
+ if registered.key?(configured_name)
13
+ require registered[configured_name]
14
+ end
15
+ end
16
+
17
+ def configured_name
18
+ ActiveRecord::Base.connection_pool.spec.config[:adapter]
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,70 @@
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
+ extend ActiveSupport::Concern
16
+
17
+ included do
18
+ alias_method_chain :references, :foreign_keys
19
+ end
20
+
21
+ # Adds a new foreign key to the table. +to_table+ can be a single Symbol, or
22
+ # an Array of Symbols. See SchemaStatements#add_foreign_key
23
+ #
24
+ # ===== Examples
25
+ # ====== Creating a simple foreign key
26
+ # t.foreign_key(:people)
27
+ # ====== Defining the column
28
+ # t.foreign_key(:people, :column => :sender_id)
29
+ # ====== Creating a named foreign key
30
+ # t.foreign_key(:people, :column => :sender_id, :name => 'sender_foreign_key')
31
+ # ====== Defining the column of the +to_table+.
32
+ # t.foreign_key(:people, :column => :sender_id, :primary_key => :person_id)
33
+ def foreign_key(to_table, options = {})
34
+ @base.add_foreign_key(@table_name, to_table, options)
35
+ end
36
+
37
+ # Remove the given foreign key from the table.
38
+ #
39
+ # ===== Examples
40
+ # ====== Remove the suppliers_company_id_fk in the suppliers table.
41
+ # change_table :suppliers do |t|
42
+ # t.remove_foreign_key :companies
43
+ # end
44
+ # ====== Remove the foreign key named accounts_branch_id_fk in the accounts table.
45
+ # change_table :accounts do |t|
46
+ # t.remove_foreign_key :column => :branch_id
47
+ # end
48
+ # ====== Remove the foreign key named party_foreign_key in the accounts table.
49
+ # change_table :accounts do |t|
50
+ # t.remove_index :name => :party_foreign_key
51
+ # end
52
+ def remove_foreign_key(options)
53
+ @base.remove_foreign_key(@table_name, options)
54
+ end
55
+
56
+ # Deprecated
57
+ def references_with_foreign_keys(*args)
58
+ options = args.extract_options!
59
+
60
+ if fk_options = options.delete(:foreign_key)
61
+ p ActiveSupport::Deprecation.send(:deprecation_message, caller,
62
+ ":foreign_key in t.references is deprecated. " \
63
+ "Use t.foreign_key instead")
64
+ end
65
+
66
+ references_without_foreign_keys(*(args.dup << options))
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,77 @@
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
+ # [:options]
55
+ # Any extra options you want appended to the foreign key definition.
56
+ def add_foreign_key(from_table, to_table, options = {})
57
+ end
58
+
59
+ # Remove the given foreign key from the table.
60
+ #
61
+ # ===== Examples
62
+ # ====== Remove the suppliers_company_id_fk in the suppliers table.
63
+ # remove_foreign_key :suppliers, :companies
64
+ # ====== Remove the foreign key named accounts_branch_id_fk in the accounts table.
65
+ # remove_foreign_key :accounts, :column => :branch_id
66
+ # ====== Remove the foreign key named party_foreign_key in the accounts table.
67
+ # remove_foreign_key :accounts, :name => :party_foreign_key
68
+ def remove_foreign_key(from_table, options)
69
+ end
70
+
71
+ # Return the foreign keys for the schema_dumper
72
+ def foreign_keys(table_name)
73
+ []
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,54 @@
1
+ module Foreigner
2
+ module ConnectionAdapters
3
+ module Mysql2Adapter
4
+ include Foreigner::ConnectionAdapters::Sql2003
5
+
6
+ def remove_foreign_key_sql(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
+ "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
+ [:Mysql2Adapter, :JdbcAdapter].each do |adapter|
48
+ begin
49
+ ActiveRecord::ConnectionAdapters.const_get(adapter).class_eval do
50
+ include Foreigner::ConnectionAdapters::Mysql2Adapter
51
+ end
52
+ rescue
53
+ end
54
+ end
@@ -0,0 +1 @@
1
+ p "WARNING: Please upgrade to mysql2. The old mysql adapter is not supported by foreigner."
@@ -0,0 +1,44 @@
1
+ module Foreigner
2
+ module ConnectionAdapters
3
+ module PostgreSQLAdapter
4
+ include Foreigner::ConnectionAdapters::Sql2003
5
+
6
+ def foreign_keys(table_name)
7
+ fk_info = select_all %{
8
+ SELECT t2.relname AS to_table, a1.attname AS column, a2.attname AS primary_key, c.conname AS name, c.confdeltype AS dependency
9
+ FROM pg_constraint c
10
+ JOIN pg_class t1 ON c.conrelid = t1.oid
11
+ JOIN pg_class t2 ON c.confrelid = t2.oid
12
+ JOIN pg_attribute a1 ON a1.attnum = c.conkey[1] AND a1.attrelid = t1.oid
13
+ JOIN pg_attribute a2 ON a2.attnum = c.confkey[1] AND a2.attrelid = t2.oid
14
+ JOIN pg_namespace t3 ON c.connamespace = t3.oid
15
+ WHERE c.contype = 'f'
16
+ AND t1.relname = '#{table_name}'
17
+ AND t3.nspname = ANY (current_schemas(false))
18
+ ORDER BY c.conname
19
+ }
20
+
21
+ fk_info.map do |row|
22
+ options = {:column => row['column'], :name => row['name'], :primary_key => row['primary_key']}
23
+
24
+ options[:dependent] = case row['dependency']
25
+ when 'c' then :delete
26
+ when 'n' then :nullify
27
+ when 'r' then :restrict
28
+ end
29
+
30
+ ForeignKeyDefinition.new(table_name, row['to_table'], options)
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ [:PostgreSQLAdapter, :JdbcAdapter].each do |adapter|
38
+ begin
39
+ ActiveRecord::ConnectionAdapters.const_get(adapter).class_eval do
40
+ include Foreigner::ConnectionAdapters::PostgreSQLAdapter
41
+ end
42
+ rescue
43
+ end
44
+ end
@@ -0,0 +1,66 @@
1
+ module Foreigner
2
+ module ConnectionAdapters
3
+ module Sql2003
4
+ def supports_foreign_keys?
5
+ true
6
+ end
7
+
8
+ def drop_table(*args)
9
+ disable_referential_integrity { super }
10
+ end
11
+
12
+ def add_foreign_key(from_table, to_table, options = {})
13
+ sql = "ALTER TABLE #{quote_table_name(from_table)} #{add_foreign_key_sql(from_table, to_table, options)}"
14
+ execute(sql)
15
+ end
16
+
17
+ def add_foreign_key_sql(from_table, to_table, options = {})
18
+ column = options[:column] || "#{to_table.to_s.singularize}_id"
19
+ foreign_key_name = foreign_key_name(from_table, column, options)
20
+ primary_key = options[:primary_key] || "id"
21
+ dependency = dependency_sql(options[:dependent])
22
+
23
+ sql =
24
+ "ADD CONSTRAINT #{quote_column_name(foreign_key_name)} " +
25
+ "FOREIGN KEY (#{quote_column_name(column)}) " +
26
+ "REFERENCES #{quote_table_name(ActiveRecord::Migrator.proper_table_name(to_table))}(#{primary_key})"
27
+ sql << " #{dependency}" if dependency.present?
28
+ sql << " #{options[:options]}" if options[:options]
29
+
30
+ sql
31
+ end
32
+
33
+ def remove_foreign_key(table, options)
34
+ execute "ALTER TABLE #{quote_table_name(table)} #{remove_foreign_key_sql(table, options)}"
35
+ end
36
+
37
+ def remove_foreign_key_sql(table, options)
38
+ if Hash === options
39
+ foreign_key_name = foreign_key_name(table, options[:column], options)
40
+ else
41
+ foreign_key_name = foreign_key_name(table, "#{options.to_s.singularize}_id")
42
+ end
43
+
44
+ "DROP CONSTRAINT #{quote_column_name(foreign_key_name)}"
45
+ end
46
+
47
+ private
48
+ def foreign_key_name(table, column, options = {})
49
+ if options[:name]
50
+ options[:name]
51
+ else
52
+ "#{table}_#{column}_fk"
53
+ end
54
+ end
55
+
56
+ def dependency_sql(dependency)
57
+ case dependency
58
+ when :nullify then "ON DELETE SET NULL"
59
+ when :delete then "ON DELETE CASCADE"
60
+ when :restrict then "ON DELETE RESTRICT"
61
+ else ""
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,28 @@
1
+ module Foreigner
2
+ module Migration
3
+ module CommandRecorder
4
+ def add_foreign_key(*args)
5
+ record(:add_foreign_key, args)
6
+ end
7
+
8
+ def remove_foreign_key(*args)
9
+ record(:remove_foreign_key, args)
10
+ end
11
+
12
+ def invert_add_foreign_key(args)
13
+ from_table, to_table, add_options = *args
14
+ add_options ||= {}
15
+
16
+ if add_options[:name]
17
+ options = {:name => add_options[:name]}
18
+ elsif add_options[:column]
19
+ options = {:column => add_options[:column]}
20
+ else
21
+ options = to_table
22
+ end
23
+
24
+ [:remove_foreign_key, [from_table, options]]
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,24 @@
1
+ module Foreigner
2
+ class Railtie < Rails::Railtie
3
+ initializer 'foreigner.load_adapter' do
4
+ ActiveSupport.on_load :active_record do
5
+ ActiveRecord::ConnectionAdapters.module_eval do
6
+ include Foreigner::ConnectionAdapters::SchemaStatements
7
+ include Foreigner::ConnectionAdapters::SchemaDefinitions
8
+ end
9
+
10
+ ActiveRecord::SchemaDumper.class_eval do
11
+ include Foreigner::SchemaDumper
12
+ end
13
+
14
+ if defined?(ActiveRecord::Migration::CommandRecorder)
15
+ ActiveRecord::Migration::CommandRecorder.class_eval do
16
+ include Foreigner::Migration::CommandRecorder
17
+ end
18
+ end
19
+
20
+ Foreigner::Adapter.load!
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,50 @@
1
+ module Foreigner
2
+ module SchemaDumper
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ alias_method_chain :tables, :foreign_keys
7
+ end
8
+
9
+ def tables_with_foreign_keys(stream)
10
+ tables_without_foreign_keys(stream)
11
+ @connection.tables.sort.each do |table|
12
+ next if ['schema_migrations', ignore_tables].flatten.any? do |ignored|
13
+ case ignored
14
+ when String; table == ignored
15
+ when Regexp; table =~ ignored
16
+ else
17
+ raise StandardError, 'ActiveRecord::SchemaDumper.ignore_tables accepts an array of String and / or Regexp values.'
18
+ end
19
+ end
20
+ foreign_keys(table, stream)
21
+ end
22
+ end
23
+
24
+ private
25
+ def foreign_keys(table_name, stream)
26
+ if (foreign_keys = @connection.foreign_keys(table_name)).any?
27
+ add_foreign_key_statements = foreign_keys.map do |foreign_key|
28
+ statement_parts = [ ('add_foreign_key ' + foreign_key.from_table.inspect) ]
29
+ statement_parts << foreign_key.to_table.inspect
30
+ statement_parts << (':name => ' + foreign_key.options[:name].inspect)
31
+
32
+ if foreign_key.options[:column] != "#{foreign_key.to_table.singularize}_id"
33
+ statement_parts << (':column => ' + foreign_key.options[:column].inspect)
34
+ end
35
+ if foreign_key.options[:primary_key] != 'id'
36
+ statement_parts << (':primary_key => ' + foreign_key.options[:primary_key].inspect)
37
+ end
38
+ if foreign_key.options[:dependent].present?
39
+ statement_parts << (':dependent => ' + foreign_key.options[:dependent].inspect)
40
+ end
41
+
42
+ ' ' + statement_parts.join(', ')
43
+ end
44
+
45
+ stream.puts add_foreign_key_statements.sort.join("\n")
46
+ stream.puts
47
+ end
48
+ end
49
+ end
50
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,43 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'active_record'
4
+
5
+ require File.expand_path('../../lib/foreigner', __FILE__)
6
+
7
+ # Foreigner::Adapter.registered.values.each do |file_name|
8
+ # require file_name
9
+ # end
10
+
11
+ module Foreigner
12
+ class UnitTest < ActiveSupport::TestCase
13
+ private
14
+ def execute(sql, name = nil)
15
+ sql_statements << sql
16
+ sql
17
+ end
18
+
19
+ def quote_column_name(name)
20
+ "`#{name}`"
21
+ end
22
+
23
+ def quote_table_name(name)
24
+ quote_column_name(name).gsub('.', '`.`')
25
+ end
26
+
27
+ def sql_statements
28
+ @sql_statements ||= []
29
+ end
30
+ end
31
+
32
+ class IntegrationTest < ActiveSupport::TestCase
33
+ def with_migration(&blk)
34
+ migration = Class.new(ActiveRecord::Migration)
35
+
36
+ migration.singleton_class do
37
+ define_method(:up, &blk)
38
+ end
39
+
40
+ migration
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,40 @@
1
+ require 'helper'
2
+
3
+ ActiveRecord::Migration::CommandRecorder.class_eval do
4
+ include ::Foreigner::Migration::CommandRecorder
5
+ end
6
+
7
+ class Foreigner::CommandRecorderTest < Foreigner::UnitTest
8
+ def setup
9
+ @recorder = ActiveRecord::Migration::CommandRecorder.new
10
+ end
11
+
12
+ test 'invert_add_foreign_key' do
13
+ @recorder.add_foreign_key(:employees, :companies)
14
+ remove = @recorder.inverse.first
15
+ assert_equal [:remove_foreign_key, [:employees, :companies]], remove
16
+ end
17
+
18
+ test 'invert_add_foreign_key with column' do
19
+ @recorder.add_foreign_key(:employees, :companies, :column => :place_id)
20
+ remove = @recorder.inverse.first
21
+ assert_equal [:remove_foreign_key, [:employees, {:column => :place_id}]], remove
22
+ end
23
+
24
+ test 'invert_add_foreign_key with name' do
25
+ @recorder.add_foreign_key(:employees, :companies, :name => 'the_best_fk', :column => :place_id)
26
+ remove = @recorder.inverse.first
27
+ assert_equal [:remove_foreign_key, [:employees, {:name => 'the_best_fk'}]], remove
28
+
29
+ @recorder.record :rename_table, [:old, :new]
30
+ rename = @recorder.inverse.first
31
+ assert_equal [:rename_table, [:new, :old]], rename
32
+ end
33
+
34
+ test 'remove_foreign_key is irreversible' do
35
+ @recorder.remove_foreign_key(:employees, :companies)
36
+ assert_raise ActiveRecord::IrreversibleMigration do
37
+ @recorder.inverse
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,27 @@
1
+ require 'helper'
2
+ require 'foreigner/connection_adapters/mysql2_adapter'
3
+
4
+ class Foreigner::Mysql2AdapterTest < Foreigner::UnitTest
5
+ include Foreigner::ConnectionAdapters::Mysql2Adapter
6
+
7
+ test 'remove_foreign_key_sql by table' do
8
+ assert_equal(
9
+ "DROP FOREIGN KEY `suppliers_company_id_fk`",
10
+ remove_foreign_key_sql(:suppliers, :companies)
11
+ )
12
+ end
13
+
14
+ test 'remove_foreign_key_sql by name' do
15
+ assert_equal(
16
+ "DROP FOREIGN KEY `belongs_to_supplier`",
17
+ remove_foreign_key_sql(:suppliers, :name => "belongs_to_supplier")
18
+ )
19
+ end
20
+
21
+ test 'remove_foreign_key_sql by column' do
22
+ assert_equal(
23
+ "DROP FOREIGN KEY `suppliers_ship_to_id_fk`",
24
+ remove_foreign_key_sql(:suppliers, :column => "ship_to_id")
25
+ )
26
+ end
27
+ end
@@ -0,0 +1,10 @@
1
+ require 'helper'
2
+
3
+ class Foreigner::MysqlAdapterTest < Foreigner::UnitTest
4
+ test 'warning' do
5
+ output = capture(:stdout) do
6
+ require 'foreigner/connection_adapters/mysql_adapter'
7
+ end
8
+ assert_match /WARNING: Please upgrade to mysql2. The old mysql adapter is not supported by foreigner./, output
9
+ end
10
+ end
@@ -0,0 +1,6 @@
1
+ require 'helper'
2
+ require 'foreigner/connection_adapters/postgresql_adapter'
3
+
4
+ class Foreigner::PostgreSQLAdapterTest < Foreigner::UnitTest
5
+ include Foreigner::ConnectionAdapters::PostgreSQLAdapter
6
+ end
@@ -0,0 +1,44 @@
1
+ require 'helper'
2
+
3
+ class Foreigner::SchemaDumperTest < Foreigner::UnitTest
4
+
5
+ class MockConnection
6
+ def tables
7
+ [ 'foo', 'bar' ]
8
+ end
9
+ end
10
+
11
+ class MockSchemaDumper
12
+ cattr_accessor :ignore_tables, :processed_tables
13
+ @@ignore_table = []
14
+ @@processed_tables = []
15
+
16
+ @connection = MockConnection.new
17
+
18
+ # need this here so ActiveRecord::Concern has something to redefine
19
+ def tables
20
+ end
21
+
22
+ include Foreigner::SchemaDumper
23
+
24
+ # override this method so we don't have to mock up
25
+ # all of the necessary scafolding for things to work
26
+ def foreign_keys(table, stream)
27
+ processed_tables << table
28
+ end
29
+
30
+ def tables(ignore_list)
31
+ ignore_tables = ignore_list
32
+ processed_table = nil
33
+ end
34
+ end
35
+
36
+ test 'returns_all_tables' do
37
+ assert MockSchemaDumper.new(nil).processed_tables.sort.to_s, "['bar', 'foo']"
38
+ end
39
+
40
+ test 'only_returns_1_table' do
41
+ assert MockSchemaDumper.new('foo').processed_tables.to_s, "['bar']"
42
+ end
43
+ end
44
+
@@ -0,0 +1,86 @@
1
+ require 'helper'
2
+
3
+ class Foreigner::Sql2003Test < Foreigner::UnitTest
4
+ include Foreigner::ConnectionAdapters::Sql2003
5
+
6
+ test 'add_without_options' do
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
+ test 'add_with_name' do
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
+ test 'add_with_column' do
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
+ test 'add_with_column_and_name' do
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
+ test 'add_with_delete_dependency' do
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
+ test 'add_with_nullify_dependency' do
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
+ test 'add_with_restrict_dependency' do
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
+ test 'add_with_options' do
59
+ assert_equal(
60
+ "ALTER TABLE `employees` ADD CONSTRAINT `employees_company_id_fk` FOREIGN KEY (`company_id`) REFERENCES `companies`(id) " +
61
+ "on delete foo",
62
+ add_foreign_key(:employees, :companies, :options => 'on delete foo')
63
+ )
64
+ end
65
+
66
+ test 'remove_by_table' do
67
+ assert_equal(
68
+ "ALTER TABLE `suppliers` DROP CONSTRAINT `suppliers_company_id_fk`",
69
+ remove_foreign_key(:suppliers, :companies)
70
+ )
71
+ end
72
+
73
+ test 'remove_by_name' do
74
+ assert_equal(
75
+ "ALTER TABLE `suppliers` DROP CONSTRAINT `belongs_to_supplier`",
76
+ remove_foreign_key(:suppliers, :name => "belongs_to_supplier")
77
+ )
78
+ end
79
+
80
+ test 'remove_by_column' do
81
+ assert_equal(
82
+ "ALTER TABLE `suppliers` DROP CONSTRAINT `suppliers_ship_to_id_fk`",
83
+ remove_foreign_key(:suppliers, :column => "ship_to_id")
84
+ )
85
+ end
86
+ end
metadata ADDED
@@ -0,0 +1,90 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ws-foreigner
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.2.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - ! 'Matthew Higgins // fork: polo ornelas'
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-01-05 00:00:00.000000000 -06:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: activerecord
17
+ requirement: &70162592211660 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: 3.1.0
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: *70162592211660
26
+ - !ruby/object:Gem::Dependency
27
+ name: activerecord
28
+ requirement: &70162592211200 !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: 3.1.0
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: *70162592211200
37
+ description: Adds helpers to migrations and dumps foreign keys to schema.rb
38
+ email: ! 'developer@matthewhiggins.com // fork: poloornelas@yahoo.com'
39
+ executables: []
40
+ extensions: []
41
+ extra_rdoc_files:
42
+ - README.rdoc
43
+ files:
44
+ - MIT-LICENSE
45
+ - Rakefile
46
+ - README.rdoc
47
+ - lib/foreigner/adapter.rb
48
+ - lib/foreigner/connection_adapters/abstract/schema_definitions.rb
49
+ - lib/foreigner/connection_adapters/abstract/schema_statements.rb
50
+ - lib/foreigner/connection_adapters/mysql2_adapter.rb
51
+ - lib/foreigner/connection_adapters/mysql_adapter.rb
52
+ - lib/foreigner/connection_adapters/postgresql_adapter.rb
53
+ - lib/foreigner/connection_adapters/sql2003.rb
54
+ - lib/foreigner/migration/command_recorder.rb
55
+ - lib/foreigner/railtie.rb
56
+ - lib/foreigner/schema_dumper.rb
57
+ - lib/foreigner.rb
58
+ - test/helper.rb
59
+ - test/unit/command_recorder_test.rb
60
+ - test/unit/mysql2_adapter_test.rb
61
+ - test/unit/mysql_adapter_test.rb
62
+ - test/unit/postgresql_adapter_test.rb
63
+ - test/unit/schema_dumper_test.rb
64
+ - test/unit/sql2003_test.rb
65
+ has_rdoc: true
66
+ homepage: https://github.com/warstories/foreigner
67
+ licenses: []
68
+ post_install_message:
69
+ rdoc_options: []
70
+ require_paths:
71
+ - lib
72
+ required_ruby_version: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: 1.8.7
78
+ required_rubygems_version: !ruby/object:Gem::Requirement
79
+ none: false
80
+ requirements:
81
+ - - ! '>='
82
+ - !ruby/object:Gem::Version
83
+ version: 1.3.5
84
+ requirements: []
85
+ rubyforge_project: foreigner
86
+ rubygems_version: 1.6.2
87
+ signing_key:
88
+ specification_version: 3
89
+ summary: Foreign Keys for Rails, forked to work with rails 3.1
90
+ test_files: []