@@ -65,8 +65,16 @@ func explainLiteral(sb *strings.Builder, n *ast.Literal, indent string, depth in
6565 for _ , e := range exprs {
6666 // Simple literals (numbers, strings, etc.) are OK
6767 if lit , isLit := e .(* ast.Literal ); isLit {
68- // Nested tuples/arrays are complex
69- if lit .Type == ast .LiteralTuple || lit .Type == ast .LiteralArray {
68+ // Nested tuples that contain only primitive literals are OK
69+ if lit .Type == ast .LiteralTuple {
70+ if ! containsOnlyPrimitiveLiteralsWithUnary (lit ) {
71+ hasComplexExpr = true
72+ break
73+ }
74+ continue
75+ }
76+ // Arrays are always complex in tuple context
77+ if lit .Type == ast .LiteralArray {
7078 hasComplexExpr = true
7179 break
7280 }
@@ -114,36 +122,28 @@ func explainLiteral(sb *strings.Builder, n *ast.Literal, indent string, depth in
114122 // This happens when:
115123 // 1. Contains non-literal, non-negation expressions OR
116124 // 2. Contains tuples OR
117- // 3. Contains nested arrays that all have exactly 1 element (homogeneous single-element arrays) OR
118- // 4. Contains nested arrays with non-literal expressions OR
119- // 5. Contains nested arrays that are empty or contain tuples/non-literals
125+ // 3. Contains nested arrays with non-literal expressions OR
126+ // 4. Contains nested arrays that are empty or contain tuples/non-literals
120127 shouldUseFunctionArray := false
121- allAreSingleElementArrays := true
122128 hasNestedArrays := false
123129 nestedArraysNeedFunctionFormat := false
124130
125131 for _ , e := range exprs {
126132 if lit , ok := e .(* ast.Literal ); ok {
127133 if lit .Type == ast .LiteralArray {
128134 hasNestedArrays = true
129- // Check if this inner array has exactly 1 element
135+ // Check if inner array needs Function array format:
136+ // - Contains non-literal expressions OR
137+ // - Contains tuples OR
138+ // - Is empty OR
139+ // - Contains empty arrays
130140 if innerExprs , ok := lit .Value .([]ast.Expression ); ok {
131- if len (innerExprs ) != 1 {
132- allAreSingleElementArrays = false
133- }
134- // Check if inner array needs Function array format:
135- // - Contains non-literal expressions OR
136- // - Contains tuples OR
137- // - Is empty OR
138- // - Contains empty arrays
139141 if containsNonLiteralExpressions (innerExprs ) ||
140142 len (innerExprs ) == 0 ||
141143 containsTuples (innerExprs ) ||
142144 containsEmptyArrays (innerExprs ) {
143145 nestedArraysNeedFunctionFormat = true
144146 }
145- } else {
146- allAreSingleElementArrays = false
147147 }
148148 } else if lit .Type == ast .LiteralTuple {
149149 // Tuples are complex
@@ -155,9 +155,17 @@ func explainLiteral(sb *strings.Builder, n *ast.Literal, indent string, depth in
155155 }
156156
157157 // Use Function array when:
158- // - nested arrays that are ALL single-element
159- // - nested arrays that need Function format (contain non-literals, tuples, or empty arrays)
160- if hasNestedArrays && (allAreSingleElementArrays || nestedArraysNeedFunctionFormat ) {
158+ // - nested arrays that need Function format (contain non-literals, tuples, or empty arrays at any depth)
159+ // Note: nested arrays that are ALL single-element should still be Literal format
160+ if hasNestedArrays && nestedArraysNeedFunctionFormat {
161+ shouldUseFunctionArray = true
162+ }
163+ // Also check for empty arrays at any depth within nested arrays
164+ if hasNestedArrays && containsEmptyArraysRecursive (exprs ) {
165+ shouldUseFunctionArray = true
166+ }
167+ // Also check for tuples at any depth within nested arrays
168+ if hasNestedArrays && containsTuplesRecursive (exprs ) {
161169 shouldUseFunctionArray = true
162170 }
163171
@@ -249,6 +257,43 @@ func containsEmptyArrays(exprs []ast.Expression) bool {
249257 return false
250258}
251259
260+ // containsEmptyArraysRecursive checks if any nested array at any depth is empty
261+ func containsEmptyArraysRecursive (exprs []ast.Expression ) bool {
262+ for _ , e := range exprs {
263+ if lit , ok := e .(* ast.Literal ); ok && lit .Type == ast .LiteralArray {
264+ if innerExprs , ok := lit .Value .([]ast.Expression ); ok {
265+ if len (innerExprs ) == 0 {
266+ return true
267+ }
268+ // Recursively check nested arrays
269+ if containsEmptyArraysRecursive (innerExprs ) {
270+ return true
271+ }
272+ }
273+ }
274+ }
275+ return false
276+ }
277+
278+ // containsTuplesRecursive checks if any nested array contains tuples at any depth
279+ func containsTuplesRecursive (exprs []ast.Expression ) bool {
280+ for _ , e := range exprs {
281+ if lit , ok := e .(* ast.Literal ); ok {
282+ if lit .Type == ast .LiteralTuple {
283+ return true
284+ }
285+ if lit .Type == ast .LiteralArray {
286+ if innerExprs , ok := lit .Value .([]ast.Expression ); ok {
287+ if containsTuplesRecursive (innerExprs ) {
288+ return true
289+ }
290+ }
291+ }
292+ }
293+ }
294+ return false
295+ }
296+
252297func explainBinaryExpr (sb * strings.Builder , n * ast.BinaryExpr , indent string , depth int ) {
253298 // Convert operator to function name
254299 fnName := OperatorToFunction (n .Op )
@@ -377,14 +422,18 @@ func explainAliasedExpr(sb *strings.Builder, n *ast.AliasedExpr, depth int) {
377422 // Check if this is a tuple with complex expressions that should be rendered as Function tuple
378423 if e .Type == ast .LiteralTuple {
379424 if exprs , ok := e .Value .([]ast.Expression ); ok {
380- hasComplexExpr := false
425+ needsFunctionFormat := false
426+ // Empty tuples always use Function tuple format
427+ if len (exprs ) == 0 {
428+ needsFunctionFormat = true
429+ }
381430 for _ , expr := range exprs {
382431 if _ , isLit := expr .(* ast.Literal ); ! isLit {
383- hasComplexExpr = true
432+ needsFunctionFormat = true
384433 break
385434 }
386435 }
387- if hasComplexExpr {
436+ if needsFunctionFormat {
388437 // Render as Function tuple with alias
389438 fmt .Fprintf (sb , "%sFunction tuple (alias %s) (children %d)\n " , indent , escapeAlias (n .Alias ), 1 )
390439 fmt .Fprintf (sb , "%s ExpressionList (children %d)\n " , indent , len (exprs ))
@@ -489,6 +538,12 @@ func explainAliasedExpr(sb *strings.Builder, n *ast.AliasedExpr, depth int) {
489538 case * ast.FunctionCall :
490539 // Function calls already handle aliases
491540 explainFunctionCallWithAlias (sb , e , n .Alias , indent , depth )
541+ case * ast.Lambda :
542+ // Lambda expressions with alias
543+ explainLambdaWithAlias (sb , e , n .Alias , indent , depth )
544+ case * ast.ExtractExpr :
545+ // EXTRACT expressions with alias
546+ explainExtractExprWithAlias (sb , e , n .Alias , indent , depth )
492547 case * ast.Identifier :
493548 // Identifiers with alias
494549 fmt .Fprintf (sb , "%sIdentifier %s (alias %s)\n " , indent , e .Name (), escapeAlias (n .Alias ))
@@ -632,6 +687,18 @@ func explainWithElement(sb *strings.Builder, n *ast.WithElement, indent string,
632687 // When name is empty, don't show the alias part
633688 switch e := n .Query .(type ) {
634689 case * ast.Literal :
690+ // Empty tuples should be rendered as Function tuple, not Literal
691+ if e .Type == ast .LiteralTuple {
692+ if exprs , ok := e .Value .([]ast.Expression ); ok && len (exprs ) == 0 {
693+ if n .Name != "" {
694+ fmt .Fprintf (sb , "%sFunction tuple (alias %s) (children %d)\n " , indent , n .Name , 1 )
695+ } else {
696+ fmt .Fprintf (sb , "%sFunction tuple (children %d)\n " , indent , 1 )
697+ }
698+ fmt .Fprintf (sb , "%s ExpressionList\n " , indent )
699+ return
700+ }
701+ }
635702 if n .Name != "" {
636703 fmt .Fprintf (sb , "%sLiteral %s (alias %s)\n " , indent , FormatLiteral (e ), n .Name )
637704 } else {
@@ -645,6 +712,8 @@ func explainWithElement(sb *strings.Builder, n *ast.WithElement, indent string,
645712 }
646713 case * ast.FunctionCall :
647714 explainFunctionCallWithAlias (sb , e , n .Name , indent , depth )
715+ case * ast.Lambda :
716+ explainLambdaWithAlias (sb , e , n .Name , indent , depth )
648717 case * ast.BinaryExpr :
649718 // Binary expressions become functions
650719 fnName := OperatorToFunction (e .Op )
0 commit comments