schema_plus 2.0.0.pre15 → 2.0.0.pre16

Sign up to get free protection for your applications and to get access to all the features.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +6 -78
  3. data/lib/schema_plus.rb +1 -0
  4. data/lib/schema_plus/auto_foreign_keys.rb +31 -0
  5. data/lib/schema_plus/auto_foreign_keys/active_record/connection_adapters/sqlite3_adapter.rb +22 -0
  6. data/lib/schema_plus/auto_foreign_keys/active_record/migration/command_recorder.rb +14 -0
  7. data/lib/schema_plus/auto_foreign_keys/middleware/migration.rb +66 -0
  8. data/lib/schema_plus/{foreign_keys → auto_foreign_keys}/middleware/schema.rb +1 -1
  9. data/lib/schema_plus/version.rb +1 -1
  10. data/schema_plus.gemspec +2 -1
  11. data/spec/{schema_plus_foreign_keys → schema_auto_foreign_keys}/foreign_key_spec.rb +0 -0
  12. data/spec/{schema_plus_foreign_keys → schema_auto_foreign_keys}/migration_spec.rb +3 -2
  13. data/spec/{schema_plus_foreign_keys → schema_auto_foreign_keys}/schema_dumper_spec.rb +0 -0
  14. data/spec/{schema_plus_foreign_keys → schema_auto_foreign_keys}/schema_spec.rb +0 -0
  15. metadata +31 -32
  16. data/lib/schema_plus/foreign_keys.rb +0 -93
  17. data/lib/schema_plus/foreign_keys/active_record/base.rb +0 -33
  18. data/lib/schema_plus/foreign_keys/active_record/connection_adapters/abstract_adapter.rb +0 -168
  19. data/lib/schema_plus/foreign_keys/active_record/connection_adapters/foreign_key_definition.rb +0 -138
  20. data/lib/schema_plus/foreign_keys/active_record/connection_adapters/mysql2_adapter.rb +0 -126
  21. data/lib/schema_plus/foreign_keys/active_record/connection_adapters/postgresql_adapter.rb +0 -89
  22. data/lib/schema_plus/foreign_keys/active_record/connection_adapters/sqlite3_adapter.rb +0 -98
  23. data/lib/schema_plus/foreign_keys/active_record/connection_adapters/table_definition.rb +0 -108
  24. data/lib/schema_plus/foreign_keys/active_record/migration/command_recorder.rb +0 -35
  25. data/lib/schema_plus/foreign_keys/middleware/dumper.rb +0 -79
  26. data/lib/schema_plus/foreign_keys/middleware/migration.rb +0 -184
  27. data/lib/schema_plus/foreign_keys/middleware/model.rb +0 -15
  28. data/lib/schema_plus/foreign_keys/middleware/mysql.rb +0 -20
  29. data/lib/schema_plus/foreign_keys/middleware/sql.rb +0 -20
  30. data/lib/schema_plus/foreign_keys/version.rb +0 -3
  31. data/spec/schema_plus_foreign_keys/foreign_key_definition_spec.rb +0 -34
  32. 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
@@ -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