Skip to content

Commit 294aafb

Browse files
authored
Allow using JSON path in select results (#189)
1 parent 171c3e8 commit 294aafb

14 files changed

+673
-249
lines changed

parser/ast.go

Lines changed: 25 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2860,53 +2860,44 @@ func (n *NestedIdentifier) Accept(visitor ASTVisitor) error {
28602860
return visitor.VisitNestedIdentifier(n)
28612861
}
28622862

2863-
type ColumnIdentifier struct {
2864-
Database *Ident
2865-
Table *Ident
2866-
Column *Ident
2863+
type Path struct {
2864+
Fields []*Ident
28672865
}
28682866

2869-
func (c *ColumnIdentifier) Pos() Pos {
2870-
if c.Database != nil {
2871-
return c.Database.NamePos
2872-
} else if c.Table != nil {
2873-
return c.Table.NamePos
2874-
} else {
2875-
return c.Column.NamePos
2867+
func (p *Path) Pos() Pos {
2868+
if len(p.Fields) > 0 {
2869+
return p.Fields[0].Pos()
28762870
}
2871+
return 0
28772872
}
28782873

2879-
func (c *ColumnIdentifier) End() Pos {
2880-
return c.Column.NameEnd
2881-
}
2882-
2883-
func (c *ColumnIdentifier) String() string {
2884-
if c.Database != nil {
2885-
return c.Database.String() + "." + c.Table.String() + "." + c.Column.String()
2886-
} else if c.Table != nil {
2887-
return c.Table.String() + "." + c.Column.String()
2888-
} else {
2889-
return c.Column.String()
2874+
func (p *Path) End() Pos {
2875+
if len(p.Fields) > 0 {
2876+
return p.Fields[len(p.Fields)-1].End()
28902877
}
2878+
return 0
28912879
}
28922880

2893-
func (c *ColumnIdentifier) Accept(visitor ASTVisitor) error {
2894-
visitor.Enter(c)
2895-
defer visitor.Leave(c)
2896-
if c.Database != nil {
2897-
if err := c.Database.Accept(visitor); err != nil {
2898-
return err
2881+
func (p *Path) String() string {
2882+
var builder strings.Builder
2883+
for i, ident := range p.Fields {
2884+
if i > 0 {
2885+
builder.WriteByte('.')
28992886
}
2887+
builder.WriteString(ident.String())
29002888
}
2901-
if c.Table != nil {
2902-
if err := c.Table.Accept(visitor); err != nil {
2889+
return builder.String()
2890+
}
2891+
2892+
func (p *Path) Accept(visitor ASTVisitor) error {
2893+
visitor.Enter(p)
2894+
defer visitor.Leave(p)
2895+
for _, ident := range p.Fields {
2896+
if err := ident.Accept(visitor); err != nil {
29032897
return err
29042898
}
29052899
}
2906-
if err := c.Column.Accept(visitor); err != nil {
2907-
return err
2908-
}
2909-
return visitor.VisitColumnIdentifier(c)
2900+
return visitor.VisitPath(p)
29102901
}
29112902

29122903
type TableIdentifier struct {

parser/ast_visitor.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,8 @@ type ASTVisitor interface {
5656
VisitConstraintExpr(expr *ConstraintClause) error
5757
VisitNullLiteral(expr *NullLiteral) error
5858
VisitNotNullLiteral(expr *NotNullLiteral) error
59+
VisitPath(expr *Path) error
5960
VisitNestedIdentifier(expr *NestedIdentifier) error
60-
VisitColumnIdentifier(expr *ColumnIdentifier) error
6161
VisitTableIdentifier(expr *TableIdentifier) error
6262
VisitTableSchemaExpr(expr *TableSchemaClause) error
6363
VisitTableArgListExpr(expr *TableArgListExpr) error
@@ -594,7 +594,7 @@ func (v *DefaultASTVisitor) VisitNestedIdentifier(expr *NestedIdentifier) error
594594
return nil
595595
}
596596

597-
func (v *DefaultASTVisitor) VisitColumnIdentifier(expr *ColumnIdentifier) error {
597+
func (v *DefaultASTVisitor) VisitPath(expr *Path) error {
598598
if v.Visit != nil {
599599
return v.Visit(expr)
600600
}

parser/parser_table.go

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -292,25 +292,18 @@ func (p *Parser) parseIdentOrFunction(_ Pos) (Expr, error) {
292292
case p.tryConsumeTokenKind(TokenKindDot) != nil:
293293
switch {
294294
case p.matchTokenKind(TokenKindIdent):
295-
nextIdent, err := p.parseIdent()
296-
if err != nil {
297-
return nil, err
298-
}
299-
if p.tryConsumeTokenKind(TokenKindDot) != nil {
300-
thirdIdent, err := p.parseIdent()
295+
fields := []*Ident{ident}
296+
for {
297+
child, err := p.parseIdent()
301298
if err != nil {
302299
return nil, err
303300
}
304-
return &ColumnIdentifier{
305-
Database: ident,
306-
Table: nextIdent,
307-
Column: thirdIdent,
308-
}, nil
301+
fields = append(fields, child)
302+
if p.tryConsumeTokenKind(TokenKindDot) == nil {
303+
break
304+
}
309305
}
310-
return &ColumnIdentifier{
311-
Table: ident,
312-
Column: nextIdent,
313-
}, nil
306+
return &Path{Fields: fields}, nil
314307
case p.matchTokenKind("*"):
315308
nextIdent, err := p.parseColumnStar(p.Pos())
316309
if err != nil {

parser/testdata/ddl/output/bug_001.sql.golden.json

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -529,24 +529,26 @@
529529
"WherePos": 606,
530530
"Expr": {
531531
"LeftExpr": {
532-
"Database": {
533-
"Name": "db",
534-
"QuoteType": 1,
535-
"NamePos": 612,
536-
"NameEnd": 614
537-
},
538-
"Table": {
539-
"Name": "table",
540-
"QuoteType": 1,
541-
"NamePos": 615,
542-
"NameEnd": 620
543-
},
544-
"Column": {
545-
"Name": "event",
546-
"QuoteType": 1,
547-
"NamePos": 621,
548-
"NameEnd": 626
549-
}
532+
"Fields": [
533+
{
534+
"Name": "db",
535+
"QuoteType": 1,
536+
"NamePos": 612,
537+
"NameEnd": 614
538+
},
539+
{
540+
"Name": "table",
541+
"QuoteType": 1,
542+
"NamePos": 615,
543+
"NameEnd": 620
544+
},
545+
{
546+
"Name": "event",
547+
"QuoteType": 1,
548+
"NamePos": 621,
549+
"NameEnd": 626
550+
}
551+
]
550552
},
551553
"Operation": "=",
552554
"RightExpr": {

parser/testdata/ddl/output/create_materialized_view_basic.sql.golden.json

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -496,24 +496,26 @@
496496
"WherePos": 487,
497497
"Expr": {
498498
"LeftExpr": {
499-
"Database": {
500-
"Name": "infra_bm",
501-
"QuoteType": 1,
502-
"NamePos": 497,
503-
"NameEnd": 505
504-
},
505-
"Table": {
506-
"Name": "table_name1",
507-
"QuoteType": 1,
508-
"NamePos": 506,
509-
"NameEnd": 517
510-
},
511-
"Column": {
512-
"Name": "event",
513-
"QuoteType": 1,
514-
"NamePos": 518,
515-
"NameEnd": 523
516-
}
499+
"Fields": [
500+
{
501+
"Name": "infra_bm",
502+
"QuoteType": 1,
503+
"NamePos": 497,
504+
"NameEnd": 505
505+
},
506+
{
507+
"Name": "table_name1",
508+
"QuoteType": 1,
509+
"NamePos": 506,
510+
"NameEnd": 517
511+
},
512+
{
513+
"Name": "event",
514+
"QuoteType": 1,
515+
"NamePos": 518,
516+
"NameEnd": 523
517+
}
518+
]
517519
},
518520
"Operation": "=",
519521
"RightExpr": {

parser/testdata/ddl/output/create_mv_with_not_op.sql.golden.json

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -498,24 +498,26 @@
498498
"LeftExpr": {
499499
"LeftExpr": {
500500
"LeftExpr": {
501-
"Database": {
502-
"Name": "infra_bm",
503-
"QuoteType": 1,
504-
"NamePos": 476,
505-
"NameEnd": 484
506-
},
507-
"Table": {
508-
"Name": "table_name1",
509-
"QuoteType": 1,
510-
"NamePos": 485,
511-
"NameEnd": 496
512-
},
513-
"Column": {
514-
"Name": "event",
515-
"QuoteType": 1,
516-
"NamePos": 497,
517-
"NameEnd": 502
518-
}
501+
"Fields": [
502+
{
503+
"Name": "infra_bm",
504+
"QuoteType": 1,
505+
"NamePos": 476,
506+
"NameEnd": 484
507+
},
508+
{
509+
"Name": "table_name1",
510+
"QuoteType": 1,
511+
"NamePos": 485,
512+
"NameEnd": 496
513+
},
514+
{
515+
"Name": "event",
516+
"QuoteType": 1,
517+
"NamePos": 497,
518+
"NameEnd": 502
519+
}
520+
]
519521
},
520522
"Operation": "=",
521523
"RightExpr": {

parser/testdata/ddl/output/create_table_with_index.sql.golden.json

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -297,19 +297,20 @@
297297
},
298298
"ColumnExpr": {
299299
"Expr": {
300-
"Database": null,
301-
"Table": {
302-
"Name": "common",
303-
"QuoteType": 1,
304-
"NamePos": 251,
305-
"NameEnd": 257
306-
},
307-
"Column": {
308-
"Name": "id",
309-
"QuoteType": 1,
310-
"NamePos": 258,
311-
"NameEnd": 260
312-
}
300+
"Fields": [
301+
{
302+
"Name": "common",
303+
"QuoteType": 1,
304+
"NamePos": 251,
305+
"NameEnd": 257
306+
},
307+
{
308+
"Name": "id",
309+
"QuoteType": 1,
310+
"NamePos": 258,
311+
"NameEnd": 260
312+
}
313+
]
313314
},
314315
"Alias": null
315316
},
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
-- Origin SQL:
2+
SELECT a, a.b, a.b.c.d.e;
3+
SELECT JSON_TYPE('{"a": 1, "b": {"c": 2}}', '$.b');
4+
SELECT CAST(some, 'String') AS value;
5+
SELECT CAST(some.long, 'String') AS value;
6+
SELECT CAST(some.long.json, 'String') AS value;
7+
SELECT CAST(some.long.json.path, 'String') AS value;
8+
9+
10+
11+
-- Format SQL:
12+
SELECT a, a.b, a.b.c.d.e;
13+
SELECT JSON_TYPE('{"a": 1, "b": {"c": 2}}', '$.b');
14+
SELECT CAST(some, 'String') AS value;
15+
SELECT CAST(some.long, 'String') AS value;
16+
SELECT CAST(some.long.json, 'String') AS value;
17+
SELECT CAST(some.long.json.path, 'String') AS value;

0 commit comments

Comments
 (0)