Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
go-version: '1.13'

- name: Test sqlc
run: go test --tags=examples -v ./...
run: go test --tags=examples,exp -v ./...
env:
PG_USER: postgres
PG_HOST: localhost
Expand Down
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@ module github.com/kyleconroy/sqlc
go 1.13

require (
github.com/antlr/antlr4 v0.0.0-20200209180723-1177c0b58d07
github.com/davecgh/go-spew v1.1.1
github.com/google/go-cmp v0.3.0
github.com/jinzhu/inflection v1.0.0
github.com/lfittl/pg_query_go v1.0.0
github.com/lib/pq v1.3.0
github.com/pingcap/parser v0.0.0-20200218113622-517beb2e39c2
github.com/pingcap/tidb v1.1.0-beta.0.20200219045929-1344d6ddd9e7
github.com/spf13/cobra v0.0.5
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 // indirect
golang.org/x/sys v0.0.0-20191220220014-0732a990476f // indirect
Expand Down
173 changes: 173 additions & 0 deletions go.sum

Large diffs are not rendered by default.

11 changes: 11 additions & 0 deletions internal/cmd/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"path/filepath"
"strings"

"github.com/kyleconroy/sqlc/internal/compiler"
"github.com/kyleconroy/sqlc/internal/config"
"github.com/kyleconroy/sqlc/internal/dinosql"
"github.com/kyleconroy/sqlc/internal/dinosql/kotlin"
Expand Down Expand Up @@ -207,6 +208,16 @@ func parse(name, dir string, sql config.SQL, combo config.CombinedSettings, pars
return nil, true
}
return &kotlin.Result{Result: q}, false

case config.EngineXLemon, config.EngineXDolphin, config.EngineXElephant:
r, err := compiler.Run(sql, combo)
if err != nil {
fmt.Fprintf(stderr, "# package %s\n", name)
fmt.Fprintf(stderr, "error: %s\n", err)
return nil, true
}
return r, false

default:
panic("invalid engine")
}
Expand Down
77 changes: 77 additions & 0 deletions internal/compiler/compile.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// +build exp

package compiler

import (
"fmt"
"io"
"os"
"sort"
"strings"

"github.com/kyleconroy/sqlc/internal/config"
"github.com/kyleconroy/sqlc/internal/dinosql"
"github.com/kyleconroy/sqlc/internal/dolphin"
"github.com/kyleconroy/sqlc/internal/pg"
"github.com/kyleconroy/sqlc/internal/postgresql"
"github.com/kyleconroy/sqlc/internal/sql/ast"
"github.com/kyleconroy/sqlc/internal/sql/catalog"
"github.com/kyleconroy/sqlc/internal/sqlite"
)

type Parser interface {
Parse(io.Reader) ([]ast.Statement, error)
}

func Run(conf config.SQL, combo config.CombinedSettings) (*Result, error) {
var p Parser

switch conf.Engine {
case config.EngineXLemon:
p = sqlite.NewParser()
case config.EngineXDolphin:
p = dolphin.NewParser()
case config.EngineXElephant:
p = postgresql.NewParser()
default:
return nil, fmt.Errorf("unknown engine: %s", conf.Engine)
}

rd, err := os.Open(conf.Schema)
if err != nil {
return nil, err
}

stmts, err := p.Parse(rd)
if err != nil {
return nil, err
}

c, err := catalog.Build(stmts)
if err != nil {
return nil, err
}

var structs []dinosql.GoStruct
for _, schema := range c.Schemas {
for _, table := range schema.Tables {
s := dinosql.GoStruct{
Table: pg.FQN{Schema: table.Rel.Schema, Rel: table.Rel.Name},
Name: strings.Title(table.Rel.Name),
}
for _, col := range table.Columns {
s.Fields = append(s.Fields, dinosql.GoField{
Name: strings.Title(col.Name),
Type: "string",
Tags: map[string]string{"json:": col.Name},
})
}
structs = append(structs, s)
}
}
if len(structs) > 0 {
sort.Slice(structs, func(i, j int) bool { return structs[i].Name < structs[j].Name })
}

return &Result{structs: structs}, nil
}
13 changes: 13 additions & 0 deletions internal/compiler/noop.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// +build !exp

package compiler

import (
"fmt"

"github.com/kyleconroy/sqlc/internal/config"
)

func Run(conf config.SQL, combo config.CombinedSettings) (*Result, error) {
return nil, fmt.Errorf("unimplemented")
}
23 changes: 23 additions & 0 deletions internal/compiler/result.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package compiler

import (
"github.com/kyleconroy/sqlc/internal/config"
"github.com/kyleconroy/sqlc/internal/dinosql"
)

type Result struct {
structs []dinosql.GoStruct
queries []dinosql.GoQuery
}

func (r *Result) Structs(settings config.CombinedSettings) []dinosql.GoStruct {
return r.structs
}

func (r *Result) GoQueries(settings config.CombinedSettings) []dinosql.GoQuery {
return r.queries
}

func (r *Result) Enums(settings config.CombinedSettings) []dinosql.GoEnum {
return nil
}
9 changes: 7 additions & 2 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ type Engine string
const (
EngineMySQL Engine = "mysql"
EnginePostgreSQL Engine = "postgresql"

// Experimental engines
EngineXLemon Engine = "_lemon"
EngineXDolphin Engine = "_dolphin"
EngineXElephant Engine = "_elephant"
)

type Config struct {
Expand All @@ -47,7 +52,7 @@ type Config struct {
}

type Gen struct {
Go *GenGo `json:"go,omitempty" yaml:"go"`
Go *GenGo `json:"go,omitempty" yaml:"go"`
Kotlin *GenKotlin `json:"kotlin,omitempty" yaml:"kotlin"`
}

Expand All @@ -68,7 +73,7 @@ type SQL struct {
}

type SQLGen struct {
Go *SQLGo `json:"go,omitempty" yaml:"go"`
Go *SQLGo `json:"go,omitempty" yaml:"go"`
Kotlin *SQLKotlin `json:"kotlin,omitempty" yaml:"kotlin"`
}

Expand Down
163 changes: 163 additions & 0 deletions internal/dolphin/parse.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
package dolphin

import (
"io"
"io/ioutil"

"github.com/kyleconroy/sqlc/internal/sql/ast"

"github.com/pingcap/parser"
pcast "github.com/pingcap/parser/ast"
_ "github.com/pingcap/tidb/types/parser_driver"
)

func NewParser() *Parser {
return &Parser{parser.New()}

}

type Parser struct {
pingcap *parser.Parser
}

type nodeSearch struct {
list []pcast.Node
check func(pcast.Node) bool
}

func (s *nodeSearch) Enter(n pcast.Node) (pcast.Node, bool) {
if s.check(n) {
s.list = append(s.list, n)
}
return n, false // skipChildren
}

func (s *nodeSearch) Leave(n pcast.Node) (pcast.Node, bool) {
return n, true // ok
}

func collect(root pcast.Node, f func(pcast.Node) bool) []pcast.Node {
if root == nil {
return nil
}
ns := &nodeSearch{check: f}
root.Accept(ns)
return ns.list
}

type nodeVisit struct {
fn func(pcast.Node)
}

func (s *nodeVisit) Enter(n pcast.Node) (pcast.Node, bool) {
s.fn(n)
return n, false // skipChildren
}

func (s *nodeVisit) Leave(n pcast.Node) (pcast.Node, bool) {
return n, true // ok
}

func visit(root pcast.Node, f func(pcast.Node)) {
if root == nil {
return
}
ns := &nodeVisit{fn: f}
root.Accept(ns)
}

// Maybe not useful?
func text(nodes []pcast.Node) []string {
str := make([]string, len(nodes))
for i := range nodes {
if nodes[i] == nil {
continue
}
str[i] = nodes[i].Text()
}
return str
}

func (p *Parser) Parse(r io.Reader) ([]ast.Statement, error) {
blob, err := ioutil.ReadAll(r)
if err != nil {
return nil, err
}
stmtNodes, _, err := p.pingcap.Parse(string(blob), "", "")
if err != nil {
return nil, err
}
var stmts []ast.Statement
for i := range stmtNodes {
var stmt ast.Node
switch n := stmtNodes[i].(type) {

case *pcast.CreateTableStmt:
create := &ast.CreateTableStmt{
Name: &ast.TableName{
Schema: n.Table.Schema.String(),
Name: n.Table.Name.String(),
},
IfNotExists: n.IfNotExists,
}
for _, def := range n.Cols {
create.Cols = append(create.Cols, &ast.ColumnDef{
Colname: def.Name.String(),
// TODO: Use n.Tp to generate type name
TypeName: &ast.TypeName{Name: "text"},
})
}
stmt = create

case *pcast.DropTableStmt:
drop := &ast.DropTableStmt{IfExists: n.IfExists}
for _, name := range n.Tables {
drop.Tables = append(drop.Tables, &ast.TableName{
Schema: name.Schema.String(),
Name: name.Name.String(),
})
}
stmt = drop

case *pcast.SelectStmt:
sel := &ast.SelectStmt{}
var tables []ast.Node
visit(n.From, func(n pcast.Node) {
name, ok := n.(*pcast.TableName)
if !ok {
return
}
tables = append(tables, &ast.TableName{
Schema: name.Schema.String(),
Name: name.Name.String(),
})
})
var cols []ast.Node
visit(n.Fields, func(n pcast.Node) {
col, ok := n.(*pcast.ColumnName)
if !ok {
return
}
cols = append(cols, &ast.ResTarget{
Val: &ast.ColumnRef{
Name: col.Name.String(),
},
})
})
sel.From = &ast.List{Items: tables}
sel.Fields = &ast.List{Items: cols}
stmt = sel

default:
// spew.Dump(n)

}

if stmt != nil {
stmts = append(stmts, ast.Statement{
Raw: &ast.RawStmt{Stmt: stmt},
})
}
}
return stmts, nil
}
2 changes: 1 addition & 1 deletion internal/endtoend/regenerate.sh
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#!/usr/bin/env bash
set -x
for dir in testdata/*; do (cd "$dir" && sqlc generate); done
for dir in testdata/*; do (cd "$dir" && sqlc-dev generate); done
29 changes: 29 additions & 0 deletions internal/endtoend/testdata/experimental_dolphin/go/db.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading