diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2015-04-28 19:20:01 -0400 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2015-04-28 19:20:01 -0400 |
commit | 4f6e9ccae93b9c50298b041356953cb8a96b4895 (patch) | |
tree | 32b9814c8d7629ab593cd9bf8ada5fdef86522c8 | |
parent | ac52239b328f6dc573fdfb9acbbc7d5d528fa982 (diff) | |
download | sqlalchemy-4f6e9ccae93b9c50298b041356953cb8a96b4895.tar.gz |
- 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'))``
fixes #3397
-rw-r--r-- | doc/build/changelog/changelog_10.rst | 9 | ||||
-rw-r--r-- | lib/sqlalchemy/ext/associationproxy.py | 16 | ||||
-rw-r--r-- | test/ext/test_associationproxy.py | 30 |
3 files changed, 47 insertions, 8 deletions
diff --git a/doc/build/changelog/changelog_10.rst b/doc/build/changelog/changelog_10.rst index 5c39566b9..fd791ea97 100644 --- a/doc/build/changelog/changelog_10.rst +++ b/doc/build/changelog/changelog_10.rst @@ -19,6 +19,15 @@ :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 diff --git a/lib/sqlalchemy/ext/associationproxy.py b/lib/sqlalchemy/ext/associationproxy.py index a74141973..d837aab52 100644 --- a/lib/sqlalchemy/ext/associationproxy.py +++ b/lib/sqlalchemy/ext/associationproxy.py @@ -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 diff --git a/test/ext/test_associationproxy.py b/test/ext/test_associationproxy.py index 34c1a8322..8fb335b06 100644 --- a/test/ext/test_associationproxy.py +++ b/test/ext/test_associationproxy.py @@ -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 |