Skip to content

Commit ce71699

Browse files
committed
feat: Add support for generic process plugins
1 parent b75b919 commit ce71699

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 {
@@ -161,160 +176,22 @@ type SQLJSON struct {
161176
Indent string `json:"indent,omitempty" yaml:"indent"`
162177
}
163178

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

319196
func ParseConfig(rd io.Reader) (Config, error) {
320197
var buf bytes.Buffer
@@ -368,6 +245,11 @@ func Combine(conf Config, pkg SQL) CombinedSettings {
368245
Global: conf,
369246
Package: pkg,
370247
}
248+
249+
for i, cg := range pkg.Codegen {
250+
fmt.Printf("%d: %s\n", i, convert.YAMLtoJSON(cg.Options))
251+
}
252+
371253
if conf.Gen.Go != nil {
372254
cs.Rename = conf.Gen.Go.Rename
373255
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)