Skip to content

Commit 0a7599e

Browse files
committed
postgresql: Add experimental parser for MySQL
1 parent 7bddb83 commit 0a7599e

File tree

1 file changed

+143
-0
lines changed

1 file changed

+143
-0
lines changed

internal/postgresql/parse.go

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
package postgresql
2+
3+
import (
4+
"fmt"
5+
"io"
6+
"io/ioutil"
7+
"strings"
8+
9+
"github.com/kyleconroy/sqlc/internal/sql/ast"
10+
11+
pg "github.com/lfittl/pg_query_go"
12+
nodes "github.com/lfittl/pg_query_go/nodes"
13+
)
14+
15+
func stringSlice(list nodes.List) []string {
16+
items := []string{}
17+
for _, item := range list.Items {
18+
if n, ok := item.(nodes.String); ok {
19+
items = append(items, n.Str)
20+
}
21+
}
22+
return items
23+
}
24+
25+
func parseTableName(node nodes.Node) (*ast.TableName, error) {
26+
switch n := node.(type) {
27+
28+
case nodes.List:
29+
parts := stringSlice(n)
30+
switch len(parts) {
31+
case 1:
32+
return &ast.TableName{
33+
Name: parts[0],
34+
}, nil
35+
case 2:
36+
return &ast.TableName{
37+
Schema: parts[0],
38+
Name: parts[1],
39+
}, nil
40+
case 3:
41+
return &ast.TableName{
42+
Catalog: parts[0],
43+
Schema: parts[1],
44+
Name: parts[2],
45+
}, nil
46+
default:
47+
return nil, fmt.Errorf("invalid table name: %s", join(n, "."))
48+
}
49+
50+
case nodes.RangeVar:
51+
name := ast.TableName{}
52+
if n.Catalogname != nil {
53+
name.Catalog = *n.Catalogname
54+
}
55+
if n.Schemaname != nil {
56+
name.Schema = *n.Schemaname
57+
}
58+
if n.Relname != nil {
59+
name.Name = *n.Relname
60+
}
61+
return &name, nil
62+
63+
default:
64+
return nil, fmt.Errorf("unexpected node type: %T", n)
65+
}
66+
}
67+
68+
func join(list nodes.List, sep string) string {
69+
return strings.Join(stringSlice(list), sep)
70+
}
71+
72+
func NewParser() *Parser {
73+
return &Parser{}
74+
}
75+
76+
type Parser struct {
77+
}
78+
79+
func (p *Parser) Parse(r io.Reader) ([]ast.Statement, error) {
80+
contents, err := ioutil.ReadAll(r)
81+
if err != nil {
82+
return nil, err
83+
}
84+
tree, err := pg.Parse(string(contents))
85+
if err != nil {
86+
return nil, err
87+
}
88+
89+
var stmts []ast.Statement
90+
for _, stmt := range tree.Statements {
91+
raw, ok := stmt.(nodes.RawStmt)
92+
if !ok {
93+
return nil, fmt.Errorf("expected RawStmt; got %T", stmt)
94+
}
95+
switch n := raw.Stmt.(type) {
96+
97+
case nodes.CreateStmt:
98+
name, err := parseTableName(*n.Relation)
99+
if err != nil {
100+
return nil, err
101+
}
102+
create := &ast.CreateTableStmt{
103+
Name: name,
104+
IfNotExists: n.IfNotExists,
105+
}
106+
for _, elt := range n.TableElts.Items {
107+
switch n := elt.(type) {
108+
case nodes.ColumnDef:
109+
create.Cols = append(create.Cols, &ast.ColumnDef{
110+
Colname: *n.Colname,
111+
// TODO: Maybe type name shouldn't be a string?
112+
TypeName: &ast.TypeName{Name: join(n.TypeName.Names, ".")},
113+
})
114+
}
115+
}
116+
stmts = append(stmts, ast.Statement{
117+
Raw: &ast.RawStmt{Stmt: create},
118+
})
119+
120+
case nodes.DropStmt:
121+
drop := &ast.DropTableStmt{
122+
IfExists: n.MissingOk,
123+
}
124+
for _, obj := range n.Objects.Items {
125+
if n.RemoveType == nodes.OBJECT_TABLE {
126+
name, err := parseTableName(obj)
127+
if err != nil {
128+
return nil, err
129+
}
130+
drop.Tables = append(drop.Tables, name)
131+
}
132+
}
133+
stmts = append(stmts, ast.Statement{
134+
Raw: &ast.RawStmt{Stmt: drop},
135+
})
136+
137+
default:
138+
// spew.Dump(n)
139+
140+
}
141+
}
142+
return stmts, nil
143+
}

0 commit comments

Comments
 (0)