diff --git a/README.md b/README.md index 399fd0b7..0c326006 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ ActiveRecord 3.2.x and 4.x (mysql and mysql2 adapters). ## Limitations -Due to the Chunker implementation, Lhm requires that the table to migrate has a +Due to the Chunker implementation, Lhm requires that the table to migrate has a single integer numeric key column called `id`. Another note about the Chunker, it performs static sized row copies against the `id` @@ -78,6 +78,7 @@ ActiveRecord::Base.establish_connection( # and migrate Lhm.change_table :users do |m| m.add_column :arbitrary, "INT(12)" + m.add_column :locale, "VARCHAR(2) NOT NULL DEFAULT 'en'" m.add_index [:arbitrary_id, :created_at] m.ddl("alter table %s add column flag tinyint(1)" % m.name) end diff --git a/lib/lhm/chunker.rb b/lib/lhm/chunker.rb index 1e5252a3..3e423335 100644 --- a/lib/lhm/chunker.rb +++ b/lib/lhm/chunker.rb @@ -27,7 +27,7 @@ def initialize(migration, connection = nil, options = {}) def execute return unless @start && @limit @next_to_insert = @start - while @next_to_insert < @limit || (@start == @limit) + while @next_to_insert <= @limit stride = @throttler.stride affected_rows = @connection.update(copy(bottom, top(stride))) diff --git a/spec/unit/chunker_spec.rb b/spec/unit/chunker_spec.rb index de8eeb5f..f30b4e92 100644 --- a/spec/unit/chunker_spec.rb +++ b/spec/unit/chunker_spec.rb @@ -107,13 +107,56 @@ def @throttler.stride @connection.verify end + it 'correctly copies single record tables when start is not 1' do + @chunker = Lhm::Chunker.new(@migration, @connection, :throttler => @throttler, + :start => 2, + :limit => 2) + + @connection.expect(:update, 1) do |stmt| + stmt = stmt.first if stmt.is_a?(Array) + stmt =~ /between 2 and 2/ + end + + @chunker.run + @connection.verify + end + + it 'correctly copies every record tables when difference is a multiple of stride plus one' do + def @throttler.stride + 2 + end + @chunker = Lhm::Chunker.new(@migration, @connection, :throttler => @throttler, + :start => 1, + :limit => 5) + + @connection.expect(:update, 2) do |stmt| + stmt = stmt.first if stmt.is_a?(Array) + stmt =~ /between 1 and 2/ + end + @connection.expect(:update, 2) do |stmt| + stmt = stmt.first if stmt.is_a?(Array) + stmt =~ /between 3 and 4/ + end + @connection.expect(:update, 1) do |stmt| + stmt = stmt.first if stmt.is_a?(Array) + stmt =~ /between 5 and 5/ + end + + @chunker.run + @connection.verify + end + it 'separates filter conditions from chunking conditions' do + def @throttler.stride + 2 + end @chunker = Lhm::Chunker.new(@migration, @connection, :throttler => @throttler, :start => 1, :limit => 2) @connection.expect(:update, 1) do |stmt| stmt = stmt.first if stmt.is_a?(Array) stmt =~ /where \(foo.created_at > '2013-07-10' or foo.baz = 'quux'\) and `foo`/ + stmt =~ /between 1 and 2/ end def @migration.conditions @@ -125,12 +168,16 @@ def @migration.conditions end it "doesn't mess with inner join filters" do + def @throttler.stride + 2 + end @chunker = Lhm::Chunker.new(@migration, @connection, :throttler => @throttler, :start => 1, :limit => 2) @connection.expect(:update, 1) do |stmt| stmt = stmt.first if stmt.is_a?(Array) stmt =~ /inner join bar on foo.id = bar.foo_id and/ + stmt =~ /between 1 and 2/ end def @migration.conditions