]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- Fixed bug in association proxy where an any()/has()
authorMike Bayer <mike_mp@zzzcomputing.com>
Tue, 28 Apr 2015 23:20:01 +0000 (19:20 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Tue, 28 Apr 2015 23:20:01 +0000 (19:20 -0400)
on an relationship->scalar non-object attribute comparison would fail,
e.g.
``filter(Parent.some_collection_to_attribute.any(Child.attr == 'foo'))``
fixes #3397

doc/build/changelog/changelog_10.rst
lib/sqlalchemy/ext/associationproxy.py
test/ext/test_associationproxy.py

index 5c39566b9050365425990bd72357a6f6924491d0..fd791ea97993d5deb76f1f19b3e55f1b57a15d98 100644 (file)
 .. changelog::
     :version: 1.0.3
 
+    .. change::
+        :tags: bug, ext
+        :tickets: 3397
+
+        Fixed bug in association proxy where an any()/has()
+        on an relationship->scalar non-object attribute comparison would fail,
+        e.g.
+        ``filter(Parent.some_collection_to_attribute.any(Child.attr == 'foo'))``
+
     .. change::
         :tags: bug, sql
         :tickets: 3396
index a741419735824082587df67d54519ee85ca5ec35..d837aab520abc71b177ffe0d9c8c06e9016421ab 100644 (file)
@@ -365,13 +365,17 @@ class AssociationProxy(interfaces.InspectionAttrInfo):
         operators of the underlying proxied attributes.
 
         """
-
-        if self._value_is_scalar:
-            value_expr = getattr(
-                self.target_class, self.value_attr).has(criterion, **kwargs)
+        if self._target_is_object:
+            if self._value_is_scalar:
+                value_expr = getattr(
+                    self.target_class, self.value_attr).has(
+                    criterion, **kwargs)
+            else:
+                value_expr = getattr(
+                    self.target_class, self.value_attr).any(
+                    criterion, **kwargs)
         else:
-            value_expr = getattr(
-                self.target_class, self.value_attr).any(criterion, **kwargs)
+            value_expr = criterion
 
         # check _value_is_scalar here, otherwise
         # we're scalar->scalar - call .any() so that
index 34c1a83220ce6e4cd235b2cee5c57c513cd77f95..8fb335b064b02c9a05072a2633e44f1543a0aa93 100644 (file)
@@ -1089,7 +1089,8 @@ class ComparatorTest(fixtures.MappedTest, AssertsCompiledSQL):
     def define_tables(cls, metadata):
         Table('userkeywords', metadata,
           Column('keyword_id', Integer, ForeignKey('keywords.id'), primary_key=True),
-          Column('user_id', Integer, ForeignKey('users.id'))
+          Column('user_id', Integer, ForeignKey('users.id')),
+          Column('value', String(50))
         )
         Table('users', metadata,
             Column('id', Integer,
@@ -1128,6 +1129,9 @@ class ComparatorTest(fixtures.MappedTest, AssertsCompiledSQL):
             # nonuselist
             singular_value = association_proxy('singular', 'value')
 
+            # o2m -> scalar
+            singular_collection = association_proxy('user_keywords', 'value')
+
         class Keyword(cls.Comparable):
             def __init__(self, keyword):
                 self.keyword = keyword
@@ -1195,8 +1199,9 @@ class ComparatorTest(fixtures.MappedTest, AssertsCompiledSQL):
             for jj in words[(ii % len(words)):((ii + 3) % len(words))]:
                 k = Keyword(jj)
                 user.keywords.append(k)
-                if ii % 3 == None:
+                if ii % 2 == 0:
                     user.singular.keywords.append(k)
+                    user.user_keywords[-1].value = "singular%d" % ii
 
         orphan = Keyword('orphan')
         orphan.user_keyword = UserKeyword(keyword=orphan, user=None)
@@ -1213,6 +1218,27 @@ class ComparatorTest(fixtures.MappedTest, AssertsCompiledSQL):
     def _equivalent(self, q_proxy, q_direct):
         eq_(q_proxy.all(), q_direct.all())
 
+    def test_filter_any_criterion_ul_scalar(self):
+        UserKeyword, User = self.classes.UserKeyword, self.classes.User
+
+        q1 = self.session.query(User).filter(
+            User.singular_collection.any(UserKeyword.value == 'singular8'))
+        self.assert_compile(
+            q1,
+            "SELECT users.id AS users_id, users.name AS users_name, "
+            "users.singular_id AS users_singular_id "
+            "FROM users "
+            "WHERE EXISTS (SELECT 1 "
+            "FROM userkeywords "
+            "WHERE users.id = userkeywords.user_id AND "
+            "userkeywords.value = :value_1)",
+            checkparams={'value_1': 'singular8'}
+        )
+
+        q2 = self.session.query(User).filter(
+            User.user_keywords.any(UserKeyword.value == 'singular8'))
+        self._equivalent(q1, q2)
+
     def test_filter_any_kwarg_ul_nul(self):
         UserKeyword, User = self.classes.UserKeyword, self.classes.User