Skip to content

Commit

Permalink
Add revert method for Sequel.migration blocks, to revert changes insi…
Browse files Browse the repository at this point in the history
…de the block on up, and apply the changes on down

This makes it simple to revert migrtions created with change.
  • Loading branch information
jeremyevans committed Oct 13, 2023
1 parent 01613aa commit b196221
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 4 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
=== master

* Add revert method for Sequel.migration blocks, to revert changes inside the block on up, and apply the changes on down (jeremyevans)

* Re-add is_json and is_not_json methods to the pg_json_ops extension, as the support was re-added in PostgreSQL 16 (jeremyevans)

* Avoid infinite loop when handling exceptions with a cause loop in jdbc adapter (jeremyevans)
Expand Down
14 changes: 14 additions & 0 deletions doc/migration.rdoc
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,20 @@ the following methods:

If you use any other methods, you should create your own +down+ block.

To revert a migration created with +change+, you can copy the migration to a new file, and
replace +change+ with +revert+. For example, if you no longer need the artists table, you
can use the following migration. This will drop the artists table when migrating up, and
recreate it when migrating down:

Sequel.migration do
revert do
create_table(:artists) do
primary_key :id
String :name, null: false
end
end
end

In normal usage, when Sequel's migrator runs, it runs the +up+ blocks for all
migrations that have not yet been applied. However, you can use the <tt>-M</tt>
switch to specify the version to which to migrate, and if it is lower than the
Expand Down
13 changes: 13 additions & 0 deletions lib/sequel/extensions/migration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,19 @@ def change(&block)
migration.up = block
migration.down = MigrationReverser.new.reverse(&block)
end

# Creates a revert migration. This is the same as creating
# the same block with +down+, but it also calls the block and attempts
# to create a +up+ block that will reverse the changes made by
# the block. This is designed to revert the changes in the
# provided block.
#
# There are no guarantees that this will work perfectly
# in all cases, but it works for some simple cases.
def revert(&block)
migration.down = block
migration.up = MigrationReverser.new.reverse(&block)
end
end

# Handles the reversing of reversible migrations. Basically records
Expand Down
64 changes: 60 additions & 4 deletions spec/extensions/migration_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@
end
end

describe "Reversible Migrations with Sequel.migration{change{}}" do
describe "Reversible/Revert Migrations with Sequel.migration{change|revert}" do
before do
@c = Class.new do
self::AT = Class.new do
Expand Down Expand Up @@ -154,7 +154,7 @@ def alter_table(*args, &block)
end
end

it "should apply up with normal actions in normal order" do
it "change should apply up with given actions in given order" do
p = @p
Sequel.migration{change(&p)}.apply(@db, :up)
@db.actions.must_equal [[:create_table, :a, {:foo=>:bar}],
Expand Down Expand Up @@ -182,7 +182,7 @@ def alter_table(*args, &block)
[:create_join_table, {:cat_id=>:cats, :dog_id=>:dogs}]]
end

it "should execute down with reversing actions in reverse order" do
it "change should execute down with reversing actions in reverse order" do
p = @p
Sequel.migration{change(&p)}.apply(@db, :down)
@db.actions.must_equal [
Expand Down Expand Up @@ -258,6 +258,63 @@ def alter_table(*args, &block)
error = proc{m.apply(@db, :down)}.must_raise(Sequel::Error)
error.message.must_match(/irreversible migration method used in .*spec\/extensions\/migration_spec.rb/)
end

it "revert should apply down with given actions in given order" do
p = @p
Sequel.migration{revert(&p)}.apply(@db, :down)
@db.actions.must_equal [[:create_table, :a, {:foo=>:bar}],
[:add_column, :a, :b, String],
[:add_index, :a, :b],
[:rename_column, :a, :b, :c],
[:rename_table, :a, :b],
[:alter_table, [
[:add_column, :d, String],
[:add_constraint, :blah, "d IS NOT NULL"],
[:add_constraint, {:name=>:merp}, "a > 1"],
[:add_foreign_key, :e, :b],
[:add_foreign_key, [:e], :b, {:name=>"e_fk"}],
[:add_foreign_key, [:e, :a], :b],
[:add_primary_key, :f, :b],
[:add_index, :e, {:name=>"e_n"}],
[:add_full_text_index, :e, {:name=>"e_ft"}],
[:add_spatial_index, :e, {:name=>"e_s"}],
[:rename_column, :e, :g],
[:set_column_allow_null, :c],
[:set_column_allow_null, :d, true],
[:set_column_allow_null, :d, false]]
],
[:create_view, :c, "SELECT * FROM b", {:foo=>:bar}],
[:create_join_table, {:cat_id=>:cats, :dog_id=>:dogs}]]
end

it "revert should execute up with reversing actions in reverse order" do
p = @p
Sequel.migration{revert(&p)}.apply(@db, :up)
@db.actions.must_equal [
[:drop_join_table, {:cat_id=>:cats, :dog_id=>:dogs}],
[:drop_view, :c, {:foo=>:bar}],
[:alter_table, [
[:set_column_allow_null, :d, true],
[:set_column_allow_null, :d, false],
[:set_column_allow_null, :c, false],
[:rename_column, :g, :e],
[:drop_index, :e, {:name=>"e_s"}],
[:drop_index, :e, {:name=>"e_ft"}],
[:drop_index, :e, {:name=>"e_n"}],
[:drop_column, :f],
[:drop_foreign_key, [:e, :a]],
[:drop_foreign_key, [:e], {:name=>"e_fk"}],
[:drop_foreign_key, :e],
[:drop_constraint, :merp],
[:drop_constraint, :blah],
[:drop_column, :d]]
],
[:rename_table, :b, :a],
[:rename_column, :a, :c, :b],
[:drop_index, :a, :b],
[:drop_column, :a, :b],
[:drop_table, :a, {:foo=>:bar}]]
end
end

describe "Sequel::Migrator.migrator_class" do
Expand All @@ -277,7 +334,6 @@ def alter_table(*args, &block)
it "should raise an error if the migration folder does not exist" do
proc{Sequel::Migrator.apply(@db, "spec/files/nonexistant_migration_path")}.must_raise(Sequel::Migrator::Error)
end

end

describe "Sequel::IntegerMigrator" do
Expand Down

0 comments on commit b196221

Please sign in to comment.