Repository: tobymao/sqlglot

Issue:
Transforming a presto literal timestamp query to duckdb 
**Before you file an issue**
- Make sure you specify the "read" dialect eg. parse_one(sql, read="spark")
This issue report contains 2 problems with target dialect of duckdb
The read dialect is "presto"
The target dialect is "duckdb"
The query was generated by Looker 


- Check if the issue still exists on main 
Confirmed

**Fully reproducible code snippet**
```
import sqlglot

sql = "select ((DATE_ADD('week', -5, DATE_TRUNC('DAY', DATE_ADD('day', (0 - MOD((DAY_OF_WEEK(CAST(CAST(DATE_TRUNC('DAY', NOW()) AS DATE) AS TIMESTAMP)) % 7) - 1 + 7, 7)), CAST(CAST(DATE_TRUNC('DAY', NOW()) AS DATE) AS TIMESTAMP)))))) as t1"
glot_tree = sqlglot.parse_one(sql, "presto");
print(glot_tree.sql("duckdb"))

# Produces the below output which is non functional on DuckDB
# SELECT ((DATE_TRUNC('DAY', CAST(CAST(DATE_TRUNC('DAY', CURRENT_TIMESTAMP) AS DATE) AS TIMESTAMP) + INTERVAL (0 - MOD((DAYOFWEEK(CAST(CAST(DATE_TRUNC('DAY', CURRENT_TIMESTAMP) AS DATE) AS TIMESTAMP)) % 7) - 1 + 7, 7)) day) + INTERVAL -5 week)) AS t1

# The below is the correct output, DUCKDB does not like negative intervals nor does it support week intervals
# Bad Query
# SELECT interval -1 day
# Good Alternatives
# SELECT interval (-1) day
# SELECT to_days(-1)

# DuckDB does not support week intervals
# Bad Query
# SELECT interval -1 week
# Good Query
# SELECT interval (-1 * 7 )  day
# SELECT to_days(-1 * 7)


```

**Official Documentation**
Please include links to official SQL documentation related to your issue.

https://duckdb.org/docs/sql/functions/interval.html

Finally i realized that there is an easier fix by wrapping the interval part in simple quote but it the macro call approach might be more flexible in terms of compos-ability of one what might do with SQL 
select '-1 week'
select '5 day'



Discussion:

Resolving patch:
diff --git a/sqlglot/dialects/duckdb.py b/sqlglot/dialects/duckdb.py
--- a/sqlglot/dialects/duckdb.py
+++ b/sqlglot/dialects/duckdb.py
@@ -237,11 +237,27 @@ class Generator(generator.Generator):
 
         STAR_MAPPING = {**generator.Generator.STAR_MAPPING, "except": "EXCLUDE"}
 
+        UNWRAPPED_INTERVAL_VALUES = (exp.Column, exp.Literal, exp.Paren)
+
         PROPERTIES_LOCATION = {
             **generator.Generator.PROPERTIES_LOCATION,
             exp.VolatileProperty: exp.Properties.Location.UNSUPPORTED,
         }
 
+        def interval_sql(self, expression: exp.Interval) -> str:
+            multiplier: t.Optional[int] = None
+            unit = expression.text("unit").lower()
+
+            if unit.startswith("week"):
+                multiplier = 7
+            if unit.startswith("quarter"):
+                multiplier = 90
+
+            if multiplier:
+                return f"({multiplier} * {super().interval_sql(exp.Interval(this=expression.this, unit=exp.var('day')))})"
+
+            return super().interval_sql(expression)
+
         def tablesample_sql(
             self, expression: exp.TableSample, seed_prefix: str = "SEED", sep: str = " AS "
         ) -> str:
diff --git a/sqlglot/generator.py b/sqlglot/generator.py
--- a/sqlglot/generator.py
+++ b/sqlglot/generator.py
@@ -234,9 +234,21 @@ class Generator:
     # Keywords that can't be used as unquoted identifier names
     RESERVED_KEYWORDS: t.Set[str] = set()
 
-    WITH_SEPARATED_COMMENTS = (exp.Select, exp.From, exp.Where, exp.With)
+    # Expressions whose comments are separated from them for better formatting
+    WITH_SEPARATED_COMMENTS: t.Tuple[t.Type[exp.Expression], ...] = (
+        exp.Select,
+        exp.From,
+        exp.Where,
+        exp.With,
+    )
 
-    UNWRAPPED_INTERVAL_VALUES = (exp.Column, exp.Literal, exp.Neg, exp.Paren)
+    # Expressions that can remain unwrapped when appearing in the context of an INTERVAL
+    UNWRAPPED_INTERVAL_VALUES: t.Tuple[t.Type[exp.Expression], ...] = (
+        exp.Column,
+        exp.Literal,
+        exp.Neg,
+        exp.Paren,
+    )
 
     SENTINEL_LINE_BREAK = "__SQLGLOT__LB__"
 


Test patch:
diff --git a/tests/dialects/test_duckdb.py b/tests/dialects/test_duckdb.py
--- a/tests/dialects/test_duckdb.py
+++ b/tests/dialects/test_duckdb.py
@@ -9,6 +9,20 @@ def test_time(self):
         self.validate_identity("SELECT CURRENT_DATE")
         self.validate_identity("SELECT CURRENT_TIMESTAMP")
 
+        self.validate_all(
+            "SELECT CAST('2020-01-01' AS DATE) + INTERVAL (-1) DAY",
+            read={"mysql": "SELECT DATE '2020-01-01' + INTERVAL -1 DAY"},
+        )
+        self.validate_all(
+            "SELECT INTERVAL '1 quarter'",
+            write={"duckdb": "SELECT (90 * INTERVAL '1' day)"},
+        )
+        self.validate_all(
+            "SELECT ((DATE_TRUNC('DAY', CAST(CAST(DATE_TRUNC('DAY', CURRENT_TIMESTAMP) AS DATE) AS TIMESTAMP) + INTERVAL (0 - MOD((DAYOFWEEK(CAST(CAST(DATE_TRUNC('DAY', CURRENT_TIMESTAMP) AS DATE) AS TIMESTAMP)) % 7) - 1 + 7, 7)) day) + (7 * INTERVAL (-5) day))) AS t1",
+            read={
+                "presto": "SELECT ((DATE_ADD('week', -5, DATE_TRUNC('DAY', DATE_ADD('day', (0 - MOD((DAY_OF_WEEK(CAST(CAST(DATE_TRUNC('DAY', NOW()) AS DATE) AS TIMESTAMP)) % 7) - 1 + 7, 7)), CAST(CAST(DATE_TRUNC('DAY', NOW()) AS DATE) AS TIMESTAMP)))))) AS t1",
+            },
+        )
         self.validate_all(
             "EPOCH(x)",
             read={