From: Samuel Chou Date: Wed, 19 Sep 2018 17:30:24 +0000 (-0400) Subject: Allow dialects to customize group by clause compilation X-Git-Tag: rel_1_3_0b1~71^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=33fccc486111fc6b41eab651cc7325c83099ad45;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git Allow dialects to customize group by clause compilation Refactored :class:`.SQLCompiler` to expose a :meth:`.SQLCompiler.group_by_clause` method similar to the :meth:`.SQLCompiler.order_by_clause` and :meth:`.SQLCompiler.limit_clause` methods, which can be overridden by dialects to customize how GROUP BY renders. Pull request courtesy Samuel Chou. Change-Id: I0a7238e55032558c27a0c56a72907c7b883456f1 Pull-request: https://github.com/zzzeek/sqlalchemy/pull/474 --- diff --git a/doc/build/changelog/unreleased_12/pr474.rst b/doc/build/changelog/unreleased_12/pr474.rst new file mode 100644 index 0000000000..571fe5e97c --- /dev/null +++ b/doc/build/changelog/unreleased_12/pr474.rst @@ -0,0 +1,9 @@ +.. change:: + :tags: feature, sql + :versions: 1.3.0b1 + + Refactored :class:`.SQLCompiler` to expose a + :meth:`.SQLCompiler.group_by_clause` method similar to the + :meth:`.SQLCompiler.order_by_clause` and :meth:`.SQLCompiler.limit_clause` + methods, which can be overridden by dialects to customize how GROUP BY + renders. Pull request courtesy Samuel Chou. diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py index e45db428a5..2f68b7e2e4 100644 --- a/lib/sqlalchemy/sql/compiler.py +++ b/lib/sqlalchemy/sql/compiler.py @@ -968,11 +968,7 @@ class SQLCompiler(Compiled): for i, c in enumerate(cs.selects)) ) - group_by = cs._group_by_clause._compiler_dispatch( - self, asfrom=asfrom, **kwargs) - if group_by: - text += " GROUP BY " + group_by - + text += self.group_by_clause(cs, **dict(asfrom=asfrom, **kwargs)) text += self.order_by_clause(cs, **kwargs) text += (cs._limit_clause is not None or cs._offset_clause is not None) and \ @@ -1929,10 +1925,7 @@ class SQLCompiler(Compiled): text += " \nWHERE " + t if select._group_by_clause.clauses: - group_by = select._group_by_clause._compiler_dispatch( - self, **kwargs) - if group_by: - text += " GROUP BY " + group_by + text += self.group_by_clause(select, **kwargs) if select._having is not None: t = select._having._compiler_dispatch(self, **kwargs) @@ -1988,7 +1981,18 @@ class SQLCompiler(Compiled): """ return select._distinct and "DISTINCT " or "" + def group_by_clause(self, select, **kw): + """allow dialects to customize how GROUP BY is rendered.""" + + group_by = select._group_by_clause._compiler_dispatch(self, **kw) + if group_by: + return " GROUP BY " + group_by + else: + return "" + def order_by_clause(self, select, **kw): + """allow dialects to customize how ORDER BY is rendered.""" + order_by = select._order_by_clause._compiler_dispatch(self, **kw) if order_by: return " ORDER BY " + order_by diff --git a/test/sql/test_compiler.py b/test/sql/test_compiler.py index 7f2c44bf11..993008c072 100644 --- a/test/sql/test_compiler.py +++ b/test/sql/test_compiler.py @@ -28,6 +28,7 @@ from sqlalchemy.sql.expression import ClauseList, _literal_as_text, HasPrefixes from sqlalchemy.engine import default from sqlalchemy.dialects import mysql, mssql, postgresql, oracle, \ sqlite, sybase +from sqlalchemy.dialects.postgresql.base import PGCompiler, PGDialect from sqlalchemy.ext.compiler import compiles from sqlalchemy.sql import compiler @@ -1297,6 +1298,42 @@ class SelectTest(fixtures.TestBase, AssertsCompiledSQL): "GROUP BY myothertable.othername ORDER BY myothertable.othername" ) + def test_custom_order_by_clause(self): + class CustomCompiler(PGCompiler): + def order_by_clause(self, select, **kw): + return super(CustomCompiler, self).\ + order_by_clause(select, **kw) + " CUSTOMIZED" + + class CustomDialect(PGDialect): + name = 'custom' + statement_compiler = CustomCompiler + + stmt = select([table1.c.myid]).order_by(table1.c.myid) + self.assert_compile( + stmt, + "SELECT mytable.myid FROM mytable ORDER BY " + "mytable.myid CUSTOMIZED", + dialect=CustomDialect() + ) + + def test_custom_group_by_clause(self): + class CustomCompiler(PGCompiler): + def group_by_clause(self, select, **kw): + return super(CustomCompiler, self).\ + group_by_clause(select, **kw) + " CUSTOMIZED" + + class CustomDialect(PGDialect): + name = 'custom' + statement_compiler = CustomCompiler + + stmt = select([table1.c.myid]).group_by(table1.c.myid) + self.assert_compile( + stmt, + "SELECT mytable.myid FROM mytable GROUP BY " + "mytable.myid CUSTOMIZED", + dialect=CustomDialect() + ) + def test_for_update(self): self.assert_compile( table1.select(table1.c.myid == 7).with_for_update(),