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
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
var (
|
||||
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")
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
files, err := filepath.Glob(*input)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
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)
|
||||
app := cli.NewApp()
|
||||
app.Name = "sqlbin"
|
||||
app.Usage = "sqlbin provides command line tools for generating embedded sql opterations"
|
||||
app.Version = "1.0.0-alpha"
|
||||
app.Commands = []cli.Command{
|
||||
ddlCommand,
|
||||
sqlCommand,
|
||||
}
|
||||
|
||||
buf.Reset()
|
||||
err = generate(&buf, *pkgname, stmts)
|
||||
if err != nil {
|
||||
if err := app.Run(os.Args); err != nil {
|
||||
fmt.Println(err)
|
||||
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 (
|
||||
"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