schema_plus 2.0.0.pre15 → 2.0.0.pre16
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.
- checksums.yaml +4 -4
- data/README.md +6 -78
- data/lib/schema_plus.rb +1 -0
- data/lib/schema_plus/auto_foreign_keys.rb +31 -0
- data/lib/schema_plus/auto_foreign_keys/active_record/connection_adapters/sqlite3_adapter.rb +22 -0
- data/lib/schema_plus/auto_foreign_keys/active_record/migration/command_recorder.rb +14 -0
- data/lib/schema_plus/auto_foreign_keys/middleware/migration.rb +66 -0
- data/lib/schema_plus/{foreign_keys → auto_foreign_keys}/middleware/schema.rb +1 -1
- data/lib/schema_plus/version.rb +1 -1
- data/schema_plus.gemspec +2 -1
- data/spec/{schema_plus_foreign_keys → schema_auto_foreign_keys}/foreign_key_spec.rb +0 -0
- data/spec/{schema_plus_foreign_keys → schema_auto_foreign_keys}/migration_spec.rb +3 -2
- data/spec/{schema_plus_foreign_keys → schema_auto_foreign_keys}/schema_dumper_spec.rb +0 -0
- data/spec/{schema_plus_foreign_keys → schema_auto_foreign_keys}/schema_spec.rb +0 -0
- metadata +31 -32
- data/lib/schema_plus/foreign_keys.rb +0 -93
- data/lib/schema_plus/foreign_keys/active_record/base.rb +0 -33
- data/lib/schema_plus/foreign_keys/active_record/connection_adapters/abstract_adapter.rb +0 -168
- data/lib/schema_plus/foreign_keys/active_record/connection_adapters/foreign_key_definition.rb +0 -138
- data/lib/schema_plus/foreign_keys/active_record/connection_adapters/mysql2_adapter.rb +0 -126
- data/lib/schema_plus/foreign_keys/active_record/connection_adapters/postgresql_adapter.rb +0 -89
- data/lib/schema_plus/foreign_keys/active_record/connection_adapters/sqlite3_adapter.rb +0 -98
- data/lib/schema_plus/foreign_keys/active_record/connection_adapters/table_definition.rb +0 -108
- data/lib/schema_plus/foreign_keys/active_record/migration/command_recorder.rb +0 -35
- data/lib/schema_plus/foreign_keys/middleware/dumper.rb +0 -79
- data/lib/schema_plus/foreign_keys/middleware/migration.rb +0 -184
- data/lib/schema_plus/foreign_keys/middleware/model.rb +0 -15
- data/lib/schema_plus/foreign_keys/middleware/mysql.rb +0 -20
- data/lib/schema_plus/foreign_keys/middleware/sql.rb +0 -20
- data/lib/schema_plus/foreign_keys/version.rb +0 -3
- data/spec/schema_plus_foreign_keys/foreign_key_definition_spec.rb +0 -34
- data/spec/schema_plus_foreign_keys/named_schemas_spec.rb +0 -136
@@ -1,93 +0,0 @@
|
|
1
|
-
require 'schema_plus/core'
|
2
|
-
require 'valuable'
|
3
|
-
|
4
|
-
require_relative 'foreign_keys/version'
|
5
|
-
require_relative 'foreign_keys/active_record/base'
|
6
|
-
require_relative 'foreign_keys/active_record/connection_adapters/abstract_adapter'
|
7
|
-
require_relative 'foreign_keys/active_record/connection_adapters/table_definition'
|
8
|
-
require_relative 'foreign_keys/active_record/connection_adapters/foreign_key_definition'
|
9
|
-
require_relative 'foreign_keys/active_record/migration/command_recorder'
|
10
|
-
require_relative 'foreign_keys/middleware/dumper'
|
11
|
-
require_relative 'foreign_keys/middleware/migration'
|
12
|
-
require_relative 'foreign_keys/middleware/model'
|
13
|
-
require_relative 'foreign_keys/middleware/mysql'
|
14
|
-
require_relative 'foreign_keys/middleware/schema'
|
15
|
-
require_relative 'foreign_keys/middleware/sql'
|
16
|
-
|
17
|
-
module SchemaPlus::ForeignKeys
|
18
|
-
module ActiveRecord
|
19
|
-
module ConnectionAdapters
|
20
|
-
autoload :Mysql2Adapter, 'schema_plus/foreign_keys/active_record/connection_adapters/mysql2_adapter'
|
21
|
-
autoload :PostgresqlAdapter, 'schema_plus/foreign_keys/active_record/connection_adapters/postgresql_adapter'
|
22
|
-
autoload :Sqlite3Adapter, 'schema_plus/foreign_keys/active_record/connection_adapters/sqlite3_adapter'
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
# This global configuation options for SchemaPlus::ForeignKeys.
|
27
|
-
# Set them in +config/initializers/schema_plus_foreign_keys.rb+ using:
|
28
|
-
#
|
29
|
-
# SchemaPlus::ForeignKeys.setup do |config|
|
30
|
-
# ...
|
31
|
-
# end
|
32
|
-
#
|
33
|
-
class Config < Valuable
|
34
|
-
|
35
|
-
##
|
36
|
-
# :attr_accessor: auto_create
|
37
|
-
#
|
38
|
-
# Whether to automatically create foreign key constraints for columns
|
39
|
-
# suffixed with +_id+. Boolean, default is +true+.
|
40
|
-
has_value :auto_create, :klass => :boolean, :default => true
|
41
|
-
|
42
|
-
##
|
43
|
-
# :attr_accessor: auto_index
|
44
|
-
#
|
45
|
-
# Whether to automatically create indexes when creating foreign key constraints for columns.
|
46
|
-
# Boolean, default is +true+.
|
47
|
-
has_value :auto_index, :klass => :boolean, :default => true
|
48
|
-
|
49
|
-
##
|
50
|
-
# :attr_accessor: on_update
|
51
|
-
#
|
52
|
-
# The default value for +:on_update+ when creating foreign key
|
53
|
-
# constraints for columns. Valid values are as described in
|
54
|
-
# ForeignKeyDefinition, or +nil+ to let the database connection use
|
55
|
-
# its own default. Default is +nil+.
|
56
|
-
has_value :on_update
|
57
|
-
|
58
|
-
##
|
59
|
-
# :attr_accessor: on_delete
|
60
|
-
#
|
61
|
-
# The default value for +:on_delete+ when creating foreign key
|
62
|
-
# constraints for columns. Valid values are as described in
|
63
|
-
# ForeignKeyDefinition, or +nil+ to let the database connection use
|
64
|
-
# its own default. Default is +nil+.
|
65
|
-
has_value :on_delete
|
66
|
-
|
67
|
-
def merge(opts)
|
68
|
-
dup.update_attributes(opts)
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
|
73
|
-
# Returns the global configuration, i.e., the singleton instance of Config
|
74
|
-
def self.config
|
75
|
-
@config ||= Config.new
|
76
|
-
end
|
77
|
-
|
78
|
-
# Initialization block is passed a global Config instance that can be
|
79
|
-
# used to configure SchemaPlus::ForeignKeys behavior. E.g., if you want to disable
|
80
|
-
# automation creation of foreign key constraints for columns name *_id,
|
81
|
-
# put the following in config/initializers/schema_plus_foreign_keys.rb :
|
82
|
-
#
|
83
|
-
# SchemaPlus::ForeignKeys.setup do |config|
|
84
|
-
# config.auto_create = false
|
85
|
-
# end
|
86
|
-
#
|
87
|
-
def self.setup # :yields: config
|
88
|
-
yield config
|
89
|
-
end
|
90
|
-
|
91
|
-
end
|
92
|
-
|
93
|
-
SchemaMonkey.register SchemaPlus::ForeignKeys
|
@@ -1,33 +0,0 @@
|
|
1
|
-
module SchemaPlus::ForeignKeys
|
2
|
-
module ActiveRecord
|
3
|
-
|
4
|
-
#
|
5
|
-
# SchemaPlus::ForeignKeys adds several methods to ActiveRecord::Base
|
6
|
-
#
|
7
|
-
module Base
|
8
|
-
module ClassMethods #:nodoc:
|
9
|
-
|
10
|
-
public
|
11
|
-
|
12
|
-
# Returns a list of ForeignKeyDefinition objects, for each foreign
|
13
|
-
# key constraint defined in this model's table
|
14
|
-
#
|
15
|
-
# (memoized result gets reset in Middleware::Model::ResetColumnInformation)
|
16
|
-
def foreign_keys
|
17
|
-
@foreign_keys ||= connection.foreign_keys(table_name, "#{name} Foreign Keys")
|
18
|
-
end
|
19
|
-
|
20
|
-
def reset_foreign_key_information
|
21
|
-
@foreign_keys = @reverse_foreign_keys = nil
|
22
|
-
end
|
23
|
-
|
24
|
-
# Returns a list of ForeignKeyDefinition objects, for each foreign
|
25
|
-
# key constraint of other tables that refer to this model's table
|
26
|
-
def reverse_foreign_keys
|
27
|
-
@reverse_foreign_keys ||= connection.reverse_foreign_keys(table_name, "#{name} Reverse Foreign Keys")
|
28
|
-
end
|
29
|
-
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
@@ -1,168 +0,0 @@
|
|
1
|
-
module SchemaPlus::ForeignKeys
|
2
|
-
module ActiveRecord
|
3
|
-
# SchemaPlus::ForeignKeys adds several methods to the connection adapter (as returned by ActiveRecordBase#connection). See AbstractAdapter for details.
|
4
|
-
module ConnectionAdapters
|
5
|
-
|
6
|
-
#
|
7
|
-
# SchemaPlus::ForeignKeys adds several methods to
|
8
|
-
# ActiveRecord::ConnectionAdapters::AbstractAdapter. In most cases
|
9
|
-
# you don't call these directly, but rather the methods that define
|
10
|
-
# things are called by schema statements, and methods that query
|
11
|
-
# things are called by ActiveRecord::Base.
|
12
|
-
#
|
13
|
-
module AbstractAdapter
|
14
|
-
|
15
|
-
# Define a foreign key constraint. Valid options are :on_update,
|
16
|
-
# :on_delete, and :deferrable, with values as described at
|
17
|
-
# ConnectionAdapters::ForeignKeyDefinition
|
18
|
-
#
|
19
|
-
# (NOTE: Sqlite3 does not support altering a table to add foreign-key
|
20
|
-
# constraints; they must be included in the table specification when
|
21
|
-
# it's created. If you're using Sqlite3, this method will raise an
|
22
|
-
# error.)
|
23
|
-
def add_foreign_key(*args) # (table_name, column, to_table, primary_key, options = {})
|
24
|
-
options = args.extract_options!
|
25
|
-
case args.length
|
26
|
-
when 2
|
27
|
-
from_table, to_table = args
|
28
|
-
when 4
|
29
|
-
ActiveSupport::Deprecation.warn "4-argument form of add_foreign_key is deprecated. use add_foreign_key(from_table, to_table, options)"
|
30
|
-
(from_table, column, to_table, primary_key) = args
|
31
|
-
options.merge!(column: column, primary_key: primary_key)
|
32
|
-
end
|
33
|
-
|
34
|
-
options = options.dup
|
35
|
-
options[:column] ||= foreign_key_column_for(to_table)
|
36
|
-
options[:name] ||= ForeignKeyDefinition.default_name(from_table, options[:column])
|
37
|
-
|
38
|
-
foreign_key_sql = add_foreign_key_sql(from_table, to_table, options)
|
39
|
-
execute "ALTER TABLE #{quote_table_name(from_table)} #{foreign_key_sql}"
|
40
|
-
end
|
41
|
-
|
42
|
-
# called directly by AT's bulk_change_table, for migration
|
43
|
-
# change_table :name, :bulk => true { ... }
|
44
|
-
def add_foreign_key_sql(from_table, to_table, options = {}) #:nodoc:
|
45
|
-
foreign_key = ::ActiveRecord::ConnectionAdapters::ForeignKeyDefinition.new(from_table, AbstractAdapter.proper_table_name(to_table), options)
|
46
|
-
"ADD #{foreign_key.to_sql}"
|
47
|
-
end
|
48
|
-
|
49
|
-
def _build_foreign_key(from_table, to_table, options = {}) #:nodoc:
|
50
|
-
::ActiveRecord::ConnectionAdapters::ForeignKeyDefinition.new(from_table, AbstractAdapter.proper_table_name(to_table), options)
|
51
|
-
end
|
52
|
-
|
53
|
-
def self.proper_table_name(name)
|
54
|
-
proper_name = ::ActiveRecord::Migration.new.proper_table_name(name)
|
55
|
-
end
|
56
|
-
|
57
|
-
# Remove a foreign key constraint
|
58
|
-
#
|
59
|
-
# Arguments are the same as for add_foreign_key, or by name:
|
60
|
-
#
|
61
|
-
# remove_foreign_key table_name, to_table, options
|
62
|
-
# remove_foreign_key table_name, name: constraint_name
|
63
|
-
#
|
64
|
-
# (NOTE: Sqlite3 does not support altering a table to remove
|
65
|
-
# foreign-key constraints. If you're using Sqlite3, this method will
|
66
|
-
# raise an error.)
|
67
|
-
def remove_foreign_key(*args)
|
68
|
-
from_table, to_table, options = normalize_remove_foreign_key_args(*args)
|
69
|
-
options[:column] ||= foreign_key_column_for(to_table)
|
70
|
-
if sql = remove_foreign_key_sql(from_table, to_table, options)
|
71
|
-
execute "ALTER TABLE #{quote_table_name(from_table)} #{sql}"
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
def normalize_remove_foreign_key_args(*args)
|
76
|
-
options = args.extract_options!
|
77
|
-
if options.has_key? :column_names
|
78
|
-
ActiveSupport::Deprecation.warn ":column_names option is deprecated, use :column"
|
79
|
-
options[:column] = options.delete(:column_names)
|
80
|
-
end
|
81
|
-
if options.has_key? :references_column_names
|
82
|
-
ActiveSupport::Deprecation.warn ":references_column_names option is deprecated, use :primary_key"
|
83
|
-
options[:primary_key] = options.delete(:references_column_names)
|
84
|
-
end
|
85
|
-
if options.has_key? :references_table_name
|
86
|
-
ActiveSupport::Deprecation.warn ":references_table_name option is deprecated, use :to_table"
|
87
|
-
options[:to_table] = options.delete(:references_table_name)
|
88
|
-
end
|
89
|
-
case args.length
|
90
|
-
when 1
|
91
|
-
from_table = args[0]
|
92
|
-
when 2
|
93
|
-
from_table, to_table = args
|
94
|
-
when 3, 4
|
95
|
-
ActiveSupport::Deprecation.warn "3- and 4-argument forms of remove_foreign_key are deprecated. use add_foreign_key(from_table, to_table, options)"
|
96
|
-
(from_table, column, to_table, primary_key) = args
|
97
|
-
options.merge!(column: column, primary_key: primary_key)
|
98
|
-
else
|
99
|
-
raise ArgumentError, "Wrong number of arguments(args.length) to remove_foreign_key"
|
100
|
-
end
|
101
|
-
to_table ||= options.delete(:to_table)
|
102
|
-
[from_table, to_table, options]
|
103
|
-
end
|
104
|
-
|
105
|
-
def get_foreign_key_name(from_table, to_table, options)
|
106
|
-
return options[:name] if options[:name]
|
107
|
-
|
108
|
-
fks = foreign_keys(from_table)
|
109
|
-
if fks.detect(&its.name == to_table)
|
110
|
-
ActiveSupport::Deprecation.warn "remove_foreign_key(table, name) is deprecated. use remove_foreign_key(table, name: name)"
|
111
|
-
return to_table
|
112
|
-
end
|
113
|
-
test_fk = _build_foreign_key(from_table, to_table, options)
|
114
|
-
if fk = fks.detect { |fk| fk.match(test_fk) }
|
115
|
-
fk.name
|
116
|
-
else
|
117
|
-
raise "SchemaPlus::ForeignKeys: no foreign key constraint found on #{from_table.inspect} matching #{[to_table, options].inspect}" unless options[:if_exists]
|
118
|
-
nil
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
def remove_foreign_key_sql(from_table, to_table, options)
|
123
|
-
if foreign_key_name = get_foreign_key_name(from_table, to_table, options)
|
124
|
-
"DROP CONSTRAINT #{options[:if_exists] ? "IF EXISTS" : ""} #{foreign_key_name}"
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
|
129
|
-
# called from individual adpaters, after renaming table from old
|
130
|
-
# name to
|
131
|
-
def rename_foreign_keys(oldname, newname) #:nodoc:
|
132
|
-
foreign_keys(newname).each do |fk|
|
133
|
-
index = indexes(newname).find{|index| index.name == ForeignKeyDefinition.auto_index_name(oldname, fk.column)}
|
134
|
-
begin
|
135
|
-
remove_foreign_key(newname, name: fk.name)
|
136
|
-
rescue NotImplementedError
|
137
|
-
# sqlite3 can't remove foreign keys, so just skip it
|
138
|
-
end
|
139
|
-
# rename the index only when the fk constraint doesn't exist.
|
140
|
-
# mysql doesn't allow the rename (which is a delete & add)
|
141
|
-
# if the index is on a foreign key constraint
|
142
|
-
rename_index(newname, index.name, ForeignKeyDefinition.auto_index_name(newname, index.columns)) if index
|
143
|
-
begin
|
144
|
-
add_foreign_key(newname, fk.to_table, :column => fk.column, :primary_key => fk.primary_key, :name => fk.name.sub(/#{oldname}/, newname), :on_update => fk.on_update, :on_delete => fk.on_delete, :deferrable => fk.deferrable)
|
145
|
-
rescue NotImplementedError
|
146
|
-
# sqlite3 can't add foreign keys, so just skip it
|
147
|
-
end
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
|
-
|
152
|
-
#####################################################################
|
153
|
-
#
|
154
|
-
# The functions below here are abstract; each subclass should
|
155
|
-
# define them all. Defining them here only for reference.
|
156
|
-
#
|
157
|
-
|
158
|
-
# (abstract) Return the ForeignKeyDefinition objects for foreign key
|
159
|
-
# constraints defined on this table
|
160
|
-
def foreign_keys(table_name, name = nil) raise "Internal Error: Connection adapter didn't override abstract function"; [] end
|
161
|
-
|
162
|
-
# (abstract) Return the ForeignKeyDefinition objects for foreign key
|
163
|
-
# constraints defined on other tables that reference this table
|
164
|
-
def reverse_foreign_keys(table_name, name = nil) raise "Internal Error: Connection adapter didn't override abstract function"; [] end
|
165
|
-
end
|
166
|
-
end
|
167
|
-
end
|
168
|
-
end
|
data/lib/schema_plus/foreign_keys/active_record/connection_adapters/foreign_key_definition.rb
DELETED
@@ -1,138 +0,0 @@
|
|
1
|
-
require 'active_record/connection_adapters/abstract/schema_definitions'
|
2
|
-
|
3
|
-
module SchemaPlus::ForeignKeys
|
4
|
-
module ActiveRecord
|
5
|
-
module ConnectionAdapters
|
6
|
-
# Instances of this class are returned by the queries ActiveRecord::Base#foreign_keys and ActiveRecord::Base#reverse_foreign_keys (via AbstractAdapter#foreign_keys and AbstractAdapter#reverse_foreign_keys)
|
7
|
-
#
|
8
|
-
# The on_update and on_delete attributes can take on the following values:
|
9
|
-
# :cascade
|
10
|
-
# :restrict
|
11
|
-
# :nullify
|
12
|
-
# :set_default
|
13
|
-
# :no_action
|
14
|
-
#
|
15
|
-
# The deferrable attribute can take on the following values:
|
16
|
-
# true
|
17
|
-
# :initially_deferred
|
18
|
-
module ForeignKeyDefinition
|
19
|
-
|
20
|
-
def column_names
|
21
|
-
ActiveSupport::Deprecation.warn "ForeignKeyDefinition#column_names is deprecated, use Array.wrap(column)"
|
22
|
-
Array.wrap(column)
|
23
|
-
end
|
24
|
-
|
25
|
-
def references_column_names
|
26
|
-
ActiveSupport::Deprecation.warn "ForeignKeyDefinition#references_column_names is deprecated, use Array.wrap(primary_key)"
|
27
|
-
Array.wrap(primary_key)
|
28
|
-
end
|
29
|
-
|
30
|
-
def references_table_name
|
31
|
-
ActiveSupport::Deprecation.warn "ForeignKeyDefinition#references_table_name is deprecated, use #to_table"
|
32
|
-
to_table
|
33
|
-
end
|
34
|
-
|
35
|
-
def table_name
|
36
|
-
ActiveSupport::Deprecation.warn "ForeignKeyDefinition#table_name is deprecated, use #from_table"
|
37
|
-
from_table
|
38
|
-
end
|
39
|
-
|
40
|
-
ACTIONS = { :cascade => "CASCADE", :restrict => "RESTRICT", :nullify => "SET NULL", :set_default => "SET DEFAULT", :no_action => "NO ACTION" }.freeze
|
41
|
-
ACTION_LOOKUP = ACTIONS.invert.freeze
|
42
|
-
|
43
|
-
def initialize(from_table, to_table, options={})
|
44
|
-
[:on_update, :on_delete].each do |key|
|
45
|
-
if options[key] == :set_null
|
46
|
-
ActiveSupport::Deprecation.warn ":set_null value for #{key} is deprecated. use :nullify instead"
|
47
|
-
options[key] = :nullify
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
super from_table, to_table, options
|
52
|
-
|
53
|
-
if column.is_a?(Array) and column.length == 1
|
54
|
-
options[:column] = column[0]
|
55
|
-
end
|
56
|
-
if primary_key.is_a?(Array) and primary_key.length == 1
|
57
|
-
options[:primary_key] = primary_key[0]
|
58
|
-
end
|
59
|
-
|
60
|
-
ACTIONS.has_key?(on_update) or raise(ArgumentError, "invalid :on_update action: #{on_update.inspect}") if on_update
|
61
|
-
ACTIONS.has_key?(on_delete) or raise(ArgumentError, "invalid :on_delete action: #{on_delete.inspect}") if on_delete
|
62
|
-
if ::ActiveRecord::Base.connection.adapter_name =~ /^mysql/i
|
63
|
-
raise(NotImplementedError, "MySQL does not support ON UPDATE SET DEFAULT") if on_update == :set_default
|
64
|
-
raise(NotImplementedError, "MySQL does not support ON DELETE SET DEFAULT") if on_delete == :set_default
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
# Truthy if the constraint is deferrable
|
69
|
-
def deferrable
|
70
|
-
options[:deferrable]
|
71
|
-
end
|
72
|
-
|
73
|
-
# Dumps a definition of foreign key.
|
74
|
-
def to_dump(column: nil, inline: nil)
|
75
|
-
dump = case
|
76
|
-
when column then "foreign_key: {references:"
|
77
|
-
when inline then "t.foreign_key"
|
78
|
-
else "add_foreign_key #{from_table.inspect},"
|
79
|
-
end
|
80
|
-
dump << " #{to_table.inspect}"
|
81
|
-
|
82
|
-
val_or_array = -> val { val.is_a?(Array) ? "[#{val.map(&:inspect).join(', ')}]" : val.inspect }
|
83
|
-
|
84
|
-
dump << ", column: #{val_or_array.call self.column}" unless column
|
85
|
-
dump << ", primary_key: #{val_or_array.call self.primary_key}" if custom_primary_key?
|
86
|
-
dump << ", name: #{name.inspect}" if name
|
87
|
-
dump << ", on_update: #{on_update.inspect}" if on_update
|
88
|
-
dump << ", on_delete: #{on_delete.inspect}" if on_delete
|
89
|
-
dump << ", deferrable: #{deferrable.inspect}" if deferrable
|
90
|
-
dump << "}" if column
|
91
|
-
dump
|
92
|
-
end
|
93
|
-
|
94
|
-
def to_sql
|
95
|
-
sql = name ? "CONSTRAINT #{name} " : ""
|
96
|
-
sql << "FOREIGN KEY (#{quoted_column_names.join(", ")}) REFERENCES #{quoted_to_table} (#{quoted_primary_keys.join(", ")})"
|
97
|
-
sql << " ON UPDATE #{ACTIONS[on_update]}" if on_update
|
98
|
-
sql << " ON DELETE #{ACTIONS[on_delete]}" if on_delete
|
99
|
-
sql << " DEFERRABLE" if deferrable
|
100
|
-
sql << " INITIALLY DEFERRED" if deferrable == :initially_deferred
|
101
|
-
sql
|
102
|
-
end
|
103
|
-
|
104
|
-
def quoted_column_names
|
105
|
-
Array(column).map { |name| ::ActiveRecord::Base.connection.quote_column_name(name) }
|
106
|
-
end
|
107
|
-
|
108
|
-
def quoted_primary_keys
|
109
|
-
Array(primary_key).map { |name| ::ActiveRecord::Base.connection.quote_column_name(name) }
|
110
|
-
end
|
111
|
-
|
112
|
-
def quoted_to_table
|
113
|
-
::ActiveRecord::Base.connection.quote_table_name(to_table)
|
114
|
-
end
|
115
|
-
|
116
|
-
def self.default_name(from_table, column)
|
117
|
-
"fk_#{fixup_schema_name(from_table)}_#{Array.wrap(column).join('_and_')}"
|
118
|
-
end
|
119
|
-
|
120
|
-
def self.auto_index_name(from_table, column_name)
|
121
|
-
"fk__#{fixup_schema_name(from_table)}_#{Array.wrap(column_name).join('_and_')}"
|
122
|
-
end
|
123
|
-
|
124
|
-
def self.fixup_schema_name(table_name)
|
125
|
-
# replace . with _
|
126
|
-
table_name.to_s.gsub(/[.]/, '_')
|
127
|
-
end
|
128
|
-
|
129
|
-
def match(test)
|
130
|
-
return false unless from_table == test.from_table
|
131
|
-
[:to_table, :column].reject{ |attr| test.send(attr).blank? }.all? { |attr|
|
132
|
-
test.send(attr).to_s == self.send(attr).to_s
|
133
|
-
}
|
134
|
-
end
|
135
|
-
end
|
136
|
-
end
|
137
|
-
end
|
138
|
-
end
|
@@ -1,126 +0,0 @@
|
|
1
|
-
module SchemaPlus::ForeignKeys
|
2
|
-
module ActiveRecord
|
3
|
-
module ConnectionAdapters
|
4
|
-
# SchemaPlus::ForeignKeys includes a MySQL implementation of the AbstractAdapter
|
5
|
-
# extensions.
|
6
|
-
module Mysql2Adapter
|
7
|
-
|
8
|
-
#:enddoc:
|
9
|
-
|
10
|
-
def remove_column(table_name, column_name, type=nil, options={})
|
11
|
-
foreign_keys(table_name).select { |foreign_key| Array.wrap(foreign_key.column).include?(column_name.to_s) }.each do |foreign_key|
|
12
|
-
remove_foreign_key(table_name, name: foreign_key.name)
|
13
|
-
end
|
14
|
-
super table_name, column_name, type, options
|
15
|
-
end
|
16
|
-
|
17
|
-
def rename_table(oldname, newname)
|
18
|
-
super
|
19
|
-
rename_foreign_keys(oldname, newname)
|
20
|
-
end
|
21
|
-
|
22
|
-
def remove_foreign_key(*args)
|
23
|
-
from_table, to_table, options = normalize_remove_foreign_key_args(*args)
|
24
|
-
if options[:if_exists]
|
25
|
-
foreign_key_name = get_foreign_key_name(from_table, to_table, options)
|
26
|
-
return if !foreign_key_name or not foreign_keys(from_table).detect{|fk| fk.name == foreign_key_name}
|
27
|
-
end
|
28
|
-
options.delete(:if_exists)
|
29
|
-
super from_table, to_table, options
|
30
|
-
end
|
31
|
-
|
32
|
-
def remove_foreign_key_sql(*args)
|
33
|
-
super.tap { |ret|
|
34
|
-
ret.sub!(/DROP CONSTRAINT/, 'DROP FOREIGN KEY') if ret
|
35
|
-
}
|
36
|
-
end
|
37
|
-
|
38
|
-
def foreign_keys(table_name, name = nil)
|
39
|
-
results = select_all("SHOW CREATE TABLE #{quote_table_name(table_name)}", name)
|
40
|
-
|
41
|
-
table_name = table_name.to_s
|
42
|
-
namespace_prefix = table_namespace_prefix(table_name)
|
43
|
-
|
44
|
-
foreign_keys = []
|
45
|
-
|
46
|
-
results.each do |result|
|
47
|
-
create_table_sql = result["Create Table"]
|
48
|
-
create_table_sql.lines.each do |line|
|
49
|
-
if line =~ /^ CONSTRAINT [`"](.+?)[`"] FOREIGN KEY \([`"](.+?)[`"]\) REFERENCES [`"](.+?)[`"] \((.+?)\)( ON DELETE (.+?))?( ON UPDATE (.+?))?,?$/
|
50
|
-
name = $1
|
51
|
-
columns = $2
|
52
|
-
to_table = $3
|
53
|
-
to_table = namespace_prefix + to_table if table_namespace_prefix(to_table).blank?
|
54
|
-
primary_keys = $4
|
55
|
-
on_update = $8
|
56
|
-
on_delete = $6
|
57
|
-
on_update = ForeignKeyDefinition::ACTION_LOOKUP[on_update] || :restrict
|
58
|
-
on_delete = ForeignKeyDefinition::ACTION_LOOKUP[on_delete] || :restrict
|
59
|
-
|
60
|
-
options = { :name => name,
|
61
|
-
:on_delete => on_delete,
|
62
|
-
:on_update => on_update,
|
63
|
-
:column => columns.gsub('`', '').split(', '),
|
64
|
-
:primary_key => primary_keys.gsub('`', '').split(', ')
|
65
|
-
}
|
66
|
-
|
67
|
-
foreign_keys << ::ActiveRecord::ConnectionAdapters::ForeignKeyDefinition.new(
|
68
|
-
namespace_prefix + table_name,
|
69
|
-
to_table,
|
70
|
-
options)
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
foreign_keys
|
76
|
-
end
|
77
|
-
|
78
|
-
def reverse_foreign_keys(table_name, name = nil)
|
79
|
-
results = select_all(<<-SQL, name)
|
80
|
-
SELECT constraint_name, table_name, column_name, referenced_table_name, referenced_column_name
|
81
|
-
FROM information_schema.key_column_usage
|
82
|
-
WHERE table_schema = #{table_schema_sql(table_name)}
|
83
|
-
AND referenced_table_schema = table_schema
|
84
|
-
ORDER BY constraint_name, ordinal_position;
|
85
|
-
SQL
|
86
|
-
|
87
|
-
constraints = results.to_a.group_by do |r|
|
88
|
-
r.values_at('constraint_name', 'table_name', 'referenced_table_name')
|
89
|
-
end
|
90
|
-
|
91
|
-
from_table_constraints = constraints.select do |(_, _, to_table), _|
|
92
|
-
table_name_without_namespace(table_name).casecmp(to_table) == 0
|
93
|
-
end
|
94
|
-
|
95
|
-
from_table_constraints.map do |(constraint_name, from_table, to_table), columns|
|
96
|
-
from_table = table_namespace_prefix(from_table) + from_table
|
97
|
-
to_table = table_namespace_prefix(to_table) + to_table
|
98
|
-
|
99
|
-
options = {
|
100
|
-
:name => constraint_name,
|
101
|
-
:column => columns.map { |row| row['column_name'] },
|
102
|
-
:primary_key => columns.map { |row| row['referenced_column_name'] }
|
103
|
-
}
|
104
|
-
|
105
|
-
::ActiveRecord::ConnectionAdapters::ForeignKeyDefinition.new(from_table, to_table, options)
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
private
|
110
|
-
|
111
|
-
def table_namespace_prefix(table_name)
|
112
|
-
table_name.to_s =~ /(.*[.])/ ? $1 : ""
|
113
|
-
end
|
114
|
-
|
115
|
-
def table_schema_sql(table_name)
|
116
|
-
table_name.to_s =~ /(.*)[.]/ ? "'#{$1}'" : "SCHEMA()"
|
117
|
-
end
|
118
|
-
|
119
|
-
def table_name_without_namespace(table_name)
|
120
|
-
table_name.to_s.sub /.*[.]/, ''
|
121
|
-
end
|
122
|
-
|
123
|
-
end
|
124
|
-
end
|
125
|
-
end
|
126
|
-
end
|