Skip to content

Commit 71ae360

Browse files
committed
feat: Add support for generic process plugins
1 parent 2d18667 commit 71ae360

File tree

4 files changed

+293
-165
lines changed

4 files changed

+293
-165
lines changed

internal/config/config.go

Lines changed: 46 additions & 164 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,10 @@ import (
66
"errors"
77
"fmt"
88
"io"
9-
"os"
10-
"strings"
11-
12-
"github.com/kyleconroy/sqlc/internal/pattern"
13-
"github.com/kyleconroy/sqlc/internal/sql/ast"
149

1510
yaml "gopkg.in/yaml.v3"
11+
12+
"github.com/kyleconroy/sqlc/internal/config/convert"
1613
)
1714

1815
const errMessageNoVersion = `The configuration file must have a version number.
@@ -78,16 +75,27 @@ const (
7875
)
7976

8077
type Config struct {
81-
Version string `json:"version" yaml:"version"`
82-
Project Project `json:"project" yaml:"project"`
83-
SQL []SQL `json:"sql" yaml:"sql"`
84-
Gen Gen `json:"overrides,omitempty" yaml:"overrides"`
78+
Version string `json:"version" yaml:"version"`
79+
Project Project `json:"project" yaml:"project"`
80+
SQL []SQL `json:"sql" yaml:"sql"`
81+
Gen Gen `json:"overrides,omitempty" yaml:"overrides"`
82+
Plugins []Plugin `json:"plugins" yaml:"plugins"`
8583
}
8684

8785
type Project struct {
8886
ID string `json:"id" yaml:"id"`
8987
}
9088

89+
type Plugin struct {
90+
Name string `json:"name" yaml:"name"`
91+
Process *struct {
92+
Cmd string `json:"cmd" yaml:"cmd"`
93+
} `json:"process" yaml:"process"`
94+
WASM *struct {
95+
URL string `json:"url" yaml:"url"`
96+
} `json:"wasm" yaml:"wasm"`
97+
}
98+
9199
type Gen struct {
92100
Go *GenGo `json:"go,omitempty" yaml:"go"`
93101
Kotlin *GenKotlin `json:"kotlin,omitempty" yaml:"kotlin"`
@@ -103,11 +111,18 @@ type GenKotlin struct {
103111
}
104112

105113
type SQL struct {
106-
Engine Engine `json:"engine,omitempty" yaml:"engine"`
107-
Schema Paths `json:"schema" yaml:"schema"`
108-
Queries Paths `json:"queries" yaml:"queries"`
109-
StrictFunctionChecks bool `json:"strict_function_checks" yaml:"strict_function_checks"`
110-
Gen SQLGen `json:"gen" yaml:"gen"`
114+
Engine Engine `json:"engine,omitempty" yaml:"engine"`
115+
Schema Paths `json:"schema" yaml:"schema"`
116+
Queries Paths `json:"queries" yaml:"queries"`
117+
StrictFunctionChecks bool `json:"strict_function_checks" yaml:"strict_function_checks"`
118+
Gen SQLGen `json:"gen" yaml:"gen"`
119+
Codegen []Codegen `json:"codegen" yaml:"codegen"`
120+
}
121+
122+
type Codegen struct {
123+
Out string `json:"out" yaml:"out"`
124+
Plugin string `json:"plugin" yaml:"plugin"`
125+
Options yaml.Node `json:"options" yaml:"options"`
111126
}
112127

113128
type SQLGen struct {
@@ -163,160 +178,22 @@ type SQLJSON struct {
163178
Indent string `json:"indent,omitempty" yaml:"indent"`
164179
}
165180

166-
type Override struct {
167-
// name of the golang type to use, e.g. `github.com/segmentio/ksuid.KSUID`
168-
GoType GoType `json:"go_type" yaml:"go_type"`
169-
170-
// name of the python type to use, e.g. `mymodule.TypeName`
171-
PythonType PythonType `json:"python_type" yaml:"python_type"`
172-
173-
// fully qualified name of the Go type, e.g. `github.com/segmentio/ksuid.KSUID`
174-
DBType string `json:"db_type" yaml:"db_type"`
175-
Deprecated_PostgresType string `json:"postgres_type" yaml:"postgres_type"`
176-
177-
// for global overrides only when two different engines are in use
178-
Engine Engine `json:"engine,omitempty" yaml:"engine"`
179-
180-
// True if the GoType should override if the maching postgres type is nullable
181-
Nullable bool `json:"nullable" yaml:"nullable"`
182-
// Deprecated. Use the `nullable` property instead
183-
Deprecated_Null bool `json:"null" yaml:"null"`
184-
185-
// fully qualified name of the column, e.g. `accounts.id`
186-
Column string `json:"column" yaml:"column"`
187-
188-
ColumnName *pattern.Match
189-
TableCatalog *pattern.Match
190-
TableSchema *pattern.Match
191-
TableRel *pattern.Match
192-
GoImportPath string
193-
GoPackage string
194-
GoTypeName string
195-
GoBasicType bool
196-
}
197-
198-
func (o *Override) Matches(n *ast.TableName, defaultSchema string) bool {
199-
if n == nil {
200-
return false
201-
}
202-
203-
schema := n.Schema
204-
if n.Schema == "" {
205-
schema = defaultSchema
206-
}
207-
208-
if o.TableCatalog != nil && !o.TableCatalog.MatchString(n.Catalog) {
209-
return false
210-
}
211-
212-
if o.TableSchema == nil && schema != "" {
213-
return false
214-
}
215-
216-
if o.TableSchema != nil && !o.TableSchema.MatchString(schema) {
217-
return false
218-
}
219-
220-
if o.TableRel == nil && n.Name != "" {
221-
return false
222-
}
223-
224-
if o.TableRel != nil && !o.TableRel.MatchString(n.Name) {
225-
return false
226-
}
227-
228-
return true
229-
}
230-
231-
func (o *Override) Parse() (err error) {
232-
233-
// validate deprecated postgres_type field
234-
if o.Deprecated_PostgresType != "" {
235-
fmt.Fprintf(os.Stderr, "WARNING: \"postgres_type\" is deprecated. Instead, use \"db_type\" to specify a type override.\n")
236-
if o.DBType != "" {
237-
return fmt.Errorf(`Type override configurations cannot have "db_type" and "postres_type" together. Use "db_type" alone`)
238-
}
239-
o.DBType = o.Deprecated_PostgresType
240-
}
241-
242-
// validate deprecated null field
243-
if o.Deprecated_Null {
244-
fmt.Fprintf(os.Stderr, "WARNING: \"null\" is deprecated. Instead, use the \"nullable\" field.\n")
245-
o.Nullable = true
246-
}
247-
248-
// validate option combinations
249-
switch {
250-
case o.Column != "" && o.DBType != "":
251-
return fmt.Errorf("Override specifying both `column` (%q) and `db_type` (%q) is not valid.", o.Column, o.DBType)
252-
case o.Column == "" && o.DBType == "":
253-
return fmt.Errorf("Override must specify one of either `column` or `db_type`")
254-
}
255-
256-
// validate Column
257-
if o.Column != "" {
258-
colParts := strings.Split(o.Column, ".")
259-
switch len(colParts) {
260-
case 2:
261-
if o.ColumnName, err = pattern.MatchCompile(colParts[1]); err != nil {
262-
return err
263-
}
264-
if o.TableRel, err = pattern.MatchCompile(colParts[0]); err != nil {
265-
return err
266-
}
267-
if o.TableSchema, err = pattern.MatchCompile("public"); err != nil {
268-
return err
269-
}
270-
case 3:
271-
if o.ColumnName, err = pattern.MatchCompile(colParts[2]); err != nil {
272-
return err
273-
}
274-
if o.TableRel, err = pattern.MatchCompile(colParts[1]); err != nil {
275-
return err
276-
}
277-
if o.TableSchema, err = pattern.MatchCompile(colParts[0]); err != nil {
278-
return err
279-
}
280-
case 4:
281-
if o.ColumnName, err = pattern.MatchCompile(colParts[3]); err != nil {
282-
return err
283-
}
284-
if o.TableRel, err = pattern.MatchCompile(colParts[2]); err != nil {
285-
return err
286-
}
287-
if o.TableSchema, err = pattern.MatchCompile(colParts[1]); err != nil {
288-
return err
289-
}
290-
if o.TableCatalog, err = pattern.MatchCompile(colParts[0]); err != nil {
291-
return err
292-
}
293-
default:
294-
return fmt.Errorf("Override `column` specifier %q is not the proper format, expected '[catalog.][schema.]tablename.colname'", o.Column)
295-
}
296-
}
297-
298-
// validate GoType
299-
parsed, err := o.GoType.Parse()
300-
if err != nil {
301-
return err
302-
}
303-
o.GoImportPath = parsed.ImportPath
304-
o.GoPackage = parsed.Package
305-
o.GoTypeName = parsed.TypeName
306-
o.GoBasicType = parsed.BasicType
307-
308-
return nil
309-
}
310-
311-
var ErrMissingVersion = errors.New("no version number")
312-
var ErrUnknownVersion = errors.New("invalid version number")
313181
var ErrMissingEngine = errors.New("unknown engine")
314-
var ErrUnknownEngine = errors.New("invalid engine")
315-
var ErrNoPackages = errors.New("no packages")
182+
var ErrMissingVersion = errors.New("no version number")
183+
var ErrNoOutPath = errors.New("no output path")
316184
var ErrNoPackageName = errors.New("missing package name")
317185
var ErrNoPackagePath = errors.New("missing package path")
318-
var ErrNoOutPath = errors.New("no output path")
186+
var ErrNoPackages = errors.New("no packages")
319187
var ErrNoQuerierType = errors.New("no querier emit type enabled")
188+
var ErrUnknownEngine = errors.New("invalid engine")
189+
var ErrUnknownVersion = errors.New("invalid version number")
190+
191+
var ErrPluginBuiltin = errors.New("a built-in plugin with that name already exists")
192+
var ErrPluginNoName = errors.New("missing plugin name")
193+
var ErrPluginExists = errors.New("a plugin with that name already exists")
194+
var ErrPluginNoType = errors.New("plugin: field `process` or `wasm` required")
195+
var ErrPluginBothTypes = errors.New("plugin: both `process` and `wasm` cannot both be defined")
196+
var ErrPluginProcessNoCmd = errors.New("plugin: missing process command")
320197

321198
func ParseConfig(rd io.Reader) (Config, error) {
322199
var buf bytes.Buffer
@@ -370,6 +247,11 @@ func Combine(conf Config, pkg SQL) CombinedSettings {
370247
Global: conf,
371248
Package: pkg,
372249
}
250+
251+
for i, cg := range pkg.Codegen {
252+
fmt.Printf("%d: %s\n", i, convert.YAMLtoJSON(cg.Options))
253+
}
254+
373255
if conf.Gen.Go != nil {
374256
cs.Rename = conf.Gen.Go.Rename
375257
cs.Overrides = append(cs.Overrides, conf.Gen.Go.Overrides...)

internal/config/convert/convert.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package convert
2+
3+
import (
4+
"encoding/json"
5+
"strconv"
6+
7+
"gopkg.in/yaml.v3"
8+
)
9+
10+
func gen(n *yaml.Node) interface{} {
11+
switch n.Kind {
12+
13+
case yaml.MappingNode:
14+
nn := map[string]interface{}{}
15+
for i, _ := range n.Content {
16+
if i%2 == 0 {
17+
k := n.Content[i]
18+
nn[k.Value] = gen(n.Content[i+1])
19+
}
20+
}
21+
return nn
22+
23+
case yaml.SequenceNode:
24+
nn := []interface{}{}
25+
for i, _ := range n.Content {
26+
nn = append(nn, gen(n.Content[i]))
27+
}
28+
return nn
29+
30+
case yaml.ScalarNode:
31+
switch n.Tag {
32+
33+
case "!!bool":
34+
return n.Value == "true"
35+
36+
case "!!int":
37+
i, err := strconv.Atoi(n.Value)
38+
if err != nil {
39+
panic(err)
40+
}
41+
return i
42+
43+
default:
44+
return n.Value
45+
46+
}
47+
48+
default:
49+
return ""
50+
51+
}
52+
}
53+
54+
func YAMLtoJSON(n yaml.Node) []byte {
55+
blob, err := json.Marshal(gen(&n))
56+
if err != nil {
57+
panic(err)
58+
}
59+
return blob
60+
}

0 commit comments

Comments
 (0)