Skip to content

Commit

Permalink
Define code generation interface via Protocol Buffers (#1406)
Browse files Browse the repository at this point in the history
* Define CodeGenRequest and CodeGenResponse via `proto/plugin/codegen.proto`
* Move pattern matching to another package
  • Loading branch information
kyleconroy committed Feb 6, 2022
1 parent 45bd150 commit 6ceb473
Show file tree
Hide file tree
Showing 12 changed files with 2,458 additions and 441 deletions.
3 changes: 3 additions & 0 deletions Makefile
Expand Up @@ -21,6 +21,9 @@ sqlc-pg-gen:
start:
docker-compose up -d

fmt:
go fmt ./...

psql:
PGPASSWORD=mysecretpassword psql --host=127.0.0.1 --port=5432 --username=postgres dinotest

Expand Down
11 changes: 10 additions & 1 deletion internal/cmd/generate.go
Expand Up @@ -19,6 +19,7 @@ import (
"github.com/kyleconroy/sqlc/internal/debug"
"github.com/kyleconroy/sqlc/internal/multierr"
"github.com/kyleconroy/sqlc/internal/opts"
"github.com/kyleconroy/sqlc/internal/plugin"
)

const errMessageNoVersion = `The configuration file must have a version number.
Expand Down Expand Up @@ -187,6 +188,7 @@ func Generate(ctx context.Context, e Env, dir, filename string, stderr io.Writer
region = trace.StartRegion(ctx, "codegen")
}
var files map[string]string
var resp *plugin.CodeGenResponse
var out string
switch {
case sql.Gen.Go != nil:
Expand All @@ -197,14 +199,21 @@ func Generate(ctx context.Context, e Env, dir, filename string, stderr io.Writer
files, err = kotlin.Generate(result, combo)
case sql.Gen.Python != nil:
out = combo.Python.Out
files, err = python.Generate(result, combo)
resp, err = python.Generate(codeGenRequest(result, combo))
default:
panic("missing language backend")
}
if region != nil {
region.End()
}

if resp != nil {
files = map[string]string{}
for _, file := range resp.Files {
files[file.Name] = string(file.Contents)
}
}

if err != nil {
fmt.Fprintf(stderr, "# package %s\n", name)
fmt.Fprintf(stderr, "error generating code: %s\n", err)
Expand Down
217 changes: 217 additions & 0 deletions internal/cmd/shim.go
@@ -0,0 +1,217 @@
package cmd

import (
"strings"

"github.com/kyleconroy/sqlc/internal/compiler"
"github.com/kyleconroy/sqlc/internal/config"
"github.com/kyleconroy/sqlc/internal/plugin"
"github.com/kyleconroy/sqlc/internal/sql/catalog"
)

func pluginOverride(o config.Override) *plugin.Override {
var column string
var table plugin.Identifier

if o.Column != "" {
colParts := strings.Split(o.Column, ".")
switch len(colParts) {
case 2:
table.Schema = "public"
table.Name = colParts[0]
column = colParts[1]
case 3:
table.Schema = colParts[0]
table.Name = colParts[1]
column = colParts[2]
case 4:
table.Catalog = colParts[0]
table.Schema = colParts[1]
table.Name = colParts[2]
column = colParts[3]
}
}
return &plugin.Override{
CodeType: "", // FIXME
DbType: o.DBType,
Nullable: o.Nullable,
Column: o.Column,
ColumnName: column,
Table: &table,
PythonType: pluginPythonType(o.PythonType),
}
}

func pluginSettings(cs config.CombinedSettings) *plugin.Settings {
var over []*plugin.Override
for _, o := range cs.Overrides {
over = append(over, pluginOverride(o))
}
return &plugin.Settings{
Version: cs.Global.Version,
Engine: string(cs.Package.Engine),
Schema: []string(cs.Package.Schema),
Queries: []string(cs.Package.Queries),
Overrides: over,
Rename: cs.Rename,
Python: pluginPythonCode(cs.Python),
}
}

func pluginPythonCode(s config.SQLPython) *plugin.PythonCode {
return &plugin.PythonCode{
Out: s.Out,
Package: s.Package,
EmitExactTableNames: s.EmitExactTableNames,
EmitSyncQuerier: s.EmitSyncQuerier,
EmitAsyncQuerier: s.EmitAsyncQuerier,
}
}

func pluginPythonType(pt config.PythonType) *plugin.PythonType {
return &plugin.PythonType{
Module: pt.Module,
Name: pt.Name,
}
}

func pluginCatalog(c *catalog.Catalog) *plugin.Catalog {
var schemas []*plugin.Schema
for _, s := range c.Schemas {
var enums []*plugin.Enum
for _, typ := range s.Types {
enum, ok := typ.(*catalog.Enum)
if !ok {
continue
}
enums = append(enums, &plugin.Enum{
Name: enum.Name,
Comment: enum.Comment,
Vals: enum.Vals,
})
}
var tables []*plugin.Table
for _, t := range s.Tables {
var columns []*plugin.Column
for _, c := range t.Columns {
l := -1
if c.Length != nil {
l = *c.Length
}
columns = append(columns, &plugin.Column{
Name: c.Name,
Type: &plugin.Identifier{
Catalog: c.Type.Catalog,
Schema: c.Type.Schema,
Name: c.Type.Name,
},
Comment: c.Comment,
NotNull: c.IsNotNull,
IsArray: c.IsArray,
Length: int32(l),
Table: &plugin.Identifier{
Catalog: t.Rel.Catalog,
Schema: t.Rel.Schema,
Name: t.Rel.Name,
},
})
}
tables = append(tables, &plugin.Table{
Rel: &plugin.Identifier{
Catalog: t.Rel.Catalog,
Schema: t.Rel.Schema,
Name: t.Rel.Name,
},
Columns: columns,
Comment: t.Comment,
})
}
schemas = append(schemas, &plugin.Schema{
Comment: s.Comment,
Name: s.Name,
Tables: tables,
Enums: enums,
})
}
return &plugin.Catalog{
Name: c.Name,
DefaultSchema: c.DefaultSchema,
Comment: c.Comment,
Schemas: schemas,
}
}

func pluginQueries(r *compiler.Result) []*plugin.Query {
var out []*plugin.Query
for _, q := range r.Queries {
var params []*plugin.Parameter
var columns []*plugin.Column
for _, c := range q.Columns {
columns = append(columns, pluginQueryColumn(c))
}
for _, p := range q.Params {
params = append(params, pluginQueryParam(p))
}
out = append(out, &plugin.Query{
Name: q.Name,
Cmd: q.Cmd,
Text: q.SQL,
Comments: q.Comments,
Columns: columns,
Params: params,
Filename: q.Filename,
})
}
return out
}

func pluginQueryColumn(c *compiler.Column) *plugin.Column {
l := -1
if c.Length != nil {
l = *c.Length
}
out := &plugin.Column{
Name: c.Name,
Comment: c.Comment,
NotNull: c.NotNull,
IsArray: c.IsArray,
Length: int32(l),
}

if c.Type != nil {
out.Type = &plugin.Identifier{
Catalog: c.Type.Catalog,
Schema: c.Type.Schema,
Name: c.Type.Name,
}
} else {
out.Type = &plugin.Identifier{
Name: c.DataType,
}
}

if c.Table != nil {
out.Table = &plugin.Identifier{
Catalog: c.Table.Catalog,
Schema: c.Table.Schema,
Name: c.Table.Name,
}
}

return out
}

func pluginQueryParam(p compiler.Parameter) *plugin.Parameter {
return &plugin.Parameter{
Number: int32(p.Number),
Column: pluginQueryColumn(p.Column),
}
}

func codeGenRequest(r *compiler.Result, settings config.CombinedSettings) *plugin.CodeGenRequest {
return &plugin.CodeGenRequest{
Settings: pluginSettings(settings),
Catalog: pluginCatalog(r.Catalog),
Queries: pluginQueries(r),
}
}

0 comments on commit 6ceb473

Please sign in to comment.