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.
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