Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #5 from anthonyalberto/patch-AR-migrations
Change strategy to patch sql statements issued to the db
- Loading branch information
Showing
19 changed files
with
583 additions
and
422 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,12 @@ | |||
language: ruby | |||
rvm: | |||
- 2.0.0 | |||
|
|||
before_script: | |||
- mysql -e 'create database mysql_online_migrations;' | |||
|
|||
gemfile: | |||
- gemfiles/rails3.gemfile | |||
- gemfiles/rails4.gemfile | |||
|
|||
script: bundle exec rspec spec |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,7 @@ | |||
source :rubygems | |||
gem "activerecord", "3.2.16" | |||
gem "activesupport", "3.2.16" | |||
gem "mysql2" | |||
gem "logger" | |||
gem "rspec" | |||
gem "pry" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,7 @@ | |||
source :rubygems | |||
gem "activerecord", "4.0.2" | |||
gem "activesupport", "4.0.2" | |||
gem "mysql2" | |||
gem "logger" | |||
gem "rspec" | |||
gem "pry" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -1,33 +1,28 @@ | |||
require 'active_record' | require 'active_record' | ||
require "active_record/migration" | |||
require "active_record/connection_adapters/mysql2_adapter" | require "active_record/connection_adapters/mysql2_adapter" | ||
require "pry" | |||
|
|
||
%w(*.rb).each do |path| | %w(*.rb).each do |path| | ||
Dir["#{File.dirname(__FILE__)}/mysql_online_migrations/#{path}"].each { |f| require(f) } | Dir["#{File.dirname(__FILE__)}/mysql_online_migrations/#{path}"].each { |f| require(f) } | ||
end | end | ||
|
|
||
module MysqlOnlineMigrations | module MysqlOnlineMigrations | ||
include Indexes | def self.prepended(base) | ||
include Columns | |||
|
|||
def self.included(base) | |||
ActiveRecord::Base.send(:class_attribute, :mysql_online_migrations, :instance_writer => false) | ActiveRecord::Base.send(:class_attribute, :mysql_online_migrations, :instance_writer => false) | ||
ActiveRecord::Base.send("mysql_online_migrations=", true) | ActiveRecord::Base.send("mysql_online_migrations=", true) | ||
end | end | ||
|
|
||
def lock_statement(lock, with_comma = false) | def connection | ||
return "" if lock == true | @no_lock_adapter ||= ActiveRecord::ConnectionAdapters::Mysql2AdapterWithoutLock.new(super) | ||
return "" unless perform_migrations_online? | |||
puts "ONLINE MIGRATION" | |||
"#{with_comma ? ', ' : ''} LOCK=NONE" | |||
end | |||
|
|||
def extract_lock_from_options(options) | |||
[options[:lock], options.except(:lock)] | |||
end | end | ||
|
|
||
def perform_migrations_online? | def with_lock | ||
ActiveRecord::Base.mysql_online_migrations == true | original_value = ActiveRecord::Base.mysql_online_migrations | ||
ActiveRecord::Base.mysql_online_migrations = false | |||
yield | |||
ActiveRecord::Base.mysql_online_migrations = original_value | |||
end | end | ||
end | end | ||
|
|
||
ActiveRecord::ConnectionAdapters::Mysql2Adapter.send(:include, MysqlOnlineMigrations) | ActiveRecord::Migration.send(:prepend, MysqlOnlineMigrations) |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
32 changes: 32 additions & 0 deletions
32
lib/mysql_online_migrations/mysql2_adapter_without_lock.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,32 @@ | |||
module ActiveRecord | |||
module ConnectionAdapters | |||
class Mysql2AdapterWithoutLock < Mysql2Adapter | |||
OPTIMIZABLE_DDL_REGEX = /^(alter|create (unique )? ?index|drop index) /i | |||
DDL_WITH_COMMA_REGEX = /^alter /i | |||
DDL_WITH_LOCK_NONE_REGEX = / LOCK=NONE\s*$/i | |||
|
|||
def initialize(mysql2_adapter) | |||
params = [:@connection, :@logger, :@connection_options, :@config].map do |sym| | |||
mysql2_adapter.instance_variable_get(sym) | |||
end | |||
super(*params) | |||
end | |||
|
|||
alias_method :original_execute, :execute | |||
def execute(sql, name = nil) | |||
if sql =~ OPTIMIZABLE_DDL_REGEX | |||
sql = "#{sql} #{lock_none_statement(sql)}" | |||
puts "EXECUTING #{sql}" | |||
end | |||
original_execute(sql, name) | |||
end | |||
|
|||
def lock_none_statement(sql) | |||
return "" unless ActiveRecord::Base.mysql_online_migrations | |||
return "" if sql =~ DDL_WITH_LOCK_NONE_REGEX | |||
comma_delimiter = (sql =~ DDL_WITH_COMMA_REGEX ? "," : "") | |||
"#{comma_delimiter} LOCK=NONE" | |||
end | |||
end | |||
end | |||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,138 @@ | |||
require "spec_helper" | |||
|
|||
describe ActiveRecord::Migration do | |||
let(:comma_before_lock_none) { true } | |||
let(:migration_arguments_with_lock) { [] } | |||
|
|||
context "#add_column" do | |||
let(:method_name) { :add_column } | |||
let(:migration_arguments) do | |||
[ | |||
[:testing, :foo2, :string], | |||
[:testing, :foo2, :string, { limit: 20, null: false, default: 'def' }], | |||
[:testing, :foo2, :decimal, { precision:3, scale: 2 }] | |||
] | |||
end | |||
|
|||
it_behaves_like "a migration that adds LOCK=NONE when needed" | |||
it_behaves_like "a migration that succeeds in MySQL" | |||
end | |||
|
|||
context "#add_timestamps" do | |||
let(:migration_arguments) do | |||
[ | |||
[:testing2] | |||
] | |||
end | |||
|
|||
let(:method_name) { :add_timestamps } | |||
|
|||
it_behaves_like "a migration that adds LOCK=NONE when needed" | |||
it_behaves_like "a migration that succeeds in MySQL" | |||
end | |||
|
|||
context "#remove_column" do | |||
let(:migration_arguments) do | |||
[ | |||
[:testing, :foo], | |||
[:testing, :foo, :bar] | |||
] | |||
end | |||
|
|||
let(:method_name) { :remove_column } | |||
|
|||
it_behaves_like "a migration that adds LOCK=NONE when needed" | |||
it_behaves_like "a migration that succeeds in MySQL" | |||
end | |||
|
|||
context "#remove_timestamps" do | |||
let(:migration_arguments) do | |||
[ | |||
[:testing] | |||
] | |||
end | |||
|
|||
let(:method_name) { :remove_timestamps } | |||
|
|||
it_behaves_like "a migration that adds LOCK=NONE when needed" | |||
it_behaves_like "a migration that succeeds in MySQL" | |||
end | |||
|
|||
context "#change_column" do | |||
let(:migration_arguments) do | |||
# Unsupported with lock=none : change column type, change limit, set NOT NULL. | |||
[ | |||
[:testing, :foo, :string, { default: 'def', limit: 100 }], | |||
[:testing, :foo, :string, { null: true, limit: 100 }] | |||
] | |||
end | |||
|
|||
let(:migration_arguments_with_lock) do | |||
[ | |||
[:testing, :foo, :string, { limit: 200 }], | |||
[:testing, :foo, :string, { default: 'def' }], | |||
[:testing, :foo, :string, { null: false }], | |||
[:testing, :foo, :string, { null: false, default: 'def', limit: 200 }], | |||
[:testing, :foo, :string, { null: true }], | |||
[:testing, :foo, :integer, { null: true, limit: 6 }], | |||
[:testing, :foo, :integer, { null: true, limit: 1 }] | |||
] | |||
end | |||
|
|||
let(:method_name) { :change_column } | |||
|
|||
it_behaves_like "a migration that adds LOCK=NONE when needed" | |||
it_behaves_like "a migration that succeeds in MySQL" | |||
it_behaves_like "a migration with a non-lockable statement" | |||
end | |||
|
|||
context "#change_column_default" do | |||
let(:migration_arguments) do | |||
[ | |||
[:testing, :foo, 'def'], | |||
[:testing, :foo, nil] | |||
] | |||
end | |||
|
|||
let(:method_name) { :change_column_default } | |||
|
|||
it_behaves_like "a migration that adds LOCK=NONE when needed" | |||
it_behaves_like "a migration that succeeds in MySQL" | |||
end | |||
|
|||
context "#change_column_null" do | |||
let(:migration_arguments) do | |||
#change_column_null doesn't set DEFAULT in sql. It just issues an update statement before setting the NULL value if setting NULL to false | |||
[ | |||
[:testing, :bam, true, nil], | |||
[:testing, :bam, true, 'def'] | |||
] | |||
end | |||
|
|||
let(:migration_arguments_with_lock) do | |||
[ | |||
[:testing, :bam, false, nil], | |||
[:testing, :bam, false, 'def'] | |||
] | |||
end | |||
|
|||
let(:method_name) { :change_column_null } | |||
|
|||
it_behaves_like "a migration that adds LOCK=NONE when needed" | |||
it_behaves_like "a migration that succeeds in MySQL" | |||
it_behaves_like "a migration with a non-lockable statement" | |||
end | |||
|
|||
context "#rename_column" do | |||
let(:migration_arguments) do | |||
[ | |||
[:testing, :foo, :foo2] | |||
] | |||
end | |||
|
|||
let(:method_name) { :rename_column } | |||
|
|||
it_behaves_like "a migration that adds LOCK=NONE when needed" | |||
it_behaves_like "a migration that succeeds in MySQL" | |||
end | |||
end |
Oops, something went wrong.