Signed-off-by: Michel Loiseleur <[email protected]>
---
 src/vendor/plugins/foreigner/MIT-LICENSE           |   20 +++
 src/vendor/plugins/foreigner/README                |  106 +++++++++++++
 src/vendor/plugins/foreigner/Rakefile              |   23 +++
 src/vendor/plugins/foreigner/foreigner.gemspec     |   45 ++++++
 src/vendor/plugins/foreigner/init.rb               |    1 +
 src/vendor/plugins/foreigner/install.rb            |    1 +
 src/vendor/plugins/foreigner/lib/foreigner.rb      |   21 +++
 .../abstract/schema_definitions.rb                 |  155 ++++++++++++++++++++
 .../abstract/schema_statements.rb                  |   75 ++++++++++
 .../foreigner/connection_adapters/mysql_adapter.rb |   43 ++++++
 .../connection_adapters/postgresql_adapter.rb      |   46 ++++++
 .../lib/foreigner/connection_adapters/sql_2003.rb  |   58 ++++++++
 .../foreigner/lib/foreigner/schema_dumper.rb       |   45 ++++++
 .../plugins/foreigner/tasks/foreigner_tasks.rake   |    4 +
 src/vendor/plugins/foreigner/test/helper.rb        |    8 +
 .../plugins/foreigner/test/mysql_adapter_test.rb   |   83 +++++++++++
 src/vendor/plugins/foreigner/uninstall.rb          |    1 +
 17 files changed, 735 insertions(+), 0 deletions(-)
 create mode 100644 src/vendor/plugins/foreigner/MIT-LICENSE
 create mode 100644 src/vendor/plugins/foreigner/README
 create mode 100644 src/vendor/plugins/foreigner/Rakefile
 create mode 100644 src/vendor/plugins/foreigner/foreigner.gemspec
 create mode 100644 src/vendor/plugins/foreigner/init.rb
 create mode 100644 src/vendor/plugins/foreigner/install.rb
 create mode 100644 src/vendor/plugins/foreigner/lib/foreigner.rb
 create mode 100644 
src/vendor/plugins/foreigner/lib/foreigner/connection_adapters/abstract/schema_definitions.rb
 create mode 100644 
src/vendor/plugins/foreigner/lib/foreigner/connection_adapters/abstract/schema_statements.rb
 create mode 100644 
src/vendor/plugins/foreigner/lib/foreigner/connection_adapters/mysql_adapter.rb
 create mode 100644 
src/vendor/plugins/foreigner/lib/foreigner/connection_adapters/postgresql_adapter.rb
 create mode 100644 
src/vendor/plugins/foreigner/lib/foreigner/connection_adapters/sql_2003.rb
 create mode 100644 src/vendor/plugins/foreigner/lib/foreigner/schema_dumper.rb
 create mode 100644 src/vendor/plugins/foreigner/tasks/foreigner_tasks.rake
 create mode 100644 src/vendor/plugins/foreigner/test/helper.rb
 create mode 100644 src/vendor/plugins/foreigner/test/mysql_adapter_test.rb
 create mode 100644 src/vendor/plugins/foreigner/uninstall.rb

diff --git a/src/vendor/plugins/foreigner/MIT-LICENSE 
b/src/vendor/plugins/foreigner/MIT-LICENSE
new file mode 100644
index 0000000..9376605
--- /dev/null
+++ b/src/vendor/plugins/foreigner/MIT-LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2009 [name of plugin creator]
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/src/vendor/plugins/foreigner/README 
b/src/vendor/plugins/foreigner/README
new file mode 100644
index 0000000..4a1a8b5
--- /dev/null
+++ b/src/vendor/plugins/foreigner/README
@@ -0,0 +1,106 @@
+Foreigner
+=========
+
+Rails does not come with methods to add foreign keys. Foreigner introduces a 
few
+methods to your migrations for adding and removing foreign key constraints.
+
+Since each adapter implements the API, migrations using Foreigner will 
continue to
+work on databases that do not support foreign keys, such as sqlite3.
+
+Installation
+------------
+
+Install as a plugin:
+
+  ruby script/plugin install git://github.com/matthuhiggins/foreigner.git
+
+Install as a gem by adding the following to environment.rb:
+
+  config.gem "matthuhiggins-foreigner", :lib => "foreigner"
+
+API
+---
+
+An adapter implementing the Foreigner API implements three methods.
+(Options are documented in connection_adapters/abstract/schema_definitions.rb):
+
+  add_foreign_key(from_table, to_table, options)
+  remove_foreign_key(from_table, options)
+  foreign_keys(table_name)
+
+Example
+-------
+
+The most common use of foreign keys is to reference a table that a model 
belongs to.
+For example, given the following model:
+
+  class Comment < ActiveRecord::Base
+    belongs_to :post
+  end
+  
+  class Post < ActiveRecord::Base
+    has_many :comments, :dependent => :delete_all
+  end
+  
+You should add a foreign key in your migration:
+
+  add_foreign_key(:comments, :posts)
+
+The :dependent option can be moved from the has_many definition to the foreign 
key:
+
+  add_foreign_key(:comments, :posts, :dependent => :delete)
+
+If the column is named article_id instead of post_id, use the :column option:
+
+  add_foreign_key(:comments, :posts, :column => 'article_id')
+  
+Lastly, a name can be specified for the foreign key constraint:
+
+  add_foreign_key(:comments, :posts, :name => 'comment_article_foreign_key')
+
+Create/Change Table Shorthand
+-----------------------------
+
+Foreigner adds extra behavior to create_table and change_table, which lets you 
define foreign keys using shorthand.
+
+Create the comments table with a foreign key to posts:
+
+create_table :comments do |t|
+  t.integer :post_id
+  t.foreign_key :posts
+end
+
+Add a missing foreign key to comments:
+
+change_table :comments do |t|
+  t.foreign_key :posts, :dependent => :delete
+end
+
+t.foreign_key accepts the same options as add_foreign_key.
+
+
+Additional t.references option
+------------------------------
+
+Foreigner extends table.references with the :foreign_key option. Pass true, 
and the default
+foreign key options are used:
+
+create_table :comments do |t|
+  t.references :post, :foreign_key => true
+end
+
+An options hash can also be passed. It accepts the same options as 
add_foreign_key:
+
+change_table :comments do |t|
+  t.references :author, :foreign_key => {:dependent => :destroy}
+end
+
+By default, t.references will not generate a foreign key.
+
+schema.rb
+---------
+
+Similar to indexes, the foreign keys in your database are automatically dumped 
to schema.rb.
+This allows you to use foreign keys without fighting Rails!
+
+Copyright (c) 2009 Matthew Higgins, released under the MIT license
diff --git a/src/vendor/plugins/foreigner/Rakefile 
b/src/vendor/plugins/foreigner/Rakefile
new file mode 100644
index 0000000..122a501
--- /dev/null
+++ b/src/vendor/plugins/foreigner/Rakefile
@@ -0,0 +1,23 @@
+require 'rake'
+require 'rake/testtask'
+require 'rake/rdoctask'
+
+desc 'Default: run unit tests.'
+task :default => :test
+
+desc 'Test the foreigner plugin.'
+Rake::TestTask.new(:test) do |t|
+  t.libs << 'lib'
+  t.libs << 'test'
+  t.pattern = 'test/**/*_test.rb'
+  t.verbose = true
+end
+
+desc 'Generate documentation for the foreigner plugin.'
+Rake::RDocTask.new(:rdoc) do |rdoc|
+  rdoc.rdoc_dir = 'rdoc'
+  rdoc.title    = 'Foreigner'
+  rdoc.options << '--line-numbers' << '--inline-source'
+  rdoc.rdoc_files.include('README')
+  rdoc.rdoc_files.include('lib/**/*.rb')
+end
diff --git a/src/vendor/plugins/foreigner/foreigner.gemspec 
b/src/vendor/plugins/foreigner/foreigner.gemspec
new file mode 100644
index 0000000..c988664
--- /dev/null
+++ b/src/vendor/plugins/foreigner/foreigner.gemspec
@@ -0,0 +1,45 @@
+# -*- encoding: utf-8 -*-
+ 
+Gem::Specification.new do |s|
+  s.name = %q{foreigner}
+  s.version = "0.2.1"
+ 
+  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? 
:required_rubygems_version=
+  s.authors = ["Matthew Higgins"]
+  s.date = %q{2009-09-07}
+  s.email = %q{[email protected]}
+  s.extra_rdoc_files = ["README"]
+  s.files = %w(
+    MIT-LICENSE
+    Rakefile
+    README
+    lib/foreigner.rb
+    lib/foreigner
+    lib/foreigner/schema_dumper.rb
+    lib/foreigner/connection_adapters
+    lib/foreigner/connection_adapters/sql_2003.rb
+    lib/foreigner/connection_adapters/mysql_adapter.rb
+    lib/foreigner/connection_adapters/postgresql_adapter.rb
+    lib/foreigner/connection_adapters/abstract/schema_definitions.rb
+    lib/foreigner/connection_adapters/abstract/schema_statements.rb
+    test/helper.rb
+    test/mysql_adapter_test.rb
+  )
+  s.homepage = "http://github.com/matthuhiggins/foreigner/tree/master";
+  s.rdoc_options = ["--line-numbers", "--main", "README"]
+  s.require_paths = %w(lib)
+  s.rubyforge_project = "foreigner"
+  s.rubygems_version = "1.3.4"
+  s.summary = "Foreign keys for Rails migrations"
+  s.description = "Foreign keys for Rails migrations"
+ 
+  if s.respond_to? :specification_version then
+    current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
+    s.specification_version = 1
+ 
+    if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
+    else
+    end
+  else
+  end
+end
\ No newline at end of file
diff --git a/src/vendor/plugins/foreigner/init.rb 
b/src/vendor/plugins/foreigner/init.rb
new file mode 100644
index 0000000..8b33fb9
--- /dev/null
+++ b/src/vendor/plugins/foreigner/init.rb
@@ -0,0 +1 @@
+require 'foreigner'
diff --git a/src/vendor/plugins/foreigner/install.rb 
b/src/vendor/plugins/foreigner/install.rb
new file mode 100644
index 0000000..f7732d3
--- /dev/null
+++ b/src/vendor/plugins/foreigner/install.rb
@@ -0,0 +1 @@
+# Install hook code here
diff --git a/src/vendor/plugins/foreigner/lib/foreigner.rb 
b/src/vendor/plugins/foreigner/lib/foreigner.rb
new file mode 100644
index 0000000..0cccdf5
--- /dev/null
+++ b/src/vendor/plugins/foreigner/lib/foreigner.rb
@@ -0,0 +1,21 @@
+require 'foreigner/connection_adapters/abstract/schema_statements'
+require 'foreigner/connection_adapters/abstract/schema_definitions'
+require 'foreigner/connection_adapters/sql_2003'
+require 'foreigner/schema_dumper'
+
+module ActiveRecord
+  module ConnectionAdapters
+    include Foreigner::ConnectionAdapters::SchemaStatements
+    include Foreigner::ConnectionAdapters::SchemaDefinitions
+  end
+  
+  SchemaDumper.class_eval do
+    include Foreigner::SchemaDumper
+  end
+  
+  Base.class_eval do
+    if %w(MySQL PostgreSQL).include? connection.adapter_name
+      require 
"foreigner/connection_adapters/#{connection.adapter_name.downcase}_adapter"
+    end
+  end
+end
\ No newline at end of file
diff --git 
a/src/vendor/plugins/foreigner/lib/foreigner/connection_adapters/abstract/schema_definitions.rb
 
b/src/vendor/plugins/foreigner/lib/foreigner/connection_adapters/abstract/schema_definitions.rb
new file mode 100644
index 0000000..e417c5b
--- /dev/null
+++ 
b/src/vendor/plugins/foreigner/lib/foreigner/connection_adapters/abstract/schema_definitions.rb
@@ -0,0 +1,155 @@
+module Foreigner
+  module ConnectionAdapters
+    class ForeignKeyDefinition < Struct.new(:from_table, :to_table, :options) 
#:nodoc:
+    end
+
+    module SchemaDefinitions
+      def self.included(base)
+        base::TableDefinition.class_eval do
+          include Foreigner::ConnectionAdapters::TableDefinition
+        end
+        
+        base::Table.class_eval do
+          include Foreigner::ConnectionAdapters::Table
+        end
+      end
+    end
+  
+    module TableDefinition
+      class ForeignKey < Struct.new(:base, :to_table, :options)
+        def to_sql
+          base.foreign_key_definition(to_table, options)
+        end
+        alias to_s :to_sql
+      end
+
+      def self.included(base)
+        base.class_eval do
+          include InstanceMethods
+          alias_method_chain :references, :foreign_keys
+          alias_method_chain :to_sql, :foreign_keys
+        end
+      end
+    
+      module InstanceMethods
+        # Adds a :foreign_key option to TableDefinition.references.
+        # If :foreign_key is true, a foreign key constraint is added to the 
table.
+        # You can also specify a hash, which is passed as foreign key options.
+        # 
+        # ===== Examples
+        # ====== Add goat_id column and a foreign key to the goats table.
+        #  t.references(:goat, :foreign_key => true)
+        # ====== Add goat_id column and a cascading foreign key to the goats 
table.
+        #  t.references(:goat, :foreign_key => {:dependent => :delete})
+        # 
+        # Note: No foreign key is created if :polymorphic => true is used.
+        # Note: If no name is specified, the database driver creates one for 
you!
+        def references_with_foreign_keys(*args)
+          options = args.extract_options!
+          fk_options = options.delete(:foreign_key)
+
+          if fk_options && !options[:polymorphic]
+            fk_options = {} if fk_options == true
+            args.each { |to_table| foreign_key(to_table, fk_options) }
+          end
+
+          references_without_foreign_keys(*(args << options))
+        end
+    
+        # Defines a foreign key for the table. +to_table+ can be a single 
Symbol, or
+        # an Array of Symbols. See SchemaStatements#add_foreign_key
+        #
+        # ===== Examples
+        # ====== Creating a simple foreign key
+        #  t.foreign_key(:people)
+        # ====== Defining the column
+        #  t.foreign_key(:people, :column => :sender_id)
+        # ====== Creating a named foreign key
+        #  t.foreign_key(:people, :column => :sender_id, :name => 
'sender_foreign_key')
+        # ====== Defining the column of the +to_table+.
+        #  t.foreign_key(:people, :column => :sender_id, :primary_key => 
:person_id)
+        def foreign_key(to_table, options = {})
+          if @base.supports_foreign_keys?
+            to_table = to_table.to_s.pluralize if 
ActiveRecord::Base.pluralize_table_names
+            foreign_keys << ForeignKey.new(@base, to_table, options)
+          end
+        end
+      
+        def to_sql_with_foreign_keys
+          sql = to_sql_without_foreign_keys
+          sql << ', ' << (foreign_keys * ', ') if foreign_keys.present?
+          sql
+        end
+      
+        private
+          def foreign_keys
+            @foreign_keys ||= []
+          end
+      end
+    end
+
+    module Table
+      def self.included(base)
+        base.class_eval do
+          include InstanceMethods
+          alias_method_chain :references, :foreign_keys
+        end
+      end
+
+      module InstanceMethods
+        # Adds a new foreign key to the table. +to_table+ can be a single 
Symbol, or
+        # an Array of Symbols. See SchemaStatements#add_foreign_key
+        #
+        # ===== Examples
+        # ====== Creating a simple foreign key
+        #  t.foreign_key(:people)
+        # ====== Defining the column
+        #  t.foreign_key(:people, :column => :sender_id)
+        # ====== Creating a named foreign key
+        #  t.foreign_key(:people, :column => :sender_id, :name => 
'sender_foreign_key')
+        # ====== Defining the column of the +to_table+.
+        #  t.foreign_key(:people, :column => :sender_id, :primary_key => 
:person_id)
+        def foreign_key(to_table, options = {})
+          @base.add_foreign_key(@table_name, to_table, options)
+        end
+    
+        # Remove the given foreign key from the table.
+        #
+        # ===== Examples
+        # ====== Remove the suppliers_company_id_fk in the suppliers table.
+        #   t.remove_foreign_key :companies
+        # ====== Remove the foreign key named accounts_branch_id_fk in the 
accounts table.
+        #   remove_foreign_key :column => :branch_id
+        # ====== Remove the foreign key named party_foreign_key in the 
accounts table.
+        #   remove_index :name => :party_foreign_key
+        def remove_foreign_key(options = {})
+          @base.remove_foreign_key(@table_name, options)
+        end
+      
+        # Adds a :foreign_key option to TableDefinition.references.
+        # If :foreign_key is true, a foreign key constraint is added to the 
table.
+        # You can also specify a hash, which is passed as foreign key options.
+        # 
+        # ===== Examples
+        # ====== Add goat_id column and a foreign key to the goats table.
+        #  t.references(:goat, :foreign_key => true)
+        # ====== Add goat_id column and a cascading foreign key to the goats 
table.
+        #  t.references(:goat, :foreign_key => {:dependent => :delete})
+        # 
+        # Note: No foreign key is created if :polymorphic => true is used.
+        def references_with_foreign_keys(*args)
+          options = args.extract_options!
+          polymorphic = options[:polymorphic]
+          fk_options = options.delete(:foreign_key)
+
+          references_without_foreign_keys(*(args << options))
+
+          if fk_options && !polymorphic
+            fk_options = {} if fk_options == true
+            args.each { |to_table| foreign_key(to_table, fk_options) }
+          end
+        end
+      end
+    end
+  end
+end
diff --git 
a/src/vendor/plugins/foreigner/lib/foreigner/connection_adapters/abstract/schema_statements.rb
 
b/src/vendor/plugins/foreigner/lib/foreigner/connection_adapters/abstract/schema_statements.rb
new file mode 100644
index 0000000..f611dd4
--- /dev/null
+++ 
b/src/vendor/plugins/foreigner/lib/foreigner/connection_adapters/abstract/schema_statements.rb
@@ -0,0 +1,75 @@
+module Foreigner
+  module ConnectionAdapters
+    module SchemaStatements
+      def self.included(base)
+        base::AbstractAdapter.class_eval do
+          include Foreigner::ConnectionAdapters::AbstractAdapter
+        end
+      end
+    end
+    
+    module AbstractAdapter
+      def supports_foreign_keys?
+        false
+      end
+
+      # Adds a new foreign key to the +from_table+, referencing the primary 
key of +to_table+
+      #
+      # The foreign key will be named after the from and to tables unless you 
pass
+      # <tt>:name</tt> as an option.
+      #
+      # ===== Examples
+      # ====== Creating a foreign key
+      #  add_foreign_key(:comments, :posts)
+      # generates
+      #  ALTER TABLE `comments` ADD CONSTRAINT
+      #     `comments_post_id_fk` FOREIGN KEY (`post_id`) REFERENCES `posts` 
(`id`)
+      # 
+      # ====== Creating a named foreign key
+      #  add_foreign_key(:comments, :posts, :name => 
'comments_belongs_to_posts')
+      # generates
+      #  ALTER TABLE `comments` ADD CONSTRAINT
+      #     `comments_belongs_to_posts` FOREIGN KEY (`post_id`) REFERENCES 
`posts` (`id`)
+      # 
+      # ====== Creating a cascading foreign_key on a custom column
+      #  add_foreign_key(:people, :people, :column => 'best_friend_id', 
:dependent => :nullify)
+      # generates
+      #  ALTER TABLE `people` ADD CONSTRAINT
+      #     `people_best_friend_id_fk` FOREIGN KEY (`best_friend_id`) 
REFERENCES `people` (`id`)
+      #     ON DELETE SET NULL
+      # 
+      # === Supported options
+      # [:column]
+      #   Specify the column name on the from_table that references the 
to_table. By default this is guessed
+      #   to be the singular name of the to_table with "_id" suffixed. So a 
to_table of :posts will use "post_id"
+      #   as the default <tt>:column</tt>.
+      # [:primary_key]
+      #   Specify the column name on the to_table that is referenced by this 
foreign key. By default this is
+      #   assumed to be "id".
+      # [:name]
+      #   Specify the name of the foreign key constraint. This defaults to use 
from_table and foreign key column.
+      # [:dependent]
+      #   If set to <tt>:delete</tt>, the associated records in from_table are 
deleted when records in to_table table are deleted.
+      #   If set to <tt>:nullify</tt>, the foreign key column is set to +NULL+.
+      def add_foreign_key(from_table, to_table, options = {})
+      end
+
+      # Remove the given foreign key from the table.
+      #
+      # ===== Examples
+      # ====== Remove the suppliers_company_id_fk in the suppliers table.
+      #   remove_foreign_key :suppliers, :companies
+      # ====== Remove the foreign key named accounts_branch_id_fk in the 
accounts table.
+      #   remove_foreign_key :accounts, :column => :branch_id
+      # ====== Remove the foreign key named party_foreign_key in the accounts 
table.
+      #   remove_foreign_key :accounts, :name => :party_foreign_key
+      def remove_foreign_key(from_table, options)
+      end
+
+      # Return the foreign keys for the schema_dumper
+      def foreign_keys(table_name)
+        []
+      end
+    end
+  end
+end
diff --git 
a/src/vendor/plugins/foreigner/lib/foreigner/connection_adapters/mysql_adapter.rb
 
b/src/vendor/plugins/foreigner/lib/foreigner/connection_adapters/mysql_adapter.rb
new file mode 100644
index 0000000..d831d24
--- /dev/null
+++ 
b/src/vendor/plugins/foreigner/lib/foreigner/connection_adapters/mysql_adapter.rb
@@ -0,0 +1,43 @@
+module Foreigner
+  module ConnectionAdapters
+    module MysqlAdapter
+      include Foreigner::ConnectionAdapters::Sql2003
+      
+      def foreign_keys(table_name)
+        fk_info = select_all %{
+          SELECT fk.referenced_table_name as 'to_table'
+                ,fk.referenced_column_name as 'primary_key'
+                ,fk.column_name as 'column'
+                ,fk.constraint_name as 'name'
+          FROM information_schema.key_column_usage fk
+          WHERE fk.referenced_column_name is not null
+            AND fk.table_schema = '#...@config[:database]}'
+            AND fk.table_name = '#{table_name}'
+        }
+
+        create_table_info = select_one("SHOW CREATE TABLE 
#{quote_table_name(table_name)}")["Create Table"]
+
+        fk_info.map do |row|
+          options = {:column => row['column'], :name => row['name'], 
:primary_key => row['primary_key']}
+
+          if create_table_info =~ /CONSTRAINT 
#{quote_column_name(row['name'])} FOREIGN KEY .* REFERENCES .* ON DELETE 
(CASCADE|SET NULL)/
+            if $1 == 'CASCADE'
+              options[:dependent] = :delete
+            elsif $1 == 'SET NULL'
+              options[:dependent] = :nullify
+            end
+          end
+          ForeignKeyDefinition.new(table_name, row['to_table'], options)
+        end
+      end
+    end
+  end
+end
+
+module ActiveRecord
+  module ConnectionAdapters
+    MysqlAdapter.class_eval do
+      include Foreigner::ConnectionAdapters::MysqlAdapter
+    end
+  end
+end
diff --git 
a/src/vendor/plugins/foreigner/lib/foreigner/connection_adapters/postgresql_adapter.rb
 
b/src/vendor/plugins/foreigner/lib/foreigner/connection_adapters/postgresql_adapter.rb
new file mode 100644
index 0000000..be662b3
--- /dev/null
+++ 
b/src/vendor/plugins/foreigner/lib/foreigner/connection_adapters/postgresql_adapter.rb
@@ -0,0 +1,46 @@
+module Foreigner
+  module ConnectionAdapters
+    module PostgreSQLAdapter
+      include Foreigner::ConnectionAdapters::Sql2003
+      
+      def foreign_keys(table_name)
+        fk_info = select_all %{
+          SELECT tc.constraint_name as name
+                ,ccu.table_name as to_table
+                ,ccu.column_name as primary_key
+                ,kcu.column_name as column
+                ,rc.delete_rule as dependency
+          FROM information_schema.table_constraints tc
+          JOIN information_schema.key_column_usage kcu
+          USING (constraint_catalog, constraint_schema, constraint_name)
+          JOIN information_schema.referential_constraints rc
+          USING (constraint_catalog, constraint_schema, constraint_name)
+          JOIN information_schema.constraint_column_usage ccu
+          USING (constraint_catalog, constraint_schema, constraint_name)
+          WHERE tc.constraint_type = 'FOREIGN KEY'
+            AND tc.constraint_catalog = '#...@config[:database]}'
+            AND tc.table_name = '#{table_name}'
+        }
+        
+        fk_info.map do |row|
+          options = {:column => row['column'], :name => row['name'], 
:primary_key = row['primary_key']}
+
+          if row['dependency'] == 'CASCADE'
+            options[:dependent] = :delete
+          elsif row['dependency'] == 'SET NULL'
+            options[:dependent] = :nullify
+          end
+          ForeignKeyDefinition.new(table_name, row['to_table'], options)
+        end
+      end
+    end
+  end
+end
+
+module ActiveRecord
+  module ConnectionAdapters
+    PostgreSQLAdapter.class_eval do
+      include Foreigner::ConnectionAdapters::PostgreSQLAdapter
+    end
+  end
+end
\ No newline at end of file
diff --git 
a/src/vendor/plugins/foreigner/lib/foreigner/connection_adapters/sql_2003.rb 
b/src/vendor/plugins/foreigner/lib/foreigner/connection_adapters/sql_2003.rb
new file mode 100644
index 0000000..1a1019b
--- /dev/null
+++ b/src/vendor/plugins/foreigner/lib/foreigner/connection_adapters/sql_2003.rb
@@ -0,0 +1,58 @@
+module Foreigner
+  module ConnectionAdapters
+    module Sql2003
+      def supports_foreign_keys?
+        true
+      end
+    
+      def add_foreign_key(from_table, to_table, options = {})
+        column  = options[:column] || "#{to_table.to_s.singularize}_id"
+        foreign_key_name = foreign_key_name(from_table, column, options)
+
+        sql =
+          "ALTER TABLE #{quote_table_name(from_table)} " +
+          "ADD CONSTRAINT #{quote_column_name(foreign_key_name)} " +
+          foreign_key_definition(to_table, options)
+      
+        execute(sql)
+      end
+    
+      def foreign_key_definition(to_table, options = {})
+        column  = options[:column] || "#{to_table.to_s.singularize}_id"
+        primary_key = options[:primary_key] || "id"
+        dependency = dependency_sql(options[:dependent])
+
+        sql = "FOREIGN KEY (#{quote_column_name(column)}) REFERENCES 
#{quote_table_name(to_table)}(#{primary_key})"
+        sql << " #{dependency}" unless dependency.blank?
+        sql
+      end
+
+      def remove_foreign_key(table, options)
+        if Hash === options
+          foreign_key_name = foreign_key_name(table, options[:column], options)
+        else
+          foreign_key_name = foreign_key_name(table, 
"#{options.to_s.singularize}_id")
+        end
+
+        execute "ALTER TABLE #{quote_table_name(table)} DROP FOREIGN KEY 
#{quote_column_name(foreign_key_name)}"
+      end
+    
+      private
+        def foreign_key_name(table, column, options = {})
+          if options[:name]
+            options[:name]
+          else
+            "#{table}_#{column}_fk"
+          end
+        end
+
+        def dependency_sql(dependency)
+          case dependency
+            when :nullify then "ON DELETE SET NULL"
+            when :delete  then "ON DELETE CASCADE"
+            else ""
+          end
+        end
+    end
+  end
+end
\ No newline at end of file
diff --git a/src/vendor/plugins/foreigner/lib/foreigner/schema_dumper.rb 
b/src/vendor/plugins/foreigner/lib/foreigner/schema_dumper.rb
new file mode 100644
index 0000000..2c31090
--- /dev/null
+++ b/src/vendor/plugins/foreigner/lib/foreigner/schema_dumper.rb
@@ -0,0 +1,45 @@
+module Foreigner
+  module SchemaDumper
+    def self.included(base)
+      base.class_eval do
+        include InstanceMethods
+        alias_method_chain :tables, :foreign_keys
+      end
+    end
+    
+    module InstanceMethods
+      def tables_with_foreign_keys(stream)
+        tables_without_foreign_keys(stream)
+        @connection.tables.sort.each do |table|
+          foreign_keys(table, stream)
+        end
+      end
+      
+      private
+        def foreign_keys(table_name, stream)
+          if (foreign_keys = @connection.foreign_keys(table_name)).any?
+            add_foreign_key_statements = foreign_keys.map do |foreign_key|
+              statement_parts = [ ('add_foreign_key ' + 
foreign_key.from_table.inspect) ]
+              statement_parts << foreign_key.to_table.inspect
+              statement_parts << (':name => ' + 
foreign_key.options[:name].inspect)
+              
+              if foreign_key.options[:column] != 
"#{foreign_key.to_table.singularize}_id"
+                statement_parts << (':column => ' + 
foreign_key.options[:column].inspect)
+              end
+              if foreign_key.options[:primary_key] != 'id'
+                statement_parts << (':primary_key => ' + 
foreign_key.options[:primary_key].inspect)
+              end
+              if foreign_key.options[:dependent].present?
+                statement_parts << (':dependent => ' + 
foreign_key.options[:dependent].inspect)
+              end
+
+              '  ' + statement_parts.join(', ')
+            end
+
+            stream.puts add_foreign_key_statements.sort.join("\n")
+            stream.puts
+          end
+        end
+    end
+  end
+end
\ No newline at end of file
diff --git a/src/vendor/plugins/foreigner/tasks/foreigner_tasks.rake 
b/src/vendor/plugins/foreigner/tasks/foreigner_tasks.rake
new file mode 100644
index 0000000..a5028e3
--- /dev/null
+++ b/src/vendor/plugins/foreigner/tasks/foreigner_tasks.rake
@@ -0,0 +1,4 @@
+# desc "Explaining what the task does"
+# task :foreigner do
+#   # Task goes here
+# end
diff --git a/src/vendor/plugins/foreigner/test/helper.rb 
b/src/vendor/plugins/foreigner/test/helper.rb
new file mode 100644
index 0000000..05eab24
--- /dev/null
+++ b/src/vendor/plugins/foreigner/test/helper.rb
@@ -0,0 +1,8 @@
+require 'test/unit'
+require 'rubygems'
+require 'active_support'
+require 'active_support/test_case'
+require 'active_record'
+require 'active_record/test_case'
+require 'active_record/connection_adapters/mysql_adapter'
+require 'foreigner'
\ No newline at end of file
diff --git a/src/vendor/plugins/foreigner/test/mysql_adapter_test.rb 
b/src/vendor/plugins/foreigner/test/mysql_adapter_test.rb
new file mode 100644
index 0000000..8cf977f
--- /dev/null
+++ b/src/vendor/plugins/foreigner/test/mysql_adapter_test.rb
@@ -0,0 +1,83 @@
+require File.dirname(__FILE__) + '/helper'
+
+class MysqlAdapterTest < ActiveRecord::TestCase
+  include Foreigner::MysqlAdapter
+
+  def test_add_without_options
+    assert_equal(
+      "ALTER TABLE `employees` ADD CONSTRAINT `employees_company_id_fk` 
FOREIGN KEY (`company_id`) REFERENCES `companies`(id)",
+      add_foreign_key(:employees, :companies)
+    )
+  end
+  
+  def test_add_with_name
+    assert_equal(
+      "ALTER TABLE `employees` ADD CONSTRAINT `favorite_company_fk` FOREIGN 
KEY (`company_id`) REFERENCES `companies`(id)",
+      add_foreign_key(:employees, :companies, :name => 'favorite_company_fk')
+    )
+  end
+  
+  def test_add_with_column
+    assert_equal(
+      "ALTER TABLE `employees` ADD CONSTRAINT `employees_last_employer_id_fk` 
FOREIGN KEY (`last_employer_id`) REFERENCES `companies`(id)",
+      add_foreign_key(:employees, :companies, :column => 'last_employer_id')
+    ) 
+  end
+  
+  def test_add_with_column_and_name
+    assert_equal(
+      "ALTER TABLE `employees` ADD CONSTRAINT `favorite_company_fk` FOREIGN 
KEY (`last_employer_id`) REFERENCES `companies`(id)",
+      add_foreign_key(:employees, :companies, :column => 'last_employer_id', 
:name => 'favorite_company_fk')
+    )
+  end
+  
+  def test_add_with_delete_dependency
+    assert_equal(
+      "ALTER TABLE `employees` ADD CONSTRAINT `employees_company_id_fk` 
FOREIGN KEY (`company_id`) REFERENCES `companies`(id) " +
+      "ON DELETE CASCADE",
+      add_foreign_key(:employees, :companies, :dependent => :delete)
+    )
+  end
+  
+  def test_add_with_nullify_dependency
+    assert_equal(
+      "ALTER TABLE `employees` ADD CONSTRAINT `employees_company_id_fk` 
FOREIGN KEY (`company_id`) REFERENCES `companies`(id) " +
+      "ON DELETE SET NULL",
+      add_foreign_key(:employees, :companies, :dependent => :nullify)
+    )
+  end
+  
+  def test_remove_by_table
+    assert_equal(
+      "ALTER TABLE `suppliers` DROP FOREIGN KEY `suppliers_company_id_fk`",
+      remove_foreign_key(:suppliers, :companies)
+    )
+  end
+  
+  def test_remove_by_name
+    assert_equal(
+      "ALTER TABLE `suppliers` DROP FOREIGN KEY `belongs_to_supplier`",
+      remove_foreign_key(:suppliers, :name => "belongs_to_supplier")
+    )
+  end
+  
+  def test_remove_by_column
+    assert_equal(
+      "ALTER TABLE `suppliers` DROP FOREIGN KEY `suppliers_ship_to_id_fk`",
+      remove_foreign_key(:suppliers, :column => "ship_to_id")
+    )
+  end
+  
+  private
+    def execute(sql, name = nil)
+      sql
+    end
+  
+    def quote_column_name(name)
+      "`#{name}`"
+    end
+    
+    def quote_table_name(name)
+      quote_column_name(name).gsub('.', '`.`')
+    end
+end
\ No newline at end of file
diff --git a/src/vendor/plugins/foreigner/uninstall.rb 
b/src/vendor/plugins/foreigner/uninstall.rb
new file mode 100644
index 0000000..9738333
--- /dev/null
+++ b/src/vendor/plugins/foreigner/uninstall.rb
@@ -0,0 +1 @@
+# Uninstall hook code here
-- 
1.6.2.5

_______________________________________________
Ovirt-devel mailing list
[email protected]
https://www.redhat.com/mailman/listinfo/ovirt-devel

Reply via email to