diff --git a/ast/ast.go b/ast/ast.go index cea9c9a1..7a7cb8db 100644 --- a/ast/ast.go +++ b/ast/ast.go @@ -154,6 +154,7 @@ type PipeOperator interface { func (PipeSelect) isPipeOperator() {} func (PipeWhere) isPipeOperator() {} +func (PipeAs) isPipeOperator() {} // SelectItem represents expression in SELECT clause result columns list. type SelectItem interface { @@ -1164,6 +1165,17 @@ type PipeWhere struct { Expr Expr } +// PipeAs is AS pipe operator node. +// +// |> AS {{.Alias | sql}} +type PipeAs struct { + // pos = Pipe + // end = Alias.end + + Pipe token.Pos // position of "|>" + Alias *Ident +} + // ================================================================================ // // JOIN diff --git a/ast/pos.go b/ast/pos.go index fea4bc6d..ddcca60c 100644 --- a/ast/pos.go +++ b/ast/pos.go @@ -326,6 +326,14 @@ func (p *PipeWhere) End() token.Pos { return nodeEnd(wrapNode(p.Expr)) } +func (p *PipeAs) Pos() token.Pos { + return p.Pipe +} + +func (p *PipeAs) End() token.Pos { + return nodeEnd(wrapNode(p.Alias)) +} + func (u *Unnest) Pos() token.Pos { return u.Unnest } diff --git a/ast/sql.go b/ast/sql.go index 4661bb1e..e50d823e 100644 --- a/ast/sql.go +++ b/ast/sql.go @@ -330,6 +330,8 @@ func (p *PipeWhere) SQL() string { return "|> WHERE " + p.Expr.SQL() } +func (p *PipeAs) SQL() string { return "|> AS " + p.Alias.SQL() } + // ================================================================================ // // JOIN diff --git a/ast/walk_internal.go b/ast/walk_internal.go index 690880cf..df232855 100644 --- a/ast/walk_internal.go +++ b/ast/walk_internal.go @@ -149,6 +149,9 @@ func walkInternal(node Node, v Visitor, stack []*stackItem) []*stackItem { case *PipeWhere: stack = append(stack, &stackItem{node: wrapNode(n.Expr), visitor: v.Field("Expr")}) + case *PipeAs: + stack = append(stack, &stackItem{node: wrapNode(n.Alias), visitor: v.Field("Alias")}) + case *Unnest: stack = append(stack, &stackItem{node: wrapNode(n.Sample), visitor: v.Field("Sample")}) stack = append(stack, &stackItem{node: wrapNode(n.WithOffset), visitor: v.Field("WithOffset")}) diff --git a/parser.go b/parser.go index 4512396a..16a7c9d5 100644 --- a/parser.go +++ b/parser.go @@ -428,6 +428,9 @@ func (p *Parser) parsePipeOperator() ast.PipeOperator { Pipe: pos, Expr: expr, } + case "AS": + p.nextToken() + return &ast.PipeAs{Pipe: pos, Alias: p.parseIdent()} default: panic(p.errorfAtToken(&p.Token, "expected pipe operator name, but: %q", p.Token.AsString)) } diff --git a/testdata/input/query/pipe_as.sql b/testdata/input/query/pipe_as.sql new file mode 100644 index 00000000..6ff5acc2 --- /dev/null +++ b/testdata/input/query/pipe_as.sql @@ -0,0 +1,3 @@ +FROM Singers +|> AS s +|> WHERE s.FirstName = "John" diff --git a/testdata/result/query/pipe_as.sql.txt b/testdata/result/query/pipe_as.sql.txt new file mode 100644 index 00000000..7cf994ef --- /dev/null +++ b/testdata/result/query/pipe_as.sql.txt @@ -0,0 +1,59 @@ +--- pipe_as.sql +FROM Singers +|> AS s +|> WHERE s.FirstName = "John" + +--- AST +&ast.QueryStatement{ + Query: &ast.Query{ + Query: &ast.FromQuery{ + From: &ast.From{ + Source: &ast.TableName{ + Table: &ast.Ident{ + NamePos: 5, + NameEnd: 12, + Name: "Singers", + }, + }, + }, + }, + PipeOperators: []ast.PipeOperator{ + &ast.PipeAs{ + Pipe: 13, + Alias: &ast.Ident{ + NamePos: 19, + NameEnd: 20, + Name: "s", + }, + }, + &ast.PipeWhere{ + Pipe: 21, + Expr: &ast.BinaryExpr{ + Op: "=", + Left: &ast.Path{ + Idents: []*ast.Ident{ + &ast.Ident{ + NamePos: 30, + NameEnd: 31, + Name: "s", + }, + &ast.Ident{ + NamePos: 32, + NameEnd: 41, + Name: "FirstName", + }, + }, + }, + Right: &ast.StringLiteral{ + ValuePos: 44, + ValueEnd: 50, + Value: "John", + }, + }, + }, + }, + }, +} + +--- SQL +FROM Singers |> AS s |> WHERE s.FirstName = "John" diff --git a/testdata/result/statement/pipe_as.sql.txt b/testdata/result/statement/pipe_as.sql.txt new file mode 100644 index 00000000..7cf994ef --- /dev/null +++ b/testdata/result/statement/pipe_as.sql.txt @@ -0,0 +1,59 @@ +--- pipe_as.sql +FROM Singers +|> AS s +|> WHERE s.FirstName = "John" + +--- AST +&ast.QueryStatement{ + Query: &ast.Query{ + Query: &ast.FromQuery{ + From: &ast.From{ + Source: &ast.TableName{ + Table: &ast.Ident{ + NamePos: 5, + NameEnd: 12, + Name: "Singers", + }, + }, + }, + }, + PipeOperators: []ast.PipeOperator{ + &ast.PipeAs{ + Pipe: 13, + Alias: &ast.Ident{ + NamePos: 19, + NameEnd: 20, + Name: "s", + }, + }, + &ast.PipeWhere{ + Pipe: 21, + Expr: &ast.BinaryExpr{ + Op: "=", + Left: &ast.Path{ + Idents: []*ast.Ident{ + &ast.Ident{ + NamePos: 30, + NameEnd: 31, + Name: "s", + }, + &ast.Ident{ + NamePos: 32, + NameEnd: 41, + Name: "FirstName", + }, + }, + }, + Right: &ast.StringLiteral{ + ValuePos: 44, + ValueEnd: 50, + Value: "John", + }, + }, + }, + }, + }, +} + +--- SQL +FROM Singers |> AS s |> WHERE s.FirstName = "John"