summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/sql/naming.py
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2014-02-01 18:21:04 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2014-02-01 18:21:04 -0500
commit5b0919f3f5c7678c587858a47e38acd4a5b82f25 (patch)
tree236ff9c4c4e8688aa9b1b5b5a9ea7f20ea3807fd /lib/sqlalchemy/sql/naming.py
parent32a1db368599f6f3dbb3765ef5f11640d1725672 (diff)
downloadsqlalchemy-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.py110
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