summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/sql/util.py
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2008-11-03 02:52:30 +0000
committerMike Bayer <mike_mp@zzzcomputing.com>2008-11-03 02:52:30 +0000
commita5dfbeedb9f7ae148081d1dbc3e91e876526eb90 (patch)
tree070cede0b9a927c5672a7b847113a9947a2726ce /lib/sqlalchemy/sql/util.py
parent334d5118bb7bcf6fcf052c1b12182009fe54ebef (diff)
downloadsqlalchemy-a5dfbeedb9f7ae148081d1dbc3e91e876526eb90.tar.gz
- Improved the behavior of aliased() objects such that they more
accurately adapt the expressions generated, which helps particularly with self-referential comparisons. [ticket:1171] - Fixed bug involving primaryjoin/secondaryjoin conditions constructed from class-bound attributes (as often occurs when using declarative), which later would be inappropriately aliased by Query, particularly with the various EXISTS based comparators.
Diffstat (limited to 'lib/sqlalchemy/sql/util.py')
-rw-r--r--lib/sqlalchemy/sql/util.py70
1 files changed, 63 insertions, 7 deletions
diff --git a/lib/sqlalchemy/sql/util.py b/lib/sqlalchemy/sql/util.py
index d9c3ed899..2a510906b 100644
--- a/lib/sqlalchemy/sql/util.py
+++ b/lib/sqlalchemy/sql/util.py
@@ -159,6 +159,20 @@ class Annotated(object):
clone.__dict__ = self.__dict__.copy()
clone._annotations = _values
return clone
+
+ def _deannotate(self):
+ return self.__element
+
+ def _clone(self):
+ clone = self.__element._clone()
+ if clone is self.__element:
+ # detect immutable, don't change anything
+ return self
+ else:
+ # update the clone with any changes that have occured
+ # to this object's __dict__.
+ clone.__dict__.update(self.__dict__)
+ return Annotated(clone, self._annotations)
def __hash__(self):
return hash(self.__element)
@@ -166,6 +180,39 @@ class Annotated(object):
def __cmp__(self, other):
return cmp(hash(self.__element), hash(other))
+def _deep_annotate(element, annotations, exclude=None):
+ """Deep copy the given ClauseElement, annotating each element with the given annotations dictionary.
+
+ Elements within the exclude collection will be cloned but not annotated.
+
+ """
+ def clone(elem):
+ # check if element is present in the exclude list.
+ # take into account proxying relationships.
+ if exclude and elem.proxy_set.intersection(exclude):
+ elem = elem._clone()
+ elif annotations != elem._annotations:
+ elem = elem._annotate(annotations.copy())
+ elem._copy_internals(clone=clone)
+ return elem
+
+ if element is not None:
+ element = clone(element)
+ return element
+
+def _deep_deannotate(element):
+ """Deep copy the given element, removing all annotations."""
+
+ def clone(elem):
+ elem = elem._deannotate()
+ elem._copy_internals(clone=clone)
+ return elem
+
+ if element is not None:
+ element = clone(element)
+ return element
+
+
def splice_joins(left, right, stop_on=None):
if left is None:
return right
@@ -208,7 +255,6 @@ def reduce_columns(columns, *clauses, **kw):
in the the selectable to just those that are not repeated.
"""
-
ignore_nonexistent_tables = kw.pop('ignore_nonexistent_tables', False)
columns = util.OrderedSet(columns)
@@ -317,7 +363,12 @@ def folded_equivalents(join, equivs=None):
return collist
class AliasedRow(object):
+ """Wrap a RowProxy with a translation map.
+
+ This object allows a set of keys to be translated
+ to those present in a RowProxy.
+ """
def __init__(self, row, map):
# AliasedRow objects don't nest, so un-nest
# if another AliasedRow was passed
@@ -341,10 +392,8 @@ class AliasedRow(object):
class ClauseAdapter(visitors.ReplacingCloningVisitor):
- """Given a clause (like as in a WHERE criterion), locate columns
- which are embedded within a given selectable, and changes those
- columns to be that of the selectable.
-
+ """Clones and modifies clauses based on column correspondence.
+
E.g.::
table1 = Table('sometable', metadata,
@@ -358,7 +407,7 @@ class ClauseAdapter(visitors.ReplacingCloningVisitor):
condition = table1.c.col1 == table2.c.col1
- and make an alias of table1::
+ make an alias of table1::
s = table1.alias('foo')
@@ -401,7 +450,14 @@ class ClauseAdapter(visitors.ReplacingCloningVisitor):
return self._corresponding_column(col, True)
class ColumnAdapter(ClauseAdapter):
-
+ """Extends ClauseAdapter with extra utility functions.
+
+ Provides the ability to "wrap" this ClauseAdapter
+ around another, a columns dictionary which returns
+ cached, adapted elements given an original, and an
+ adapted_row() factory.
+
+ """
def __init__(self, selectable, equivalents=None, chain_to=None, include=None, exclude=None):
ClauseAdapter.__init__(self, selectable, equivalents, include, exclude)
if chain_to: