Skip to content

Commit e6c475b

Browse files
author
awitas
committed
moved from viant/sqlx/metadata/ast
1 parent 7325b5f commit e6c475b

58 files changed

Lines changed: 2335 additions & 0 deletions

Some content is hidden

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

binary.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package sqlparser
2+
3+
import (
4+
"github.com/viant/parsly"
5+
"github.com/viant/parsly/matcher"
6+
"github.com/viant/sqlx/metadata/ast/expr"
7+
)
8+
9+
func parseBinaryExpr(cursor *parsly.Cursor, binary *expr.Binary) error {
10+
var err error
11+
if binary.X == nil {
12+
binary.X, err = expectOperand(cursor)
13+
if err != nil || binary.X == nil {
14+
return err
15+
}
16+
}
17+
//fmt.Printf("After op %v,: %s\n", binary.Op, cursor.Input[cursor.Pos:])
18+
pos := cursor.Pos
19+
if binary.Op == "" {
20+
match := cursor.MatchAfterOptional(whitespaceMatcher, betweenKeywordMatcher, binaryOperatorMatcher, logicalOperatorMatcher)
21+
switch match.Code {
22+
case logicalOperator:
23+
if !matcher.IsWhiteSpace(cursor.Input[cursor.Pos]) {
24+
cursor.Pos = pos
25+
return nil
26+
}
27+
binary.Op = match.Text(cursor)
28+
case binaryOperator:
29+
binary.Op = match.Text(cursor)
30+
case betweenToken:
31+
binary.Op = match.Text(cursor)
32+
rng := &expr.Range{}
33+
if rng.Min, err = expectOperand(cursor); err != nil {
34+
return err
35+
}
36+
match := cursor.MatchAfterOptional(whitespaceMatcher, rangeOperatorMatcher)
37+
if match.Code != rangeOperator {
38+
return cursor.NewError(rangeOperatorMatcher)
39+
}
40+
if rng.Max, err = expectOperand(cursor); err != nil {
41+
return err
42+
}
43+
yExpr := &expr.Binary{X: rng}
44+
if err := parseBinaryExpr(cursor, yExpr); err != nil {
45+
return err
46+
}
47+
if yExpr.Y == nil {
48+
binary.Y = rng
49+
} else {
50+
binary.Y = yExpr
51+
}
52+
return nil
53+
default:
54+
return nil
55+
}
56+
}
57+
if binary.Y == nil {
58+
yExpr := &expr.Binary{}
59+
if err := parseBinaryExpr(cursor, yExpr); err != nil {
60+
return err
61+
}
62+
if yExpr.X != nil {
63+
binary.Y = yExpr
64+
}
65+
if yExpr.Op == "" {
66+
binary.Y = yExpr.X
67+
}
68+
}
69+
return nil
70+
}

delete.go

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
package sqlparser
2+
3+
import (
4+
"github.com/viant/parsly"
5+
del "github.com/viant/sqlx/metadata/ast/delete"
6+
"github.com/viant/sqlx/metadata/ast/expr"
7+
"github.com/viant/sqlx/metadata/ast/query"
8+
)
9+
10+
func ParseDelete(SQL string) (*del.Statement, error) {
11+
aStmt := &del.Statement{}
12+
cursor := parsly.NewCursor("", []byte(SQL), 0)
13+
return aStmt, parseDelete(aStmt, cursor)
14+
}
15+
16+
func parseDelete(stmt *del.Statement, cursor *parsly.Cursor) error {
17+
matched := cursor.MatchAfterOptional(whitespaceMatcher, deleteMatcher)
18+
if matched.Code != deleteCode {
19+
return cursor.NewError(deleteMatcher)
20+
}
21+
22+
var err error
23+
stmt.Items, err = tryParseDeleteItems(cursor)
24+
if err != nil {
25+
return err
26+
}
27+
28+
lastMatchedCode, err := buildDeleteTarget(stmt, cursor)
29+
if err != nil {
30+
return err
31+
}
32+
33+
stmt.Qualify, err = tryParseQualify(cursor, lastMatchedCode)
34+
if err != nil {
35+
return err
36+
}
37+
38+
return nil
39+
}
40+
41+
func buildDeleteTarget(stmt *del.Statement, cursor *parsly.Cursor) (int, error) {
42+
matchable := []*parsly.Token{whereKeywordMatcher, joinToken, selectorMatcher}
43+
44+
var targetData []string
45+
lastMatched := parsly.Invalid
46+
var matched *parsly.TokenMatch
47+
48+
for {
49+
prevPos := cursor.Pos
50+
51+
switch lastMatched {
52+
case whereKeyword:
53+
stmt.Target = buildTarget(targetData, cursor)
54+
return lastMatched, nil
55+
56+
case selectorTokenCode:
57+
targetData = append(targetData, matched.Text(cursor))
58+
if len(targetData) >= 2 {
59+
matchable = matchable[:len(matchable)-1]
60+
}
61+
62+
case joinTokenCode:
63+
join := query.NewJoin(matched.Text(cursor))
64+
if _, err := parseJoin(cursor, join); err != nil {
65+
return lastMatched, err
66+
}
67+
68+
stmt.Joins = append(stmt.Joins, join)
69+
matchable = matchable[:len(matchable)-1]
70+
case parsly.EOF:
71+
stmt.Target = buildTarget(targetData, cursor)
72+
return lastMatched, nil
73+
default:
74+
if matched != nil {
75+
return lastMatched, cursor.NewError(matchable...)
76+
}
77+
}
78+
79+
if prevPos == cursor.Pos {
80+
matched = cursor.MatchAfterOptional(whitespaceMatcher, matchable...)
81+
}
82+
83+
lastMatched = matched.Code
84+
}
85+
}
86+
87+
func buildTarget(targetData []string, cursor *parsly.Cursor) del.Target {
88+
alias := ""
89+
if len(targetData) >= 2 {
90+
alias = targetData[1]
91+
}
92+
93+
target := del.Target{
94+
X: expr.NewSelector(targetData[0]),
95+
Comments: matchComment(cursor),
96+
Alias: alias,
97+
}
98+
return target
99+
}
100+
101+
func tryParseDeleteItems(cursor *parsly.Cursor) ([]*del.Item, error) {
102+
var items []*del.Item
103+
matchable := []*parsly.Token{fromKeywordMatcher, selectorMatcher}
104+
for cursor.Pos < cursor.InputSize {
105+
matched := cursor.MatchAfterOptional(whitespaceMatcher, matchable...)
106+
switch matched.Code {
107+
case fromKeyword:
108+
return items, nil
109+
case selectorTokenCode:
110+
selName := matched.Text(cursor)
111+
comment := matchComment(cursor)
112+
items = append(items, &del.Item{
113+
Comments: comment,
114+
Raw: selName,
115+
})
116+
117+
matched = cursor.MatchAfterOptional(whitespaceMatcher, nextMatcher)
118+
if matched.Code != nextCode {
119+
matchable = matchable[:1]
120+
}
121+
122+
default:
123+
return nil, cursor.NewError(matchable...)
124+
}
125+
}
126+
return items, nil
127+
}
128+
129+
func tryParseQualify(cursor *parsly.Cursor, lastMatchedCode int) (*expr.Qualify, error) {
130+
if lastMatchedCode != whereKeyword {
131+
return nil, nil
132+
}
133+
134+
qualify := expr.NewQualify()
135+
return qualify, ParseQualify(cursor, qualify)
136+
}

delete/item.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package del
2+
3+
type Item struct {
4+
Comments string
5+
Raw string
6+
}

delete/statement.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package del
2+
3+
import (
4+
"github.com/viant/sqlx/metadata/ast/expr"
5+
"github.com/viant/sqlx/metadata/ast/query"
6+
)
7+
8+
type Statement struct {
9+
Target Target
10+
Items []*Item
11+
Joins []*query.Join
12+
Qualify *expr.Qualify
13+
}

delete/target.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package del
2+
3+
import "github.com/viant/sqlx/metadata/ast/node"
4+
5+
type Target struct {
6+
X node.Node
7+
Comments string
8+
Alias string
9+
}

delete_test.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package sqlparser
2+
3+
import (
4+
"github.com/stretchr/testify/assert"
5+
"testing"
6+
)
7+
8+
func TestParseDelete(t *testing.T) {
9+
testcases := []struct {
10+
SQL string
11+
expect string
12+
description string
13+
}{
14+
{
15+
description: "basic",
16+
SQL: "DELETE FROM PRODUCTS",
17+
expect: "DELETE FROM PRODUCTS",
18+
},
19+
{
20+
description: "with qualify",
21+
SQL: "DELETE FROM PRODUCTS WHERE ID = 10",
22+
expect: "DELETE FROM PRODUCTS WHERE ID = 10",
23+
},
24+
{
25+
description: "with aliases",
26+
SQL: "DELETE p FROM PRODUCTS p WHERE p.ID = 10",
27+
expect: "DELETE p FROM PRODUCTS p WHERE p.ID = 10",
28+
},
29+
{
30+
description: "with joins",
31+
SQL: "DELETE p, o FROM PRODUCTS p JOIN OTHER o ON p.ID = o.PRODUCT_ID WHERE p.ID = 10",
32+
expect: "DELETE p, o FROM PRODUCTS p JOIN OTHER o ON p.ID = o.PRODUCT_ID WHERE p.ID = 10",
33+
},
34+
}
35+
36+
//for _, testcase := range testcases[len(testcases)-1:] {
37+
for _, testcase := range testcases {
38+
statement, err := ParseDelete(testcase.SQL)
39+
if !assert.Nil(t, err, testcase.description) {
40+
continue
41+
}
42+
43+
assert.Equal(t, testcase.expect, Stringify(statement), testcase.description)
44+
}
45+
}

expr/binary.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package expr
2+
3+
import "github.com/viant/sqlx/metadata/ast/node"
4+
5+
type Binary struct {
6+
X, Y node.Node
7+
Op string
8+
}
9+
10+
func NewBinary(x node.Node) *Binary {
11+
return &Binary{X: x}
12+
}

expr/call.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package expr
2+
3+
import "github.com/viant/sqlx/metadata/ast/node"
4+
5+
type Call struct {
6+
X node.Node
7+
Args []node.Node
8+
Raw string
9+
}

expr/ident.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package expr
2+
3+
type Ident struct {
4+
Name string
5+
}

expr/literal.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package expr
2+
3+
type Literal struct {
4+
Value string
5+
Kind string
6+
}
7+
8+
func NewIntLiteral(v string) *Literal {
9+
return &Literal{Value: v, Kind: "int"}
10+
}
11+
12+
func NewStringLiteral(v string) *Literal {
13+
return &Literal{Value: v, Kind: "string"}
14+
}
15+
16+
func NewBoolLiteral(v string) *Literal {
17+
return &Literal{Value: v, Kind: "bool"}
18+
}
19+
20+
func NewNullLiteral(v string) *Literal {
21+
return &Literal{Value: v, Kind: "null"}
22+
}
23+
24+
func NewNumericLiteral(v string) *Literal {
25+
return &Literal{Value: v, Kind: "numeric"}
26+
}

0 commit comments

Comments
 (0)