Repository: tobymao/sqlglot

Issue:
Support for parsing ClickHouse `Nested` type
**Is your feature request related to a problem? Please describe.**

Not related to a problem.

**Describe the solution you'd like**

I'd like `Nested` to be parsed into an array of struct. This seems like the right approach looking at [the documentation](https://clickhouse.com/docs/en/sql-reference/data-types/nested-data-structures/nested).

**Describe alternatives you've considered**

I haven't considered any alternatives

**Additional context**

N/A

Discussion:

Patch:
diff --git a/sqlglot/dialects/clickhouse.py b/sqlglot/dialects/clickhouse.py
index 53bcf5e7..cfde5fdb 100644
--- a/sqlglot/dialects/clickhouse.py
+++ b/sqlglot/dialects/clickhouse.py
@@ -52,6 +52,7 @@ class ClickHouse(Dialect):
             "INT8": TokenType.TINYINT,
             "LOWCARDINALITY": TokenType.LOWCARDINALITY,
             "MAP": TokenType.MAP,
+            "NESTED": TokenType.NESTED,
             "TUPLE": TokenType.STRUCT,
             "UINT128": TokenType.UINT128,
             "UINT16": TokenType.USMALLINT,
@@ -308,6 +309,7 @@ class ClickHouse(Dialect):
             exp.DataType.Type.INT256: "Int256",
             exp.DataType.Type.LOWCARDINALITY: "LowCardinality",
             exp.DataType.Type.MAP: "Map",
+            exp.DataType.Type.NESTED: "Nested",
             exp.DataType.Type.NULLABLE: "Nullable",
             exp.DataType.Type.SMALLINT: "Int16",
             exp.DataType.Type.STRUCT: "Tuple",
diff --git a/sqlglot/expressions.py b/sqlglot/expressions.py
index fedf7e36..6570dcc5 100644
--- a/sqlglot/expressions.py
+++ b/sqlglot/expressions.py
@@ -3435,6 +3435,7 @@ class DataType(Expression):
         MEDIUMTEXT = auto()
         MONEY = auto()
         NCHAR = auto()
+        NESTED = auto()
         NULL = auto()
         NULLABLE = auto()
         NUMMULTIRANGE = auto()
diff --git a/sqlglot/parser.py b/sqlglot/parser.py
index 034d8386..9efb21ed 100644
--- a/sqlglot/parser.py
+++ b/sqlglot/parser.py
@@ -102,12 +102,17 @@ class Parser(metaclass=_Parser):
         TokenType.CURRENT_USER: exp.CurrentUser,
     }
 
+    STRUCT_TYPE_TOKENS = {
+        TokenType.NESTED,
+        TokenType.STRUCT,
+    }
+
     NESTED_TYPE_TOKENS = {
         TokenType.ARRAY,
         TokenType.LOWCARDINALITY,
         TokenType.MAP,
         TokenType.NULLABLE,
-        TokenType.STRUCT,
+        *STRUCT_TYPE_TOKENS,
     }
 
     ENUM_TYPE_TOKENS = {
@@ -3117,7 +3122,7 @@ class Parser(metaclass=_Parser):
             return self.expression(exp.PseudoType, this=self._prev.text)
 
         nested = type_token in self.NESTED_TYPE_TOKENS
-        is_struct = type_token == TokenType.STRUCT
+        is_struct = type_token in self.STRUCT_TYPE_TOKENS
         expressions = None
         maybe_func = False
 
diff --git a/sqlglot/tokens.py b/sqlglot/tokens.py
index 0b427062..ce39dc41 100644
--- a/sqlglot/tokens.py
+++ b/sqlglot/tokens.py
@@ -155,6 +155,7 @@ class TokenType(AutoName):
     ENUM16 = auto()
     FIXEDSTRING = auto()
     LOWCARDINALITY = auto()
+    NESTED = auto()
 
     # keywords
     ALIAS = auto()


Test patch:
diff --git a/tests/dialects/test_clickhouse.py b/tests/dialects/test_clickhouse.py
index 4b1406df..583be3ef 100644
--- a/tests/dialects/test_clickhouse.py
+++ b/tests/dialects/test_clickhouse.py
@@ -10,6 +10,7 @@ class TestClickhouse(Validator):
         self.assertEqual(expr.sql(dialect="clickhouse"), "COUNT(x)")
         self.assertIsNone(expr._meta)
 
+        self.validate_identity("CAST(x AS Nested(ID UInt32, Serial UInt32, EventTime DATETIME))")
         self.validate_identity("CAST(x AS Enum('hello' = 1, 'world' = 2))")
         self.validate_identity("CAST(x AS Enum('hello', 'world'))")
         self.validate_identity("CAST(x AS Enum('hello' = 1, 'world'))")