From 9154e1eff1da41c41b31e2a24a6128ff457c7716 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Mon, 5 Mar 2007 23:08:52 +0000 Subject: - added concept of 'require_embedded' to corresponding_column. requires that the target column be present in a sub-element of the target selectable. - embedded logic above more appropriate for ClauseAdapter functionality since its trying to "pull up" clauses that represent columns within a larger union up to the level of the union itself. - the "direction" test against the "foreign_keys" collection apparently works for an exact "column 'x' is present in the collection", no proxy relationships needed. fixes the case of relating a selectable/alias to one of its underlying tables, probably fixes other scenarios --- lib/sqlalchemy/sql.py | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) (limited to 'lib/sqlalchemy/sql.py') diff --git a/lib/sqlalchemy/sql.py b/lib/sqlalchemy/sql.py index da1afe799..073277d57 100644 --- a/lib/sqlalchemy/sql.py +++ b/lib/sqlalchemy/sql.py @@ -506,6 +506,21 @@ class ClauseVisitor(object): def visit_label(self, label):pass def visit_typeclause(self, typeclause):pass +class VisitColumnMixin(object): + """a mixin that adds Column traversal to a ClauseVisitor""" + def visit_table(self, table): + for c in table.c: + c.accept_visitor(self) + def visit_select(self, select): + for c in select.c: + c.accept_visitor(self) + def visit_compound_select(self, select): + for c in select.c: + c.accept_visitor(self) + def visit_alias(self, alias): + for c in alias.c: + c.accept_visitor(self) + class Executor(object): """Represent a *thing that can produce Compiled objects and execute them*.""" @@ -1041,20 +1056,25 @@ class FromClause(Selectable): self._oid_column = self._locate_oid_column() return self._oid_column - def corresponding_column(self, column, raiseerr=True, keys_ok=False, require_exact=False): + def _get_all_embedded_columns(self): + ret = [] + class FindCols(VisitColumnMixin, ClauseVisitor): + def visit_column(self, col): + ret.append(col) + self.accept_visitor(FindCols()) + return ret + + def corresponding_column(self, column, raiseerr=True, keys_ok=False, require_embedded=False): """Given a ``ColumnElement``, return the ``ColumnElement`` object from this ``Selectable`` which corresponds to that original ``Column`` via a proxy relationship. """ - if require_exact: - if self.columns.get(column.name) is column: - return column + if require_embedded and column not in util.Set(self._get_all_embedded_columns()): + if not raiseerr: + return None else: - if not raiseerr: - return None - else: - raise exceptions.InvalidRequestError("Column instance '%s' is not directly present in table '%s'" % (str(column), str(column.table))) + raise exceptions.InvalidRequestError("Column instance '%s' is not directly present within selectable '%s'" % (str(column), column.table)) for c in column.orig_set: try: return self.original_columns[c] -- cgit v1.2.1