Skip to content

Commit 5b6ea17

Browse files
kyleconroyclaude
andcommitted
Format function calls in AggregateFunction type parameters
When outputting types like AggregateFunction(1, sumMapFiltered([1, 2]), ...), properly format nested function calls and array literals instead of using raw Go struct representation. Added formatFunctionCallForType and formatExprForType to handle nested expressions in type parameters. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 1e10e2e commit 5b6ea17

File tree

3 files changed

+41
-12
lines changed

3 files changed

+41
-12
lines changed

internal/explain/format.go

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ func FormatDataType(dt *ast.DataType) string {
318318
// Binary expression (e.g., 'hello' = 1 for Enum types)
319319
params = append(params, formatBinaryExprForType(binExpr))
320320
} else if fn, ok := p.(*ast.FunctionCall); ok {
321-
// Function call (e.g., SKIP for JSON types)
321+
// Function call (e.g., SKIP for JSON types, or function args in AggregateFunction)
322322
if fn.Name == "SKIP" && len(fn.Arguments) > 0 {
323323
if ident, ok := fn.Arguments[0].(*ast.Identifier); ok {
324324
params = append(params, "SKIP "+ident.Name())
@@ -328,7 +328,8 @@ func FormatDataType(dt *ast.DataType) string {
328328
params = append(params, fmt.Sprintf("SKIP REGEXP \\\\\\'%s\\\\\\'", lit.Value))
329329
}
330330
} else {
331-
params = append(params, fmt.Sprintf("%v", p))
331+
// General function call (e.g., sumMapFiltered([1, 2]) in AggregateFunction)
332+
params = append(params, formatFunctionCallForType(fn))
332333
}
333334
} else if ident, ok := p.(*ast.Identifier); ok {
334335
// Identifier (e.g., function name in AggregateFunction types)
@@ -389,6 +390,42 @@ func formatUnaryExprForType(expr *ast.UnaryExpr) string {
389390
return expr.Op + fmt.Sprintf("%v", expr.Operand)
390391
}
391392

393+
// formatFunctionCallForType formats a function call for use in type parameters
394+
// e.g., sumMapFiltered([1, 2]) -> "sumMapFiltered([1, 2])"
395+
func formatFunctionCallForType(fn *ast.FunctionCall) string {
396+
args := make([]string, 0, len(fn.Arguments))
397+
for _, arg := range fn.Arguments {
398+
args = append(args, formatExprForType(arg))
399+
}
400+
return fn.Name + "(" + strings.Join(args, ", ") + ")"
401+
}
402+
403+
// formatExprForType formats an expression for use in type parameters
404+
func formatExprForType(expr ast.Expression) string {
405+
switch e := expr.(type) {
406+
case *ast.Literal:
407+
if e.Type == ast.LiteralArray {
408+
// Format array literal: [1, 2] -> "[1, 2]"
409+
if elements, ok := e.Value.([]ast.Expression); ok {
410+
parts := make([]string, 0, len(elements))
411+
for _, elem := range elements {
412+
parts = append(parts, formatExprForType(elem))
413+
}
414+
return "[" + strings.Join(parts, ", ") + "]"
415+
}
416+
}
417+
return fmt.Sprintf("%v", e.Value)
418+
case *ast.Identifier:
419+
return e.Name()
420+
case *ast.FunctionCall:
421+
return formatFunctionCallForType(e)
422+
case *ast.DataType:
423+
return FormatDataType(e)
424+
default:
425+
return fmt.Sprintf("%v", expr)
426+
}
427+
}
428+
392429
// NormalizeFunctionName normalizes function names to match ClickHouse's EXPLAIN AST output
393430
func NormalizeFunctionName(name string) string {
394431
// ClickHouse normalizes certain function names in EXPLAIN AST
Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1 @@
1-
{
2-
"explain_todo": {
3-
"stmt2": true
4-
}
5-
}
1+
{}
Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1 @@
1-
{
2-
"explain_todo": {
3-
"stmt3": true
4-
}
5-
}
1+
{}

0 commit comments

Comments
 (0)