Ticket #6799: parallel_migrations.diff
| File parallel_migrations.diff, 8.5 kB (added by court3nay, 2 years ago) |
|---|
-
test/migration_test.rb
old new 3 3 4 4 require 'fixtures/person' 5 5 require 'fixtures/topic' 6 require 'fixtures/monkey' 7 require 'fixtures/task' 6 8 require File.dirname(__FILE__) + '/fixtures/migrations/1_people_have_last_names' 7 9 require File.dirname(__FILE__) + '/fixtures/migrations/2_we_need_reminders' 8 10 require File.dirname(__FILE__) + '/fixtures/migrations_with_decimal/1_give_me_big_numbers' … … 34 36 ActiveRecord::Base.connection.initialize_schema_information 35 37 ActiveRecord::Base.connection.update "UPDATE #{ActiveRecord::Migrator.schema_info_table_name} SET version = 0" 36 38 37 %w(reminders people_reminders prefix_reminders_suffix ).each do |table|39 %w(reminders people_reminders prefix_reminders_suffix monkeys tasks ).each do |table| 38 40 Reminder.connection.drop_table(table) rescue nil 39 41 end 40 42 Reminder.reset_column_information … … 508 510 def test_migrator 509 511 assert !Person.column_methods_hash.include?(:last_name) 510 512 assert !Reminder.table_exists? 513 assert !Task.table_exists? 514 assert !Monkey.table_exists? 511 515 512 516 ActiveRecord::Migrator.up(File.dirname(__FILE__) + '/fixtures/migrations/') 513 517 514 assert_equal 3, ActiveRecord::Migrator.current_version518 assert_equal 4, ActiveRecord::Migrator.current_version 515 519 Person.reset_column_information 516 520 assert Person.column_methods_hash.include?(:last_name) 517 521 assert Reminder.create("content" => "hello world", "remind_at" => Time.now) … … 542 546 end 543 547 544 548 def test_migrator_one_down 545 ActiveRecord::Migrator.up(File.dirname(__FILE__) + '/fixtures/migrations/') 546 549 assert !Person.column_methods_hash.include?(:last_name) 550 551 ActiveRecord::Migrator.up(File.dirname(__FILE__) + '/fixtures/migrations/', 4) 552 553 Person.reset_column_information 554 assert Person.column_methods_hash.include?(:last_name), Person.column_methods_hash.inspect 555 assert Reminder.table_exists? 556 assert Author.table_exists? 557 547 558 ActiveRecord::Migrator.down(File.dirname(__FILE__) + '/fixtures/migrations/', 1) 548 559 549 560 Person.reset_column_information 550 assert Person.column_methods_hash.include?(:last_name) 561 assert Person.column_methods_hash.include?(:last_name), Person.column_methods_hash.inspect 551 562 assert !Reminder.table_exists? 563 assert !Monkey.table_exists? 564 assert !Task.table_exists? 552 565 end 553 566 554 567 def test_migrator_one_up_one_down -
test/fixtures/monkey.rb
old new 1 class Monkey < ActiveRecord::Base 2 end -
test/fixtures/migrations/4_duplicate_one.rb
old new 1 class DuplicateOne < ActiveRecord::IndependentMigration 2 def self.up 3 create_table("tasks", :id => false) do |t| 4 t.column :person_id, :integer 5 end 6 end 7 8 def self.down 9 drop_table "tasks" 10 end 11 end -
test/fixtures/migrations/4_duplicate_two.rb
old new 1 class DuplicateTwo < ActiveRecord::IndependentMigration 2 def self.up 3 create_table("monkeys", :id => false) do |t| 4 t.column :person_id, :integer 5 end 6 end 7 8 def self.down 9 drop_table "monkeys" 10 end 11 end -
lib/active_record/migration.rb
old new 3 3 end 4 4 5 5 class DuplicateMigrationVersionError < ActiveRecordError#:nodoc: 6 def initialize(version )7 super("Multiple migrations have the version number #{version} ")6 def initialize(version, name) 7 super("Multiple migrations have the version number #{version} (bad file: #{name})") 8 8 end 9 9 end 10 10 … … 276 276 end 277 277 end 278 278 end 279 280 # An IndependentMigration is used whenener you have two or more migrations occurring with the same number. 281 # This is useful if you are mirroring another project where you don't have control of the migration numbering, 282 # but want to modify your local database, or if you want to indicate that a succession of migrations 283 # are independent of each other, and can occur in parallel. 284 # 285 # Additionally, when merging multiple branches to trunk, setting conflicting migration classes to IndependentMigration 286 # will remove the DuplicateMigrationVersionError error that is normally raised, so you don't have to renumber. 287 # Note that all migrations sharing the same number should be IndependentMigration class. 288 # 289 # == Usage 290 # 291 # Use like a normal migration. 292 # 293 # db/migrate 294 # 067_add_person_field.rb # ActiveRecord::Migration 295 # 068_add_monkey_table.rb # ActiveRecord::IndependentMigration 296 # 068_add_banana_table.rb # ActiveRecord::IndependentMigration 297 # 069_remove_link_id.rb # ActiveRecord::Migration 298 # 299 class IndependentMigration < Migration 300 end 279 301 280 302 class Migrator#:nodoc: 281 303 class << self … … 326 348 end 327 349 328 350 def migrate 329 migration_classes.each do |(version, migration_class)| 330 Base.logger.info("Reached target version: #{@target_version}") and break if reached_target_version?(version) 331 next if irrelevant_migration?(version) 332 351 @target_version ||= up? ? 999 : 0 # have to set a default version number 352 classes = migration_classes.select { |a| 353 (up? && a[0] > current_version && a[0] <= @target_version) || 354 (down? && a[0] <= current_version && a[0] > @target_version) 355 } 356 # Migrating #{@direction} from #{current_version} to #{@target_version} :: #{classes.inspect} 357 358 classes.each do |(version, migration_class)| 333 359 Base.logger.info "Migrating to #{migration_class} (#{version})" 334 360 migration_class.migrate(@direction) 335 361 set_schema_version(version) … … 341 367 migrations = migration_files.inject([]) do |migrations, migration_file| 342 368 load(migration_file) 343 369 version, name = migration_version_and_name(migration_file) 344 assert_unique_migration_version(migrations, version.to_i )370 assert_unique_migration_version(migrations, version.to_i, name) 345 371 migrations << [ version.to_i, migration_class(name) ] 346 372 end 347 373 348 down? ? migrations.sort .reverse : migrations.sort374 down? ? migrations.sort_by { |a| -a[0] } : migrations.sort_by {|a| a[0] } 349 375 end 350 376 351 def assert_unique_migration_version(migrations, version )377 def assert_unique_migration_version(migrations, version, name) 352 378 if !migrations.empty? && migrations.transpose.first.include?(version) 353 raise DuplicateMigrationVersionError.new(version) 379 conflicts = migrations.select { |m| m[0].to_i == version } << [version, migration_class(name)] 380 # Found multiple migrations at #{version}: #{conflicts.inspect} 381 dependents = conflicts.select { |m| m[1].superclass != ActiveRecord::IndependentMigration } 382 if dependents.any? 383 raise DuplicateMigrationVersionError.new(version, dependents.inspect) 384 else 385 # All clear, no dependent migrations. 386 end 354 387 end 355 388 end 356 389 … … 368 401 def migration_version_and_name(migration_file) 369 402 return *migration_file.scan(/([0-9]+)_([_a-z0-9]*).rb/).first 370 403 end 371 404 372 405 def set_schema_version(version) 373 406 Base.connection.update("UPDATE #{self.class.schema_info_table_name} SET version = #{down? ? version.to_i - 1 : version.to_i}") 374 407 end … … 380 413 def down? 381 414 @direction == :down 382 415 end 383 384 def reached_target_version?(version)385 return false if @target_version == nil386 (up? && version.to_i - 1 >= @target_version) || (down? && version.to_i <= @target_version)387 end388 389 def irrelevant_migration?(version)390 (up? && version.to_i <= current_version) || (down? && version.to_i > current_version)391 end392 416 end 393 417 end