diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2012-05-16 12:16:34 -0400 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2012-05-16 12:16:34 -0400 |
commit | 7bdc7e43325612739d049202cf24e5a0e5be5724 (patch) | |
tree | c6b37fea2a363eee28ac4a4d612cdae42f56be3f | |
parent | 6ed983fc075450d874557e81feb0237d7a28a222 (diff) | |
download | alembic-7bdc7e43325612739d049202cf24e5a0e5be5724.tar.gz |
- [feature] Added support for "relative" migration
identifiers, i.e. "alembic upgrade +2",
"alembic downgrade -1". Courtesy
Atsushi Odagiri for this feature.
-rw-r--r-- | CHANGES | 5 | ||||
-rw-r--r-- | alembic/script.py | 21 | ||||
-rw-r--r-- | docs/build/tutorial.rst | 13 | ||||
-rw-r--r-- | tests/test_revision_paths.py | 71 |
4 files changed, 109 insertions, 1 deletions
@@ -10,6 +10,11 @@ EnvironmentContext.configure(), allowing for the configuration of the version table name. #34 +- [feature] Added support for "relative" migration + identifiers, i.e. "alembic upgrade +2", + "alembic downgrade -1". Courtesy + Atsushi Odagiri for this feature. + 0.3.2 ===== - [feature] Basic support for Oracle added, diff --git a/alembic/script.py b/alembic/script.py index bef7dfb..4718e79 100644 --- a/alembic/script.py +++ b/alembic/script.py @@ -12,6 +12,7 @@ _legacy_rev = re.compile(r'([a-f0-9]+)\.py$') _mod_def_re = re.compile(r'(upgrade|downgrade)_([a-z0-9]+)') _slug_re = re.compile(r'\w+') _default_file_template = "%(rev)s_%(slug)s" +_relative_destination = re.compile(r'(?:\+|-)\d+') class ScriptDirectory(object): """Provides operations upon an Alembic script directory. @@ -130,6 +131,26 @@ class ScriptDirectory(object): The iterator yields :class:`.Script` objects. """ + if upper is not None and _relative_destination.match(upper): + relative = int(upper) + revs = list(self._iterate_revisions("head", lower)) + revs = revs[-relative:] + if len(revs) != abs(relative): + raise util.CommandError("Relative revision %s didn't " + "produce %d migrations" % (upper, abs(relative))) + return iter(revs) + elif lower is not None and _relative_destination.match(lower): + relative = int(lower) + revs = list(self._iterate_revisions(upper, "base")) + revs = revs[0:-relative] + if len(revs) != abs(relative): + raise util.CommandError("Relative revision %s didn't " + "produce %d migrations" % (lower, abs(relative))) + return iter(revs) + else: + return self._iterate_revisions(upper, lower) + + def _iterate_revisions(self, upper, lower): lower = self.get_revision(lower) upper = self.get_revision(upper) script = upper diff --git a/docs/build/tutorial.rst b/docs/build/tutorial.rst index 019697a..af3380c 100644 --- a/docs/build/tutorial.rst +++ b/docs/build/tutorial.rst @@ -347,6 +347,17 @@ Running again to ``head``:: We've now added the ``last_transaction_date`` column to the database. +Relative Migration Identifiers +============================== + +As of 0.3.3, relative upgrades/downgrades are also supported. To move two versions from the current, a decimal value "+N" can be supplied:: + + $ alembic upgrade +2 + +Negative values are accepted for downgrades:: + + $ alembic downgrade -1 + Getting Information =================== @@ -373,6 +384,7 @@ If we wanted to upgrade directly to ``ae1027a6acf`` we could say:: Alembic will stop and let you know if more than one version starts with that prefix. + Downgrading =========== @@ -393,6 +405,7 @@ Back to nothing - and up again:: INFO [alembic.context] Running upgrade None -> 1975ea83b712 INFO [alembic.context] Running upgrade 1975ea83b712 -> ae1027a6acf + Auto Generating Migrations =========================== diff --git a/tests/test_revision_paths.py b/tests/test_revision_paths.py index 127fda8..dedfa8b 100644 --- a/tests/test_revision_paths.py +++ b/tests/test_revision_paths.py @@ -1,4 +1,5 @@ -from tests import clear_staging_env, staging_env, eq_, ne_ +from tests import clear_staging_env, staging_env, eq_, ne_, \ + assert_raises_message from alembic import util @@ -35,6 +36,44 @@ def test_upgrade_path(): ] ) +def test_relative_upgrade_path(): + eq_( + env._upgrade_revs("+2", a.revision), + [ + (b.module.upgrade, a.revision, b.revision), + (c.module.upgrade, b.revision, c.revision), + ] + ) + + eq_( + env._upgrade_revs("+1", a.revision), + [ + (b.module.upgrade, a.revision, b.revision), + ] + ) + + eq_( + env._upgrade_revs("+3", b.revision), + [ + (c.module.upgrade, b.revision, c.revision), + (d.module.upgrade, c.revision, d.revision), + (e.module.upgrade, d.revision, e.revision), + ] + ) + +def test_invalid_relative_upgrade_path(): + assert_raises_message( + util.CommandError, + "Relative revision -2 didn't produce 2 migrations", + env._upgrade_revs, "-2", b.revision + ) + + assert_raises_message( + util.CommandError, + r"Relative revision \+5 didn't produce 5 migrations", + env._upgrade_revs, "+5", b.revision + ) + def test_downgrade_path(): eq_( @@ -53,3 +92,33 @@ def test_downgrade_path(): (a.module.downgrade, a.revision, a.down_revision), ] ) + +def test_relative_downgrade_path(): + eq_( + env._downgrade_revs("-1", c.revision), + [ + (c.module.downgrade, c.revision, c.down_revision), + ] + ) + + eq_( + env._downgrade_revs("-3", e.revision), + [ + (e.module.downgrade, e.revision, e.down_revision), + (d.module.downgrade, d.revision, d.down_revision), + (c.module.downgrade, c.revision, c.down_revision), + ] + ) + +def test_invalid_relative_downgrade_path(): + assert_raises_message( + util.CommandError, + "Relative revision -5 didn't produce 5 migrations", + env._downgrade_revs, "-5", b.revision + ) + + assert_raises_message( + util.CommandError, + r"Relative revision \+2 didn't produce 2 migrations", + env._downgrade_revs, "+2", b.revision + ) |