Module: SchemaPlus::ActiveRecord::ConnectionAdapters::AbstractAdapter

Defined in:
lib/schema_plus/active_record/connection_adapters/abstract_adapter.rb

Overview

SchemaPlus adds several methods to ActiveRecord::ConnectionAdapters::AbstractAdapter. In most cases you don't call these directly, but rather the methods that define things are called by schema statements, and methods that query things are called by ActiveRecord::Base.

Defined Under Namespace

Modules: AddColumnOptions, VisitTableDefinition

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.included(base) ⇒ Object

:nodoc:


14
15
16
17
# File 'lib/schema_plus/active_record/connection_adapters/abstract_adapter.rb', line 14

def self.included(base) #:nodoc:
  base.alias_method_chain :initialize, :schema_plus
  base.alias_method_chain :remove_index, :schema_plus
end

.proper_table_name(name) ⇒ Object


94
95
96
97
98
99
100
# File 'lib/schema_plus/active_record/connection_adapters/abstract_adapter.rb', line 94

def self.proper_table_name(name)
   if ::ActiveRecord::Migration.instance_methods(false).include? :proper_table_name
   proper_name = ::ActiveRecord::Migration.new.proper_table_name(name) # Rails >= 4.1
 else
   proper_name = ::ActiveRecord::Migrator.proper_table_name(name) # Rails <= 4.0 ; Deprecated in 4.1
 end
end

Instance Method Details

#_build_foreign_key(table_name, column_names, references_table_name, references_column_names, options = {}) ⇒ Object

:nodoc:


88
89
90
91
92
# File 'lib/schema_plus/active_record/connection_adapters/abstract_adapter.rb', line 88

def _build_foreign_key(table_name, column_names, references_table_name, references_column_names, options = {}) #:nodoc:
  options.merge!(:column_names => column_names, :references_column_names => references_column_names)
  options.reverse_merge!(:name => ForeignKeyDefinition.default_name(table_name, column_names))
  ForeignKeyDefinition.new(table_name, AbstractAdapter.proper_table_name(references_table_name), options)
end

#add_foreign_key(table_name, column_names, references_table_name, references_column_names, options = {}) ⇒ Object

Define a foreign key constraint. Valid options are :on_update, :on_delete, and :deferrable, with values as described at ConnectionAdapters::ForeignKeyDefinition

(NOTE: Sqlite3 does not support altering a table to add foreign-key constraints; they must be included in the table specification when it's created. If you're using Sqlite3, this method will raise an error.)


76
77
78
79
# File 'lib/schema_plus/active_record/connection_adapters/abstract_adapter.rb', line 76

def add_foreign_key(table_name, column_names, references_table_name, references_column_names, options = {})
  foreign_key_sql = add_foreign_key_sql(table_name, column_names, references_table_name, references_column_names, options)
  execute "ALTER TABLE #{quote_table_name(table_name)} #{foreign_key_sql}"
end

#add_foreign_key_sql(table_name, column_names, references_table_name, references_column_names, options = {}) ⇒ Object

called directly by AT's bulk_change_table, for migration change_table :name, :bulk => true { … }


83
84
85
86
# File 'lib/schema_plus/active_record/connection_adapters/abstract_adapter.rb', line 83

def add_foreign_key_sql(table_name, column_names, references_table_name, references_column_names, options = {}) #:nodoc:
  foreign_key = _build_foreign_key(table_name, column_names, references_table_name, references_column_names, options)
  "ADD #{foreign_key.to_sql}"
end

#create_view(view_name, definition, options = {}) ⇒ Object

Create a view given the SQL definition. Specify :force => true to first drop the view if it already exists.


50
51
52
53
54
55
56
# File 'lib/schema_plus/active_record/connection_adapters/abstract_adapter.rb', line 50

def create_view(view_name, definition, options={})
  definition = definition.to_sql if definition.respond_to? :to_sql
  if options[:force]
    drop_view(view_name, if_exists: true)
  end
  execute "CREATE VIEW #{quote_table_name(view_name)} AS #{definition}"
end

#drop_table(name, options = {}) ⇒ Object

Extends rails' drop_table to include these options:

:cascade
:if_exists

143
144
145
146
147
148
149
# File 'lib/schema_plus/active_record/connection_adapters/abstract_adapter.rb', line 143

def drop_table(name, options = {})
  sql = "DROP TABLE"
  sql += " IF EXISTS" if options[:if_exists]
  sql += " #{quote_table_name(name)}"
  sql += " CASCADE" if options[:cascade]
  execute sql
end

#drop_view(view_name, options = {}) ⇒ Object

Drop the named view. Specify :if_exists => true to fail silently if the view doesn't exist.


60
61
62
63
64
65
# File 'lib/schema_plus/active_record/connection_adapters/abstract_adapter.rb', line 60

def drop_view(view_name, options = {})
  sql = "DROP VIEW"
  sql += " IF EXISTS" if options[:if_exists]
  sql += " #{quote_table_name(view_name)}"
  execute sql
end

#foreign_keys(table_name, name = nil) ⇒ Object

(abstract) Return the ForeignKeyDefinition objects for foreign key constraints defined on this table


279
# File 'lib/schema_plus/active_record/connection_adapters/abstract_adapter.rb', line 279

def foreign_keys(table_name, name = nil) raise "Internal Error: Connection adapter didn't override abstract function"; [] end

#initialize_with_schema_plus(*args) ⇒ Object

:nodoc:


19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/schema_plus/active_record/connection_adapters/abstract_adapter.rb', line 19

def initialize_with_schema_plus(*args) #:nodoc:
  initialize_without_schema_plus(*args)
  adapter = case adapter_name
              # name of MySQL adapter depends on mysql gem
              # * with mysql gem adapter is named MySQL
              # * with mysql2 gem adapter is named Mysql2
              # Here we handle this and hopefully futher adapter names
            when /^MySQL/i                 then 'MysqlAdapter'
            when 'PostgreSQL', 'PostGIS'   then 'PostgresqlAdapter'
            when 'SQLite'                  then 'Sqlite3Adapter'
            end
  if adapter.nil?
    unless adapter_name == 'JDBC' # ARJDBC
      ::ActiveRecord::Base.logger.warn "SchemaPlus: Unsupported adapter name #{adapter_name.inspect}.  Leaving it alone."
    end
    return
  end
  adapter_module = SchemaPlus::ActiveRecord::ConnectionAdapters.const_get(adapter)
  self.class.send(:include, adapter_module) unless self.class.include?(adapter_module)

  if "#{::ActiveRecord::VERSION::MAJOR}.#{::ActiveRecord::VERSION::MINOR}".to_r >= "4.1".to_r
    self.class.const_get(:SchemaCreation).send(:include, adapter_module.const_get(:AddColumnOptions))
  else
    self.class.send(:include, adapter_module.const_get(:AddColumnOptions))
  end

  extend(SchemaPlus::ActiveRecord::ForeignKeys)
end

#remove_foreign_key(table_name, *args) ⇒ Object

Remove a foreign key constraint

Arguments are the same as for add_foreign_key, or by name:

remove_foreign_key table_name, column_names, references_table_name, references_column_names
remove_foreign_key name: constraint_name

(NOTE: Sqlite3 does not support altering a table to remove foreign-key constraints. If you're using Sqlite3, this method will raise an error.)


112
113
114
115
116
# File 'lib/schema_plus/active_record/connection_adapters/abstract_adapter.rb', line 112

def remove_foreign_key(table_name, *args)
  case sql = remove_foreign_key_sql(table_name, *args)
  when String then execute "ALTER TABLE #{quote_table_name(table_name)} #{sql}"
  end
end

#remove_foreign_key_sql(table_name, *args) ⇒ Object


118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/schema_plus/active_record/connection_adapters/abstract_adapter.rb', line 118

def remove_foreign_key_sql(table_name, *args)
  column_names, references_table_name, references_column_names, options = args
  options ||= {}
  foreign_key_name = case
                     when args.length == 1
                       case args[0]
                       when Hash then   args[0][:name]
                       else args[0]
                       end
                     else
                       test_fk = _build_foreign_key(table_name, column_names, references_table_name, references_column_names, options)
                       if foreign_keys(table_name).detect { |fk| fk == test_fk }
                         test_fk.name
                       else
                         raise "SchemaPlus: no foreign key constraint found on #{table_name.inspect} matching #{args.inspect}" unless options[:if_exists]
                         nil
                       end
                     end
  foreign_key_name ? "DROP CONSTRAINT #{foreign_key_name}" : []  # hack -- return empty array rather than nil, so that result will disappear when caller flattens but doesn't compact
end

#remove_index_with_schema_plus(table_name, *args) ⇒ Object

Extends rails' remove_index to include this options:

:if_exists

153
154
155
156
157
158
159
160
# File 'lib/schema_plus/active_record/connection_adapters/abstract_adapter.rb', line 153

def remove_index_with_schema_plus(table_name, *args)
  options = args.extract_options!
  if_exists = options.delete(:if_exists)
  options.delete(:column) if options[:name] and ::ActiveRecord::VERSION::MAJOR < 4
  args << options if options.any?
  return if if_exists and not index_name_exists?(table_name, options[:name] || index_name(table_name, *args), false)
  remove_index_without_schema_plus(table_name, *args)
end

#rename_indexes_and_foreign_keys(oldname, newname) ⇒ Object

called from individual adpaters, after renaming table from old name to


164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
# File 'lib/schema_plus/active_record/connection_adapters/abstract_adapter.rb', line 164

def rename_indexes_and_foreign_keys(oldname, newname) #:nodoc:
  indexes(newname).select{|index| index.name == index_name(oldname, index.columns)}.each do |index|
    rename_index(newname, index.name, index_name(newname, index.columns))
  end
  foreign_keys(newname).each do |fk|
    index = indexes(newname).find{|index| index.name == ForeignKeyDefinition.auto_index_name(oldname, fk.column_names)}
    begin
      remove_foreign_key(newname, fk.name)
    rescue NotImplementedError
      # sqlite3 can't remove foreign keys, so just skip it
    end
    # rename the index only when the fk constraint doesn't exist.
    # mysql doesn't allow the rename (which is a delete & add)
    # if the index is on a foreign key constraint
    rename_index(newname, index.name, ForeignKeyDefinition.auto_index_name(newname, index.columns)) if index
    begin
      add_foreign_key(newname, fk.column_names, fk.references_table_name, fk.references_column_names, :name => fk.name.sub(/#{oldname}/, newname), :on_update => fk.on_update, :on_delete => fk.on_delete, :deferrable => fk.deferrable)
    rescue NotImplementedError
      # sqlite3 can't add foreign keys, so just skip it
    end
  end
end

#reverse_foreign_keys(table_name, name = nil) ⇒ Object

(abstract) Return the ForeignKeyDefinition objects for foreign key constraints defined on other tables that reference this table


283
# File 'lib/schema_plus/active_record/connection_adapters/abstract_adapter.rb', line 283

def reverse_foreign_keys(table_name, name = nil) raise "Internal Error: Connection adapter didn't override abstract function"; [] end

#supports_partial_indexes?Boolean

Returns true if the database supports parital indexes (abstract; only Postgresql returns true)

Returns:

  • (Boolean)

189
190
191
# File 'lib/schema_plus/active_record/connection_adapters/abstract_adapter.rb', line 189

def supports_partial_indexes?
  false
end

#view_definition(view_name, name = nil) ⇒ Object

(abstract) Returns the SQL definition of a given view. This is the literal SQL would come after 'CREATVE VIEW viewname AS ' in the SQL statement to create a view.


275
# File 'lib/schema_plus/active_record/connection_adapters/abstract_adapter.rb', line 275

def view_definition(view_name, name = nil) raise "Internal Error: Connection adapter didn't override abstract function"; end

#views(name = nil) ⇒ Object

(abstract) Returns the names of all views, as an array of strings


270
# File 'lib/schema_plus/active_record/connection_adapters/abstract_adapter.rb', line 270

def views(name = nil) raise "Internal Error: Connection adapter didn't override abstract function"; [] end