Skip to content

Commit

Permalink
- Do not load the adapter unless it is the current one in use
Browse files Browse the repository at this point in the history
- Extract mysql foreign key definitions into the sql_2003 specification
- Add postgressql support, sans schema dumping. I will add foreign_keys to schema.rb soon.
  • Loading branch information
Matthew Higgins committed Sep 7, 2009
1 parent b13c78e commit 33ec743
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 80 deletions.
11 changes: 6 additions & 5 deletions lib/foreigner.rb
@@ -1,17 +1,12 @@
require 'foreigner/connection_adapters/abstract/schema_statements'
require 'foreigner/connection_adapters/abstract/schema_definitions'
require 'foreigner/connection_adapters/mysql_adapter'
require 'foreigner/schema_dumper'

module ActiveRecord
module ConnectionAdapters
AbstractAdapter.class_eval do
include Foreigner::AdapterMethods
end

MysqlAdapter.class_eval do
include Foreigner::MysqlAdapter
end

TableDefinition.class_eval do
include Foreigner::TableDefinition
Expand All @@ -25,4 +20,10 @@ module ConnectionAdapters
SchemaDumper.class_eval do
include Foreigner::SchemaDumper
end

Base.class_eval do
if ['MySQL', 'PostgreSQL'].include? connection.adapter_name
require "foreigner/connection_adapters/#{connection.adapter_name.downcase}_adapter"
end
end
end
112 changes: 37 additions & 75 deletions lib/foreigner/connection_adapters/mysql_adapter.rb
@@ -1,84 +1,46 @@
module Foreigner
module MysqlAdapter
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)
require 'foreigner/connection_adapters/sql_2003'

sql =
"ALTER TABLE #{quote_table_name(from_table)} " +
"ADD CONSTRAINT #{quote_column_name(foreign_key_name)} " +
foreign_key_definition(to_table, options)
module Foreigner
module ConnectionAdapters
module MysqlAdapter
include Foreigner::ConnectionAdapters::Sql2003

execute(sql)
end

def foreign_key_definition(to_table, options = {})
column = options[:column] || "#{to_table.to_s.singularize}_id"
dependency = dependency_sql(options[:dependent])

sql = "FOREIGN KEY (#{quote_column_name(column)}) REFERENCES #{quote_table_name(to_table)}(id)"
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

def foreign_keys(table_name)
foreign_keys = []
fk_info = select_all %{
SELECT fk.referenced_table_name as 'to_table'
,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.each do |row|
options = {:column => row['column'], :name => row['name']}
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
def foreign_keys(table_name)
foreign_keys = []
fk_info = select_all %{
SELECT fk.referenced_table_name as 'to_table'
,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.each do |row|
options = {:column => row['column'], :name => row['name']}
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
foreign_keys << ForeignKeyDefinition.new(table_name, row['to_table'], options)
end
foreign_keys << ForeignKeyDefinition.new(table_name, row['to_table'], options)
end

foreign_keys
end

private
def foreign_key_name(table, column, options = {})
if options[:name]
options[:name]
else
"#{table}_#{column}_fk"
end
foreign_keys
end
end
end
end

def dependency_sql(dependency)
case dependency
when :nullify then "ON DELETE SET NULL"
when :delete then "ON DELETE CASCADE"
else ""
end
end
module ActiveRecord
module ConnectionAdapters
MysqlAdapter.class_eval do
include Foreigner::ConnectionAdapters::MysqlAdapter
end
end
end
21 changes: 21 additions & 0 deletions lib/foreigner/connection_adapters/postgresql_adapter.rb
@@ -0,0 +1,21 @@
require 'foreigner/connection_adapters/sql_2003'

module Foreigner
module ConnectionAdapters
module PostgreSQLAdapter
include Foreigner::ConnectionAdapters::Sql2003

def foreign_keys(table_name)

end
end
end
end

module ActiveRecord
module ConnectionAdapters
PostgreSQLAdapter.class_eval do
include Foreigner::ConnectionAdapters::PostgreSQLAdapter
end
end
end
57 changes: 57 additions & 0 deletions lib/foreigner/connection_adapters/sql_2003.rb
@@ -0,0 +1,57 @@
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"
dependency = dependency_sql(options[:dependent])

sql = "FOREIGN KEY (#{quote_column_name(column)}) REFERENCES #{quote_table_name(to_table)}(id)"
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

0 comments on commit 33ec743

Please sign in to comment.