frac-foreigner 0.0.1

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,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
+ A name can be specified for the foreign key constraint:
54
+
55
+ add_foreign_key(:comments, :posts, :name => 'comment_article_foreign_key')
56
+
57
+ == 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
data/Rakefile ADDED
@@ -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 frac-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 = 'Frac-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,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,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,68 @@
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 add_primary_key(table,options)
17
+ constraint_name = "pk_#{table}_#{options[:column]}"
18
+ execute "ALTER TABLE #{table} ADD CONSTRAINT #{constraint_name} PRIMARY KEY (#{options[:column]})"
19
+ end
20
+
21
+ def remove_primary_key(table, options)
22
+ constraint_name = "pk_#{table}_#{options[:column]}"
23
+ execute "ALTER TABLE #{table} DROP CONSTRAINT #{constraint_name}"
24
+ end
25
+
26
+ def foreign_keys(table_name)
27
+ fk_info = select_all %{
28
+ SELECT tc.constraint_name as name
29
+ ,ccu.table_name as to_table
30
+ ,ccu.column_name as primary_key
31
+ ,kcu.column_name as column
32
+ ,rc.delete_rule as dependency
33
+ FROM information_schema.table_constraints tc
34
+ JOIN information_schema.key_column_usage kcu
35
+ USING (constraint_catalog, constraint_schema, constraint_name)
36
+ JOIN information_schema.referential_constraints rc
37
+ USING (constraint_catalog, constraint_schema, constraint_name)
38
+ JOIN information_schema.constraint_column_usage ccu
39
+ USING (constraint_catalog, constraint_schema, constraint_name)
40
+ WHERE tc.constraint_type = 'FOREIGN KEY'
41
+ AND tc.constraint_catalog = '#{@config[:database]}'
42
+ AND tc.table_name = '#{table_name}'
43
+ }
44
+
45
+ fk_info.map do |row|
46
+ options = {:column => row['column'], :name => row['name'], :primary_key => row['primary_key']}
47
+
48
+ options[:dependent] = case row['dependency']
49
+ when 'CASCADE' then :delete
50
+ when 'SET NULL' then :nullify
51
+ when 'RESTRICT' then :restrict
52
+ end
53
+
54
+ ForeignKeyDefinition.new(table_name, row['to_table'], options)
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+
61
+ [:PostgreSQLAdapter, :JdbcAdapter].each do |adapter|
62
+ begin
63
+ ActiveRecord::ConnectionAdapters.const_get(adapter).class_eval do
64
+ include Foreigner::ConnectionAdapters::PostgreSQLAdapter
65
+ end
66
+ rescue
67
+ end
68
+ end
@@ -0,0 +1,44 @@
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
+ sql << " #{options[:options]}" if options[:options]
21
+
22
+ execute(sql)
23
+ end
24
+
25
+ private
26
+ def foreign_key_name(table, column, options = {})
27
+ if options[:name]
28
+ options[:name]
29
+ else
30
+ "#{table}_#{column}_fk"
31
+ end
32
+ end
33
+
34
+ def dependency_sql(dependency)
35
+ case dependency
36
+ when :nullify then "ON DELETE SET NULL"
37
+ when :delete then "ON DELETE CASCADE"
38
+ when :restrict then "ON DELETE RESTRICT"
39
+ else ""
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,90 @@
1
+ module Foreigner
2
+ module ConnectionAdapters
3
+ module SqlserverAdapter
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
+ execute "IF EXISTS (SELECT 1 from sys.objects where name = '#{foreign_key_name}') ALTER TABLE #{table} DROP CONSTRAINT #{foreign_key_name}"
13
+ end
14
+
15
+ def add_primary_key(table,options)
16
+ constraint_name = "pk_#{table}_#{options[:column]}"
17
+ execute "alter table #{table} add constraint #{constraint_name} primary key (#{options[:column]})"
18
+ end
19
+
20
+ def remove_primary_key(table, options)
21
+ constraint_name = "pk_#{table}_#{options[:column]}"
22
+ execute "alter table #{table} drop constraint #{constraint_name}"
23
+ end
24
+
25
+
26
+ def pk(table_name)
27
+ pk_info = select_all %{
28
+ select c.COLUMN_NAME as 'pk'
29
+ from INFORMATION_SCHEMA.TABLE_CONSTRAINTS pk ,
30
+ INFORMATION_SCHEMA.KEY_COLUMN_USAGE c
31
+ where pk.TABLE_NAME = '#{table_name}'
32
+ and CONSTRAINT_TYPE = 'PRIMARY KEY'
33
+ and c.TABLE_NAME = pk.TABLE_NAME
34
+ and c.CONSTRAINT_NAME = pk.CONSTRAINT_NAME
35
+ }
36
+ pk_info.map do |row|
37
+ options = {:pk => row['pk']}
38
+ options
39
+ end
40
+ end
41
+
42
+ def foreign_keys(table_name)
43
+ fk_info = select_all %{
44
+ SELECT
45
+ 'column' = CU.COLUMN_NAME,
46
+ to_table = PK.TABLE_NAME,
47
+ primary_key = PT.COLUMN_NAME,
48
+ 'name' = C.CONSTRAINT_NAME
49
+ FROM
50
+ INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS C
51
+ INNER JOIN
52
+ INFORMATION_SCHEMA.TABLE_CONSTRAINTS FK
53
+ ON C.CONSTRAINT_NAME = FK.CONSTRAINT_NAME
54
+ INNER JOIN
55
+ INFORMATION_SCHEMA.TABLE_CONSTRAINTS PK
56
+ ON C.UNIQUE_CONSTRAINT_NAME = PK.CONSTRAINT_NAME
57
+ INNER JOIN
58
+ INFORMATION_SCHEMA.KEY_COLUMN_USAGE CU
59
+ ON C.CONSTRAINT_NAME = CU.CONSTRAINT_NAME
60
+ INNER JOIN
61
+ (
62
+ SELECT
63
+ i1.TABLE_NAME, i2.COLUMN_NAME
64
+ FROM
65
+ INFORMATION_SCHEMA.TABLE_CONSTRAINTS i1
66
+ INNER JOIN
67
+ INFORMATION_SCHEMA.KEY_COLUMN_USAGE i2
68
+ ON i1.CONSTRAINT_NAME = i2.CONSTRAINT_NAME
69
+ WHERE i1.CONSTRAINT_TYPE = 'PRIMARY KEY'
70
+ ) PT ON PT.TABLE_NAME = PK.TABLE_NAME
71
+ WHERE FK.TABLE_NAME= '#{table_name}'
72
+ }
73
+
74
+ fk_info.map do |row|
75
+ options = {:column => row['column'], :name => row['name'], :primary_key => row['primary_key']}
76
+ ForeignKeyDefinition.new(table_name, row['to_table'], options)
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
82
+
83
+ [:SQLServerAdapter].each do |adapter|
84
+ begin
85
+ ActiveRecord::ConnectionAdapters.const_get(adapter).class_eval do
86
+ include Foreigner::ConnectionAdapters::SqlserverAdapter
87
+ end
88
+ rescue
89
+ end
90
+ end
@@ -0,0 +1,81 @@
1
+ module Foreigner
2
+ module SchemaDumper
3
+
4
+ def self.included(base)
5
+ base.class_eval do
6
+ include InstanceMethods
7
+ alias_method_chain :tables, :foreign_keys
8
+ end
9
+ end
10
+
11
+ module InstanceMethods
12
+ def tables_with_foreign_keys(stream)
13
+ @connection.tables.sort.each do |table|
14
+ remove_foreign_keys(table, stream)
15
+ end
16
+ tables_without_foreign_keys(stream)
17
+ @connection.tables.sort.each do |table|
18
+ primary_keys(table, stream)
19
+ end
20
+ @connection.tables.sort.each do |table|
21
+ foreign_keys(table, stream)
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def remove_foreign_keys(table_name, stream)
28
+ if (foreign_keys = @connection.foreign_keys(table_name)).any?
29
+ remove_foreign_key_statements = foreign_keys.map do |foreign_key|
30
+ statement_parts = [('remove_foreign_key ' + foreign_key.from_table.inspect)]
31
+ statement_parts << (':name => ' + foreign_key.options[:name].inspect)
32
+ ' ' + statement_parts.join(', ')
33
+ end
34
+
35
+ stream.puts remove_foreign_key_statements.sort.join("\n")
36
+ stream.puts
37
+ end
38
+ end
39
+
40
+ def primary_keys(table_name,stream)
41
+ if (primary_keys = @connection.pk(table_name)).any? && table_name != "sysdiagrams"
42
+ add_primary_keys_statement = primary_keys.map do |primary_key|
43
+ if primary_key[:pk] != 'id'
44
+ statement_parts = [('add_primary_key ' + table_name.inspect)]
45
+ statement_parts << (':column => ' + primary_key[:pk].inspect)
46
+ ' ' + statement_parts.join(', ')
47
+ end
48
+ end
49
+ stream.puts add_primary_keys_statement.sort.join("\n")
50
+ stream.puts
51
+
52
+ end
53
+ end
54
+
55
+ def foreign_keys(table_name, stream)
56
+ if (foreign_keys = @connection.foreign_keys(table_name)).any?
57
+ add_foreign_key_statements = foreign_keys.map do |foreign_key|
58
+ statement_parts = [('add_foreign_key ' + foreign_key.from_table.inspect)]
59
+ statement_parts << foreign_key.to_table.inspect
60
+ statement_parts << (':name => ' + foreign_key.options[:name].inspect)
61
+
62
+ if foreign_key.options[:column] != "#{foreign_key.to_table.singularize}_id"
63
+ statement_parts << (':column => ' + foreign_key.options[:column].inspect)
64
+ end
65
+ if foreign_key.options[:primary_key] != 'id'
66
+ statement_parts << (':primary_key => ' + foreign_key.options[:primary_key].inspect)
67
+ end
68
+ if foreign_key.options[:dependent].present?
69
+ statement_parts << (':dependent => ' + foreign_key.options[:dependent].inspect)
70
+ end
71
+
72
+ ' ' + statement_parts.join(', ')
73
+ end
74
+
75
+ stream.puts add_foreign_key_statements.sort.join("\n")
76
+ stream.puts
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,52 @@
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 'postgresql', 'foreigner/connection_adapters/postgresql_adapter'
38
+ Foreigner.register 'sqlserver', 'foreigner/connection_adapters/sqlserver_adapter'
39
+
40
+ if defined?(Rails::Railtie)
41
+ module Foreigner
42
+ class Railtie < Rails::Railtie
43
+ initializer 'foreigner.load_adapter' do
44
+ ActiveSupport.on_load :active_record do
45
+ Foreigner.load_adapter!
46
+ end
47
+ end
48
+ end
49
+ end
50
+ else
51
+ Foreigner.load_adapter!
52
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,5 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'rails/all'
4
+
5
+ require 'foreigner'
@@ -0,0 +1,100 @@
1
+ require 'helper'
2
+ require 'foreigner/connection_adapters/mysql_adapter'
3
+
4
+ class MysqlAdapterTest < ActiveRecord::TestCase
5
+ include Foreigner::ConnectionAdapters::MysqlAdapter
6
+
7
+ def test_add_without_options
8
+ assert_equal(
9
+ "ALTER TABLE `employees` ADD CONSTRAINT `employees_company_id_fk` FOREIGN KEY (`company_id`) REFERENCES `companies`(id)",
10
+ add_foreign_key(:employees, :companies)
11
+ )
12
+ end
13
+
14
+ def test_add_with_name
15
+ assert_equal(
16
+ "ALTER TABLE `employees` ADD CONSTRAINT `favorite_company_fk` FOREIGN KEY (`company_id`) REFERENCES `companies`(id)",
17
+ add_foreign_key(:employees, :companies, :name => 'favorite_company_fk')
18
+ )
19
+ end
20
+
21
+ def test_add_with_column
22
+ assert_equal(
23
+ "ALTER TABLE `employees` ADD CONSTRAINT `employees_last_employer_id_fk` FOREIGN KEY (`last_employer_id`) REFERENCES `companies`(id)",
24
+ add_foreign_key(:employees, :companies, :column => 'last_employer_id')
25
+ )
26
+ end
27
+
28
+ def test_add_with_column_and_name
29
+ assert_equal(
30
+ "ALTER TABLE `employees` ADD CONSTRAINT `favorite_company_fk` FOREIGN KEY (`last_employer_id`) REFERENCES `companies`(id)",
31
+ add_foreign_key(:employees, :companies, :column => 'last_employer_id', :name => 'favorite_company_fk')
32
+ )
33
+ end
34
+
35
+ def test_add_with_delete_dependency
36
+ assert_equal(
37
+ "ALTER TABLE `employees` ADD CONSTRAINT `employees_company_id_fk` FOREIGN KEY (`company_id`) REFERENCES `companies`(id) " +
38
+ "ON DELETE CASCADE",
39
+ add_foreign_key(:employees, :companies, :dependent => :delete)
40
+ )
41
+ end
42
+
43
+ def test_add_with_nullify_dependency
44
+ assert_equal(
45
+ "ALTER TABLE `employees` ADD CONSTRAINT `employees_company_id_fk` FOREIGN KEY (`company_id`) REFERENCES `companies`(id) " +
46
+ "ON DELETE SET NULL",
47
+ add_foreign_key(:employees, :companies, :dependent => :nullify)
48
+ )
49
+ end
50
+
51
+ def test_add_with_restrict_dependency
52
+ assert_equal(
53
+ "ALTER TABLE `employees` ADD CONSTRAINT `employees_company_id_fk` FOREIGN KEY (`company_id`) REFERENCES `companies`(id) " +
54
+ "ON DELETE RESTRICT",
55
+ add_foreign_key(:employees, :companies, :dependent => :restrict)
56
+ )
57
+ end
58
+
59
+ def test_add_with_options
60
+ assert_equal(
61
+ "ALTER TABLE `employees` ADD CONSTRAINT `employees_company_id_fk` FOREIGN KEY (`company_id`) REFERENCES `companies`(id) " +
62
+ "on delete foo",
63
+ add_foreign_key(:employees, :companies, :options => 'on delete foo')
64
+ )
65
+ end
66
+
67
+ def test_remove_by_table
68
+ assert_equal(
69
+ "ALTER TABLE `suppliers` DROP FOREIGN KEY `suppliers_company_id_fk`",
70
+ remove_foreign_key(:suppliers, :companies)
71
+ )
72
+ end
73
+
74
+ def test_remove_by_name
75
+ assert_equal(
76
+ "ALTER TABLE `suppliers` DROP FOREIGN KEY `belongs_to_supplier`",
77
+ remove_foreign_key(:suppliers, :name => "belongs_to_supplier")
78
+ )
79
+ end
80
+
81
+ def test_remove_by_column
82
+ assert_equal(
83
+ "ALTER TABLE `suppliers` DROP FOREIGN KEY `suppliers_ship_to_id_fk`",
84
+ remove_foreign_key(:suppliers, :column => "ship_to_id")
85
+ )
86
+ end
87
+
88
+ private
89
+ def execute(sql, name = nil)
90
+ sql
91
+ end
92
+
93
+ def quote_column_name(name)
94
+ "`#{name}`"
95
+ end
96
+
97
+ def quote_table_name(name)
98
+ quote_column_name(name).gsub('.', '`.`')
99
+ end
100
+ end
metadata ADDED
@@ -0,0 +1,57 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: frac-foreigner
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Cloned by Matthew Higgins
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-04-05 00:00:00.000000000Z
13
+ dependencies: []
14
+ description: ''
15
+ email: ''
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files:
19
+ - README.rdoc
20
+ files:
21
+ - MIT-LICENSE
22
+ - Rakefile
23
+ - README.rdoc
24
+ - lib/foreigner/schema_dumper.rb
25
+ - lib/foreigner/connection_adapters/sqlserver_adapter.rb
26
+ - lib/foreigner/connection_adapters/sql_2003.rb
27
+ - lib/foreigner/connection_adapters/postgresql_adapter.rb
28
+ - lib/foreigner/connection_adapters/abstract/schema_definitions.rb
29
+ - lib/foreigner/connection_adapters/abstract/schema_statements.rb
30
+ - lib/frac-foreigner.rb
31
+ - test/mysql_adapter_test.rb
32
+ - test/helper.rb
33
+ homepage: ''
34
+ licenses: []
35
+ post_install_message:
36
+ rdoc_options: []
37
+ require_paths:
38
+ - lib
39
+ required_ruby_version: !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ! '>='
43
+ - !ruby/object:Gem::Version
44
+ version: 1.8.6
45
+ required_rubygems_version: !ruby/object:Gem::Requirement
46
+ none: false
47
+ requirements:
48
+ - - ! '>='
49
+ - !ruby/object:Gem::Version
50
+ version: 1.3.5
51
+ requirements: []
52
+ rubyforge_project: frac-foreigner
53
+ rubygems_version: 1.7.1
54
+ signing_key:
55
+ specification_version: 3
56
+ summary: Foreigner adapted to SQLServer and with (partial) natural pk support
57
+ test_files: []