summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/sqlalchemy/sql/compiler.py8
-rw-r--r--lib/sqlalchemy/sql/elements.py6
-rw-r--r--lib/sqlalchemy/sql/selectable.py1
-rw-r--r--test/orm/test_query.py40
-rw-r--r--test/sql/test_text.py5
5 files changed, 57 insertions, 3 deletions
diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py
index e4597dcd8..23e5456a7 100644
--- a/lib/sqlalchemy/sql/compiler.py
+++ b/lib/sqlalchemy/sql/compiler.py
@@ -495,6 +495,12 @@ class SQLCompiler(Compiled):
return "(" + grouping.element._compiler_dispatch(self, **kwargs) + ")"
def visit_label_reference(self, element, **kwargs):
+ if not self.stack:
+ # compiling the element outside of the context of a SELECT
+ return self.process(
+ element._text_clause
+ )
+
selectable = self.stack[-1]['selectable']
try:
col = selectable._inner_column_dict[element.text]
@@ -504,7 +510,7 @@ class SQLCompiler(Compiled):
"Can't resolve label reference %r; converting to text()",
util.ellipses_string(element.text))
return self.process(
- elements.TextClause._create_text(element.text)
+ element._text_clause
)
else:
kwargs['render_label_as_label'] = col
diff --git a/lib/sqlalchemy/sql/elements.py b/lib/sqlalchemy/sql/elements.py
index 0ea05fa0e..984cfe0ee 100644
--- a/lib/sqlalchemy/sql/elements.py
+++ b/lib/sqlalchemy/sql/elements.py
@@ -2292,7 +2292,11 @@ class _label_reference(ColumnElement):
__visit_name__ = 'label_reference'
def __init__(self, text):
- self.text = text
+ self.text = self.key = text
+
+ @util.memoized_property
+ def _text_clause(self):
+ return TextClause._create_text(self.text)
class UnaryExpression(ColumnElement):
diff --git a/lib/sqlalchemy/sql/selectable.py b/lib/sqlalchemy/sql/selectable.py
index cf2c213d2..a49493995 100644
--- a/lib/sqlalchemy/sql/selectable.py
+++ b/lib/sqlalchemy/sql/selectable.py
@@ -2976,6 +2976,7 @@ class Select(HasPrefixes, GenerativeSelect):
def name_for_col(c):
if c._columns_clause_label is None:
return (None, c)
+
name = c._columns_clause_label
if name in names:
name = c.anon_label
diff --git a/test/orm/test_query.py b/test/orm/test_query.py
index c0e9f9e1c..cb67057e4 100644
--- a/test/orm/test_query.py
+++ b/test/orm/test_query.py
@@ -2276,7 +2276,7 @@ class HintsTest(QueryTest, AssertsCompiledSQL):
)
-class TextTest(QueryTest):
+class TextTest(QueryTest, AssertsCompiledSQL):
def test_fulltext(self):
User = self.classes.User
@@ -2380,6 +2380,44 @@ class TextTest(QueryTest):
[User(id=7), User(id=8), User(id=9), User(id=10)]
)
+ def test_order_by_w_eager(self):
+ User = self.classes.User
+ Address = self.classes.Address
+ s = create_session()
+
+ # here, we are seeing how Query has to take the order by expressions
+ # of the query and then add them to the columns list, so that the
+ # outer subquery can order by that same label. With the anonymous
+ # label, our column gets sucked up and restated again in the
+ # inner columns list!
+ # we could try to play games with making this "smarter" but it
+ # would add permanent overhead to Select._columns_plus_names,
+ # since that's where references would need to be resolved.
+ # so as it is, this query takes the _label_reference and makes a
+ # full blown proxy and all the rest of it.
+ self.assert_compile(
+ s.query(User).options(joinedload("addresses")).
+ order_by(desc("name")).limit(1),
+ "SELECT anon_1.users_id AS anon_1_users_id, "
+ "anon_1.users_name AS anon_1_users_name, "
+ "anon_1.anon_2 AS anon_1_anon_2, "
+ "addresses_1.id AS addresses_1_id, "
+ "addresses_1.user_id AS addresses_1_user_id, "
+ "addresses_1.email_address AS addresses_1_email_address "
+ "FROM (SELECT users.id AS users_id, users.name AS users_name, "
+ "users.name AS anon_2 FROM users ORDER BY users.name "
+ "DESC LIMIT ? OFFSET ?) AS anon_1 "
+ "LEFT OUTER JOIN addresses AS addresses_1 "
+ "ON anon_1.users_id = addresses_1.user_id "
+ "ORDER BY anon_1.anon_2 DESC, addresses_1.id"
+ )
+
+ eq_(
+ s.query(User).options(joinedload("addresses")).
+ order_by(desc("name")).first(),
+ User(name='jack', addresses=[Address()])
+ )
+
class TextWarningTest(QueryTest, AssertsCompiledSQL):
def _test(self, fn, arg, offending_clause, expected):
diff --git a/test/sql/test_text.py b/test/sql/test_text.py
index 182c63624..e84a2907c 100644
--- a/test/sql/test_text.py
+++ b/test/sql/test_text.py
@@ -674,3 +674,8 @@ class OrderByLabelResolutionTest(fixtures.TestBase, AssertsCompiledSQL):
"SELECT foo(:foo_1) AS x UNION SELECT foo(:foo_2) AS y ORDER BY x"
)
+ def test_standalone_units_stringable(self):
+ self.assert_compile(
+ desc("somelabel"),
+ "somelabel DESC"
+ )