diff --git a/.gitignore b/.gitignore index 088af20..1d8084a 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ pkg/* +.swp +*.swp diff --git a/lib/db_migrate_merge.rb b/lib/db_migrate_merge.rb new file mode 100644 index 0000000..b6e64d9 --- /dev/null +++ b/lib/db_migrate_merge.rb @@ -0,0 +1,32 @@ +class DbMigrateMerge + def self.generate_down_indexes lines + indexes = lines.collect do |line| + columns_regex = /add_index "[^"]+", ?(?::column ?=> ?)?(\[[^\]]+\]|"[^"]+")/ + + index_regex = /add_index "[^"]+", ?(?::name ?=> ?)?"([^"]+)"/ + table_regex = /add_index "([^"]+)"/ + + if line =~ table_regex + table_name = $1 + remove = "remove_index :#{table_name}," + + columns = line =~ columns_regex + if columns + if $1.index "[" + "#{remove} :column => #{$1}" + else + "#{remove} :column => [#{$1}]" + end + elsif line =~ index_regex + "#{remove} :name => \"#{$1}\"" + else + raise Exception.new "Expected to find an index name or column names in the db/schema.rb file but none were found:\n #{line}" + end + end + + end + + indexes.compact.reverse + end + +end diff --git a/lib/tasks/db_migrate_merge.rake b/lib/tasks/db_migrate_merge.rake index 592b256..6dc78c1 100644 --- a/lib/tasks/db_migrate_merge.rake +++ b/lib/tasks/db_migrate_merge.rake @@ -1,49 +1,50 @@ require 'fileutils' namespace :db do - + namespace :migrate do - + desc "Uses schema.rb to build a new base migration with the timestamp of the current migration. Other migrations are moved to a backup folder." - task :compact => [:abort_if_pending_migrations, :environment] do - + task :compact => [:abort_if_pending_migrations, :environment] do + file = File.read("#{RAILS_ROOT}/db/schema.rb") - + main_content_regex = /ActiveRecord::Schema.define\(:version => (.*)\) do(.*)^end/m main_content_regex.match file create_part = $2 # the second group holds what I want. - - lines = file.split("\n") - - index_regex = /add_index "(.*)", (.*):name => "(.*)"/ + + lines = file.split("\n") + table_regex = /create_table (.*),(.*)/ - + + index_regex = /add_index "(.*)", \[(.*)\], :name => "(.*)"/ + tables = lines.collect{|line| " drop_table #{$1}" if line =~ table_regex } - indexes = lines.collect{|line| " remove_index :#{$1}, :name => :#{$3}" if line =~ index_regex} - + # hack to correct spacing so it "looks pretty" create_part.gsub!("\n", "\n ") - + # reverse the order so the indexes get taken out in the opposite order # they were added. Also add two spaces to the start of each line drop_tables = tables.compact.reverse.join("\n ") - drop_indexes = indexes.compact.reverse.join("\n ") - + drop_indexes = DbMigrateMerge.generate_down_indexes lines + drop_indexes = drop_indexes.join("\n ") + new_migration = %Q{# Migration created #{Time.now.to_s} by lazy_developer class InitialMigration < ActiveRecord::Migration def self.up #{create_part} end - + def self.down - #{drop_indexes} - + #{drop_indexes} + #{drop_tables} end end } version = ActiveRecord::Migrator.current_version backups = RAILS_ROOT+"/db/migrate_#{version}" - + svn=File.exist?(RAILS_ROOT+"/db/migrate/.svn") if svn `svn mkdir #{backups}` @@ -55,7 +56,7 @@ end FileUtils.mv(RAILS_ROOT+"/db/migrate", backups) FileUtils.mkdir(RAILS_ROOT+"/db/migrate") end - + new_file = RAILS_ROOT+"/db/migrate/#{version}_initial_migration.rb" File.open(new_file, "w") do |f| @@ -63,11 +64,11 @@ end end `svn add #{new_file}` if svn - + puts "Created #{new_file}." puts "Previous migrations are in #{backups}" end - + end - + end diff --git a/spec/db_migrate_merge_spec.rb b/spec/db_migrate_merge_spec.rb new file mode 100644 index 0000000..e868a97 --- /dev/null +++ b/spec/db_migrate_merge_spec.rb @@ -0,0 +1,92 @@ +current_directory = File.join File.dirname(__FILE__) +require File.join(current_directory, '../lib/db_migrate_merge') + +describe DbMigrateMerge do + describe "#remove_index" do + #___________________ + it "handles indexes with just a column name" do + line = <<-eof +add_index "versions", "versioned_type" +eof + + expected = <<-ex +remove_index :versions, :column => ["versioned_type"] +ex + + DbMigrateMerge.generate_down_indexes([line]).should == expected[0..-2] + end + + + + + + #___________________ + it "handles indexes with only one column name and an index name" do + + line = <<-eof +add_index "audited", "transaction", :name => "index_audited_on_transaction" +eof + + expected_line = <<-eof +remove_index :audited, :column => ["transaction"] +eof + + expected = [expected_line].join()[0..-2] + DbMigrateMerge.generate_down_indexes([line]).should == expected + + end + + + #___________________ + it "works with an array of column names and an index name" do + line = <<-eof +add_index "versions", ["versioned_type", "versioned_id"], :name => "index_versions_on_versioned_type_and_versioned_id" +eof + + expected = <<-ex +remove_index :versions, :column => ["versioned_type", "versioned_id"] +ex + DbMigrateMerge.generate_down_indexes([line]).should == expected[0..-2] + end + + it "handles indexes with a column name with the :column => hash rocket syntax" do + line = <<-eof +add_index "versions", :column => ["versioned_type", "versioned_id"], :name => "index_versions_on_versioned_type_and_versioned_id" +eof + + expected = <<-ex +remove_index :versions, :column => ["versioned_type", "versioned_id"] +ex + + DbMigrateMerge.generate_down_indexes([line]).should == expected[0..-2] + + line = <<-eof +add_index "versions", :column => ["versioned_type"], :name => "index_versions_on_versioned_type" +eof + + expected = <<-ex +remove_index :versions, :column => ["versioned_type"] +ex + + DbMigrateMerge.generate_down_indexes([line]).should == expected[0..-2] + + + end + + + + it "handles indexes with a column name with the :column => hash rocket syntax" do + line = <<-eof +add_index "versions", :name => "index_versions_on_versioned_type_and_versioned_id" +eof + + expected = <<-ex +remove_index :versions, :name => "index_versions_on_versioned_type_and_versioned_id" +ex + + DbMigrateMerge.generate_down_indexes([line]).should == expected[0..-2] + + end + end + +end