]> 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:44:27 +0000 (22:44 -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

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 735a125d73fb744794603b1503db455ad30ff60c..6d1174d202d2619e0e7bb83a5400111dd7fc99c1 100644 (file)
@@ -3808,6 +3808,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 b8bbb45252184e1380309ba2c81933aeb7096b61..4a1a0dcd4c3868560e1f17e6aff49dd21d299386 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)
 
@@ -1448,6 +1452,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 e0efb100862076a892213505ee172763d8a1d20d..d0e68f1e33255b85d34cd6eaa55ec6d293a8e91e 100644 (file)
@@ -557,6 +557,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(