go/sqlgen/parse.go
2024-11-19 16:30:42 +01:00

145 lines
3.0 KiB
Go

package sqlgen
import (
"errors"
"os"
"strings"
)
func parsePath(driver, filePath string) (*schema, error) {
fileBytes, err := os.ReadFile(filePath)
if err != nil {
return nil, err
}
return parseBytes(driver, fileBytes)
}
func parseBytes(driver string, fileBytes []byte) (*schema, error) {
s := string(fileBytes)
for _, c := range []string{",", "(", ")", ";"} {
s = strings.ReplaceAll(s, c, " "+c+" ")
}
var (
tokens = strings.Fields(s)
schema = &schema{}
err error
)
for len(tokens) > 0 {
switch tokens[0] {
case "TABLE":
tokens, err = parseTable(driver, schema, tokens)
if err != nil {
return nil, err
}
default:
return nil, errors.New("invalid token: " + tokens[0])
}
}
return schema, nil
}
func parseTable(driver string, schema *schema, tokens []string) ([]string, error) {
tokens = tokens[1:]
if len(tokens) < 3 {
return tokens, errors.New("incomplete table definition")
}
if tokens[1] != "OF" {
return tokens, errors.New("expected OF in table definition")
}
table := &table{
driver: driver,
Name: tokens[0],
Type: tokens[2],
}
schema.Tables = append(schema.Tables, table)
tokens = tokens[3:]
if len(tokens) == 0 {
return tokens, errors.New("missing table definition body")
}
for len(tokens) > 0 {
switch tokens[0] {
case "NoInsert":
table.NoInsert = true
tokens = tokens[1:]
case "NoUpdate":
table.NoUpdate = true
tokens = tokens[1:]
case "NoDelete":
table.NoDelete = true
tokens = tokens[1:]
case "(":
return parseTableBody(table, tokens[1:])
default:
return tokens, errors.New("unexpected token in table definition: " + tokens[0])
}
}
return tokens, errors.New("incomplete table definition")
}
func parseTableBody(table *table, tokens []string) ([]string, error) {
var err error
for len(tokens) > 0 && tokens[0] != ";" {
tokens, err = parseTableColumn(table, tokens)
if err != nil {
return tokens, err
}
}
if len(tokens) < 1 || tokens[0] != ";" {
return tokens, errors.New("incomplete table column definitions")
}
return tokens[1:], nil
}
func parseTableColumn(table *table, tokens []string) ([]string, error) {
if len(tokens) < 2 {
return tokens, errors.New("incomplete column definition")
}
column := &column{
Name: tokens[0],
Type: tokens[1],
SqlName: tokens[0],
}
table.Columns = append(table.Columns, column)
tokens = tokens[2:]
for len(tokens) > 0 && tokens[0] != "," && tokens[0] != ")" {
switch tokens[0] {
case "AS":
if len(tokens) < 2 {
return tokens, errors.New("incomplete AS clause in column definition")
}
column.Name = tokens[1]
tokens = tokens[2:]
case "PK":
column.PK = true
tokens = tokens[1:]
case "NoInsert":
column.NoInsert = true
tokens = tokens[1:]
case "NoUpdate":
column.NoUpdate = true
tokens = tokens[1:]
default:
return tokens, errors.New("unexpected token in column definition: " + tokens[0])
}
}
if len(tokens) == 0 {
return tokens, errors.New("incomplete column definition")
}
return tokens[1:], nil
}