aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb')
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb124
1 files changed, 75 insertions, 49 deletions
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
index ce4c5a1383..30a4f9aa35 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
@@ -1,9 +1,12 @@
-require 'active_support/core_ext/array/wrap'
require 'active_support/deprecation/reporting'
+require 'active_record/schema_migration'
+require 'active_record/migration/join_table'
module ActiveRecord
module ConnectionAdapters # :nodoc:
module SchemaStatements
+ include ActiveRecord::Migration::JoinTable
+
# Returns a Hash of mappings from the abstract data types to the native
# database types. See TableDefinition#column for details on the recognized
# abstract data types.
@@ -13,11 +16,9 @@ module ActiveRecord
# Truncates a table alias according to the limits of the current adapter.
def table_alias_for(table_name)
- table_name[0...table_alias_length].gsub(/\./, '_')
+ table_name[0...table_alias_length].tr('.', '_')
end
- # def tables(name = nil) end
-
# Checks to see if the table +table_name+ exists on the database.
#
# === Example
@@ -44,7 +45,7 @@ module ActiveRecord
# # Check an index with a custom name exists
# index_exists?(:suppliers, :company_id, :name => "idx_company_id"
def index_exists?(table_name, column_name, options = {})
- column_names = Array.wrap(column_name)
+ column_names = Array(column_name)
index_name = options.key?(:name) ? options[:name].to_s : index_name(table_name, :column => column_names)
if options[:unique]
indexes(table_name).any?{ |i| i.unique && i.name == index_name }
@@ -55,7 +56,7 @@ module ActiveRecord
# Returns an array of Column objects for the table specified by +table_name+.
# See the concrete implementation for details on the expected parameter values.
- def columns(table_name, name = nil) end
+ def columns(table_name) end
# Checks to see if a column exists in a given table.
#
@@ -162,7 +163,7 @@ module ActiveRecord
yield td if block_given?
if options[:force] && table_exists?(table_name)
- drop_table(table_name)
+ drop_table(table_name, options)
end
create_sql = "CREATE#{' TEMPORARY' if options[:temporary]} TABLE "
@@ -170,6 +171,46 @@ module ActiveRecord
create_sql << td.to_sql
create_sql << ") #{options[:options]}"
execute create_sql
+ td.indexes.each_pair { |c,o| add_index table_name, c, o }
+ end
+
+ # Creates a new join table with the name created using the lexical order of the first two
+ # arguments. These arguments can be a String or a Symbol.
+ #
+ # # Creates a table called 'assemblies_parts' with no id.
+ # create_join_table(:assemblies, :parts)
+ #
+ # You can pass a +options+ hash can include the following keys:
+ # [<tt>:table_name</tt>]
+ # Sets the table name overriding the default
+ # [<tt>:column_options</tt>]
+ # Any extra options you want appended to the columns definition.
+ # [<tt>:options</tt>]
+ # Any extra options you want appended to the table definition.
+ # [<tt>:temporary</tt>]
+ # Make a temporary table.
+ # [<tt>:force</tt>]
+ # Set to true to drop the table before creating it.
+ # Defaults to false.
+ #
+ # ===== Examples
+ # ====== Add a backend specific option to the generated SQL (MySQL)
+ # create_join_table(:assemblies, :parts, :options => 'ENGINE=InnoDB DEFAULT CHARSET=utf8')
+ # generates:
+ # CREATE TABLE assemblies_parts (
+ # assembly_id int NOT NULL,
+ # part_id int NOT NULL,
+ # ) ENGINE=InnoDB DEFAULT CHARSET=utf8
+ def create_join_table(table_1, table_2, options = {})
+ join_table_name = find_join_table_name(table_1, table_2, options)
+
+ column_options = options.delete(:column_options) || {}
+ column_options.reverse_merge!({:null => false})
+
+ create_table(join_table_name, options.merge!(:id => false)) do |td|
+ td.integer :"#{table_1.to_s.singularize}_id", column_options
+ td.integer :"#{table_2.to_s.singularize}_id", column_options
+ end
end
# A block for changing columns in +table+.
@@ -254,7 +295,7 @@ module ActiveRecord
end
# Drops a table from the database.
- def drop_table(table_name)
+ def drop_table(table_name, options = {})
execute "DROP TABLE #{quote_table_name(table_name)}"
end
@@ -303,15 +344,8 @@ module ActiveRecord
# Adds a new index to the table. +column_name+ can be a single Symbol, or
# an Array of Symbols.
#
- # The index will be named after the table and the first column name,
- # unless you pass <tt>:name</tt> as an option.
- #
- # When creating an index on multiple columns, the first column is used as a name
- # for the index. For example, when you specify an index on two columns
- # [<tt>:first</tt>, <tt>:last</tt>], the DBMS creates an index for both columns as well as an
- # index for the first column <tt>:first</tt>. Using just the first name for this index
- # makes sense, because you will never have to create a singular index with this
- # name.
+ # The index will be named after the table and the column name(s), unless
+ # you pass <tt>:name</tt> as an option.
#
# ===== Examples
#
@@ -342,15 +376,22 @@ module ActiveRecord
# Note: SQLite doesn't support index length
#
# ====== Creating an index with a sort order (desc or asc, asc is the default)
- # add_index(:accounts, [:branch_id, :party_id, :surname], :order => {:branch_id => :desc, :part_id => :asc})
+ # add_index(:accounts, [:branch_id, :party_id, :surname], :order => {:branch_id => :desc, :party_id => :asc})
# generates
# CREATE INDEX by_branch_desc_party ON accounts(branch_id DESC, party_id ASC, surname)
#
# Note: mysql doesn't yet support index order (it accepts the syntax but ignores it)
#
+ # ====== Creating a partial index
+ # add_index(:accounts, [:branch_id, :party_id], :unique => true, :where => "active")
+ # generates
+ # CREATE UNIQUE INDEX index_accounts_on_branch_id_and_party_id ON accounts(branch_id, party_id) WHERE active
+ #
+ # Note: only supported by PostgreSQL
+ #
def add_index(table_name, column_name, options = {})
- index_name, index_type, index_columns = add_index_options(table_name, column_name, options)
- execute "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} (#{index_columns})"
+ index_name, index_type, index_columns, index_options = add_index_options(table_name, column_name, options)
+ execute "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} (#{index_columns})#{index_options}"
end
# Remove the given index from the table.
@@ -386,7 +427,7 @@ module ActiveRecord
def index_name(table_name, options) #:nodoc:
if Hash === options # legacy support
if options[:column]
- "index_#{table_name}_on_#{Array.wrap(options[:column]) * '_and_'}"
+ "index_#{table_name}_on_#{Array(options[:column]) * '_and_'}"
elsif options[:name]
options[:name]
else
@@ -414,38 +455,20 @@ module ActiveRecord
def dump_schema_information #:nodoc:
sm_table = ActiveRecord::Migrator.schema_migrations_table_name
- migrated = select_values("SELECT version FROM #{sm_table} ORDER BY version")
- migrated.map { |v| "INSERT INTO #{sm_table} (version) VALUES ('#{v}');" }.join("\n\n")
+
+ ActiveRecord::SchemaMigration.order('version').all.map { |sm|
+ "INSERT INTO #{sm_table} (version) VALUES ('#{sm.version}');"
+ }.join "\n\n"
end
# Should not be called normally, but this operation is non-destructive.
# The migrations module handles this automatically.
def initialize_schema_migrations_table
- sm_table = ActiveRecord::Migrator.schema_migrations_table_name
-
- unless table_exists?(sm_table)
- create_table(sm_table, :id => false) do |schema_migrations_table|
- schema_migrations_table.column :version, :string, :null => false
- end
- add_index sm_table, :version, :unique => true,
- :name => "#{Base.table_name_prefix}unique_schema_migrations#{Base.table_name_suffix}"
-
- # Backwards-compatibility: if we find schema_info, assume we've
- # migrated up to that point:
- si_table = Base.table_name_prefix + 'schema_info' + Base.table_name_suffix
-
- if table_exists?(si_table)
- ActiveRecord::Deprecation.warn "Usage of the schema table `#{si_table}` is deprecated. Please switch to using `schema_migrations` table"
-
- old_version = select_value("SELECT version FROM #{quote_table_name(si_table)}").to_i
- assume_migrated_upto_version(old_version)
- drop_table(si_table)
- end
- end
+ ActiveRecord::SchemaMigration.create_table
end
def assume_migrated_upto_version(version, migrations_paths = ActiveRecord::Migrator.migrations_paths)
- migrations_paths = Array.wrap(migrations_paths)
+ migrations_paths = Array(migrations_paths)
version = version.to_i
sm_table = quote_table_name(ActiveRecord::Migrator.schema_migrations_table_name)
@@ -517,8 +540,8 @@ module ActiveRecord
# ===== Examples
# add_timestamps(:suppliers)
def add_timestamps(table_name)
- add_column table_name, :created_at, :datetime, :null => false
- add_column table_name, :updated_at, :datetime, :null => false
+ add_column table_name, :created_at, :datetime
+ add_column table_name, :updated_at, :datetime
end
# Removes the timestamp columns (created_at and updated_at) from the table definition.
@@ -560,12 +583,15 @@ module ActiveRecord
end
def add_index_options(table_name, column_name, options = {})
- column_names = Array.wrap(column_name)
+ column_names = Array(column_name)
index_name = index_name(table_name, :column => column_names)
if Hash === options # legacy support, since this param was a string
index_type = options[:unique] ? "UNIQUE" : ""
index_name = options[:name].to_s if options.key?(:name)
+ if supports_partial_index?
+ index_options = options[:where] ? " WHERE #{options[:where]}" : ""
+ end
else
index_type = options
end
@@ -578,7 +604,7 @@ module ActiveRecord
end
index_columns = quoted_columns_for_index(column_names, options).join(", ")
- [index_name, index_type, index_columns]
+ [index_name, index_type, index_columns, index_options]
end
def index_name_for_remove(table_name, options = {})