Skip to content

MySQL support #230

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 26 commits into from
Jan 7, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
89bb36e
MySQL support (#1)
cmoog Dec 30, 2019
129a851
MySQL (#2) (#2)
cmoog Dec 31, 2019
cdd5f1b
Update README.md
cmoog Dec 31, 2019
4b04203
Merge branch 'master' of https://github.com/kyleconroy/sqlc
cmoog Dec 31, 2019
778e9b6
minimizes diff and fixes bug in Comparable EqualTo method
cmoog Dec 31, 2019
947d824
properly replaces "?" in query string
cmoog Dec 31, 2019
add6ea7
patch test
cmoog Dec 31, 2019
12491c8
adds additional example queries
cmoog Dec 31, 2019
903f87c
adds support for table alias'
cmoog Jan 1, 2020
ea0ac86
allows null returns for left join colums
cmoog Jan 1, 2020
9f31cb9
patches left join nulls and gives example
cmoog Jan 1, 2020
b2c24e7
patches named param replacement
cmoog Jan 1, 2020
e95074e
comments for exported items
cmoog Jan 2, 2020
644f77b
adds a few common col types
cmoog Jan 2, 2020
a65460e
adds support for group _concat
cmoog Jan 2, 2020
5498437
adds support for delete statement
cmoog Jan 2, 2020
d016d47
removes debug logging
cmoog Jan 3, 2020
54c5c49
patches config parsing
cmoog Jan 3, 2020
32de207
patches json tags
cmoog Jan 3, 2020
0438f56
Merge pull request #225 from cmoog/master
kyleconroy Jan 6, 2020
865e3b0
internal/cmd: Add database field to packages
kyleconroy Jan 6, 2020
a0f799c
internal/mysql: Parse a directory of SQL files
kyleconroy Jan 6, 2020
1381ab3
internal/mysql: Parse SQL via sqlparser.Tokenizer
kyleconroy Jan 7, 2020
e6d12d5
internal/mysql: Handle more DDL types
kyleconroy Jan 7, 2020
5d740df
Fix some more one-off errors
kyleconroy Jan 7, 2020
930afe5
/s/database/engine/g
kyleconroy Jan 7, 2020
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
14 changes: 10 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,8 @@ Each package document has the following keys:
- Directory of SQL queries or path to single SQL file
- `schema`:
- Directory of SQL migrations or path to single SQL file
- `engine`:
- Either `postgresql` or `mysql`. Defaults to `postgresql`. MySQL support is experimental

### Type Overrides

Expand Down Expand Up @@ -411,13 +413,17 @@ Each commit is deployed to the [`devel` channel on Equinox](https://dl.equinox.i
- [Linux](https://bin.equinox.io/c/gvM95th6ps1/sqlc-devel-linux-amd64.tgz)
- [macOS](https://bin.equinox.io/c/gvM95th6ps1/sqlc-devel-darwin-amd64.zip)

## Other Database Engines
## Other Databases and Languages

sqlc currently only supports PostgreSQL. If you'd like to support another database, we'd welcome a contribution.
sqlc currently only supports PostgreSQL / Go. MySQL support has been merged,
but it's marked as experimental. SQLite and TypeScript support are planned.

## Other Language Backends
| Language | PostgreSQL | MySQL | SQLite |
| ------------ |:----------------:|:----------------:|:----------------:|
| Go |:white_check_mark:|:warning: |:timer_clock: |
| TypeScript |:timer_clock: |:timer_clock: |:timer_clock: |

sqlc currently only generates Go code, but if you'd like to build another language backend, we'd welcome a contribution.
If you'd like to add another database or language, we'd welcome a contribution.

## Acknowledgements

Expand Down
6 changes: 6 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,10 @@ require (
github.com/jinzhu/inflection v1.0.0
github.com/lfittl/pg_query_go v1.0.0
github.com/spf13/cobra v0.0.5
github.com/spf13/pflag v1.0.5 // indirect
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 // indirect
golang.org/x/sys v0.0.0-20191220220014-0732a990476f // indirect
google.golang.org/genproto v0.0.0-20191223191004-3caeed10a8bf // indirect
google.golang.org/grpc v1.26.0 // indirect
vitess.io/vitess v0.0.0-20191113025808-0629f0da20ab
)
289 changes: 289 additions & 0 deletions go.sum

Large diffs are not rendered by default.

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

"github.com/kyleconroy/sqlc/internal/dinosql"
"github.com/kyleconroy/sqlc/internal/mysql"

"github.com/davecgh/go-spew/spew"
pg "github.com/lfittl/pg_query_go"
Expand Down Expand Up @@ -126,48 +127,57 @@ var genCmd = &cobra.Command{

output := map[string]string{}

for i, pkg := range settings.Packages {
for _, pkg := range settings.Packages {
name := pkg.Name

if pkg.Path == "" {
fmt.Fprintf(os.Stderr, "package[%d]: path must be set\n", i)
errored = true
continue
}
var result dinosql.Generateable

if name == "" {
name = filepath.Base(pkg.Path)
}
switch pkg.Engine {

c, err := dinosql.ParseCatalog(pkg.Schema)
if err != nil {
fmt.Fprintf(os.Stderr, "# package %s\n", name)
if parserErr, ok := err.(*dinosql.ParserErr); ok {
for _, fileErr := range parserErr.Errs {
fmt.Fprintf(os.Stderr, "%s:%d:%d: %s\n", fileErr.Filename, fileErr.Line, fileErr.Column, fileErr.Err)
case dinosql.EngineMySQL:
// Experimental MySQL support
q, err := mysql.GeneratePkg(name, pkg.Schema, pkg.Queries, settings)
if err != nil {
fmt.Fprintf(os.Stderr, "# package %s\n", name)
fmt.Fprintf(os.Stderr, "error parsing file: %s\n", err)
errored = true
continue
}
result = q

case dinosql.EnginePostgreSQL:
c, err := dinosql.ParseCatalog(pkg.Schema)
if err != nil {
fmt.Fprintf(os.Stderr, "# package %s\n", name)
if parserErr, ok := err.(*dinosql.ParserErr); ok {
for _, fileErr := range parserErr.Errs {
fmt.Fprintf(os.Stderr, "%s:%d:%d: %s\n", fileErr.Filename, fileErr.Line, fileErr.Column, fileErr.Err)
}
} else {
fmt.Fprintf(os.Stderr, "error parsing schema: %s\n", err)
}
} else {
fmt.Fprintf(os.Stderr, "error parsing schema: %s\n", err)
errored = true
continue
}
errored = true
continue
}

q, err := dinosql.ParseQueries(c, settings, pkg)
if err != nil {
fmt.Fprintf(os.Stderr, "# package %s\n", name)
if parserErr, ok := err.(*dinosql.ParserErr); ok {
for _, fileErr := range parserErr.Errs {
fmt.Fprintf(os.Stderr, "%s:%d:%d: %s\n", fileErr.Filename, fileErr.Line, fileErr.Column, fileErr.Err)
q, err := dinosql.ParseQueries(c, pkg)
if err != nil {
fmt.Fprintf(os.Stderr, "# package %s\n", name)
if parserErr, ok := err.(*dinosql.ParserErr); ok {
for _, fileErr := range parserErr.Errs {
fmt.Fprintf(os.Stderr, "%s:%d:%d: %s\n", fileErr.Filename, fileErr.Line, fileErr.Column, fileErr.Err)
}
} else {
fmt.Fprintf(os.Stderr, "error parsing queries: %s\n", err)
}
} else {
fmt.Fprintf(os.Stderr, "error parsing queries: %s\n", err)
errored = true
continue
}
errored = true
continue
result = q

}

files, err := dinosql.Generate(q, settings, pkg)
files, err := dinosql.Generate(result, settings)
if err != nil {
fmt.Fprintf(os.Stderr, "# package %s\n", name)
fmt.Fprintf(os.Stderr, "error generating code: %s\n", err)
Expand Down Expand Up @@ -199,13 +209,13 @@ var checkCmd = &cobra.Command{
Use: "compile",
Short: "Statically check SQL for syntax and type errors",
RunE: func(cmd *cobra.Command, args []string) error {
blob, err := ioutil.ReadFile("sqlc.json")
file, err := os.Open("sqlc.json")
if err != nil {
return err
}

var settings dinosql.GenerateSettings
if err := json.Unmarshal(blob, &settings); err != nil {
settings, err := dinosql.ParseConfig(file)
if err != nil {
return err
}

Expand All @@ -214,7 +224,7 @@ var checkCmd = &cobra.Command{
if err != nil {
return err
}
if _, err := dinosql.ParseQueries(c, settings, pkg); err != nil {
if _, err := dinosql.ParseQueries(c, pkg); err != nil {
return err
}
}
Expand Down
1 change: 0 additions & 1 deletion internal/dinosql/checks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import (
func TestFuncs(t *testing.T) {
_, err := ParseQueries(
pg.NewCatalog(),
GenerateSettings{},
PackageSettings{
Queries: filepath.Join("testdata", "funcs"),
},
Expand Down
62 changes: 57 additions & 5 deletions internal/dinosql/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,45 @@ import (
"errors"
"fmt"
"io"
"path/filepath"
"strings"

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

const errMessageNoVersion = `The configuration file must have a version number.
Set the version to 1 at the top of sqlc.json:

{
"version": "1"
...
}
`

const errMessageUnknownVersion = `The configuration file has an invalid version number.
The only supported version is "1".
`

const errMessageNoPackages = `No packages are configured`

type GenerateSettings struct {
Version string `json:"version"`
Packages []PackageSettings `json:"packages"`
Overrides []Override `json:"overrides,omitempty"`
Rename map[string]string `json:"rename,omitempty"`
Version string `json:"version"`
Packages []PackageSettings `json:"packages"`
Overrides []Override `json:"overrides,omitempty"`
Rename map[string]string `json:"rename,omitempty"`
PackageMap map[string]PackageSettings
}

type Engine string

const (
EngineMySQL Engine = "mysql"
EnginePostgreSQL Engine = "postgresql"
)

type PackageSettings struct {
Name string `json:"name"`
Engine Engine `json:"engine,omitempty"`
Path string `json:"path"`
Schema string `json:"schema"`
Queries string `json:"queries"`
Expand Down Expand Up @@ -96,6 +121,8 @@ func (o *Override) Parse() error {
var ErrMissingVersion = errors.New("no version number")
var ErrUnknownVersion = errors.New("invalid version number")
var ErrNoPackages = errors.New("no packages")
var ErrNoPackageName = errors.New("missing package name")
var ErrNoPackagePath = errors.New("missing package path")

func ParseConfig(rd io.Reader) (GenerateSettings, error) {
dec := json.NewDecoder(rd)
Expand All @@ -119,11 +146,36 @@ func ParseConfig(rd io.Reader) (GenerateSettings, error) {
}
}
for j := range config.Packages {
if config.Packages[j].Path == "" {
return config, ErrNoPackagePath
}
for i := range config.Packages[j].Overrides {
if err := config.Packages[j].Overrides[i].Parse(); err != nil {
return config, err
}
}
if config.Packages[j].Name == "" {
config.Packages[j].Name = filepath.Base(config.Packages[j].Path)
}
if config.Packages[j].Engine == "" {
config.Packages[j].Engine = EnginePostgreSQL
}
}
return config, nil
err := config.PopulatePkgMap()

return config, err
}

func (s *GenerateSettings) PopulatePkgMap() error {
packageMap := make(map[string]PackageSettings)

for _, c := range s.Packages {
if c.Name == "" {
return ErrNoPackageName
}
packageMap[c.Name] = c
}
s.PackageMap = packageMap

return nil
}
Loading