Skip to content

Commit

Permalink
Add support for Mysql column positioning via #add_column and #change_…
Browse files Browse the repository at this point in the history
…column

add_column and change_column in the Mysql adapter now accept some
additional options:
:first => true        # Put the column in front of all the columns
:after => column_name # Put the colmn after 'column_name'

add_column :new_col, :string, :first => true
add_column :another_col, :integer, :default => 0, :after => :new_col

[#3286 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
  • Loading branch information
bmarini authored and jeremy committed Dec 4, 2009
1 parent 96e0638 commit e55284e
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 0 deletions.
2 changes: 2 additions & 0 deletions activerecord/CHANGELOG
@@ -1,5 +1,7 @@
*Edge*

* MySQL: add_ and change_column support positioning. #3286 [Ben Marini]

* Reset your Active Record counter caches with the reset_counter_cache class method. #1211 [Mike Breen]

* Remove support for SQLite 2. Please upgrade to SQLite 3+ or install the plugin from git://github.com/rails/sqlite2_adapter.git [Pratik Naik]
Expand Down
Expand Up @@ -470,6 +470,13 @@ def rename_table(table_name, new_name)
execute "RENAME TABLE #{quote_table_name(table_name)} TO #{quote_table_name(new_name)}"
end

def add_column(table_name, column_name, type, options = {})
add_column_sql = "ALTER TABLE #{quote_table_name(table_name)} ADD #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
add_column_options!(add_column_sql, options)
add_column_position!(add_column_sql, options)
execute(add_column_sql)
end

def change_column_default(table_name, column_name, default) #:nodoc:
column = column_for(table_name, column_name)
change_column table_name, column_name, column.sql_type, :default => default
Expand Down Expand Up @@ -498,6 +505,7 @@ def change_column(table_name, column_name, type, options = {}) #:nodoc:

change_column_sql = "ALTER TABLE #{quote_table_name(table_name)} CHANGE #{quote_column_name(column_name)} #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
add_column_options!(change_column_sql, options)
add_column_position!(change_column_sql, options)
execute(change_column_sql)
end

Expand Down Expand Up @@ -529,6 +537,13 @@ def type_to_sql(type, limit = nil, precision = nil, scale = nil)
end
end

def add_column_position!(sql, options)
if options[:first]
sql << " FIRST"
elsif options[:after]
sql << " AFTER #{quote_column_name(options[:after])}"
end
end

# SHOW VARIABLES LIKE 'name'
def show_variable(name)
Expand Down
47 changes: 47 additions & 0 deletions activerecord/test/cases/migration_test.rb
Expand Up @@ -527,6 +527,53 @@ def test_add_remove_single_field_using_symbol_arguments
assert !Person.column_methods_hash.include?(:last_name)
end

if current_adapter?(:MysqlAdapter)
def testing_table_for_positioning
Person.connection.create_table :testings, :id => false do |t|
t.column :first, :integer
t.column :second, :integer
t.column :third, :integer
end

yield Person.connection
ensure
Person.connection.drop_table :testings rescue nil
end
protected :testing_table_for_positioning

def test_column_positioning
testing_table_for_positioning do |conn|
assert_equal %w(first second third), conn.columns(:testings).map {|c| c.name }
end
end

def test_add_column_with_positioning
testing_table_for_positioning do |conn|
conn.add_column :testings, :new_col, :integer
assert_equal %w(first second third new_col), conn.columns(:testings).map {|c| c.name }
end
testing_table_for_positioning do |conn|
conn.add_column :testings, :new_col, :integer, :first => true
assert_equal %w(new_col first second third), conn.columns(:testings).map {|c| c.name }
end
testing_table_for_positioning do |conn|
conn.add_column :testings, :new_col, :integer, :after => :first
assert_equal %w(first new_col second third), conn.columns(:testings).map {|c| c.name }
end
end

def test_change_column_with_positioning
testing_table_for_positioning do |conn|
conn.change_column :testings, :second, :integer, :first => true
assert_equal %w(second first third), conn.columns(:testings).map {|c| c.name }
end
testing_table_for_positioning do |conn|
conn.change_column :testings, :second, :integer, :after => :third
assert_equal %w(first third second), conn.columns(:testings).map {|c| c.name }
end
end
end

def test_add_rename
Person.delete_all

Expand Down

2 comments on commit e55284e

@adrianpacala
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome!

@janx
Copy link
Contributor

@janx janx commented on e55284e Dec 6, 2009

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sweet!

Please sign in to comment.