]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- Fixed bug whereby comparison of column
authorMike Bayer <mike_mp@zzzcomputing.com>
Mon, 13 Jun 2011 00:35:37 +0000 (20:35 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Mon, 13 Jun 2011 00:35:37 +0000 (20:35 -0400)
expression to a Query() would not call
as_scalar() on the underlying SELECT
statement to produce a scalar subquery,
in the way that occurs if you called
it on Query().subquery(). [ticket:2190]
- some cleanup to test.orm.test_query

CHANGES
lib/sqlalchemy/sql/expression.py
test/orm/test_query.py

diff --git a/CHANGES b/CHANGES
index bcd1461e47630b52727fdd932f258be3fe55274f..2048a8aa1882d1de374223c69b311148b5de1eba 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -11,6 +11,13 @@ CHANGES
     relationship.order_by, foreign_keys,
     remote_side, etc.
 
+  - Fixed bug whereby comparison of column
+    expression to a Query() would not call
+    as_scalar() on the underlying SELECT 
+    statement to produce a scalar subquery,
+    in the way that occurs if you called
+    it on Query().subquery(). [ticket:2190]
+
 - mssql
   - Adjusted the pyodbc dialect such that bound
     values are passed as bytes and not unicode
index 8eb552de9e53bee42bbd4b9bb9f02034456046be..f78015ac2ed6fcdbf6018dca1203a394a4631d61 100644 (file)
@@ -1943,7 +1943,10 @@ class _CompareMixin(ColumnOperators):
             other.type = self.type
             return other
         elif hasattr(other, '__clause_element__'):
-            return other.__clause_element__()
+            other = other.__clause_element__()
+            if isinstance(other, (_SelectBase, Alias)):
+                other = other.as_scalar()
+            return other
         elif not isinstance(other, ClauseElement):
             return self._bind_param(operator, other)
         elif isinstance(other, (_SelectBase, Alias)):
index 6c4c60c8274d571636621e809fcb034e8c1d013f..1e2d5e96d66dbe03aff25f492be081aacaa06f71 100644 (file)
@@ -1,19 +1,22 @@
 from test.lib.testing import eq_, assert_raises, assert_raises_message
 import operator
-from sqlalchemy import *
+from sqlalchemy import MetaData, null, exists, text, union, literal, \
+    literal_column, func, between, Unicode, desc, and_, bindparam, \
+    select, distinct
 from sqlalchemy import exc as sa_exc, util
 from sqlalchemy.sql import compiler, table, column
+from sqlalchemy.sql import expression
 from sqlalchemy.engine import default
-from sqlalchemy.orm import *
-from sqlalchemy.orm import attributes
+from sqlalchemy.orm import attributes, mapper, relationship, backref, \
+    configure_mappers, create_session, synonym, Session, class_mapper, \
+    aliased, column_property, joinedload_all, joinedload, Query
 from test.lib.assertsql import CompiledSQL
 from test.lib.testing import eq_
+from test.lib.schema import Table, Column
 
 import sqlalchemy as sa
-from test.lib import testing, AssertsCompiledSQL, Column, engines
-
+from test.lib import testing, AssertsCompiledSQL, engines
 from test.orm import _fixtures
-
 from test.lib import fixtures
 
 from sqlalchemy.orm.util import join, outerjoin, with_parent
@@ -731,6 +734,7 @@ class OperatorTest(QueryTest, AssertsCompiledSQL):
 
 
 class ExpressionTest(QueryTest, AssertsCompiledSQL):
+    __dialect__ = 'default'
 
     def test_deferred_instances(self):
         User, addresses, Address = (self.classes.User,
@@ -757,20 +761,27 @@ class ExpressionTest(QueryTest, AssertsCompiledSQL):
             "addresses.id AS addresses_id, addresses.user_id AS "
             "addresses_user_id, addresses.email_address AS "
             "addresses_email_address FROM users JOIN addresses "
-            "ON users.id = addresses.user_id) AS anon_1",
-            use_default_dialect=True
+            "ON users.id = addresses.user_id) AS anon_1"
         )
 
-    def test_scalar_subquery(self):
+    def test_scalar_subquery_compile_whereclause(self):
         User = self.classes.User
+        Address = self.classes.Address
 
         session = create_session()
 
-        q = session.query(User.id).filter(User.id==7).subquery()
-
-        q = session.query(User).filter(User.id==q)
+        q = session.query(User.id).filter(User.id==7)
 
-        eq_(User(id=7), q.one())
+        q = session.query(Address).filter(Address.user_id==q)
+        assert isinstance(q._criterion.right, expression.ColumnElement)
+        self.assert_compile(
+            q,
+            "SELECT addresses.id AS addresses_id, addresses.user_id "
+            "AS addresses_user_id, addresses.email_address AS "
+            "addresses_email_address FROM addresses WHERE "
+            "addresses.user_id = (SELECT users.id AS users_id "
+            "FROM users WHERE users.id = :id_1)"
+        )
 
     def test_named_subquery(self):
         User = self.classes.User
@@ -793,8 +804,7 @@ class ExpressionTest(QueryTest, AssertsCompiledSQL):
         q = session.query(User.id).filter(User.id==7).label('foo')
         self.assert_compile(
             session.query(q), 
-            "SELECT (SELECT users.id FROM users WHERE users.id = :id_1) AS foo", 
-            use_default_dialect=True
+            "SELECT (SELECT users.id FROM users WHERE users.id = :id_1) AS foo"
         )
 
     def test_as_scalar(self):
@@ -808,8 +818,7 @@ class ExpressionTest(QueryTest, AssertsCompiledSQL):
                             'SELECT users.id AS users_id, users.name '
                             'AS users_name FROM users WHERE users.id '
                             'IN (SELECT users.id FROM users WHERE '
-                            'users.id = :id_1)',
-                            use_default_dialect=True)
+                            'users.id = :id_1)')
 
 
     def test_param_transfer(self):
@@ -857,8 +866,7 @@ class ExpressionTest(QueryTest, AssertsCompiledSQL):
         self.assert_compile(
             select([q1]),
             "SELECT users_id, users_name FROM (SELECT users.id AS users_id, "
-            "users.name AS users_name FROM users WHERE users.name = :name_1)",
-            dialect=default.DefaultDialect()
+            "users.name AS users_name FROM users WHERE users.name = :name_1)"
         )
 
     def test_join(self):
@@ -2278,7 +2286,7 @@ class OptionsNoPropTest(_fixtures.FixtureTest):
         Keyword = self.classes.Keyword
         self._assert_eager_not_found_exception(
             [Keyword],
-            (eagerload(Item.keywords), ),
+            (joinedload(Item.keywords), ),
             r"Can't find property 'keywords' on any entity specified "
             r"in this Query.  Note the full path from root "
             r"\(Mapper\|Keyword\|keywords\) to target entity must be specified."
@@ -2288,7 +2296,7 @@ class OptionsNoPropTest(_fixtures.FixtureTest):
         Item = self.classes.Item
         self._assert_eager_not_found_exception(
             [Item],
-            (eagerload("foo"), ),
+            (joinedload("foo"), ),
             r"Can't find property named 'foo' on the mapped "
             r"entity Mapper\|Item\|items in this Query."
         )
@@ -2297,7 +2305,7 @@ class OptionsNoPropTest(_fixtures.FixtureTest):
         Item = self.classes.Item
         self._assert_eager_not_found_exception(
             [Item],
-            (eagerload("keywords.foo"), ),
+            (joinedload("keywords.foo"), ),
             r"Can't find property named 'foo' on the mapped entity "
             r"Mapper\|Keyword\|keywords in this Query."
         )
@@ -2306,7 +2314,7 @@ class OptionsNoPropTest(_fixtures.FixtureTest):
         Item = self.classes.Item
         self._assert_eager_not_found_exception(
             [Item],
-            (eagerload_all("keywords.foo"), ),
+            (joinedload_all("keywords.foo"), ),
             r"Can't find property named 'foo' on the mapped entity "
             r"Mapper\|Keyword\|keywords in this Query."
         )
@@ -2318,7 +2326,7 @@ class OptionsNoPropTest(_fixtures.FixtureTest):
         Keyword = self.classes.Keyword
         self._assert_eager_not_found_exception(
             [Keyword, Item],
-            (eagerload_all("keywords"), ),
+            (joinedload_all("keywords"), ),
             r"Attribute 'keywords' of entity 'Mapper\|Keyword\|keywords' "
             "does not refer to a mapped entity"
         )
@@ -2330,7 +2338,7 @@ class OptionsNoPropTest(_fixtures.FixtureTest):
         Keyword = self.classes.Keyword
         self._assert_eager_not_found_exception(
             [Keyword, Item],
-            (eagerload_all("keywords"), ),
+            (joinedload_all("keywords"), ),
             r"Attribute 'keywords' of entity 'Mapper\|Keyword\|keywords' "
             "does not refer to a mapped entity"
         )
@@ -2339,7 +2347,7 @@ class OptionsNoPropTest(_fixtures.FixtureTest):
         Item = self.classes.Item
         self._assert_eager_not_found_exception(
             [Item],
-            (eagerload_all("id", "keywords"), ),
+            (joinedload_all("id", "keywords"), ),
             r"Attribute 'id' of entity 'Mapper\|Item\|items' does not "
             r"refer to a mapped entity"
         )
@@ -2349,7 +2357,7 @@ class OptionsNoPropTest(_fixtures.FixtureTest):
         Keyword = self.classes.Keyword
         self._assert_eager_not_found_exception(
             [Keyword, Item],
-            (eagerload_all("id", "keywords"), ),
+            (joinedload_all("id", "keywords"), ),
             r"Attribute 'id' of entity 'Mapper\|Keyword\|keywords' "
             "does not refer to a mapped entity"
         )
@@ -2359,7 +2367,7 @@ class OptionsNoPropTest(_fixtures.FixtureTest):
         Keyword = self.classes.Keyword
         self._assert_eager_not_found_exception(
             [Keyword, Item],
-            (eagerload_all("description"), ),
+            (joinedload_all("description"), ),
             r"Can't find property named 'description' on the mapped "
             r"entity Mapper\|Keyword\|keywords in this Query."
         )
@@ -2369,7 +2377,7 @@ class OptionsNoPropTest(_fixtures.FixtureTest):
         Keyword = self.classes.Keyword
         self._assert_eager_not_found_exception(
             [Keyword.id, Item.id],
-            (eagerload_all("keywords"), ),
+            (joinedload_all("keywords"), ),
             r"Query has only expression-based entities - can't find property "
             "named 'keywords'."
         )
@@ -2379,7 +2387,7 @@ class OptionsNoPropTest(_fixtures.FixtureTest):
         Keyword = self.classes.Keyword
         self._assert_eager_not_found_exception(
             [Keyword, Item],
-            (eagerload_all(Keyword.id, Item.keywords), ),
+            (joinedload_all(Keyword.id, Item.keywords), ),
             r"Attribute 'Keyword.id' of entity 'Mapper\|Keyword\|keywords' "
             "does not refer to a mapped entity"
         )
@@ -2389,7 +2397,7 @@ class OptionsNoPropTest(_fixtures.FixtureTest):
         Keyword = self.classes.Keyword
         self._assert_eager_not_found_exception(
             [Keyword, Item],
-            (eagerload_all(Keyword.keywords, Item.keywords), ),
+            (joinedload_all(Keyword.keywords, Item.keywords), ),
             r"Attribute 'Keyword.keywords' of entity 'Mapper\|Keyword\|keywords' "
             "does not refer to a mapped entity"
         )
@@ -2399,7 +2407,7 @@ class OptionsNoPropTest(_fixtures.FixtureTest):
         Keyword = self.classes.Keyword
         self._assert_eager_not_found_exception(
             [Keyword.id, Item.id],
-            (eagerload_all(Keyword.keywords, Item.keywords), ),
+            (joinedload_all(Keyword.keywords, Item.keywords), ),
             r"Query has only expression-based entities - "
             "can't find property named 'keywords'."
         )
@@ -2409,7 +2417,7 @@ class OptionsNoPropTest(_fixtures.FixtureTest):
         Keyword = self.classes.Keyword
         self._assert_eager_not_found_exception(
             [Item],
-            (eagerload_all(Keyword), ),
+            (joinedload_all(Keyword), ),
             r"mapper option expects string key or list of attributes"
         )
 
@@ -2431,7 +2439,7 @@ class OptionsNoPropTest(_fixtures.FixtureTest):
         Item = self.classes.Item
 
         q = create_session().query(*entity_list).\
-                            options(eagerload(option))
+                            options(joinedload(option))
         key = ('loaderstrategy', (class_mapper(Item), 'keywords'))
         assert key in q._attributes
 
@@ -2446,4 +2454,4 @@ class OptionsNoPropTest(_fixtures.FixtureTest):
             eager_option, message):
         assert_raises_message(sa.exc.ArgumentError, message,
                               create_session().query(column).options,
-                              eagerload(eager_option))
+                              joinedload(eager_option))