_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.
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
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
===================
Alembic will stop and let you know if more than one version starts with that prefix.
+
Downgrading
===========
INFO [alembic.context] Running upgrade None -> 1975ea83b712
INFO [alembic.context] Running upgrade 1975ea83b712 -> ae1027a6acf
+
Auto Generating Migrations
===========================
-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
]
)
+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_(
(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
+ )