]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
self_group() for FunctionFilter
authorMike Bayer <mike_mp@zzzcomputing.com>
Sat, 13 Jul 2019 02:43:31 +0000 (22:43 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sat, 13 Jul 2019 02:45:41 +0000 (22:45 -0400)
Fixed issue where the :class:`.array_agg` construct in combination with
:meth:`.FunctionElement.filter` would not produce the correct operator
precedence between the FILTER keyword and the array index operator.

Fixes: #4760
Change-Id: Ic662cd3da3330554ec673bafd80495b3f1506098
(cherry picked from commit 116faee662f618d5ecd13b1e074a27d5e5a40564)

doc/build/changelog/unreleased_13/4760.rst [new file with mode: 0644]
lib/sqlalchemy/sql/elements.py
lib/sqlalchemy/sql/operators.py
test/dialect/postgresql/test_compiler.py
test/sql/test_functions.py

diff --git a/doc/build/changelog/unreleased_13/4760.rst b/doc/build/changelog/unreleased_13/4760.rst
new file mode 100644 (file)
index 0000000..762cdc9
--- /dev/null
@@ -0,0 +1,8 @@
+.. change::
+    :tags: bug, sql, postgresql
+    :tickets: 4760
+
+    Fixed issue where the :class:`.array_agg` construct in combination with
+    :meth:`.FunctionElement.filter` would not produce the correct operator
+    precedence in combination with the array index operator.
+
index 0bfba1fb7fa1ef18ffdb27b6181bb437b7cdd6b2..b976428ed70404f9014225d2f7e15996ca4ba679 100644 (file)
@@ -3670,6 +3670,12 @@ class FunctionFilter(ColumnElement):
             rows=rows,
         )
 
+    def self_group(self, against=None):
+        if operators.is_precedent(operators.filter_op, against):
+            return Grouping(self)
+        else:
+            return self
+
     @util.memoized_property
     def type(self):
         return self.func.type
index 4206de4603e413b79ad753721b99a98e338a06b8..ea7b51f799473fcf7739395f2727b58636d3f21f 100644 (file)
@@ -1345,6 +1345,10 @@ def empty_notin_op(a, b):
     raise NotImplementedError()
 
 
+def filter_op(a, b):
+    raise NotImplementedError()
+
+
 def concat_op(a, b):
     return a.concat(b)
 
@@ -1443,6 +1447,7 @@ _PRECEDENCE = {
     add: 7,
     sub: 7,
     concat_op: 6,
+    filter_op: 6,
     match_op: 5,
     notmatch_op: 5,
     ilike_op: 5,
index 13e4aaad5db215d7798d1d421d218fb7a5b64328..b65361bdad735cd10f4bc066bb4940ee2968bf2f 100644 (file)
@@ -1435,6 +1435,21 @@ class CompileTest(fixtures.TestBase, AssertsCompiledSQL):
             "FROM table1 AS foo",
         )
 
+    def test_array_agg_w_filter_subscript(self):
+        series = func.generate_series(1, 100).alias("series")
+        series_col = column("series")
+        query = select(
+            [func.array_agg(series_col).filter(series_col % 2 == 0)[3]]
+        ).select_from(series)
+        self.assert_compile(
+            query,
+            "SELECT (array_agg(series) FILTER "
+            "(WHERE series %% %(series_1)s = %(param_1)s))[%(param_2)s] "
+            "AS anon_1 FROM "
+            "generate_series(%(generate_series_1)s, %(generate_series_2)s) "
+            "AS series",
+        )
+
     def test_delete_extra_froms(self):
         t1 = table("t1", column("c1"))
         t2 = table("t2", column("c1"))
index 7f7ba14e23029018cc0168c4bc5e8a945629c30c..784c82150b28018e78f52913ac4c2e2864bedd12 100644 (file)
@@ -537,6 +537,15 @@ class CompileTest(fixtures.TestBase, AssertsCompiledSQL):
             "mytable.myid > :myid_1)",
         )
 
+    def test_funcfilter_arrayagg_subscript(self):
+        num = column("q")
+        self.assert_compile(
+            func.array_agg(num).filter(num % 2 == 0)[1],
+            "(array_agg(q) FILTER (WHERE q %% %(q_1)s = "
+            "%(param_1)s))[%(param_2)s]",
+            dialect="postgresql",
+        )
+
     def test_funcfilter_label(self):
         self.assert_compile(
             select(