diff options
author | David Heinemeier Hansson <david@loudthinking.com> | 2005-07-05 07:19:20 +0000 |
---|---|---|
committer | David Heinemeier Hansson <david@loudthinking.com> | 2005-07-05 07:19:20 +0000 |
commit | f1880cac5862172608ff26d1178a31c05b904d77 (patch) | |
tree | aab6bdf693ab0f7495e308a9813432938d95e040 /activerecord/lib | |
parent | 2418a68aa23c96ce20aae6168c71c760cb6e7809 (diff) | |
download | rails-f1880cac5862172608ff26d1178a31c05b904d77.tar.gz rails-f1880cac5862172608ff26d1178a31c05b904d77.tar.bz2 rails-f1880cac5862172608ff26d1178a31c05b904d77.zip |
Sugared up migrations with even more bling #1609 [Tobias Luekte]
git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@1697 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
Diffstat (limited to 'activerecord/lib')
4 files changed, 119 insertions, 27 deletions
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index 1b5c8184ae..e335ab4e07 100755 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -366,11 +366,17 @@ module ActiveRecord # Schema has been intialized end end - - def create_table(name, options = "") - execute "CREATE TABLE #{name} (id #{native_database_types[:primary_key]}) #{options}" - table_definition = yield TableDefinition.new - table_definition.columns.each { |column_name, type, options| add_column(name, column_name, type, options) } + + def create_table(name, options = {}) + table_definition = TableDefinition.new(self) + table_definition.primary_key(options[:primary_key] || "id") unless options[:id] == false + + yield table_definition + create_sql = "CREATE TABLE #{name} (" + create_sql << table_definition.to_sql + create_sql << ") #{options[:options]}" + + execute create_sql end def drop_table(name) @@ -379,28 +385,52 @@ module ActiveRecord def add_column(table_name, column_name, type, options = {}) native_type = native_database_types[type] - add_column_sql = "ALTER TABLE #{table_name} ADD #{column_name} #{type_to_sql(type)}" - add_column_sql << " DEFAULT '#{options[:default]}'" if options[:default] + add_column_sql = "ALTER TABLE #{table_name} ADD #{column_name} #{type_to_sql(type, options[:limit])}" + add_column_options!(add_column_sql, options) execute(add_column_sql) end - + def remove_column(table_name, column_name) execute "ALTER TABLE #{table_name} DROP #{column_name}" + end + + def change_column(table_name, column_name, type, options = {}) + raise NotImplementedError, "change_column is not implemented" end def supports_migrations? false end + def rename_column(table_name, column_name, new_column_name) + raise NotImplementedError, "rename_column is not implemented" + end + + def add_index(table_name, column_name, index_type = '') + execute "CREATE #{index_type} INDEX #{table_name}_#{column_name.to_a.first}_index ON #{table_name} (#{column_name.to_a.join(", ")})" + end + + def remove_index(table_name, column_name) + execute "DROP INDEX #{table_name}_#{column_name}_index ON #{table_name}" + end + + def supports_migrations? + false + end + + def native_database_types + {} + end + + def type_to_sql(type, limit = nil) + native = native_database_types[type] + limit ||= native[:limit] + column_type_sql = native[:name] + column_type_sql << "(#{limit})" if limit + column_type_sql + end - protected - def type_to_sql(type) - native = native_database_types[type] - column_type_sql = native[:name] - column_type_sql << "(#{native[:limit]})" if native[:limit] - column_type_sql - end - + protected def log(sql, name) begin if block_given? @@ -450,19 +480,47 @@ module ActiveRecord "%s %s" % [message, dump] end end - end + + def add_column_options!(sql, options) + sql << " DEFAULT '#{options[:default]}'" if options[:default] + end + end class TableDefinition attr_accessor :columns - def initialize + def initialize(base) @columns = [] + @base = base + end + + def primary_key(name) + @columns << "#{name} #{native[:primary_key]}" + self end def column(name, type, options = {}) - @columns << [ name, type, options ] + limit = options[:limit] || native[type.to_sym][:limit] + + column_sql = "#{name} #{type_to_sql(type.to_sym, options[:limit])}" + column_sql << " DEFAULT '#{options[:default]}'" if options[:default] + @columns << column_sql self end + + def to_sql + @columns.join(", ") + end + + private + + def type_to_sql(name, limit) + @base.type_to_sql(name, limit) + end + + def native + @base.native_database_types + end end end end diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index ec0558a4d5..14343b2750 100755 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -199,8 +199,19 @@ module ActiveRecord execute "CREATE DATABASE #{name}" end - def create_table(name) - super(name, "ENGINE=InnoDB") + def change_column(table_name, column_name, type, options = {}) + change_column_sql = "ALTER TABLE #{table_name} MODIFY #{column_name} #{type}" + add_column_options!(change_column_sql, options) + execute(change_column_sql) + end + + def rename_column(table_name, column_name, new_column_name) + current_type = select_one("SHOW COLUMNS FROM #{table_name} LIKE '#{column_name}'")["Type"] + execute "ALTER TABLE #{table_name} CHANGE #{column_name} #{new_column_name} #{current_type}" + end + + def create_table(name, options = {}) + super(name, {:options => "ENGINE=InnoDB"}.merge(options)) end private diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 3d6550ea9a..16acf321da 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -60,7 +60,6 @@ module ActiveRecord # * <tt>:encoding</tt> -- An optional client encoding that is using in a SET client_encoding TO <encoding> call on connection. # * <tt>:min_messages</tt> -- An optional client min messages that is using in a SET client_min_messages TO <min_messages> call on connection. class PostgreSQLAdapter < AbstractAdapter - def native_database_types { :primary_key => "serial primary key", @@ -132,7 +131,7 @@ module ActiveRecord %("#{name}") end - def adapter_name() + def adapter_name 'PostgreSQL' end @@ -150,8 +149,21 @@ module ActiveRecord def schema_search_path @schema_search_path ||= query('SHOW search_path')[0][0] end + + def change_column(table_name, column_name, type, options = {}) + change_column_sql = "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} TYPE #{type}" + add_column_options!(change_column_sql, options) + execute(change_column_sql) + end + + def rename_column(table_name, column_name, new_column_name) + execute "ALTER TABLE #{table_name} RENAME COLUMN #{column_name} TO #{new_column_name}" + end - + def remove_index(table_name, column_name) + execute "DROP INDEX #{table_name}_#{column_name}_index" + end + private BYTEA_COLUMN_TYPE_OID = 17 diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index cb54d2b967..365f57f366 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -51,21 +51,32 @@ module ActiveRecord # # == Available transformations # - # * <tt>create_table(name, options = "")</tt> Creates a table called +name+ and makes the table object available to a block - # that can then add columns to it, following the same format as add_column. See example above. The options string is for + # * <tt>create_table(name, options)</tt> Creates a table called +name+ and makes the table object available to a block + # that can then add columns to it, following the same format as add_column. See example above. The options hash is for # fragments like "DEFAULT CHARSET=UTF-8" that are appended to the create table definition. # * <tt>drop_table(name)</tt>: Drops the table called +name+. - # * <tt>add_column(table_name, column_name, type, options = {})</tt>: Adds a new column to the table called +table_name+ + # * <tt>add_column(table_name, column_name, type, options)</tt>: Adds a new column to the table called +table_name+ # named +column_name+ specified to be one of the following types: # :string, :text, :integer, :float, :datetime, :timestamp, :time, :date, :binary, :boolean. A default value can be specified # by passing an +options+ hash like { :default => 11 }. + # * <tt>rename_column(table_name, column_name, new_column_name)</tt>: Renames a column but keeps the type and content. + # * <tt>change_column(table_name, column_name, type, options)</tt>: Changes the column to a different type using the same + # parameters as add_column. # * <tt>remove_column(table_name, column_name)</tt>: Removes the column named +column_name+ from the table called +table_name+. + # * <tt>add_index(table_name, column_name)</tt>: Add a new index with the name of the column on the column. + # * <tt>remove_index(table_name, column_name)</tt>: Remove the index called the same as the column. # # == Irreversible transformations # # Some transformations are destructive in a manner that cannot be reversed. Migrations of that kind should raise # an <tt>IrreversibleMigration</tt> exception in their +down+ method. # + # == Running migrations from within Rails + # + # The Rails package has support for migrations with the <tt>script/generate migration my_new_migration</tt> command and + # with the <tt>rake migrate</tt> command that'll run all the pending migrations. It'll even create the needed schema_info + # table automatically if it's missing. + # # == Database support # # Migrations are currently only supported in MySQL and PostgreSQL. |