refactor
parent
d0e92aab08
commit
ad6a7de082
@ -1,22 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/urfave/cli"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
app := cli.NewApp()
|
|
||||||
app.Name = "sqlbin"
|
|
||||||
app.Usage = "sqlbin provides command line tools for generating embedded sql opterations"
|
|
||||||
app.Commands = []cli.Command{
|
|
||||||
ddlCommand,
|
|
||||||
sqlCommand,
|
|
||||||
}
|
|
||||||
if err := app.Run(os.Args); err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
)
|
|
||||||
|
|
||||||
// format formats a template using gofmt.
|
|
||||||
func format(in io.Reader) (io.Reader, error) {
|
|
||||||
var out bytes.Buffer
|
|
||||||
|
|
||||||
gofmt := exec.Command("gofmt", "-s")
|
|
||||||
gofmt.Stdin = in
|
|
||||||
gofmt.Stdout = &out
|
|
||||||
gofmt.Stderr = os.Stderr
|
|
||||||
err := gofmt.Run()
|
|
||||||
return &out, err
|
|
||||||
}
|
|
@ -1,72 +1,23 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
"github.com/urfave/cli"
|
||||||
input = flag.String("input", "", "input file name; required")
|
|
||||||
output = flag.String("o", "", "output file name; required")
|
|
||||||
pkgname = flag.String("pkg", "main", "output package name; required")
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
flag.Parse()
|
app := cli.NewApp()
|
||||||
|
app.Name = "sqlbin"
|
||||||
files, err := filepath.Glob(*input)
|
app.Usage = "sqlbin provides command line tools for generating embedded sql opterations"
|
||||||
if err != nil {
|
app.Version = "1.0.0-alpha"
|
||||||
fmt.Println(err)
|
app.Commands = []cli.Command{
|
||||||
os.Exit(1)
|
ddlCommand,
|
||||||
}
|
sqlCommand,
|
||||||
|
|
||||||
var buf bytes.Buffer
|
|
||||||
for _, file := range files {
|
|
||||||
out, ferr := ioutil.ReadFile(file)
|
|
||||||
if ferr != nil {
|
|
||||||
fmt.Println(ferr)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
buf.Write(out)
|
|
||||||
}
|
|
||||||
|
|
||||||
// parses the sql statements from the file.
|
|
||||||
stmts, err := parse(&buf)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
|
if err := app.Run(os.Args); err != nil {
|
||||||
buf.Reset()
|
|
||||||
err = generate(&buf, *pkgname, stmts)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// formats the generated file using gofmt
|
|
||||||
pretty, err := format(&buf)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "%v\n", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// create output source for file. defaults to
|
|
||||||
// stdout but may be file.
|
|
||||||
var out = os.Stdout
|
|
||||||
if *output != "" {
|
|
||||||
out, err = os.Create(*output)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "%v\n", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer out.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
io.Copy(out, pretty)
|
|
||||||
}
|
}
|
||||||
|
@ -1,54 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
prefix = "-- +statement "
|
|
||||||
comment = "--"
|
|
||||||
newline = "\n"
|
|
||||||
)
|
|
||||||
|
|
||||||
type statement struct {
|
|
||||||
Name string
|
|
||||||
Value string
|
|
||||||
Driver string
|
|
||||||
}
|
|
||||||
|
|
||||||
func parse(r io.Reader) ([]*statement, error) {
|
|
||||||
var (
|
|
||||||
stmts []*statement
|
|
||||||
stmt *statement
|
|
||||||
)
|
|
||||||
scanner := bufio.NewScanner(r)
|
|
||||||
for scanner.Scan() {
|
|
||||||
line := scanner.Text()
|
|
||||||
|
|
||||||
if strings.HasPrefix(line, prefix) {
|
|
||||||
stmt = new(statement)
|
|
||||||
stmt.Name, stmt.Driver = parsePrefix(line)
|
|
||||||
stmts = append(stmts, stmt)
|
|
||||||
}
|
|
||||||
if strings.HasPrefix(line, comment) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if stmt != nil {
|
|
||||||
stmt.Value += line + newline
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, stmt := range stmts {
|
|
||||||
stmt.Value = strings.TrimSpace(stmt.Value)
|
|
||||||
}
|
|
||||||
return stmts, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func parsePrefix(line string) (name string, driver string) {
|
|
||||||
line = strings.TrimPrefix(line, prefix)
|
|
||||||
line = strings.TrimSpace(line)
|
|
||||||
fmt.Sscanln(line, &name, &driver)
|
|
||||||
return
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
package parse
|
|
@ -1,48 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestParse(t *testing.T) {
|
|
||||||
stmts, err := parse(strings.NewReader(example))
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
enc := json.NewEncoder(os.Stderr)
|
|
||||||
enc.SetIndent("", " ")
|
|
||||||
enc.SetEscapeHTML(false)
|
|
||||||
enc.Encode(stmts)
|
|
||||||
}
|
|
||||||
|
|
||||||
var example = `
|
|
||||||
|
|
||||||
--
|
|
||||||
-- +statement select-pets
|
|
||||||
--
|
|
||||||
|
|
||||||
select *
|
|
||||||
from pets
|
|
||||||
{{ if .Type }}
|
|
||||||
WHERE type = ?
|
|
||||||
{{ else if .MaxPrice }}
|
|
||||||
WHERE price <= ?
|
|
||||||
{{ end }}
|
|
||||||
|
|
||||||
-- +statement select-pets-by-id
|
|
||||||
|
|
||||||
select *
|
|
||||||
from pets
|
|
||||||
where id = ?
|
|
||||||
|
|
||||||
-- +statement select-pets-by-type postgres
|
|
||||||
|
|
||||||
select *
|
|
||||||
from pets
|
|
||||||
where type = $1
|
|
||||||
|
|
||||||
`
|
|
@ -1,4 +1,4 @@
|
|||||||
package parse
|
package parser
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
@ -0,0 +1 @@
|
|||||||
|
package parser
|
@ -1,197 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
"strings"
|
|
||||||
"text/template"
|
|
||||||
)
|
|
||||||
|
|
||||||
var funcs = map[string]interface{}{
|
|
||||||
"join": func(a, b string) string {
|
|
||||||
if b == "" {
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
return strings.Join([]string{a, b}, "-")
|
|
||||||
},
|
|
||||||
"camelize": camelize,
|
|
||||||
}
|
|
||||||
|
|
||||||
type data struct {
|
|
||||||
Package string
|
|
||||||
Labels []string
|
|
||||||
Statements []*statement
|
|
||||||
}
|
|
||||||
|
|
||||||
func generate(w io.Writer, pkg string, stmts []*statement) error {
|
|
||||||
t, err := template.New("_").Funcs(funcs).Parse(text)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
set := map[string]string{}
|
|
||||||
for _, stmt := range stmts {
|
|
||||||
if stmt.Driver != "" {
|
|
||||||
set[stmt.Driver] = stmt.Driver
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var labels []string
|
|
||||||
for k := range set {
|
|
||||||
labels = append(labels, k)
|
|
||||||
}
|
|
||||||
return t.Execute(w, data{
|
|
||||||
Package: pkg,
|
|
||||||
Labels: labels,
|
|
||||||
Statements: stmts,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
var text = `
|
|
||||||
package {{ .Package }}
|
|
||||||
|
|
||||||
// THIS FILE WAS AUTO-GENERATED. DO NOT MODIFY.
|
|
||||||
|
|
||||||
// Lookup returns the named statement.
|
|
||||||
func Lookup(name string) (string) {
|
|
||||||
return index[name]
|
|
||||||
}
|
|
||||||
|
|
||||||
{{ if .Labels }}
|
|
||||||
// LookupTag returns the named statement by tag.
|
|
||||||
func LookupTag(name, tag string) (string) {
|
|
||||||
switch tag {
|
|
||||||
{{- range .Labels }}
|
|
||||||
case {{ printf "%q" . }}:
|
|
||||||
return {{ . }}Index[name]
|
|
||||||
{{- end }}
|
|
||||||
default:
|
|
||||||
return index[name]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{{ end }}
|
|
||||||
|
|
||||||
var index = map[string]string{
|
|
||||||
{{- range $i, $stmt := .Statements -}}
|
|
||||||
{{- if not .Driver }}
|
|
||||||
{{- $name := join .Name .Driver }}
|
|
||||||
{{ printf "%q" $stmt.Name }}: {{ camelize $name }},
|
|
||||||
{{- end -}}
|
|
||||||
{{ end }}
|
|
||||||
}
|
|
||||||
|
|
||||||
{{ $statements := .Statements }}
|
|
||||||
{{ range $ii, $label := .Labels }}
|
|
||||||
var {{ $label }}Index = map[string]string{
|
|
||||||
{{- range $i, $stmt := $statements -}}
|
|
||||||
{{- if eq $label $stmt.Driver }}
|
|
||||||
{{- $name := join .Name .Driver }}
|
|
||||||
{{ printf "%q" $stmt.Name }}: {{ camelize $name }},
|
|
||||||
{{ end -}}
|
|
||||||
{{- end -}}
|
|
||||||
}
|
|
||||||
{{ end }}
|
|
||||||
|
|
||||||
{{ range .Statements -}}
|
|
||||||
{{ $name := join .Name .Driver }}
|
|
||||||
var {{ camelize $name }} = ` + "`" + "\n{{.Value }}\n" + "`" + `
|
|
||||||
|
|
||||||
{{ end }}
|
|
||||||
`
|
|
||||||
|
|
||||||
func camelize(kebab string) (camelCase string) {
|
|
||||||
isToUpper := false
|
|
||||||
for _, runeValue := range kebab {
|
|
||||||
if isToUpper {
|
|
||||||
camelCase += strings.ToUpper(string(runeValue))
|
|
||||||
isToUpper = false
|
|
||||||
} else {
|
|
||||||
if runeValue == '-' {
|
|
||||||
isToUpper = true
|
|
||||||
} else {
|
|
||||||
camelCase += string(runeValue)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// old version of template
|
|
||||||
|
|
||||||
var textBackup = `
|
|
||||||
package {{ .Package }}
|
|
||||||
|
|
||||||
import "text/template"
|
|
||||||
|
|
||||||
type statement struct {
|
|
||||||
name string
|
|
||||||
value string
|
|
||||||
templ *template.Template
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
for _, s := range statements {
|
|
||||||
s.templ = template.Must(
|
|
||||||
template.New(s.name).Parse(s.value),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Lookup returns the named statement.
|
|
||||||
func Lookup(name string) (s string) {
|
|
||||||
stmt, ok := index[name]
|
|
||||||
if ok {
|
|
||||||
return stmt.value
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// LookupTag returns the named statement by tag.
|
|
||||||
func LookupTag(name, tag string) (s string) {
|
|
||||||
switch tag {
|
|
||||||
{{- range .Labels }}
|
|
||||||
case {{ printf "%q" . }}:
|
|
||||||
stmt, ok := {{ . }}Index[name]
|
|
||||||
if ok {
|
|
||||||
return stmt.value
|
|
||||||
}
|
|
||||||
{{- end }}
|
|
||||||
default:
|
|
||||||
// no-op
|
|
||||||
}
|
|
||||||
// fallback to default statement
|
|
||||||
return Lookup(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
var statements = []*statement{
|
|
||||||
{{ range .Statements -}}
|
|
||||||
{{ $name := join .Name .Driver -}}
|
|
||||||
{
|
|
||||||
name: {{ printf "%q" .Name }},
|
|
||||||
value: {{ camelize $name }},
|
|
||||||
},
|
|
||||||
{{ end }}
|
|
||||||
}
|
|
||||||
|
|
||||||
var index = map[string]*statement{
|
|
||||||
{{- range $i, $stmt := .Statements -}}
|
|
||||||
{{- if not .Driver }}
|
|
||||||
{{ printf "%q" $stmt.Name }}: statements[{{$i}}],
|
|
||||||
{{- end -}}
|
|
||||||
{{ end }}
|
|
||||||
}
|
|
||||||
|
|
||||||
{{ $statements := .Statements }}
|
|
||||||
{{ range $ii, $label := .Labels }}
|
|
||||||
var {{ $label }}Index = map[string]*statement{
|
|
||||||
{{- range $i, $stmt := $statements -}}
|
|
||||||
{{- if eq $label $stmt.Driver }}
|
|
||||||
{{ printf "%q" $stmt.Name }}: statements[{{$i}}],
|
|
||||||
{{ end -}}
|
|
||||||
{{- end -}}
|
|
||||||
}
|
|
||||||
{{ end }}
|
|
||||||
|
|
||||||
{{ range .Statements -}}
|
|
||||||
{{ $name := join .Name .Driver }}
|
|
||||||
var {{ camelize $name }} = ` + "`" + "\n{{.Value }}\n" + "`" + `
|
|
||||||
|
|
||||||
{{ end }}
|
|
||||||
`
|
|
Loading…
Reference in New Issue