Skip to content

Commit 73b06dc

Browse files
authored
config: Add support for YAML (#336)
* config: Add support for YAML Both version 1 and version 2 of the config formats can now be expressed in YAML. sqlc will look for `sqlc.yaml` defined in the working directory. * Add test for YAML * config: Init version 1 of config format * Fix failing test
1 parent 93f5a09 commit 73b06dc

File tree

14 files changed

+192
-115
lines changed

14 files changed

+192
-115
lines changed

README.md

Lines changed: 33 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ Available Commands:
256256
compile Statically check SQL for syntax and type errors
257257
generate Generate Go code from SQL
258258
help Help about any command
259-
init Create an empty sqlc.json settings file
259+
init Create an empty sqlc.yaml settings file
260260
version Print the sqlc version number
261261
262262
Flags:
@@ -267,24 +267,19 @@ Use "sqlc [command] --help" for more information about a command.
267267

268268
## Settings
269269

270-
The `sqlc` tool is configured via a `sqlc.json` file. This file must be
270+
The `sqlc` tool is configured via a `sqlc.yaml` file. This file must be
271271
in the directory where the `sqlc` command is run.
272272

273-
```json
274-
{
275-
"version": "1",
276-
"packages": [
277-
{
278-
"name": "db",
279-
"emit_json_tags": true,
280-
"emit_prepared_queries": false,
281-
"emit_interface": true,
282-
"path": "internal/db",
283-
"queries": "./sql/query/",
284-
"schema": "./sql/schema/"
285-
}
286-
]
287-
}
273+
```yaml
274+
version: "1"
275+
packages:
276+
- name: "db",
277+
emit_json_tags: true
278+
emit_prepared_queries: false
279+
emit_interface: true
280+
path: "internal/db"
281+
queries: "./sql/query/"
282+
schema: "./sql/schema/"
288283
```
289284
290285
Each package document has the following keys:
@@ -315,17 +310,12 @@ If a different Go package for UUIDs is required, specify the package in the
315310
`overrides` array. In this case, I'm going to use the `github.com/gofrs/uuid`
316311
instead.
317312

318-
```
319-
{
320-
"version": "1",
321-
"packages": [...],
322-
"overrides": [
323-
{
324-
"go_type": "github.com/gofrs/uuid.UUID",
325-
"db_type": "uuid"
326-
}
327-
]
328-
}
313+
```yaml
314+
version: "1"
315+
packages: [...]
316+
overrides:
317+
- go_type: "github.com/gofrs/uuid.UUID"
318+
db_type: "uuid"
329319
```
330320

331321
Each override document has the following keys:
@@ -345,37 +335,25 @@ This may be configured by specifying the `column` property in the override defin
345335
should be of the form `table.column` buy you may be even more specify by specifying `schema.table.column`
346336
or `catalog.schema.table.column`.
347337

348-
```
349-
{
350-
"version": "1",
351-
"packages": [...],
352-
"overrides": [
353-
{
354-
"column": "authors.id",
355-
"go_type": "github.com/segmentio/ksuid.KSUID"
356-
}
357-
]
358-
}
338+
```yaml
339+
version: "1"
340+
packages: [...]
341+
overrides:
342+
- column: "authors.id"
343+
go_type: "github.com/segmentio/ksuid.KSUID"
359344
```
360345

361346
### Package Level Overrides
362347

363348
Overrides can be configured globally, as demonstrated in the previous sections, or they can be configured on a per-package which
364349
scopes the override behavior to just a single package:
365350

366-
```
367-
{
368-
"version": "1",
369-
"packages": [
370-
{
371-
...
372-
"overrides": [...]
373-
}
374-
],
375-
}
351+
```yaml
352+
version: "1"
353+
packages:
354+
- overrides: [...]
376355
```
377356

378-
379357
### Renaming Struct Fields
380358

381359
Struct field names are generated from column names using a simple algorithm:
@@ -392,14 +370,11 @@ If you're not happy with a field's generated name, use the `rename` dictionary
392370
to pick a new name. The keys are column names and the values are the struct
393371
field name to use.
394372
395-
```json
396-
{
397-
"version": "1",
398-
"packages": [...],
399-
"rename": {
400-
"spotify_url": "SpotifyURL"
401-
}
402-
}
373+
```yaml
374+
version: "1"
375+
packages: [...]
376+
rename:
377+
spotify_url: "SpotifyURL"
403378
```
404379

405380
## Downloads

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,6 @@ require (
1313
golang.org/x/sys v0.0.0-20191220220014-0732a990476f // indirect
1414
google.golang.org/genproto v0.0.0-20191223191004-3caeed10a8bf // indirect
1515
google.golang.org/grpc v1.26.0 // indirect
16+
gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71
1617
vitess.io/vitess v0.0.0-20200119095853-bd8205ebca4a
1718
)

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,8 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
515515
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
516516
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
517517
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
518+
gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71 h1:Xe2gvTZUJpsvOWUnvmL/tmhVBZUmHSvLbMjRj6NUUKo=
519+
gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
518520
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
519521
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
520522
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

internal/cmd/cmd.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package cmd
22

33
import (
4-
"encoding/json"
54
"fmt"
65
"io"
76
"io/ioutil"
@@ -10,6 +9,7 @@ import (
109
"path/filepath"
1110

1211
"github.com/spf13/cobra"
12+
yaml "gopkg.in/yaml.v3"
1313

1414
"github.com/kyleconroy/sqlc/internal/config"
1515
)
@@ -47,16 +47,16 @@ var versionCmd = &cobra.Command{
4747

4848
var initCmd = &cobra.Command{
4949
Use: "init",
50-
Short: "Create an empty sqlc.json settings file",
50+
Short: "Create an empty sqlc.yaml settings file",
5151
RunE: func(cmd *cobra.Command, args []string) error {
52-
if _, err := os.Stat("sqlc.json"); !os.IsNotExist(err) {
52+
if _, err := os.Stat("sqlc.yaml"); !os.IsNotExist(err) {
5353
return nil
5454
}
55-
blob, err := json.MarshalIndent(config.Config{Version: "1"}, "", " ")
55+
blob, err := yaml.Marshal(config.V1GenerateSettings{Version: "1"})
5656
if err != nil {
5757
return err
5858
}
59-
return ioutil.WriteFile("sqlc.json", blob, 0644)
59+
return ioutil.WriteFile("sqlc.yaml", blob, 0644)
6060
},
6161
}
6262

internal/cmd/generate.go

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@ package cmd
22

33
import (
44
"bytes"
5+
"errors"
56
"fmt"
67
"io"
78
"io/ioutil"
9+
"os"
810
"path/filepath"
911
"strings"
1012

@@ -34,7 +36,33 @@ func printFileErr(stderr io.Writer, dir string, fileErr dinosql.FileErr) {
3436
}
3537

3638
func Generate(dir string, stderr io.Writer) (map[string]string, error) {
37-
blob, err := ioutil.ReadFile(filepath.Join(dir, "sqlc.json"))
39+
var yamlMissing, jsonMissing bool
40+
yamlPath := filepath.Join(dir, "sqlc.yaml")
41+
jsonPath := filepath.Join(dir, "sqlc.json")
42+
43+
if _, err := os.Stat(yamlPath); os.IsNotExist(err) {
44+
yamlMissing = true
45+
}
46+
if _, err := os.Stat(jsonPath); os.IsNotExist(err) {
47+
jsonMissing = true
48+
}
49+
50+
if yamlMissing && jsonMissing {
51+
fmt.Fprintln(stderr, "error parsing sqlc.json: file does not exist")
52+
return nil, errors.New("config file missing")
53+
}
54+
55+
if !yamlMissing && !jsonMissing {
56+
fmt.Fprintln(stderr, "error parsing sqlc.json: both files present")
57+
return nil, errors.New("sqlc.json and sqlc.yaml present")
58+
}
59+
60+
configPath := yamlPath
61+
if yamlMissing {
62+
configPath = jsonPath
63+
}
64+
65+
blob, err := ioutil.ReadFile(configPath)
3866
if err != nil {
3967
fmt.Fprintln(stderr, "error parsing sqlc.json: file does not exist")
4068
return nil, err

internal/config/config.go

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package config
22

33
import (
44
"bytes"
5-
"encoding/json"
65
"errors"
76
"fmt"
87
"go/types"
@@ -11,6 +10,8 @@ import (
1110
"strings"
1211

1312
"github.com/kyleconroy/sqlc/internal/pg"
13+
14+
yaml "gopkg.in/yaml.v3"
1415
)
1516

1617
const errMessageNoVersion = `The configuration file must have a version number.
@@ -29,7 +30,7 @@ The only supported version is "1".
2930
const errMessageNoPackages = `No packages are configured`
3031

3132
type versionSetting struct {
32-
Number string `json:"version"`
33+
Number string `json:"version" yaml:"version"`
3334
}
3435

3536
type Engine string
@@ -40,57 +41,57 @@ const (
4041
)
4142

4243
type Config struct {
43-
Version string `json:"version"`
44-
SQL []SQL `json:"sql"`
45-
Gen Gen `json:"overrides,omitempty"`
44+
Version string `json:"version" yaml:"version"`
45+
SQL []SQL `json:"sql" yaml:"sql"`
46+
Gen Gen `json:"overrides,omitempty" yaml:"overrides"`
4647
}
4748

4849
type Gen struct {
49-
Go *GenGo `json:"go,omitempty"`
50+
Go *GenGo `json:"go,omitempty" yaml:"go"`
5051
}
5152

5253
type GenGo struct {
53-
Overrides []Override `json:"overrides,omitempty"`
54-
Rename map[string]string `json:"rename,omitempty"`
54+
Overrides []Override `json:"overrides,omitempty" yaml:"overrides"`
55+
Rename map[string]string `json:"rename,omitempty" yaml:"rename"`
5556
}
5657

5758
type SQL struct {
58-
Engine Engine `json:"engine,omitempty"`
59-
Schema string `json:"schema"`
60-
Queries string `json:"queries"`
61-
Gen SQLGen `json:"gen"`
59+
Engine Engine `json:"engine,omitempty" yaml:"engine"`
60+
Schema string `json:"schema" yaml:"schema"`
61+
Queries string `json:"queries" yaml:"queries"`
62+
Gen SQLGen `json:"gen" yaml:"gen"`
6263
}
6364

6465
type SQLGen struct {
65-
Go *SQLGo `json:"go,omitempty"`
66+
Go *SQLGo `json:"go,omitempty" yaml:"go"`
6667
}
6768

6869
type SQLGo struct {
69-
EmitInterface bool `json:"emit_interface"`
70-
EmitJSONTags bool `json:"emit_json_tags"`
71-
EmitPreparedQueries bool `json:"emit_prepared_queries"`
72-
Package string `json:"package"`
73-
Out string `json:"out"`
74-
Overrides []Override `json:"overrides,omitempty"`
75-
Rename map[string]string `json:"rename,omitempty"`
70+
EmitInterface bool `json:"emit_interface" yaml:"emit_interface"`
71+
EmitJSONTags bool `json:"emit_json_tags" yaml:"emit_json_tags"`
72+
EmitPreparedQueries bool `json:"emit_prepared_queries" yaml:"emit_prepared_queries":`
73+
Package string `json:"package" yaml:"package"`
74+
Out string `json:"out" yaml:"out"`
75+
Overrides []Override `json:"overrides,omitempty" yaml:"overrides"`
76+
Rename map[string]string `json:"rename,omitempty" yaml:"rename"`
7677
}
7778

7879
type Override struct {
7980
// name of the golang type to use, e.g. `github.com/segmentio/ksuid.KSUID`
80-
GoType string `json:"go_type"`
81+
GoType string `json:"go_type" yaml:"go_type"`
8182

8283
// fully qualified name of the Go type, e.g. `github.com/segmentio/ksuid.KSUID`
83-
DBType string `json:"db_type"`
84-
Deprecated_PostgresType string `json:"postgres_type"`
84+
DBType string `json:"db_type" yaml:"db_type"`
85+
Deprecated_PostgresType string `json:"postgres_type" yaml:"postgres_type"`
8586

8687
// for global overrides only when two different engines are in use
87-
Engine Engine `json:"engine,omitempty"`
88+
Engine Engine `json:"engine,omitempty" yaml:"engine"`
8889

8990
// True if the GoType should override if the maching postgres type is nullable
90-
Null bool `json:"null"`
91+
Null bool `json:"null" yaml:"null"`
9192

9293
// fully qualified name of the column, e.g. `accounts.id`
93-
Column string `json:"column"`
94+
Column string `json:"column" yaml:"column"`
9495

9596
ColumnName string
9697
Table pg.FQN
@@ -202,8 +203,9 @@ func ParseConfig(rd io.Reader) (Config, error) {
202203
var buf bytes.Buffer
203204
var config Config
204205
var version versionSetting
206+
205207
ver := io.TeeReader(rd, &buf)
206-
dec := json.NewDecoder(ver)
208+
dec := yaml.NewDecoder(ver)
207209
if err := dec.Decode(&version); err != nil {
208210
return config, err
209211
}

internal/config/config_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ func TestBadConfigs(t *testing.T) {
4646
},
4747
{
4848
"unknown fields",
49-
"json: unknown field \"foo\"",
49+
`yaml: unmarshal errors:
50+
line 3: field foo not found in type config.V1GenerateSettings`,
5051
unknownFields,
5152
},
5253
} {

0 commit comments

Comments
 (0)