diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/sqlalchemy/sql/compiler.py | 8 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/elements.py | 16 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/naming.py | 38 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/sqltypes.py | 6 |
4 files changed, 49 insertions, 19 deletions
diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py index 7a8b07f8f..99b74b3c8 100644 --- a/lib/sqlalchemy/sql/compiler.py +++ b/lib/sqlalchemy/sql/compiler.py @@ -2902,7 +2902,13 @@ class IdentifierPreparer(object): def format_savepoint(self, savepoint, name=None): return self.quote(name or savepoint.ident) - def format_constraint(self, constraint): + @util.dependencies("sqlalchemy.sql.naming") + def format_constraint(self, naming, constraint): + if isinstance(constraint.name, elements._defer_name): + name = naming._constraint_name_for_table( + constraint, constraint.table) + if name: + return self.quote(name) return self.quote(constraint.name) def format_table(self, table, use_schema=True, name=None): diff --git a/lib/sqlalchemy/sql/elements.py b/lib/sqlalchemy/sql/elements.py index 3882d9e5b..d273d9881 100644 --- a/lib/sqlalchemy/sql/elements.py +++ b/lib/sqlalchemy/sql/elements.py @@ -3201,6 +3201,22 @@ class _truncated_label(quoted_name): def apply_map(self, map_): return self + +class _defer_name(_truncated_label): + """mark a name as 'deferred' for the purposes of automated name + generation. + + """ + def __new__(cls, value): + if value is None: + return _defer_none_name('_unnamed_') + else: + return super(_defer_name, cls).__new__(cls, value) + + +class _defer_none_name(_defer_name): + """indicate a 'deferred' name that was ultimately the value None.""" + # for backwards compatibility in case # someone is re-implementing the # _truncated_identifier() sequence in a custom diff --git a/lib/sqlalchemy/sql/naming.py b/lib/sqlalchemy/sql/naming.py index d05054bc6..bb838c542 100644 --- a/lib/sqlalchemy/sql/naming.py +++ b/lib/sqlalchemy/sql/naming.py @@ -14,7 +14,7 @@ from .schema import Constraint, ForeignKeyConstraint, PrimaryKeyConstraint, \ UniqueConstraint, CheckConstraint, Index, Table, Column from .. import event, events from .. import exc -from .elements import _truncated_label +from .elements import _truncated_label, _defer_name, _defer_none_name import re class conv(_truncated_label): @@ -77,12 +77,12 @@ class ConventionDict(object): return list(self.const.columns)[idx] def _key_constraint_name(self): - if not self._const_name: + if isinstance(self._const_name, (type(None), _defer_none_name)): raise exc.InvalidRequestError( - "Naming convention including " - "%(constraint_name)s token requires that " - "constraint is explicitly named." - ) + "Naming convention including " + "%(constraint_name)s token requires that " + "constraint is explicitly named." + ) if not isinstance(self._const_name, conv): self.const.name = None return self._const_name @@ -144,6 +144,17 @@ def _get_convention(dict_, key): else: return None +def _constraint_name_for_table(const, table): + metadata = table.metadata + convention = _get_convention(metadata.naming_convention, type(const)) + if convention is not None and ( + const.name is None or not isinstance(const.name, conv) and + "constraint_name" in convention + ): + return conv( + convention % ConventionDict(const, table, + metadata.naming_convention) + ) @event.listens_for(Constraint, "after_parent_attach") @event.listens_for(Index, "after_parent_attach") @@ -156,12 +167,9 @@ def _constraint_name(const, table): lambda col, table: _constraint_name(const, table) ) elif isinstance(table, Table): - metadata = table.metadata - convention = _get_convention(metadata.naming_convention, type(const)) - if convention is not None: - if const.name is None or "constraint_name" in convention: - newname = conv( - convention % ConventionDict(const, table, metadata.naming_convention) - ) - if const.name is None: - const.name = newname + if isinstance(const.name, (conv, _defer_name)): + return + + newname = _constraint_name_for_table(const, table) + if newname is not None: + const.name = newname diff --git a/lib/sqlalchemy/sql/sqltypes.py b/lib/sqlalchemy/sql/sqltypes.py index b4d2d2390..52e5053ef 100644 --- a/lib/sqlalchemy/sql/sqltypes.py +++ b/lib/sqlalchemy/sql/sqltypes.py @@ -13,7 +13,7 @@ import datetime as dt import codecs from .type_api import TypeEngine, TypeDecorator, to_instance -from .elements import quoted_name, type_coerce +from .elements import quoted_name, type_coerce, _defer_name from .default_comparator import _DefaultColumnComparator from .. import exc, util, processors from .base import _bind_or_error, SchemaEventTarget @@ -1132,7 +1132,7 @@ class Enum(String, SchemaType): e = schema.CheckConstraint( type_coerce(column, self).in_(self.enums), - name=self.name, + name=_defer_name(self.name), _create_rule=util.portable_instancemethod( self._should_create_constraint) ) @@ -1268,7 +1268,7 @@ class Boolean(TypeEngine, SchemaType): e = schema.CheckConstraint( type_coerce(column, self).in_([0, 1]), - name=self.name, + name=_defer_name(self.name), _create_rule=util.portable_instancemethod( self._should_create_constraint) ) |
