summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2014-03-12 17:33:03 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2014-03-12 17:33:03 -0400
commit36792434c74dea43a0f10f5fe1cc45c4206f01ee (patch)
tree792749694902e82ef088d481fca7a1fa70f7410f
parenta7ef7eccaacae5341bb03a58cc0538718c33c329 (diff)
downloadsqlalchemy-36792434c74dea43a0f10f5fe1cc45c4206f01ee.tar.gz
- Added a new feature :func:`.schema.conv`, the purpose of which is to
mark a constraint name as already having had a naming convention applied. This token will be used by Alembic migrations as of Alembic 0.6.4 in order to render constraints in migration scripts with names marked as already having been subject to a naming convention. re: #2991
-rw-r--r--doc/build/changelog/changelog_09.rst9
-rw-r--r--doc/build/core/constraints.rst1
-rw-r--r--lib/sqlalchemy/schema.py3
-rw-r--r--lib/sqlalchemy/sql/naming.py50
4 files changed, 58 insertions, 5 deletions
diff --git a/doc/build/changelog/changelog_09.rst b/doc/build/changelog/changelog_09.rst
index 20a0b656d..10879e2ca 100644
--- a/doc/build/changelog/changelog_09.rst
+++ b/doc/build/changelog/changelog_09.rst
@@ -15,6 +15,15 @@
:version: 0.9.4
.. change::
+ :tags: feature, sql
+
+ Added a new feature :func:`.schema.conv`, the purpose of which is to
+ mark a constraint name as already having had a naming convention applied.
+ This token will be used by Alembic migrations as of Alembic 0.6.4
+ in order to render constraints in migration scripts with names marked
+ as already having been subject to a naming convention.
+
+ .. change::
:tags: bug, sql
:paramref:`.MetaData.naming_convention` feature will now also
diff --git a/doc/build/core/constraints.rst b/doc/build/core/constraints.rst
index 3979631b0..580fbc0b6 100644
--- a/doc/build/core/constraints.rst
+++ b/doc/build/core/constraints.rst
@@ -459,6 +459,7 @@ Constraints API
:members:
:inherited-members:
+.. autofunction:: sqlalchemy.schema.conv
.. _schema_indexes:
diff --git a/lib/sqlalchemy/schema.py b/lib/sqlalchemy/schema.py
index 9e647e595..8556272a6 100644
--- a/lib/sqlalchemy/schema.py
+++ b/lib/sqlalchemy/schema.py
@@ -37,6 +37,9 @@ from .sql.schema import (
)
+from .sql.naming import conv
+
+
from .sql.ddl import (
DDL,
CreateTable,
diff --git a/lib/sqlalchemy/sql/naming.py b/lib/sqlalchemy/sql/naming.py
index 3ba7f5105..1c5fae193 100644
--- a/lib/sqlalchemy/sql/naming.py
+++ b/lib/sqlalchemy/sql/naming.py
@@ -16,13 +16,54 @@ from .. import exc
from .elements import _truncated_label
import re
+class conv(_truncated_label):
+ """Mark a string indicating that a name has already been converted
+ by a naming convention.
+
+ This is a string subclass that indicates a name that should not be
+ subject to any further naming conventions.
+
+ E.g. when we create a :class:`.Constraint` using a naming convention
+ as follows::
+
+ m = MetaData(naming_convention={"ck": "ck_%(table_name)s_%(constraint_name)s"})
+ t = Table('t', m, Column('x', Integer),
+ CheckConstraint('x > 5', name='x5'))
+
+ The name of the above constraint will be rendered as ``"ck_t_x5"``. That is,
+ the existing name ``x5`` is used in the naming convention as the ``constraint_name``
+ token.
+
+ In some situations, such as in migration scripts, we may be rendering
+ the above :class:`.CheckConstraint` with a name that's already been
+ converted. In order to make sure the name isn't double-modified, the
+ new name is applied using the :func:`.schema.conv` marker. We can
+ use this explicitly as follows::
+
+
+ m = MetaData(naming_convention={"ck": "ck_%(table_name)s_%(constraint_name)s"})
+ t = Table('t', m, Column('x', Integer),
+ CheckConstraint('x > 5', name=conv('ck_t_x5')))
+
+ Where above, the :func:`.schema.conv` marker indicates that the constraint
+ name here is final, and the name will render as ``"ck_t_x5"`` and not
+ ``"ck_t_ck_t_x5"``
+
+ .. versionadded:: 0.9.4
+
+ .. seealso::
+
+ :ref:`constraint_naming_conventions`
+
+ """
+
class ConventionDict(object):
def __init__(self, const, table, convention):
self.const = const
self._is_fk = isinstance(const, ForeignKeyConstraint)
self.table = table
self.convention = convention
- self._const_name = const._orig_name = getattr(const, '_orig_name', const.name)
+ self._const_name = const.name
def _key_table_name(self):
return self.table.name
@@ -41,9 +82,8 @@ class ConventionDict(object):
"%(constraint_name)s token requires that "
"constraint is explicitly named."
)
- # they asked for a name that's derived from the existing
- # name, so set the existing name to None
- self.const.name = None
+ if not isinstance(self._const_name, conv):
+ self.const.name = None
return self._const_name
def _key_column_X_name(self, idx):
@@ -118,7 +158,7 @@ def _constraint_name(const, table):
metadata = table.metadata
convention = _get_convention(metadata.naming_convention, type(const))
if convention is not None:
- newname = _truncated_label(
+ newname = conv(
convention % ConventionDict(const, table, metadata.naming_convention)
)
if const.name is None: