From 4d036d6dd4a6dde9e7ae18ebc6451fdf8da0c726 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Sat, 25 Jul 2009 19:34:02 +0000 Subject: [PATCH] - Unary expressions such as DISTINCT propagate their type handling to result sets, allowing conversions like unicode and such to take place. [ticket:1420] --- CHANGES | 5 +++++ lib/sqlalchemy/sql/compiler.py | 4 ++-- lib/sqlalchemy/sql/expression.py | 7 +++---- test/sql/test_query.py | 7 +++++++ test/sql/test_types.py | 10 ++++++++++ 5 files changed, 27 insertions(+), 6 deletions(-) diff --git a/CHANGES b/CHANGES index 5234440a0a..fa82928653 100644 --- a/CHANGES +++ b/CHANGES @@ -25,6 +25,11 @@ CHANGES the string "field" argument was getting treated as a ClauseElement, causing various errors within more complex SQL transformations. + + - Unary expressions such as DISTINCT propagate their + type handling to result sets, allowing conversions like + unicode and such to take place. [ticket:1420] + - ext - The collection proxies produced by associationproxy are now pickleable. A user-defined proxy_factory however diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py index 5140b7f20e..6af65ec140 100644 --- a/lib/sqlalchemy/sql/compiler.py +++ b/lib/sqlalchemy/sql/compiler.py @@ -405,8 +405,8 @@ class DefaultCompiler(engine.Compiled): else: return text - def visit_unary(self, unary, **kwargs): - s = self.process(unary.element) + def visit_unary(self, unary, **kw): + s = self.process(unary.element, **kw) if unary.operator: s = self.operator_string(unary.operator) + " " + s if unary.modifier: diff --git a/lib/sqlalchemy/sql/expression.py b/lib/sqlalchemy/sql/expression.py index b5eb0eee97..0dae6716d4 100644 --- a/lib/sqlalchemy/sql/expression.py +++ b/lib/sqlalchemy/sql/expression.py @@ -400,8 +400,8 @@ def not_(clause): def distinct(expr): """Return a ``DISTINCT`` clause.""" - - return _UnaryExpression(expr, operator=operators.distinct_op) + expr = _literal_as_binds(expr) + return _UnaryExpression(expr, operator=operators.distinct_op, type_=expr.type) def between(ctest, cleft, cright): """Return a ``BETWEEN`` predicate clause. @@ -1476,8 +1476,7 @@ class _CompareMixin(ColumnOperators): def distinct(self): """Produce a DISTINCT clause, i.e. ``DISTINCT ``""" - - return _UnaryExpression(self, operator=operators.distinct_op) + return _UnaryExpression(self, operator=operators.distinct_op, type_=self.type) def between(self, cleft, cright): """Produce a BETWEEN clause, i.e. `` BETWEEN AND ``""" diff --git a/test/sql/test_query.py b/test/sql/test_query.py index c9305b615f..51b933e458 100644 --- a/test/sql/test_query.py +++ b/test/sql/test_query.py @@ -469,6 +469,13 @@ class QueryTest(TestBase): self.assert_(r['query_users.user_id']) == 1 self.assert_(r['query_users.user_name']) == "john" + # unary experssions + r = select([users.c.user_name.distinct()]).order_by(users.c.user_name).execute().fetchone() + eq_(r[users.c.user_name], 'jack') + eq_(r.user_name, 'jack') + r.close() + + def test_row_as_args(self): users.insert().execute(user_id=1, user_name='john') r = users.select(users.c.user_id==1).execute().fetchone() diff --git a/test/sql/test_types.py b/test/sql/test_types.py index 13b6d0954e..15799358a7 100644 --- a/test/sql/test_types.py +++ b/test/sql/test_types.py @@ -529,6 +529,16 @@ class ExpressionTest(TestBase, AssertsExecutionResults): # this one relies upon anonymous labeling to assemble result # processing rules on the column. assert testing.db.execute(select([expr])).scalar() == -15 + + def test_distinct(self): + s = select([distinct(test_table.c.avalue)]) + eq_(testing.db.execute(s).scalar(), 25) + + s = select([test_table.c.avalue.distinct()]) + eq_(testing.db.execute(s).scalar(), 25) + + assert distinct(test_table.c.data).type == test_table.c.data.type + assert test_table.c.data.distinct().type == test_table.c.data.type class DateTest(TestBase, AssertsExecutionResults): @classmethod -- 2.47.2