]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- Fixed an unexpected-use regression whereby custom :class:`.Comparator`
authorMike Bayer <mike_mp@zzzcomputing.com>
Thu, 11 Jun 2015 20:48:00 +0000 (16:48 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Thu, 11 Jun 2015 20:48:00 +0000 (16:48 -0400)
objects that made use of the ``__clause_element__()`` method and
returned an object that was an ORM-mapped
:class:`.InstrumentedAttribute` and not explicitly a
:class:`.ColumnElement` would fail to be correctly
handled when passed as an expression to :meth:`.Session.query`.
The logic in 0.9 happened to succeed on this, so this use case is now
supported. fixes #3448

doc/build/changelog/changelog_10.rst
lib/sqlalchemy/orm/query.py
test/ext/test_hybrid.py
test/orm/test_descriptor.py
test/orm/test_query.py

index 3436a0ca6a57ac6947c1464642f39c1b8360d712..f448865591a997a8c66ab7875f1efd4752b4747b 100644 (file)
 .. changelog::
     :version: 1.0.6
 
+    .. change::
+        :tags: bug, orm
+        :tickets: 3448
+
+        Fixed an unexpected-use regression whereby custom :class:`.Comparator`
+        objects that made use of the ``__clause_element__()`` method and
+        returned an object that was an ORM-mapped
+        :class:`.InstrumentedAttribute` and not explicitly a
+        :class:`.ColumnElement` would fail to be correctly
+        handled when passed as an expression to :meth:`.Session.query`.
+        The logic in 0.9 happened to succeed on this, so this use case is now
+        supported.
+
     .. change::
         :tags: bug, sql
         :tickets: 3445
index 8421e42accb2d916b82b9bee8f371da9a91fa88d..4f8c86a144a572f8196a12e067fe9e3d71d59ce3 100644 (file)
@@ -3539,11 +3539,13 @@ class _ColumnEntity(_QueryEntity):
         self.expr = column
         self.namespace = namespace
         search_entities = True
+        check_column = False
 
         if isinstance(column, util.string_types):
             column = sql.literal_column(column)
             self._label_name = column.name
             search_entities = False
+            check_column = True
             _entity = None
         elif isinstance(column, (
             attributes.QueryableAttribute,
@@ -3554,10 +3556,12 @@ class _ColumnEntity(_QueryEntity):
                 search_entities = False
             self._label_name = column.key
             column = column._query_clause_element()
+            check_column = True
             if isinstance(column, Bundle):
                 _BundleEntity(query, column)
                 return
-        elif not isinstance(column, sql.ColumnElement):
+
+        if not isinstance(column, sql.ColumnElement):
             if hasattr(column, '_select_iterable'):
                 # break out an object like Table into
                 # individual columns
@@ -3572,7 +3576,7 @@ class _ColumnEntity(_QueryEntity):
                 "SQL expression, column, or mapped entity "
                 "expected - got '%r'" % (column, )
             )
-        else:
+        elif not check_column:
             self._label_name = getattr(column, 'key', None)
             search_entities = True
 
index b895d2fb2b59049f25aeeb0132274d4e8cbd4792..e36b8f7e9e3c244bd66f99fb4f1c1cd864ab9357 100644 (file)
@@ -7,6 +7,7 @@ from sqlalchemy.testing import eq_, AssertsCompiledSQL, assert_raises_message
 from sqlalchemy.testing import fixtures
 from sqlalchemy import inspect
 
+
 class PropertyComparatorTest(fixtures.TestBase, AssertsCompiledSQL):
     __dialect__ = 'default'
 
index 2134d87b295e4221716fe9baa2e3947e231b61ef..d9aca30e554fa9f58d2b0a873edfc1b0f91a7f8f 100644 (file)
@@ -125,3 +125,4 @@ class DescriptorInstrumentationTest(fixtures.ORMTest):
             str(aliased(Foo).foo == 'ed'),
             "foobar(foo_1.name) = foobar(:foobar_1)"
         )
+
index 6a1eb57b486e0516a434c1f84c2af9683e4f9ad4..41c0e2a210731811addd0584bd6ae856434629ab 100644 (file)
@@ -1718,6 +1718,25 @@ class ColumnPropertyTest(_fixtures.FixtureTest, AssertsCompiledSQL):
         )
 
 
+class ComparatorTest(QueryTest):
+    def test_clause_element_query_resolve(self):
+        from sqlalchemy.orm.properties import ColumnProperty
+        User = self.classes.User
+
+        class Comparator(ColumnProperty.Comparator):
+            def __init__(self, expr):
+                self.expr = expr
+
+            def __clause_element__(self):
+                return self.expr
+
+        sess = Session()
+        eq_(
+            sess.query(Comparator(User.id)).order_by(Comparator(User.id)).all(),
+            [(7, ), (8, ), (9, ), (10, )]
+        )
+
+
 # more slice tests are available in test/orm/generative.py
 class SliceTest(QueryTest):
     def test_first(self):