Skip to content

Commit f5f6652

Browse files
authored
Add ObjectTypeArgument AST type for JSON/OBJECT type parameters (#99)
1 parent 34ca664 commit f5f6652

65 files changed

Lines changed: 91 additions & 398 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

ast/ast.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,17 @@ func (d *DataType) Pos() token.Position { return d.Position }
390390
func (d *DataType) End() token.Position { return d.Position }
391391
func (d *DataType) expressionNode() {}
392392

393+
// ObjectTypeArgument wraps an expression that is an argument to JSON/OBJECT types.
394+
// This matches ClickHouse's ASTObjectTypeArgument node structure.
395+
type ObjectTypeArgument struct {
396+
Position token.Position `json:"-"`
397+
Expr Expression `json:"expr"`
398+
}
399+
400+
func (o *ObjectTypeArgument) Pos() token.Position { return o.Position }
401+
func (o *ObjectTypeArgument) End() token.Position { return o.Position }
402+
func (o *ObjectTypeArgument) expressionNode() {}
403+
393404
// NameTypePair represents a named type pair, used in Nested types.
394405
type NameTypePair struct {
395406
Position token.Position `json:"-"`

internal/explain/explain.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,8 @@ func Node(sb *strings.Builder, node interface{}, depth int) {
155155
// Types
156156
case *ast.DataType:
157157
explainDataType(sb, n, indent, depth)
158+
case *ast.ObjectTypeArgument:
159+
explainObjectTypeArgument(sb, n, indent, depth)
158160
case *ast.NameTypePair:
159161
explainNameTypePair(sb, n, indent, depth)
160162
case *ast.Parameter:

internal/explain/format.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,10 @@ func FormatDataType(dt *ast.DataType) string {
218218
}
219219
var params []string
220220
for _, p := range dt.Parameters {
221+
// Unwrap ObjectTypeArgument if present (used for JSON/OBJECT types)
222+
if ota, ok := p.(*ast.ObjectTypeArgument); ok {
223+
p = ota.Expr
224+
}
221225
if lit, ok := p.(*ast.Literal); ok {
222226
if lit.Type == ast.LiteralString {
223227
// String parameters in type need extra escaping: 'val' -> \\\'val\\\'

internal/explain/statements.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -671,6 +671,11 @@ func explainDataType(sb *strings.Builder, n *ast.DataType, indent string, depth
671671
}
672672
}
673673

674+
func explainObjectTypeArgument(sb *strings.Builder, n *ast.ObjectTypeArgument, indent string, depth int) {
675+
fmt.Fprintf(sb, "%sASTObjectTypeArgument (children %d)\n", indent, 1)
676+
Node(sb, n.Expr, depth+1)
677+
}
678+
674679
func explainNameTypePair(sb *strings.Builder, n *ast.NameTypePair, indent string, depth int) {
675680
fmt.Fprintf(sb, "%sNameTypePair %s (children %d)\n", indent, n.Name, 1)
676681
Node(sb, n.Type, depth+1)

parser/parser.go

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2413,7 +2413,9 @@ func (p *Parser) parseDataType() *ast.DataType {
24132413

24142414
// Determine if this type uses named parameters (Nested, Tuple, JSON)
24152415
upperName := strings.ToUpper(dt.Name)
2416-
usesNamedParams := upperName == "NESTED" || upperName == "TUPLE" || upperName == "JSON"
2416+
usesNamedParams := upperName == "NESTED" || upperName == "TUPLE" || upperName == "JSON" || upperName == "OBJECT"
2417+
// JSON and OBJECT types wrap their parameters in ObjectTypeArgument
2418+
isObjectType := upperName == "JSON" || upperName == "OBJECT"
24172419

24182420
// Parse type parameters, but stop on keywords that can't be part of type params
24192421
for !p.currentIs(token.RPAREN) && !p.currentIs(token.EOF) && !p.currentIs(token.COLLATE) {
@@ -2422,10 +2424,11 @@ func (p *Parser) parseDataType() *ast.DataType {
24222424
isNamedParam := false
24232425
if usesNamedParams && (p.currentIs(token.IDENT) || p.current.Token.IsKeyword()) {
24242426
// Check if current is NOT a type name and peek IS a type name or LPAREN follows for complex types
2425-
if !p.isDataTypeName(p.current.Value) {
2427+
// But NOT if peek is '=' which indicates an expression like max_dynamic_paths=8
2428+
if !p.isDataTypeName(p.current.Value) && !p.peekIs(token.EQ) {
24262429
// Current is a name (not a type), next should be a type
24272430
isNamedParam = true
2428-
} else if p.peekIs(token.IDENT) || p.peekIs(token.LPAREN) {
2431+
} else if !p.peekIs(token.EQ) && (p.peekIs(token.IDENT) || p.peekIs(token.LPAREN)) {
24292432
// Current looks like a type name but is followed by another identifier
24302433
// This happens with things like "a Tuple(...)" where "a" looks like it could be a type
24312434
// Check if peek is a known type name
@@ -2441,6 +2444,7 @@ func (p *Parser) parseDataType() *ast.DataType {
24412444
}
24422445
}
24432446

2447+
var param ast.Expression
24442448
if isNamedParam {
24452449
// Parse as name + type pair
24462450
pos := p.current.Pos
@@ -2449,19 +2453,29 @@ func (p *Parser) parseDataType() *ast.DataType {
24492453
// Parse the type for this parameter
24502454
paramType := p.parseDataType()
24512455
if paramType != nil {
2452-
ntp := &ast.NameTypePair{
2456+
param = &ast.NameTypePair{
24532457
Position: pos,
24542458
Name: paramName,
24552459
Type: paramType,
24562460
}
2457-
dt.Parameters = append(dt.Parameters, ntp)
24582461
}
24592462
} else if (p.currentIs(token.IDENT) || p.current.Token.IsKeyword()) && p.isDataTypeName(p.current.Value) {
24602463
// It's a type name, parse as data type
2461-
dt.Parameters = append(dt.Parameters, p.parseDataType())
2464+
param = p.parseDataType()
24622465
} else {
24632466
// Parse as expression (for things like Decimal(10, 2))
2464-
dt.Parameters = append(dt.Parameters, p.parseExpression(LOWEST))
2467+
param = p.parseExpression(LOWEST)
2468+
}
2469+
2470+
// Wrap in ObjectTypeArgument for JSON/OBJECT types
2471+
if param != nil {
2472+
if isObjectType {
2473+
param = &ast.ObjectTypeArgument{
2474+
Position: param.Pos(),
2475+
Expr: param,
2476+
}
2477+
}
2478+
dt.Parameters = append(dt.Parameters, param)
24652479
}
24662480

24672481
if p.currentIs(token.COMMA) {

parser/testdata/03100_lwu_36_json_skip_indexes/metadata.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
"stmt12": true,
55
"stmt14": true,
66
"stmt16": true,
7-
"stmt3": true,
87
"stmt8": true
98
}
109
}

parser/testdata/03205_json_cast_from_string/metadata.json

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,6 @@
33
"stmt10": true,
44
"stmt11": true,
55
"stmt12": true,
6-
"stmt14": true,
7-
"stmt15": true,
8-
"stmt16": true,
9-
"stmt17": true,
10-
"stmt18": true,
11-
"stmt19": true,
126
"stmt5": true,
137
"stmt6": true,
148
"stmt7": true,
Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
{
22
"explain_todo": {
3-
"stmt11": true,
4-
"stmt13": true,
53
"stmt15": true,
64
"stmt17": true,
75
"stmt19": true,
@@ -13,9 +11,6 @@
1311
"stmt31": true,
1412
"stmt33": true,
1513
"stmt35": true,
16-
"stmt37": true,
17-
"stmt5": true,
18-
"stmt7": true,
19-
"stmt9": true
14+
"stmt37": true
2015
}
2116
}
Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1 @@
1-
{
2-
"explain_todo": {
3-
"stmt10": true,
4-
"stmt4": true
5-
}
6-
}
1+
{}

parser/testdata/03222_json_squashing/metadata.json

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,11 @@
11
{
22
"explain_todo": {
3-
"stmt21": true,
4-
"stmt22": true,
5-
"stmt30": true,
6-
"stmt38": true,
7-
"stmt46": true,
8-
"stmt47": true,
93
"stmt49": true,
104
"stmt51": true,
115
"stmt53": true,
12-
"stmt55": true,
136
"stmt57": true,
147
"stmt59": true,
158
"stmt61": true,
16-
"stmt63": true,
179
"stmt65": true,
1810
"stmt67": true,
1911
"stmt69": true

0 commit comments

Comments
 (0)