Browse Source

init project

pull/6/head
Lunny Xiao 6 months ago
commit
312f37f563
Signed by: lunny <xiaolunwen@gmail.com> GPG Key ID: C3B7C91B632F738A
19 changed files with 1181 additions and 0 deletions
  1. +9
    -0
      .drone.yml
  2. +1
    -0
      .gitignore
  3. +27
    -0
      LICENSE
  4. +83
    -0
      README.md
  5. +83
    -0
      README_CN.md
  6. +328
    -0
      cmd/reverse.go
  7. +33
    -0
      cmd/reverse_test.go
  8. +49
    -0
      cmd/root.go
  9. +35
    -0
      example/custom.yml
  10. +14
    -0
      example/goxorm.yml
  11. +16
    -0
      example/template/go.tmpl
  12. +16
    -0
      example/template/goxorm.tmpl
  13. +17
    -0
      go.mod
  14. +176
    -0
      go.sum
  15. +233
    -0
      language/golang.go
  16. +35
    -0
      language/language.go
  17. +17
    -0
      main.go
  18. +9
    -0
      models/models.go
  19. BIN
      testdata/test.db

+ 9
- 0
.drone.yml View File

@@ -0,0 +1,9 @@
kind: pipeline
name: default

steps:
- name: test
image: golang:1.12
commands:
- go build
- go test -v -race -coverprofile=coverage.txt -covermode=atomic ./...

+ 1
- 0
.gitignore View File

@@ -0,0 +1 @@
reverse

+ 27
- 0
LICENSE View File

@@ -0,0 +1,27 @@
Copyright (c) 2019 The Xorm Authors
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

* Neither the name of the {organization} nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 83
- 0
README.md View File

@@ -0,0 +1,83 @@
# Reverse

A flexsible and powerful command line tool to convert database to codes.

## Installation

```
go get xorm.io/reverse
```

## Usage

```
reverse -f example/custom.yml
```

## Configuration File

How does the simplest configuration file look like?

```yml
kind: reverse
name: mydb
source:
database: sqlite3
conn_str: '../testdata/test.db'
targets:
- type: codes
language: golang
output_dir: ../models
```

A `language` defines some default configuration items, also you can define all yourselves.

```yml
kind: reverse
name: mydb
source:
database: sqlite
conn_str: ../testdata/test.db
targets:
- type: codes
include_tables: # tables included, you can use **
- a
- b
exclude_tables: # tables excluded, you can use **
- c
table_mapper: snake # how table name map to class or struct name
column_mapper: snake # how column name map to class or struct field name
table_prefix: "" # table prefix
multiple_files: true # generate multiple files or one
template: | # template for code file, it has higher perior than template_path
package models

{{$ilen := len .Imports}}
{{if gt $ilen 0}}
import (
{{range .Imports}}"{{.}}"{{end}}
)
{{end}}

{{range .Tables}}
type {{TableMapper .Name}} struct {
{{$table := .}}
{{range .ColumnsSeq}}{{$col := $table.GetColumn .}} {{ColumnMapper $col.Name}} {{Type $col}} `{{Tag $table $col}}`
{{end}}
}
{{end}}
template_path: ./template/goxorm.tmpl # template path for code file, it has higher perior than template field on language
output_dir: ./models # code output directory
```

## Template Funcs

- *UnTitle*: Convert first charator of the word to lower.
- *Upper*: Convert word to all upper.
- *TableMapper*: Mapper method to convert table name to class/struct name.
- *ColumnMapper*: Mapper method to convert column name to class/struct field name.

## Template Vars

- *Tables*: All tables.
- *Imports*: All imports needed.

+ 83
- 0
README_CN.md View File

@@ -0,0 +1,83 @@
# Reverse

一个灵活高效的数据库反转工具。

## 安装

```
go get xorm.io/reverse
```

## 使用

```
reverse -f example/custom.yml
```

## 配置文件

一个最简单的配置文件看起来如下:

```yml
kind: reverse
name: mydb
source:
database: sqlite3
conn_str: '../testdata/test.db'
targets:
- type: codes
language: golang
output_dir: ../models
```

`language` 定义了很多默认的配置,你也可以自己来进行配置。其中的模板是 Go 模板语法。

```yml
kind: reverse
name: mydb
source:
database: sqlite
conn_str: ../testdata/test.db
targets:
- type: codes
include_tables: # 包含的表,以下可以用 **
- a
- b
exclude_tables: # 排除的表,以下可以用 **
- c
table_mapper: snake # 表名到代码类或结构体的映射关系
column_mapper: snake # 字段名到代码或结构体成员的映射关系
table_prefix: "" # 表前缀
multiple_files: true # 是否生成多个文件
template: | # 生成模板,如果这里定义了,优先级比 template_path 高
package models

{{$ilen := len .Imports}}
{{if gt $ilen 0}}
import (
{{range .Imports}}"{{.}}"{{end}}
)
{{end}}

{{range .Tables}}
type {{TableMapper .Name}} struct {
{{$table := .}}
{{range .ColumnsSeq}}{{$col := $table.GetColumn .}} {{ColumnMapper $col.Name}} {{Type $col}} `{{Tag $table $col}}`
{{end}}
}
{{end}}
template_path: ./template/goxorm.tmpl # 生成的模板的路径,优先级比 template 低,但比 language 中的默认模板高
output_dir: ./models # 代码生成目录
```

## 模板函数

- *UnTitle*: 将单词的第一个字母大写。
- *Upper*: 将单词转为全部大写。
- *TableMapper*: 将表名转为结构体名的映射函数。
- *ColumnMapper*: 将字段名转为结构体成员名的函数。

## 模板变量

- *Tables*: 所有表。
- *Imports*: 所有需要的导入。

+ 328
- 0
cmd/reverse.go View File

@@ -0,0 +1,328 @@
// Copyright 2019 The Xorm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package cmd

import (
"bytes"
"errors"
"html/template"
"io/ioutil"
"os"
"path/filepath"
"strings"

"xorm.io/reverse/language"

"gitea.com/lunny/log"
_ "github.com/denisenkom/go-mssqldb"
_ "github.com/go-sql-driver/mysql"
"github.com/gobwas/glob"
_ "github.com/lib/pq"
_ "github.com/mattn/go-sqlite3"
"gopkg.in/yaml.v2"
"xorm.io/core"
"xorm.io/xorm"
)

func reverse(rFile string) error {
f, err := os.Open(rFile)
if err != nil {
return err
}
defer f.Close()

var cfg ReverseConfig
err = yaml.NewDecoder(f).Decode(&cfg)
if err != nil {
return err
}
for _, target := range cfg.Targets {
if err := runReverse(&cfg.Source, &target); err != nil {
return err
}
}

return nil
}

type ReverseSource struct {
Database string `yaml:"database"`
ConnStr string `yaml:"conn_str"`
}

// ReverseTarget represents a reverse target
type ReverseTarget struct {
Type string `yaml:"type"`
IncludeTables []string `yaml:"include_tables"`
ExcludeTables []string `yaml:"exclude_tables"`
TableMapper string `yaml:"table_mapper"`
ColumnMapper string `yaml:"column_mapper"`
TemplatePath string `yaml:"template_path"`
Template string `yaml:"template"`
MultipleFiles bool `yaml:"multiple_files"`
OutputDir string `yaml:"output_dir"`
TablePrefix string `yaml:"table_prefix"`
Language string `yaml:"language"`

Funcs map[string]string `yaml:"funcs"`
Formatter string `yaml:"formatter"`
Importter string `yaml:"importter"`
ExtName string `yaml:"ext_name"`
}

// ReverseConfig represents a reverse configuration
type ReverseConfig struct {
Kind string `yaml:"kind"`
Name string `yaml:"name"`
Source ReverseSource `yaml:"source"`
Targets []ReverseTarget `yaml:"targets"`
}

var (
formatters = map[string]func(string) (string, error){}
importters = map[string]func([]*core.Table) []string{}
defaultFuncs = template.FuncMap{
"UnTitle": unTitle,
"Upper": upTitle,
}
)

func unTitle(src string) string {
if src == "" {
return ""
}

if len(src) == 1 {
return strings.ToLower(string(src[0]))
} else {
return strings.ToLower(string(src[0])) + src[1:]
}
}

func upTitle(src string) string {
if src == "" {
return ""
}

return strings.ToUpper(src)
}

func filterTables(tables []*core.Table, target *ReverseTarget) []*core.Table {
var res = make([]*core.Table, 0, len(tables))
for _, tb := range tables {
var remove bool
for _, exclude := range target.ExcludeTables {
s, _ := glob.Compile(exclude)
remove = s.Match(tb.Name)
if remove {
break
}
}
if remove {
continue
}
if len(target.IncludeTables) == 0 {
res = append(res, tb)
continue
}

var keep bool
for _, include := range target.IncludeTables {
s, _ := glob.Compile(include)
keep = s.Match(tb.Name)
if keep {
break
}
}
if keep {
res = append(res, tb)
}
}
return res
}

func newFuncs() template.FuncMap {
var m = make(template.FuncMap)
for k, v := range defaultFuncs {
m[k] = v
}
return m
}

func runReverse(source *ReverseSource, target *ReverseTarget) error {
orm, err := xorm.NewEngine(source.Database, source.ConnStr)
if err != nil {
return err
}

tables, err := orm.DBMetas()
if err != nil {
return err
}

// filter tables according includes and excludes
tables = filterTables(tables, target)

// load configuration from language
lang := language.GetLanguage(target.Language)
funcs := newFuncs()
formatter := formatters[target.Formatter]
importter := importters[target.Importter]

// load template
var bs []byte
if target.Template != "" {
bs = []byte(target.Template)
} else if target.TemplatePath != "" {
bs, err = ioutil.ReadFile(target.TemplatePath)
if err != nil {
return err
}
}

if lang != nil {
if bs == nil {
bs = []byte(lang.Template)
}
for k, v := range lang.Funcs {
funcs[k] = v
}
if formatter == nil {
formatter = lang.Formatter
}
if importter == nil {
importter = lang.Importter
}
target.ExtName = lang.ExtName
}
if !strings.HasPrefix(target.ExtName, ".") {
target.ExtName = "." + target.ExtName
}

var tableMapper, colMapper core.IMapper
switch target.TableMapper {
case "gonic":
tableMapper = core.LintGonicMapper
case "same":
tableMapper = core.SameMapper{}
default:
tableMapper = core.SnakeMapper{}
}
switch target.ColumnMapper {
case "gonic":
colMapper = core.LintGonicMapper
case "same":
colMapper = core.SameMapper{}
default:
colMapper = core.SnakeMapper{}
}
funcs["TableMapper"] = tableMapper.Table2Obj
funcs["ColumnMapper"] = colMapper.Table2Obj

if bs == nil {
return errors.New("You have to indicate template / template path or a language")
}

t := template.New("reverse")
t.Funcs(funcs)

tmpl, err := t.Parse(string(bs))
if err != nil {
return err
}

for _, table := range tables {
if target.TablePrefix != "" {
table.Name = strings.TrimPrefix(table.Name, target.TablePrefix)
}
for _, col := range table.Columns() {
col.FieldName = colMapper.Table2Obj(col.Name)
}
}

err = os.MkdirAll(target.OutputDir, os.ModePerm)
if err != nil {
return err
}

var w *os.File
if !target.MultipleFiles {
w, err = os.Create(filepath.Join(target.OutputDir, "models"+target.ExtName))
if err != nil {
return err
}
defer w.Close()

imports := importter(tables)

newbytes := bytes.NewBufferString("")
err = tmpl.Execute(newbytes, map[string]interface{}{
"Tables": tables,
"Imports": imports,
})
if err != nil {
return err
}

tplcontent, err := ioutil.ReadAll(newbytes)
if err != nil {
return err
}
var source string
if formatter != nil {
source, err = formatter(string(tplcontent))
if err != nil {
log.Warnf("%v", err)
source = string(tplcontent)
}
} else {
source = string(tplcontent)
}

w.WriteString(source)
w.Close()
} else {
for _, table := range tables {
// imports
tbs := []*core.Table{table}
imports := importter(tbs)

w, err := os.Create(filepath.Join(target.OutputDir, table.Name+target.ExtName))
if err != nil {
return err
}
defer w.Close()

newbytes := bytes.NewBufferString("")
err = tmpl.Execute(newbytes, map[string]interface{}{
"Tables": tbs,
"Imports": imports,
})
if err != nil {
return err
}

tplcontent, err := ioutil.ReadAll(newbytes)
if err != nil {
return err
}
var source string
if formatter != nil {
source, err = formatter(string(tplcontent))
if err != nil {
log.Warnf("%v", err)
source = string(tplcontent)
}
} else {
source = string(tplcontent)
}

w.WriteString(source)
w.Close()
}
}

return nil
}

+ 33
- 0
cmd/reverse_test.go View File

@@ -0,0 +1,33 @@
// Copyright 2019 The Xorm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package cmd

import (
"fmt"
"io/ioutil"
"testing"

"github.com/stretchr/testify/assert"
)

var result = fmt.Sprintf(`package models

type A struct {
Id int %sxorm:"integer"%s
}

type B struct {
Id int %sxorm:"INTEGER"%s
}
`, "`", "`", "`", "`")

func TestReverse(t *testing.T) {
err := reverse("../example/goxorm.yml")
assert.NoError(t, err)

bs, err := ioutil.ReadFile("../models/models.go")
assert.NoError(t, err)
assert.EqualValues(t, result, string(bs))
}

+ 49
- 0
cmd/root.go View File

@@ -0,0 +1,49 @@
// Copyright 2019 The Xorm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package cmd

import (
"fmt"

"github.com/spf13/cobra"
)

var (
Version = "0.1+dev"

reverseFile string
versionFlag *bool

rootCmd = &cobra.Command{
Version: Version,
Use: "reverse",
Short: "Reverse is a database reverse command line tool",
Long: `A flexsible and powerful command line tool to generate codes/docs from databases(SQLITE/Mysql/Postgres/MSSQL)`,
Run: func(cmd *cobra.Command, args []string) {
if versionFlag != nil && *versionFlag {
fmt.Printf("Reverse %s\n", Version)
return
}
if reverseFile == "" {
fmt.Println("Need reverse file")
return
}

err := reverse(reverseFile)
if err != nil {
fmt.Println(err)
}
},
}
)

func init() {
versionFlag = rootCmd.Flags().BoolP("version", "v", false, "version of the tool")
rootCmd.Flags().StringVarP(&reverseFile, "file", "f", "", "yml file to apply for reverse")
}

func Execute() error {
return rootCmd.Execute()
}

+ 35
- 0
example/custom.yml View File

@@ -0,0 +1,35 @@
kind: reverse
name: mydb
source:
database: sqlite
conn_str: ../testdata/test.db
targets:
- type: codes
include_tables:
- a
- b
exclude_tables:
- c
table_mapper: snake
column_mapper: snake
table_prefix: ""
multiple_files: true
template: |
package models

{{$ilen := len .Imports}}
{{if gt $ilen 0}}
import (
{{range .Imports}}"{{.}}"{{end}}
)
{{end}}

{{range .Tables}}
type {{TableMapper .Name}} struct {
{{$table := .}}
{{range .ColumnsSeq}}{{$col := $table.GetColumn .}} {{ColumnMapper $col.Name}} {{Type $col}} `{{Tag $table $col}}`
{{end}}
}
{{end}}
template_path: ./template/goxorm.tmpl
output_dir: ./models

+ 14
- 0
example/goxorm.yml View File

@@ -0,0 +1,14 @@
kind: reverse
name: mydb
source:
database: sqlite3
conn_str: '../testdata/test.db'
targets:
- type: codes
include_tables:
- a
- b
exclude_tables:
- c
language: golang
output_dir: ../models

+ 16
- 0
example/template/go.tmpl View File

@@ -0,0 +1,16 @@
package models

{{$ilen := len .Imports}}
{{if gt $ilen 0}}
import (
{{range .Imports}}"{{.}}"{{end}}
)
{{end}}

{{range .Tables}}
type {{TableMapper .Name}} struct {
{{$table := .}}
{{range .ColumnsSeq}}{{$col := $table.GetColumn .}} {{ColumnMapper $col.Name}} {{Type $col}}
{{end}}
}
{{end}}

+ 16
- 0
example/template/goxorm.tmpl View File

@@ -0,0 +1,16 @@
package models

{{$ilen := len .Imports}}
{{if gt $ilen 0}}
import (
{{range .Imports}}"{{.}}"{{end}}
)
{{end}}

{{range .Tables}}
type {{TableMapper .Name}} struct {
{{$table := .}}
{{range .ColumnsSeq}}{{$col := $table.GetColumn .}} {{ColumnMapper $col.Name}} {{Type $col}} `{{Tag $table $col}}`
{{end}}
}
{{end}}

+ 17
- 0
go.mod View File

@@ -0,0 +1,17 @@
module xorm.io/reverse

go 1.13

require (
gitea.com/lunny/log v0.0.0-20190322053110-01b5df579c4e
github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4
github.com/go-sql-driver/mysql v1.4.1
github.com/gobwas/glob v0.2.3
github.com/lib/pq v1.0.0
github.com/mattn/go-sqlite3 v1.10.0
github.com/spf13/cobra v0.0.5
github.com/stretchr/testify v1.4.0
gopkg.in/yaml.v2 v2.2.2
xorm.io/core v0.7.2
xorm.io/xorm v0.8.1
)

+ 176
- 0
go.sum View File

@@ -0,0 +1,176 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.37.4 h1:glPeL3BQJsbF6aIIYfZizMwc5LTYz250bDMjttbBGAU=
cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw=
gitea.com/lunny/log v0.0.0-20190322053110-01b5df579c4e h1:r1en/D7xJmcY24VkHkjkcJFa+7ZWubVWPBrvsHkmHxk=
gitea.com/lunny/log v0.0.0-20190322053110-01b5df579c4e/go.mod h1:uJEsN4LQpeGYRCjuPXPZBClU7N5pWzGuyF4uqLpE/e0=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4 h1:YcpmyvADGYw5LqMnHqSkyIELsHCGF6PkrmM31V8rF7o=
github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM=
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/go-flutter-desktop/hover v0.37.0 h1:sO6M+HpegV3u2ihKtlyF4Xlc1xR54iUdqC2LIMs0sWc=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM=
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o=
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s=
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs=
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c h1:Vj5n4GlwjmQteupaxJ9+0FNOmBrHfq7vN4btdGoDZgI=
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
xorm.io/builder v0.3.6 h1:ha28mQ2M+TFx96Hxo+iq6tQgnkC9IZkM6D8w9sKHHF8=
xorm.io/builder v0.3.6/go.mod h1:LEFAPISnRzG+zxaxj2vPicRwz67BdhFreKg8yv8/TgU=
xorm.io/core v0.7.2 h1:mEO22A2Z7a3fPaZMk6gKL/jMD80iiyNwRrX5HOv3XLw=
xorm.io/core v0.7.2/go.mod h1:jJfd0UAEzZ4t87nbQYtVjmqpIODugN6PD2D9E+dJvdM=
xorm.io/xorm v0.8.1 h1:4f2KXuQxVdaX3RdI3Fw81NzMiSpZeyCZt8m3sEVeIkQ=
xorm.io/xorm v0.8.1/go.mod h1:ZkJLEYLoVyg7amJK/5r779bHyzs2AU8f8VMiP6BM7uY=

+ 233
- 0
language/golang.go View File

@@ -0,0 +1,233 @@
// Copyright 2019 The Xorm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package language

import (
"errors"
"fmt"
"go/format"
"html/template"
"reflect"
"sort"
"strings"

"xorm.io/core"
)

// Golang represents a golang language
var Golang = Language{
Name: "golang",
Template: defaultGolangTemplate,
Types: map[string]string{},
Funcs: template.FuncMap{
"Type": typestring,
"Tag": tag,
},
Formatter: formatGo,
Importter: genGoImports,
ExtName: ".go",
}

func init() {
RegisterLanguage(&Golang)
}

var (
errBadComparisonType = errors.New("invalid type for comparison")
errBadComparison = errors.New("incompatible types for comparison")
errNoComparison = errors.New("missing argument for comparison")
defaultGolangTemplate = fmt.Sprintf(`package models

{{$ilen := len .Imports}}{{if gt $ilen 0}}import (
{{range .Imports}}"{{.}}"{{end}}
){{end}}

{{range .Tables}}
type {{TableMapper .Name}} struct {
{{$table := .}}{{range .ColumnsSeq}}{{$col := $table.GetColumn .}} {{ColumnMapper $col.Name}} {{Type $col}} %s{{Tag $table $col}}%s
{{end}}
}
{{end}}
`, "`", "`")
)

type kind int

const (
invalidKind kind = iota
boolKind
complexKind
intKind
floatKind
integerKind
stringKind
uintKind
)

func basicKind(v reflect.Value) (kind, error) {
switch v.Kind() {
case reflect.Bool:
return boolKind, nil
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return intKind, nil
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return uintKind, nil
case reflect.Float32, reflect.Float64:
return floatKind, nil
case reflect.Complex64, reflect.Complex128:
return complexKind, nil
case reflect.String:
return stringKind, nil
}
return invalidKind, errBadComparisonType
}

func getCol(cols map[string]*core.Column, name string) *core.Column {
return cols[strings.ToLower(name)]
}

func formatGo(src string) (string, error) {
source, err := format.Source([]byte(src))
if err != nil {
return "", err
}
return string(source), nil
}

func genGoImports(tables []*core.Table) []string {
imports := make(map[string]string)
results := make([]string, 0)
for _, table := range tables {
for _, col := range table.Columns() {
if typestring(col) == "time.Time" {
if _, ok := imports["time"]; !ok {
imports["time"] = "time"
results = append(results, "time")
}
}
}
}
return results
}

func typestring(col *core.Column) string {
st := col.SQLType
t := core.SQLType2Type(st)
s := t.String()
if s == "[]uint8" {
return "[]byte"
}
return s
}

func tag(table *core.Table, col *core.Column) template.HTML {
isNameId := col.FieldName == "Id"
isIdPk := isNameId && typestring(col) == "int64"

var res []string
if !col.Nullable {
if !isIdPk {
res = append(res, "not null")
}
}
if col.IsPrimaryKey {
res = append(res, "pk")
}
if col.Default != "" {
res = append(res, "default "+col.Default)
}
if col.IsAutoIncrement {
res = append(res, "autoincr")
}

/*if col.SQLType.IsTime() && include(created, col.Name) {
res = append(res, "created")
}

if col.SQLType.IsTime() && include(updated, col.Name) {
res = append(res, "updated")
}

if col.SQLType.IsTime() && include(deleted, col.Name) {
res = append(res, "deleted")
}*/

if /*supportComment &&*/ col.Comment != "" {
res = append(res, fmt.Sprintf("comment('%s')", col.Comment))
}

names := make([]string, 0, len(col.Indexes))
for name := range col.Indexes {
names = append(names, name)
}
sort.Strings(names)

for _, name := range names {
index := table.Indexes[name]
var uistr string
if index.Type == core.UniqueType {
uistr = "unique"
} else if index.Type == core.IndexType {
uistr = "index"
}
if len(index.Cols) > 1 {
uistr += "(" + index.Name + ")"
}
res = append(res, uistr)
}

nstr := col.SQLType.Name
if col.Length != 0 {
if col.Length2 != 0 {
nstr += fmt.Sprintf("(%v,%v)", col.Length, col.Length2)
} else {
nstr += fmt.Sprintf("(%v)", col.Length)
}
} else if len(col.EnumOptions) > 0 { //enum
nstr += "("
opts := ""

enumOptions := make([]string, 0, len(col.EnumOptions))
for enumOption := range col.EnumOptions {
enumOptions = append(enumOptions, enumOption)
}
sort.Strings(enumOptions)

for _, v := range enumOptions {
opts += fmt.Sprintf(",'%v'", v)
}
nstr += strings.TrimLeft(opts, ",")
nstr += ")"
} else if len(col.SetOptions) > 0 { //enum
nstr += "("
opts := ""

setOptions := make([]string, 0, len(col.SetOptions))
for setOption := range col.SetOptions {
setOptions = append(setOptions, setOption)
}
sort.Strings(setOptions)

for _, v := range setOptions {
opts += fmt.Sprintf(",'%v'", v)
}
nstr += strings.TrimLeft(opts, ",")
nstr += ")"
}
res = append(res, nstr)
if len(res) > 0 {
return template.HTML(fmt.Sprintf(`xorm:"%s"`, strings.Join(res, " ")))
}
return ""
}

func include(source []string, target string) bool {
for _, s := range source {
if s == target {
return true
}
}
return false
}

+ 35
- 0
language/language.go View File

@@ -0,0 +1,35 @@
// Copyright 2019 The Xorm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package language

import (
"html/template"

"xorm.io/core"
)

// Language represents a languages supported when reverse codes
type Language struct {
Name string
Template string
Types map[string]string
Funcs template.FuncMap
Formatter func(string) (string, error)
Importter func([]*core.Table) []string
ExtName string
}

var (
languages = make(map[string]*Language)
)

func RegisterLanguage(l *Language) {
languages[l.Name] = l
}

// GetLanguage returns a language if exists
func GetLanguage(name string) *Language {
return languages[name]
}

+ 17
- 0
main.go View File

@@ -0,0 +1,17 @@
// Copyright 2019 The Xorm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
"fmt"

"xorm.io/reverse/cmd"
)

func main() {
if err := cmd.Execute(); err != nil {
fmt.Println(err)
}
}

+ 9
- 0
models/models.go View File

@@ -0,0 +1,9 @@
package models

type A struct {
Id int `xorm:"integer"`
}

type B struct {
Id int `xorm:"INTEGER"`
}

BIN
testdata/test.db View File


Loading…
Cancel
Save