diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2014-02-01 18:21:04 -0500 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2014-02-01 18:21:04 -0500 |
| commit | 5b0919f3f5c7678c587858a47e38acd4a5b82f25 (patch) | |
| tree | 236ff9c4c4e8688aa9b1b5b5a9ea7f20ea3807fd /lib/sqlalchemy/sql/naming.py | |
| parent | 32a1db368599f6f3dbb3765ef5f11640d1725672 (diff) | |
| download | sqlalchemy-5b0919f3f5c7678c587858a47e38acd4a5b82f25.tar.gz | |
- Added a new feature which allows automated naming conventions to be
applied to :class:`.Constraint` and :class:`.Index` objects. Based
on a recipe in the wiki, the new feature uses schema-events to set up
names as various schema objects are associated with each other. The
events then expose a configuration system through a new argument
:paramref:`.MetaData.naming_convention`. This system allows production
of both simple and custom naming schemes for constraints and indexes
on a per-:class:`.MetaData` basis. [ticket:2923]
commit 7e65e52c086652de3dd3303c723f98f09af54db8
Author: Mike Bayer <mike_mp@zzzcomputing.com>
Date: Sat Feb 1 15:09:04 2014 -0500
- first pass at new naming approach
Diffstat (limited to 'lib/sqlalchemy/sql/naming.py')
| -rw-r--r-- | lib/sqlalchemy/sql/naming.py | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/lib/sqlalchemy/sql/naming.py b/lib/sqlalchemy/sql/naming.py new file mode 100644 index 000000000..b2cf1e9a5 --- /dev/null +++ b/lib/sqlalchemy/sql/naming.py @@ -0,0 +1,110 @@ +# sqlalchemy/naming.py +# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors <see AUTHORS file> +# +# This module is part of SQLAlchemy and is released under +# the MIT License: http://www.opensource.org/licenses/mit-license.php + +"""Establish constraint and index naming conventions. + + +""" + +from .schema import Constraint, ForeignKeyConstraint, PrimaryKeyConstraint, \ + UniqueConstraint, CheckConstraint, Index, Table +from .. import event, events +from .. import exc +from .elements import _truncated_label +import re + +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.name + + def _key_table_name(self): + return self.table.name + + def _column_X(self, idx): + if self._is_fk: + fk = self.const.elements[idx] + return fk.parent + else: + return list(self.const.columns)[idx] + + def _key_constraint_name(self): + if not self._const_name: + raise exc.InvalidRequestError( + "Naming convention including " + "%(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 + return self._const_name + + def _key_column_X_name(self, idx): + return self._column_X(idx).name + + def _key_column_X_label(self, idx): + return self._column_X(idx)._label + + def _key_referred_table_name(self): + fk = self.const.elements[0] + reftable, refcol = fk.target_fullname.split(".") + return reftable + + def _key_referred_column_X_name(self, idx): + fk = self.const.elements[idx] + reftable, refcol = fk.target_fullname.split(".") + return refcol + + def __getitem__(self, key): + if key in self.convention: + return self.convention[key](self.const, self.table) + elif hasattr(self, '_key_%s' % key): + return getattr(self, '_key_%s' % key)() + else: + col_template = re.match(r".*_?column_(\d+)_.+", key) + if col_template: + idx = col_template.group(1) + attr = "_key_" + key.replace(idx, "X") + idx = int(idx) + if hasattr(self, attr): + return getattr(self, attr)(idx) + raise KeyError(key) + +_prefix_dict = { + Index: "ix", + PrimaryKeyConstraint: "pk", + CheckConstraint: "ck", + UniqueConstraint: "uq", + ForeignKeyConstraint: "fk" +} + +def _get_convention(dict_, key): + + for super_ in key.__mro__: + if super_ in _prefix_dict and _prefix_dict[super_] in dict_: + return dict_[_prefix_dict[super_]] + elif super_ in dict_: + return dict_[super_] + else: + return None + + +@event.listens_for(Constraint, "after_parent_attach") +@event.listens_for(Index, "after_parent_attach") +def _constraint_name(const, table): + if isinstance(table, Table): + metadata = table.metadata + convention = _get_convention(metadata.naming_convention, type(const)) + if convention is not None: + newname = _truncated_label( + convention % ConventionDict(const, table, metadata.naming_convention) + ) + if const.name is None: + const.name = newname |
