summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSamuel Chou <sam.chou@windystudios.com>2018-09-19 13:30:24 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2018-09-20 19:06:01 -0400
commitc9aab727c5bb8fffc9b9830a385524f8db3aac0c (patch)
treef831147c13ec8b56d1418c64e38427617a4a4878
parent911f73e72fb446c4114538051e665df343c8f9f2 (diff)
downloadsqlalchemy-c9aab727c5bb8fffc9b9830a385524f8db3aac0c.tar.gz
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 (cherry picked from commit 33fccc486111fc6b41eab651cc7325c83099ad45)
-rw-r--r--doc/build/changelog/unreleased_12/pr474.rst9
-rw-r--r--lib/sqlalchemy/sql/compiler.py22
-rw-r--r--test/sql/test_compiler.py37
3 files changed, 59 insertions, 9 deletions
diff --git a/doc/build/changelog/unreleased_12/pr474.rst b/doc/build/changelog/unreleased_12/pr474.rst
new file mode 100644
index 000000000..571fe5e97
--- /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 d93e08ece..e27a736ef 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 \
@@ -1911,10 +1907,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)
@@ -1970,7 +1963,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 7f2c44bf1..993008c07 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(),