summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2013-06-10 13:45:19 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2013-06-10 13:45:19 -0400
commitb614a24c5ddf4c7c7aa45e1eaeb3f82e36737729 (patch)
tree95c31f73e46603c154124f7c69d2a2cb7943157a /lib/sqlalchemy
parent1652491cc6ef44c803e58c0d842818ab7310f498 (diff)
downloadsqlalchemy-b614a24c5ddf4c7c7aa45e1eaeb3f82e36737729.tar.gz
Fixed the interaction between composite attributes and
the :func:`.aliased` function. Previously, composite attributes wouldn't work correctly in comparison operations when aliasing was applied. Also in 0.8.2. [ticket:2755]
Diffstat (limited to 'lib/sqlalchemy')
-rw-r--r--lib/sqlalchemy/orm/descriptor_props.py38
-rw-r--r--lib/sqlalchemy/orm/util.py1
2 files changed, 24 insertions, 15 deletions
diff --git a/lib/sqlalchemy/orm/descriptor_props.py b/lib/sqlalchemy/orm/descriptor_props.py
index 86b445bb6..c565cb715 100644
--- a/lib/sqlalchemy/orm/descriptor_props.py
+++ b/lib/sqlalchemy/orm/descriptor_props.py
@@ -298,7 +298,7 @@ class CompositeProperty(DescriptorProperty):
)
def _comparator_factory(self, mapper):
- return self.comparator_factory(self)
+ return self.comparator_factory(self, mapper)
class Comparator(PropComparator):
"""Produce boolean, comparison, and other operators for
@@ -318,29 +318,39 @@ class CompositeProperty(DescriptorProperty):
:attr:`.TypeEngine.comparator_factory`
"""
- def __init__(self, prop, adapter=None):
- self.prop = self.property = prop
- self.adapter = adapter
def __clause_element__(self):
- if self.adapter:
- # TODO: test coverage for adapted composite comparison
- return expression.ClauseList(
- *[self.adapter(x) for x in self.prop._comparable_elements])
- else:
- return expression.ClauseList(*self.prop._comparable_elements)
+ return expression.ClauseList(*self._comparable_elements)
__hash__ = None
+ @util.memoized_property
+ def _comparable_elements(self):
+ if self.adapter:
+ # we need to do a little fudging here because
+ # the adapter function we're given only accepts
+ # ColumnElements, but our prop._comparable_elements is returning
+ # InstrumentedAttribute, because we support the use case
+ # of composites that refer to relationships. The better
+ # solution here is to open up how AliasedClass interacts
+ # with PropComparators so more context is available.
+ return [self.adapter(x.__clause_element__())
+ for x in self.prop._comparable_elements]
+ else:
+ return self.prop._comparable_elements
+
def __eq__(self, other):
if other is None:
values = [None] * len(self.prop._comparable_elements)
else:
values = other.__composite_values__()
- return sql.and_(
- *[a == b
- for a, b in zip(self.prop._comparable_elements, values)]
- )
+ comparisons = [
+ a == b
+ for a, b in zip(self.prop._comparable_elements, values)
+ ]
+ if self.adapter:
+ comparisons = [self.adapter(x) for x in comparisons]
+ return sql.and_(*comparisons)
def __ne__(self, other):
return sql.not_(self.__eq__(other))
diff --git a/lib/sqlalchemy/orm/util.py b/lib/sqlalchemy/orm/util.py
index 38cf58792..ef9de760e 100644
--- a/lib/sqlalchemy/orm/util.py
+++ b/lib/sqlalchemy/orm/util.py
@@ -575,7 +575,6 @@ class AliasedClass(object):
def __adapt_prop(self, existing, key):
comparator = existing.comparator.adapted(self.__adapt_element)
-
queryattr = attributes.QueryableAttribute(
self, key,
impl=existing.impl,