Repository: tobymao/sqlglot

Issue:
Order of `IGNORE NULLS` in BigQuery generated SQL is incorrect
`IGNORE NULLS` needs to occur before `LIMIT`, otherwise it's an error.

**Fully reproducible code snippet**

```
In [7]: import sqlglot as sg

In [8]: sg.__version__
Out[8]: '21.0.1'

In [9]: sg.parse_one('select array_agg(x ignore nulls limit 1)', read='bigquery').sql('bigquery')
Out[9]: 'SELECT array_agg(x LIMIT 1 IGNORE NULLS)'
```

**Official Documentation**

https://cloud.google.com/bigquery/docs/reference/standard-sql/aggregate-function-calls


Discussion:
This one's tricky, I'm looking into it but haven't figured out the workaround yet.. The parser was recently updated and now the ignore/respect nulls expression is bubbled right above the AggFunc which makes it get generated at the end.

Resolving patch:
diff --git a/sqlglot/generator.py b/sqlglot/generator.py
--- a/sqlglot/generator.py
+++ b/sqlglot/generator.py
@@ -2850,12 +2850,20 @@ def respectnulls_sql(self, expression: exp.RespectNulls) -> str:
         return self._embed_ignore_nulls(expression, "RESPECT NULLS")
 
     def _embed_ignore_nulls(self, expression: exp.IgnoreNulls | exp.RespectNulls, text: str) -> str:
-        if self.IGNORE_NULLS_IN_FUNC:
-            this = expression.find(exp.AggFunc)
-            if this:
-                sql = self.sql(this)
-                sql = sql[:-1] + f" {text})"
-                return sql
+        if self.IGNORE_NULLS_IN_FUNC and not expression.meta.get("inline"):
+            for klass in (exp.Order, exp.Limit):
+                mod = expression.find(klass)
+
+                if mod:
+                    this = expression.__class__(this=mod.this.copy())
+                    this.meta["inline"] = True
+                    mod.this.replace(this)
+                    return self.sql(expression.this)
+
+            agg_func = expression.find(exp.AggFunc)
+
+            if agg_func:
+                return self.sql(agg_func)[:-1] + f" {text})"
 
         return f"{self.sql(expression, 'this')} {text}"
 


Test patch:
diff --git a/tests/dialects/test_bigquery.py b/tests/dialects/test_bigquery.py
--- a/tests/dialects/test_bigquery.py
+++ b/tests/dialects/test_bigquery.py
@@ -18,6 +18,11 @@ class TestBigQuery(Validator):
     maxDiff = None
 
     def test_bigquery(self):
+        self.validate_identity("ARRAY_AGG(x IGNORE NULLS LIMIT 1)")
+        self.validate_identity("ARRAY_AGG(x IGNORE NULLS ORDER BY x LIMIT 1)")
+        self.validate_identity("ARRAY_AGG(DISTINCT x IGNORE NULLS ORDER BY x LIMIT 1)")
+        self.validate_identity("ARRAY_AGG(x IGNORE NULLS)")
+
         self.validate_all(
             "SELECT SUM(x IGNORE NULLS) AS x",
             read={
@@ -55,6 +60,7 @@ def test_bigquery(self):
         self.validate_all(
             "SELECT PERCENTILE_CONT(x, 0.5 RESPECT NULLS) OVER ()",
             write={
+                "bigquery": "SELECT PERCENTILE_CONT(x, 0.5 RESPECT NULLS) OVER ()",
                 "duckdb": "SELECT QUANTILE_CONT(x, 0.5 RESPECT NULLS) OVER ()",
                 "spark": "SELECT PERCENTILE_CONT(x, 0.5) RESPECT NULLS OVER ()",
             },
@@ -62,14 +68,16 @@ def test_bigquery(self):
         self.validate_all(
             "SELECT ARRAY_AGG(DISTINCT x IGNORE NULLS ORDER BY a, b DESC LIMIT 10) AS x",
             write={
-                "duckdb": "SELECT ARRAY_AGG(DISTINCT x ORDER BY a NULLS FIRST, b DESC LIMIT 10 IGNORE NULLS) AS x",
+                "bigquery": "SELECT ARRAY_AGG(DISTINCT x IGNORE NULLS ORDER BY a, b DESC LIMIT 10) AS x",
+                "duckdb": "SELECT ARRAY_AGG(DISTINCT x IGNORE NULLS ORDER BY a NULLS FIRST, b DESC LIMIT 10) AS x",
                 "spark": "SELECT COLLECT_LIST(DISTINCT x ORDER BY a, b DESC LIMIT 10) IGNORE NULLS AS x",
             },
         )
         self.validate_all(
             "SELECT ARRAY_AGG(DISTINCT x IGNORE NULLS ORDER BY a, b DESC LIMIT 1, 10) AS x",
             write={
-                "duckdb": "SELECT ARRAY_AGG(DISTINCT x ORDER BY a NULLS FIRST, b DESC LIMIT 1, 10 IGNORE NULLS) AS x",
+                "bigquery": "SELECT ARRAY_AGG(DISTINCT x IGNORE NULLS ORDER BY a, b DESC LIMIT 1, 10) AS x",
+                "duckdb": "SELECT ARRAY_AGG(DISTINCT x IGNORE NULLS ORDER BY a NULLS FIRST, b DESC LIMIT 1, 10) AS x",
                 "spark": "SELECT COLLECT_LIST(DISTINCT x ORDER BY a, b DESC LIMIT 1, 10) IGNORE NULLS AS x",
             },
         )