]> git.ipfire.org Git - thirdparty/sqlalchemy/alembic.git/commitdiff
- [feature] Added support for "relative" migration
authorMike Bayer <mike_mp@zzzcomputing.com>
Wed, 16 May 2012 16:16:34 +0000 (12:16 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Wed, 16 May 2012 16:16:34 +0000 (12:16 -0400)
  identifiers, i.e. "alembic upgrade +2",
  "alembic downgrade -1".  Courtesy
  Atsushi Odagiri for this feature.

CHANGES
alembic/script.py
docs/build/tutorial.rst
tests/test_revision_paths.py

diff --git a/CHANGES b/CHANGES
index e49a77f565ea9a68d623fd17bc988d767129473d..093c5f64d1ccb2f463c6cd3c458c46561439ca9d 100644 (file)
--- a/CHANGES
+++ b/CHANGES
   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, 
index bef7dfb56b1dd0c915e4a3a4a4ef138fe93435eb..4718e7988fca3590c9622a668a057c4cf3e40c76 100644 (file)
@@ -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
index 019697a06692eba1f138670666de6b7888e9d0d0..af3380ce710139917bf0e05c756a06e6ba6e0153 100644 (file)
@@ -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
 ===========================
 
index 127fda8adabf2cee3d2b14b2d41f7c2f808e2664..dedfa8bcbe973790ad17b88ba87479bcb4856ad7 100644 (file)
@@ -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
+    )