From 05f28ba2fb6b9fe1e36748bb16969afc8375a9fb Mon Sep 17 00:00:00 2001 From: Iuri Diniz Date: Fri, 29 Jul 2016 12:54:22 -0400 Subject: [PATCH] Allow None to cancel Query.group_by() This replicates the same behavior as order_by(). order_by() will also be updated to deprecate passing of False as this is no longer functionally different than passing None. Change-Id: I2fc05d0317d28b6c83373769a48f7eea32d56290 Pull-request: https://github.com/zzzeek/sqlalchemy/pull/297 --- doc/build/changelog/changelog_11.rst | 8 +++++ lib/sqlalchemy/orm/query.py | 16 ++++++++- test/orm/test_query.py | 51 ++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 1 deletion(-) diff --git a/doc/build/changelog/changelog_11.rst b/doc/build/changelog/changelog_11.rst index b6129cf776..9a65e66a29 100644 --- a/doc/build/changelog/changelog_11.rst +++ b/doc/build/changelog/changelog_11.rst @@ -21,6 +21,14 @@ .. changelog:: :version: 1.1.0 + .. change:: + :tags: feature, orm + + The :meth:`.Query.group_by` method now resets the group by collection + if an argument of ``None`` is passed, in the same way that + :meth:`.Query.order_by` has worked for a long time. Pull request + courtesy Iuri Diniz. + .. changelog:: :version: 1.1.0b3 :released: July 26, 2016 diff --git a/lib/sqlalchemy/orm/query.py b/lib/sqlalchemy/orm/query.py index c1daaaf075..c5ecbaffe7 100644 --- a/lib/sqlalchemy/orm/query.py +++ b/lib/sqlalchemy/orm/query.py @@ -1549,7 +1549,21 @@ class Query(object): @_generative(_no_statement_condition, _no_limit_offset) def group_by(self, *criterion): """apply one or more GROUP BY criterion to the query and return - the newly resulting :class:`.Query`""" + the newly resulting :class:`.Query` + + All existing GROUP BY settings can be suppressed by + passing ``None`` - this will suppress any GROUP BY configured + on mappers as well. + + .. versionadded:: 1.1 GROUP BY can be cancelled by passing None, + in the same way as ORDER BY. + + """ + + if len(criterion) == 1: + if criterion[0] is None: + self._group_by = False + return criterion = list(chain(*[_orm_columns(c) for c in criterion])) criterion = self._adapt_col_list(criterion) diff --git a/test/orm/test_query.py b/test/orm/test_query.py index 34343d78d0..86be1879ef 100644 --- a/test/orm/test_query.py +++ b/test/orm/test_query.py @@ -1574,6 +1574,57 @@ class ExpressionTest(QueryTest, AssertsCompiledSQL): User(id=7, name='jack'), Address(email_address='jack@bean.com', user_id=7, id=1))]) + def test_group_by_plain(self): + User = self.classes.User + s = create_session() + + q1 = s.query(User.id, User.name).group_by(User.name) + self.assert_compile( + select([q1]), + "SELECT users_id, users_name FROM (SELECT users.id AS users_id, " + "users.name AS users_name FROM users GROUP BY users.name)" + ) + + def test_group_by_append(self): + User = self.classes.User + s = create_session() + + q1 = s.query(User.id, User.name).group_by(User.name) + + # test append something to group_by + self.assert_compile( + select([q1.group_by(User.id)]), + "SELECT users_id, users_name FROM (SELECT users.id AS users_id, " + "users.name AS users_name FROM users GROUP BY users.name, users.id)" + ) + + def test_group_by_cancellation(self): + User = self.classes.User + s = create_session() + + q1 = s.query(User.id, User.name).group_by(User.name) + # test cancellation by using None, replacement with something else + self.assert_compile( + select([q1.group_by(None).group_by(User.id)]), + "SELECT users_id, users_name FROM (SELECT users.id AS users_id, " + "users.name AS users_name FROM users GROUP BY users.id)" + ) + + # test cancellation by using None, replacement with nothing + self.assert_compile( + select([q1.group_by(None)]), + "SELECT users_id, users_name FROM (SELECT users.id AS users_id, " + "users.name AS users_name FROM users)" + ) + + def test_group_by_cancelled_still_present(self): + User = self.classes.User + s = create_session() + + q1 = s.query(User.id, User.name).group_by(User.name).group_by(None) + + q1._no_criterion_assertion("foo") + class ColumnPropertyTest(_fixtures.FixtureTest, AssertsCompiledSQL): __dialect__ = 'default' -- 2.47.2