From ee5ce09acd507430b7584aa7ff378f90c58ac48a Mon Sep 17 00:00:00 2001 From: riverchu Date: Tue, 27 Jul 2021 16:49:09 +0800 Subject: [PATCH 01/19] feat: implement generat moudel --- do.go | 2 +- generator.go | 321 ++++++++++++++++ go.mod | 6 +- go.sum | 32 ++ helper/clause.go | 83 ++++ interface.go | 2 +- internal/check/base.go | 44 +++ internal/check/checkinterface.go | 315 +++++++++++++++ internal/check/checkstruct.go | 68 ++++ internal/check/clause.go | 639 +++++++++++++++++++++++++++++++ internal/check/export.go | 70 ++++ internal/check/gen_structs.go | 125 ++++++ internal/check/utils.go | 80 ++++ internal/parser/export.go | 73 ++++ internal/parser/parser.go | 179 +++++++++ internal/parser/utils.go | 30 ++ internal/template/tmpl.go | 218 +++++++++++ log/log.go | 78 ++++ metric.go | 1 - 19 files changed, 2362 insertions(+), 4 deletions(-) create mode 100644 generator.go create mode 100644 helper/clause.go create mode 100644 internal/check/base.go create mode 100644 internal/check/checkinterface.go create mode 100644 internal/check/checkstruct.go create mode 100644 internal/check/clause.go create mode 100644 internal/check/export.go create mode 100644 internal/check/gen_structs.go create mode 100644 internal/check/utils.go create mode 100644 internal/parser/export.go create mode 100644 internal/parser/parser.go create mode 100644 internal/parser/utils.go create mode 100644 internal/template/tmpl.go create mode 100644 log/log.go diff --git a/do.go b/do.go index 784df5f4..16145105 100644 --- a/do.go +++ b/do.go @@ -68,7 +68,7 @@ func (s *DO) buildWhere() []clause.Expression { type stmtOpt func(*gorm.Statement) *gorm.Statement var ( - // withFROM 增加FROM子句 + // withFROM withFROM stmtOpt = func(stmt *gorm.Statement) *gorm.Statement { if stmt.Table == "" { _ = stmt.Parse(stmt.Model) diff --git a/generator.go b/generator.go new file mode 100644 index 00000000..49379351 --- /dev/null +++ b/generator.go @@ -0,0 +1,321 @@ +package gen + +import ( + "bytes" + "fmt" + "io" + "os" + "path/filepath" + "strconv" + "strings" + "text/template" + + "gorm.io/gorm" + + "golang.org/x/tools/imports" + "gorm.io/gen/internal/check" + "gorm.io/gen/internal/parser" + tmpl "gorm.io/gen/internal/template" + "gorm.io/gen/log" +) + +// TODO implement some unit tests + +// T genric type +type T interface{} + +// NewGenerator create a new generator +func NewGenerator(cfg Config) *Generator { + if cfg.modelPkgName == "" { + cfg.modelPkgName = check.ModelPkg + } + return &Generator{ + Config: cfg, + Data: make(map[string]*genInfo), + readInterfaceSet: new(parser.InterfaceSet), + } +} + +// Config generator's basic configuration +type Config struct { + OutPath string + OutFile string + + pkgName string + modelPkgName string //default model + db *gorm.DB //nolint +} + +func (c *Config) SetModelPkg(name string) { + c.modelPkgName = name +} + +func (c *Config) SetPkg(name string) { + c.pkgName = name +} + +func (c *Config) GetPkg() string { + return c.pkgName +} + +// genInfo info about generated code +type genInfo struct { + *check.BaseStruct + Interfaces []*check.InterfaceMethod +} + +// Generator code generator +type Generator struct { + Config + + Data map[string]*genInfo + readInterfaceSet *parser.InterfaceSet +} + +// UseDB set db connection +func (g *Generator) UseDB(db *gorm.DB) { + g.db = db +} + +// Tables collect table model +func (g *Generator) Tables(models ...interface{}) { + structs, err := check.CheckStructs(g.db, models...) + if err != nil { + log.Fatalf("gen struct error: %s", err) + } + for _, interfaceStruct := range structs { + data := g.getData(interfaceStruct.NewStructName) + if data.BaseStruct == nil { + data.BaseStruct = interfaceStruct + } + } +} + +// TableNames collect table names +func (g *Generator) TableNames(names ...string) { + structs, err := check.GenBaseStructs(g.db, g.Config.modelPkgName, names...) + if err != nil { + log.Fatalf("check struct error: %s", err) + } + for _, interfaceStruct := range structs { + data := g.getData(interfaceStruct.NewStructName) + if data.BaseStruct == nil { + data.BaseStruct = interfaceStruct + } + } +} + +// Apply specifies method interfaces on structures, implment codes will be generated after calling g.Execute() +// eg: g.Apply(func(model.Method){}, model.User{}, model.Company{}) +func (g *Generator) Apply(fc interface{}, models ...interface{}) { + var err error + + structs, err := check.CheckStructs(g.db, models...) + if err != nil { + log.Fatalf("check struct error: %s", err) + } + g.apply(fc, structs) +} + +func (g *Generator) apply(fc interface{}, structs []*check.BaseStruct) { + interfacePaths, err := parser.GetInterfacePath(fc) + if err != nil { + log.Fatalf("can't get interface name or file: %s", err) + } + + err = g.readInterfaceSet.ParseFile(interfacePaths) + if err != nil { + log.Fatalf("parser file error: %s", err) + } + + for _, interfaceStruct := range structs { + data := g.getData(interfaceStruct.NewStructName) + if data.BaseStruct == nil { + data.BaseStruct = interfaceStruct + } + + functions, err := check.CheckInterface(g.readInterfaceSet, interfaceStruct) + if err != nil { + log.Fatalf("check interface error: %s", err) + } + + for _, function := range functions { + data.Interfaces = function.DupAppend(data.Interfaces) + } + } +} + +// ApplyByModel specifies one method interface on several model structures +// eg: g.ApplyByModel(model.User{}, func(model.Method1, model.Method2){}) +func (g *Generator) ApplyByModel(model interface{}, fc interface{}) { + g.Apply(fc, model) +} + +// ApplyByTable specifies table by table names +// eg: g.ApplyByTable(func(model.Model){}, "user", "role") +func (g *Generator) ApplyByTable(fc interface{}, tableNames ...string) { + structs, err := check.GenBaseStructs(g.db, g.Config.modelPkgName, tableNames...) + if err != nil { + log.Fatalf("gen struct error: %s", err) + } + g.apply(fc, structs) +} + +// Execute generate code to output path +func (g *Generator) Execute() { + var err error + if g.OutPath == "" { + g.OutPath = "./query" + } + if g.OutFile == "" { + g.OutFile = g.OutPath + "/gorm_generated.go" + } + if _, err := os.Stat(g.OutPath); err != nil { + if err := os.Mkdir(g.OutPath, os.ModePerm); err != nil { + log.Fatalf("mkdir failed: %s", err) + } + } + g.SetPkg(filepath.Base(g.OutPath)) + + err = g.generatedBaseStruct() + if err != nil { + log.Fatalf("generate base struct fail: %s", err) + } + err = g.generatedToOutFile() + if err != nil { + log.Fatalf("generate to file fail: %s", err) + } + log.Println("Gorm generated interface file successful!") + log.Println("Generated path:", g.OutPath) + log.Println("Generated file:", g.OutFile) +} + +// generatedToOutFile save generate code to file +func (g *Generator) generatedToOutFile() (err error) { + var buf bytes.Buffer + + render := func(tmpl string, wr io.Writer, data interface{}) error { + t, err := template.New(tmpl).Parse(tmpl) + if err != nil { + return err + } + return t.Execute(wr, data) + } + + err = render(tmpl.HeaderTmpl, &buf, g.GetPkg()) + if err != nil { + return err + } + + for _, data := range g.Data { + err = render(tmpl.BaseStruct, &buf, data.BaseStruct) + if err != nil { + return err + } + + for _, method := range data.Interfaces { + err = render(tmpl.FuncTmpl, &buf, method) + if err != nil { + return err + } + } + + err = render(tmpl.BaseGormFunc, &buf, data.BaseStruct) + if err != nil { + return err + } + } + + err = render(tmpl.UseTmpl, &buf, g) + if err != nil { + return err + } + + result, err := imports.Process(g.OutFile, buf.Bytes(), nil) + if err != nil { + errLine, _ := strconv.Atoi(strings.Split(err.Error(), ":")[1]) + line := strings.Split(buf.String(), "\n") + for i := -3; i < 3; i++ { + fmt.Println(i+errLine, line[i+errLine]) + } + return fmt.Errorf("can't format generated file: %w", err) + } + return outputFile(g.OutFile, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, result) +} + +// generatedBaseStruct generate basic structures +func (g *Generator) generatedBaseStruct() (err error) { + outPath, err := filepath.Abs(g.OutPath) + if err != nil { + return err + } + pkg := g.modelPkgName + if pkg == "" { + pkg = check.ModelPkg + } + outPath = fmt.Sprint(filepath.Dir(outPath), "/", pkg, "/") + if _, err := os.Stat(outPath); err != nil { + if err := os.Mkdir(outPath, os.ModePerm); err != nil { + log.Fatalf("mkdir failed: %s", err) + } + } + for _, data := range g.Data { + if data.BaseStruct == nil || !data.BaseStruct.GenBaseStruct { + continue + } + var buf bytes.Buffer + err = render(tmpl.ModelTemplate, &buf, data.BaseStruct) + if err != nil { + return err + } + modelFile := fmt.Sprint(outPath, data.BaseStruct.TableName, ".go") + result, err := imports.Process(modelFile, buf.Bytes(), nil) + if err != nil { + for i, line := range strings.Split(buf.String(), "\n") { + fmt.Println(i, line) + } + return fmt.Errorf("can't format generated file: %w", err) + } + err = outputFile(modelFile, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, result) + if err != nil { + return nil + } + } + return nil +} + +func (g *Generator) getData(structName string) *genInfo { + if g.Data[structName] == nil { + g.Data[structName] = new(genInfo) + } + return g.Data[structName] +} + +func outputFile(filename string, flag int, data []byte) error { + out, err := os.OpenFile(filename, flag, 0640) + if err != nil { + return fmt.Errorf("can't open out file: %w", err) + } + return output(out, data) +} + +func output(wr io.WriteCloser, data []byte) (err error) { + defer func() { + if e := wr.Close(); e != nil { + err = fmt.Errorf("can't close: %w", e) + } + }() + + if _, err = wr.Write(data); err != nil { + return fmt.Errorf("can't write: %w", err) + } + return nil +} + +func render(tmpl string, wr io.Writer, data interface{}) error { + t, err := template.New(tmpl).Parse(tmpl) + if err != nil { + return err + } + return t.Execute(wr, data) +} diff --git a/go.mod b/go.mod index 816a2dfc..16482d02 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,8 @@ module gorm.io/gen go 1.16 -require gorm.io/gorm v1.21.12 +require ( + golang.org/x/tools v0.1.5 + gorm.io/driver/mysql v1.1.1 + gorm.io/gorm v1.21.12 +) diff --git a/go.sum b/go.sum index 3904ccf5..337243ec 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,38 @@ +github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= +github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.2 h1:eVKgfIdy9b6zbWBMgFpfDPoAMifwSZagU9HmEU6zgiI= github.com/jinzhu/now v1.1.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gorm.io/driver/mysql v1.1.1 h1:yr1bpyqiwuSPJ4aGGUX9nu46RHXlF8RASQVb1QQNcvo= +gorm.io/driver/mysql v1.1.1/go.mod h1:KdrTanmfLPPyAOeYGyG+UpDys7/7eeWT1zCq+oekYnU= +gorm.io/gorm v1.21.9/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0= gorm.io/gorm v1.21.12 h1:3fQM0Eiz7jcJEhPggHEpoYnsGZqynMzverL77DV40RM= gorm.io/gorm v1.21.12/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0= diff --git a/helper/clause.go b/helper/clause.go new file mode 100644 index 00000000..f61a5a52 --- /dev/null +++ b/helper/clause.go @@ -0,0 +1,83 @@ +package helper + +import "strings" + +type Cond struct { + Cond bool + Result string +} + +func IfClause(conds []Cond) string { + judge := func(c Cond) string { + if c.Cond { + return c.Result + } + return "" + } + + clauses := make([]string, len(conds)) + for i, cond := range conds { + clauses[i] = strings.Trim(judge(cond), " ") + } + return " " + strings.Join(clauses, " ") +} + +func WhereClause(conds []string) string { + return joinClause(conds, "WHERE", whereValue, " ") +} + +func SetClause(conds []string) string { + return joinClause(conds, "SET", setValue, ",") +} + +func joinClause(conds []string, keyword string, deal func(string) string, sep string) string { + clauses := make([]string, len(conds)) + for i, clause := range conds { + clauses[i] = deal(clause) + } + + sql := trimAll(strings.Join(clauses, sep)) + if sql != "" { + sql = " " + keyword + " " + sql + } + return sql +} + +func trimAll(input string) string { + input = strings.Trim(input, " ") + lowercase := strings.ToLower(input) + switch { + case strings.HasPrefix(lowercase, "and "): + return input[4:] + case strings.HasPrefix(lowercase, "or "): + return input[3:] + case strings.HasPrefix(lowercase, "xor "): + return input[4:] + case strings.HasPrefix(lowercase, ","): + return input[1:] + default: + return input + } +} + +// whereValue append a new condition with prefix "AND" +func whereValue(value string) string { + value = strings.Trim(value, " ") + lowercase := strings.ToLower(value) + switch { + case lowercase == "": + return "" + case strings.HasPrefix(lowercase, "and "): + return value + case strings.HasPrefix(lowercase, "or "): + return value + case strings.HasPrefix(lowercase, "xor "): + return value + default: + return "AND " + value + } +} + +func setValue(value string) string { + return value +} diff --git a/interface.go b/interface.go index 3533909c..de9f8374 100644 --- a/interface.go +++ b/interface.go @@ -25,7 +25,7 @@ type subQuery interface { // Dao CRUD methods type Dao interface { - clause.Expression // 用于获取其中的WHERE condition + clause.Expression subQuery As(alias string) Dao diff --git a/internal/check/base.go b/internal/check/base.go new file mode 100644 index 00000000..b598a0e5 --- /dev/null +++ b/internal/check/base.go @@ -0,0 +1,44 @@ +package check + +type Status int + +const ( + UNKNOWN Status = iota + SQL + DATA + VARIABLE + WHERE + IF + SET + ELSE + ELSEIF + END + BOOL + INT + STRING + TIME + OTHER + EXPRESSION + LOGICAL +) + +// Member user input structures +type Member struct { + Name string + Type string + NewType string + ColumnName string + ColumnComment string + ModelType string +} + +// Column table column's info +type Column struct { + TableName string `gorm:"column:TABLE_NAME"` + ColumnName string `gorm:"column:COLUMN_NAME"` + ColumnComment string `gorm:"column:COLUMN_COMMENT"` + DataType string `gorm:"column:DATA_TYPE"` + ColumnKey string `gorm:"column:COLUMN_KEY"` + ColumnType string `gorm:"column:COLUMN_TYPE"` + Extra string `gorm:"column:EXTRA"` +} diff --git a/internal/check/checkinterface.go b/internal/check/checkinterface.go new file mode 100644 index 00000000..04ff58d7 --- /dev/null +++ b/internal/check/checkinterface.go @@ -0,0 +1,315 @@ +package check + +import ( + "bytes" + "fmt" + "strconv" + "strings" + + "gorm.io/gen/internal/parser" +) + +type slice struct { + Type Status + Value string + Origin string +} + +// InterfaceMethod interface's method +type InterfaceMethod struct { + Doc string + S string + OriginStruct parser.Param + MethodStruct string + MethodName string + Params []parser.Param + Result []parser.Param + ResultData parser.Param + ExecuteResult string + SqlList []string + SqlData []string + SqlString string + GormOption string + Table string // specified by user. if empty, generate it with gorm + InterfaceName string +} + +// HasSqlData has variable or not +func (f *InterfaceMethod) HasSqlData() bool { + return len(f.SqlData) > 0 +} + +// HasGotPoint parameter has pointer or not +func (f *InterfaceMethod) HasGotPoint() bool { + return !f.HasNeedNewResult() +} + +// HasNeedNewResult need pointer or not +func (f *InterfaceMethod) HasNeedNewResult() bool { + return !f.ResultData.IsArray && f.ResultData.IsNull() && f.ResultData.IsTime() +} + +// checkParams check all parameters +func (f *InterfaceMethod) checkParams(params []parser.Param) (err error) { + paramList := make([]parser.Param, len(params)) + for i, r := range params { + if r.Package == "UNDEFINED" { + r.Package = f.OriginStruct.Package + } + paramList[i] = r + } + f.Params = paramList + return +} + +// checkResult check all parameters and replace gen.T by target structure. Parameters must be one of int/string/struct +func (f *InterfaceMethod) checkResult(result []parser.Param) (err error) { + retList := make([]parser.Param, len(result)) + for i, param := range result { + if param.Package == "UNDEFINED" { + param.Package = f.OriginStruct.Package + } + switch { + case param.IsError(): + param.SetName("err") + f.ExecuteResult = "err" + case param.Eq(f.OriginStruct) || param.IsGenT(): + param.Type = f.OriginStruct.Type + param.Package = f.OriginStruct.Package + param.SetName("result") + param.IsPointer = true + f.ResultData = param + case param.AllowType(), param.IsTime(): + param.SetName("result") + f.ResultData = param + default: + return fmt.Errorf("illegal parameter:%s.%s on struct %s.%s generated method %s \n ", param.Package, param.Type, f.OriginStruct.Package, f.OriginStruct.Type, f.MethodName) + } + retList[i] = param + } + f.Result = retList + return +} + +// checkSQL get sql from comment and check it +func (f *InterfaceMethod) checkSQL() (err error) { + f.SqlString = f.parseDocString() + if err = f.sqlStateCheck(); err != nil { + err = fmt.Errorf("interface %s member method %s check sql err:%w", f.InterfaceName, f.MethodName, err) + } + return +} + +func (f *InterfaceMethod) parseDocString() string { + docString := strings.TrimSpace(f.Doc) + switch { + case strings.HasPrefix(strings.ToLower(docString), "sql("): + docString = docString[4 : len(docString)-1] + f.GormOption = "Raw" + if f.ResultData.IsNull() { + f.GormOption = "Exec" + } + case strings.HasPrefix(strings.ToLower(docString), "where("): + docString = docString[6 : len(docString)-1] + f.GormOption = "Where" + default: + f.GormOption = "Raw" + if f.ResultData.IsNull() { + f.GormOption = "Exec" + } + } + + // if wrapped by ", trim it + if strings.HasPrefix(docString, `"`) && strings.HasSuffix(docString, `"`) { + docString = docString[1 : len(f.SqlString)-1] + } + return docString +} + +type sql struct{ bytes.Buffer } + +func (s *sql) WriteSql(b byte) { + switch b { + case '\n', '\t', ' ': + if s.Len() == 0 || s.Bytes()[s.Len()-1] != ' ' { + _ = s.WriteByte(' ') + } + default: + _ = s.WriteByte(b) + } + +} + +// sqlStateCheck check sql with an adeterministic finite automaton +func (f *InterfaceMethod) sqlStateCheck() (err error) { + sqlString := f.SqlString + " " + result := NewSlices() + var out sql + + for i := 0; i < len(sqlString); i++ { + b := sqlString[i] + switch b { + case '"': + _ = out.WriteByte(sqlString[i]) + for { + i++ + if !stringHasMore(i, sqlString) { + return fmt.Errorf("incomplete SQL:%s", sqlString) + } + _ = out.WriteByte(sqlString[i]) + if sqlString[i] == '"' && sqlString[i-1] != '\\' { + break + } + } + + case '{', '@': + sqlClause := out.String() + if strings.TrimSpace(sqlClause) != "" { + result.slices = append(result.slices, slice{ + Type: SQL, + Value: strconv.Quote(out.String()), + }) + + } + out.Reset() + + if !stringHasMore(i+1, sqlString) { + return fmt.Errorf("incomplete SQL:%s", sqlString) + } + if b == '{' && sqlString[i+1] == '{' { + i += 2 + for { + if !stringHasMore(i, sqlString) { + return fmt.Errorf("incomplete SQL:%s", sqlString) + } + if sqlString[i] == '"' { + _ = out.WriteByte(sqlString[i]) + for { + i++ + if !stringHasMore(i, sqlString) { + return fmt.Errorf("incomplete SQL:%s", sqlString) + } + _ = out.WriteByte(sqlString[i]) + if sqlString[i] == '"' && sqlString[i-1] != '\\' { + i++ + break + } + } + + } + if sqlString[i] == '}' && sqlString[i+1] == '}' { + part, err := checkTemplate(out.String(), f.Params) + if err != nil { + err := fmt.Errorf("sql [%s] dynamic template %s err:%s ", sqlString, out.String(), err) + return err + } + result.slices = append(result.slices, part) + i++ + out.Reset() + break + } + out.WriteSql(sqlString[i]) + i++ + + } + + } + if b == '@' { + t := DATA + i++ + if sqlString[i] == '@' { + t = VARIABLE + i++ + } + for { + if i == len(sqlString) || isStringEnd(sqlString[i]) { + varString := out.String() + s, err := f.isParamInMethod(varString, t) + if err != nil { + return fmt.Errorf("sql [%s] varable %s err:%s", sqlString, varString, err) + } + + result.slices = append(result.slices, s) + out.Reset() + i-- + break + } + + out.WriteSql(sqlString[i]) + i++ + } + } + default: + out.WriteSql(b) + } + } + if strings.Trim(out.String(), " ") != "" { + result.slices = append(result.slices, slice{ + Type: SQL, + Value: strconv.Quote(out.String()), + }) + } + + _, err = result.parse() + if err != nil { + return fmt.Errorf("sql [%s] parser err:%s", sqlString, err) + } + f.SqlList = result.tmpl + return +} + +// isParamInMethod if sql's param is not external(except table), generate by gorm +func (f *InterfaceMethod) isParamInMethod(param string, s Status) (result slice, err error) { + for _, p := range f.Params { + if p.Name == param { + var str string + switch s { + case DATA: + str = fmt.Sprintf("\"@%s\"", param) + case VARIABLE: + if p.Type != "string" { + err = fmt.Errorf("variable name must be string :%s type is %s", param, p.Type) + } + str = fmt.Sprintf("helper.Quote(%s)", param) + } + f.SqlData = append(f.SqlData, param) + result = slice{ + Type: s, + Value: str, + } + return + } + } + if param == "table" { + result = slice{ + Type: SQL, + Value: strconv.Quote(f.Table), + } + return + } + return result, fmt.Errorf("unknow variable param:%s", param) +} + +// checkTemplate check sql template's syntax (check if/else/where/set) +func checkTemplate(tmpl string, params []parser.Param) (result slice, err error) { + fragmentList, err := splitTemplate(tmpl, params) + if err != nil { + return + } + err = checkTempleFragmentValid(fragmentList) + if err != nil { + return + } + return fragmentToSLice(fragmentList) +} + +// DupAppend append methon and duplicate +func (f *InterfaceMethod) DupAppend(methods []*InterfaceMethod) []*InterfaceMethod { + for index, method := range methods { + if method.MethodName == f.MethodName { + methods[index] = f + return methods + } + } + return append(methods, f) +} diff --git a/internal/check/checkstruct.go b/internal/check/checkstruct.go new file mode 100644 index 00000000..08cb4cce --- /dev/null +++ b/internal/check/checkstruct.go @@ -0,0 +1,68 @@ +package check + +import ( + "fmt" + "strings" + + "gorm.io/gorm" + + "gorm.io/gen/internal/parser" + "gorm.io/gen/log" +) + +// BaseStruct struct info in generated code +type BaseStruct struct { + GenBaseStruct bool // whether to generate db model + S string // the first letter(lower case)of simple Name + NewStructName string // new struct name + StructName string // origin struct name + TableName string + StructInfo parser.Param + Members []*Member + db *gorm.DB +} + +// getMembers get all elements of struct with gorm's Parse, ignore unexport elements +func (b *BaseStruct) getMembers(st interface{}) { + stmt := gorm.Statement{DB: b.db} + _ = stmt.Parse(st) + + for _, field := range stmt.Schema.Fields { + b.Members = append(b.Members, &Member{ + Name: field.Name, + Type: DelPointer(field.FieldType.String()), + ColumnName: field.DBName, + }) + } +} + +// getTableName get table name with gorm's Parse +func (b *BaseStruct) getTableName(st interface{}) { + stmt := gorm.Statement{DB: b.db} + _ = stmt.Parse(st) + b.TableName = stmt.Table +} + +// checkStructAndMembers check if struct is exportable and if member's type is regular +func (b *BaseStruct) checkStructAndMembers() (err error) { + if !isCapitalize(b.StructName) { + err = fmt.Errorf("ignoring non exportable struct name:%s", b.NewStructName) + log.Println(err) + return + } + for index, m := range b.Members { + if !allowType(m.Type) { + b.Members[index].Type = "field" + } + b.Members[index].NewType = getNewType(m.Type) + } + return nil +} + +func getNewType(t string) string { + var newType string + for _, s := range strings.Split(t, ".") { + newType = s + } + return strings.Title(newType) +} diff --git a/internal/check/clause.go b/internal/check/clause.go new file mode 100644 index 00000000..94490ae6 --- /dev/null +++ b/internal/check/clause.go @@ -0,0 +1,639 @@ +package check + +import ( + "bytes" + "fmt" + "strings" + + "gorm.io/gen/internal/parser" +) + +// Clause a symbol of clause, it can be sql condition clause, if clause, where clause, set clause and else cluase +type Clause interface { + String() string +} + +// SQLClause sql condition clause +type SQLClause struct { + VarName string + Type Status + Value []string +} + +func (s SQLClause) String() string { + return strings.ReplaceAll(strings.Join(s.Value, "+"), `"+"`, "") +} + +// IfClause if clause +type IfClause struct { + VarName string + Cond string + Type Status + Value []Clause + Else []Clause +} + +func (i IfClause) String() string { + return fmt.Sprintf("helper.IfClause(%s)", i.VarName) +} + +// ElseClause else clause +type ElseClause struct { + VarName string + Cond string + Type Status + Value []Clause +} + +func (e ElseClause) String() (res string) { + strList := make([]string, len(e.Value)) + for i, v := range e.Value { + strList[i] = v.String() + } + return strings.ReplaceAll(strings.Join(strList, "+"), `"+"`, "") +} + +// WhereClause where clause +type WhereClause struct { + VarName string + Type Status + Value []Clause +} + +func (w WhereClause) String() string { + return fmt.Sprintf("helper.WhereClause(%s)", w.VarName) +} + +// SetClause set clause +type SetClause struct { + VarName string + Type Status + Value []Clause +} + +func (w SetClause) String() string { + return fmt.Sprintf("helper.SetClause(%s)", w.VarName) +} + +// Slices split sql into chunks +type Slices struct { + slices []slice + tmpl []string + currentIndex int + Names map[Status]int +} + +// NewSlices create and initialize Slices +func NewSlices() *Slices { + return &Slices{ + Names: map[Status]int{ + IF: 0, + WHERE: 0, + SET: 0, + }, + } +} + +// Next return next slice and increase index by 1 +func (s *Slices) Next() slice { + s.currentIndex++ + return s.slices[s.currentIndex] +} + +// SubIndex take index one step back +func (s *Slices) SubIndex() { + s.currentIndex-- +} + +// HasMore whether has more slice +func (s *Slices) HasMore() bool { + return s.currentIndex < len(s.slices)-1 +} + +// IsNull whether slice is empty +func (s *Slices) IsNull() bool { + return len(s.slices) == 0 +} + +// Current return current slice +func (s *Slices) Current() slice { + return s.slices[s.currentIndex] +} + +// GetName ... +func (s *Slices) GetName(status Status) string { + switch status { + case IF: + defer func() { s.Names[IF]++ }() + return fmt.Sprintf("ifCond%d", s.Names[IF]) + case WHERE: + defer func() { s.Names[WHERE]++ }() + return fmt.Sprintf("whereCond%d", s.Names[WHERE]) + case SET: + defer func() { s.Names[SET]++ }() + return fmt.Sprintf("setCond%d", s.Names[SET]) + default: + return fmt.Sprintf("Cond%d", s.currentIndex) + } +} + +func (s *Slices) appendIfCond(name, cond, result string) { + s.tmpl = append(s.tmpl, fmt.Sprintf("%s = append(%s, helper.Cond{%s, %s})", name, name, cond, result)) +} + +func (s *Slices) appendSetValue(name, result string) { + s.tmpl = append(s.tmpl, fmt.Sprintf("%s = append(%s, %s)", name, name, strings.TrimSpace(result))) +} + +// CreateIf create if clause code +func (s *Slices) CreateIf(name string) { + s.tmpl = append(s.tmpl, fmt.Sprintf("%s := make([]helper.Cond, 0, 100)", name)) +} + +// CreateStringSet create string set +func (s *Slices) CreateStringSet(name string) { + s.tmpl = append(s.tmpl, fmt.Sprintf("%s := make([]string, 0, 100)", name)) +} + +// parse slice and append result to tmpl, return a Clause array +func (s *Slices) parse() (res []Clause, err error) { + if s.IsNull() { + err = fmt.Errorf("sql is null") + return + } + name := "generateSQL" + for slice := s.Current(); ; slice = s.Next() { + s.tmpl = append(s.tmpl, "") + switch slice.Type { + case SQL, DATA, VARIABLE: + sqlClause := s.parseSQL(name) + res = append(res, sqlClause) + s.tmpl = append(s.tmpl, fmt.Sprintf("%s+=%s", name, sqlClause.String())) + case IF: + var ifClause IfClause + ifClause, err = s.parseIF() + if err != nil { + return + } + res = append(res, ifClause) + s.tmpl = append(s.tmpl, fmt.Sprintf("%s+=helper.IfClause(%s)", name, ifClause.VarName)) + case WHERE: + var whereClause WhereClause + whereClause, err = s.parseWhere() + if err != nil { + return + } + res = append(res, whereClause) + s.tmpl = append(s.tmpl, fmt.Sprintf("%s+=helper.WhereClause(%s)", name, whereClause.VarName)) + case SET: + var setClause SetClause + setClause, err = s.parseSet() + if err != nil { + return + } + res = append(res, setClause) + s.tmpl = append(s.tmpl, fmt.Sprintf("%s+=helper.SetClause(%s)", name, setClause.VarName)) + case END: + default: + err = fmt.Errorf("unknow clause:%s", slice.Origin) + return + } + + if !s.HasMore() { + return + } + } +} + +// parseIF parse if clause +func (s *Slices) parseIF() (res IfClause, err error) { + slice := s.Current() + name := s.GetName(slice.Type) + s.CreateIf(name) + + res.Type = slice.Type + res.Cond = slice.Value + res.VarName = name + cond := []string{res.Cond} + for s.HasMore() { + n := s.Next() + switch n.Type { + case SQL, DATA, VARIABLE: + str := s.parseSQL(name) + res.Value = append(res.Value, str) + s.appendIfCond(name, res.Cond, str.String()) + case IF: + var ifClause IfClause + ifClause, err = s.parseIF() + if err != nil { + return + } + res.Value = append(res.Value, ifClause) + s.appendIfCond(name, res.Cond, ifClause.String()) + case WHERE: + var whereClause WhereClause + whereClause, err = s.parseWhere() + if err != nil { + return + } + res.Value = append(res.Value, whereClause) + s.appendIfCond(name, res.Cond, whereClause.String()) + case SET: + var setClause SetClause + setClause, err = s.parseSet() + if err != nil { + return + } + res.Value = append(res.Value, setClause) + s.appendIfCond(name, res.Cond, setClause.String()) + case ELSEIF: + elseClause := s.parseElSE(name) + elseCond := elseClause.Cond + elseClause.Cond = fmt.Sprintf("!(%s) && %s", strings.Join(cond, " || "), elseCond) + res.Else = append(res.Else, elseClause) + s.appendIfCond(name, elseClause.Cond, elseClause.String()) + cond = append(cond, elseCond) + case ELSE: + elseClause := s.parseElSE(name) + elseClause.Cond = fmt.Sprintf("!(%s)", strings.Join(cond, " || ")) + res.Else = append(res.Else, elseClause) + s.appendIfCond(name, elseClause.Cond, elseClause.String()) + case END: + return + default: + err = fmt.Errorf("unknow clause : %s", n.Origin) + return + } + } + err = fmt.Errorf("incomplete SQL,if not end") + return +} + +// parseElSE parse else clause, the clause' type must be one of if, where, set, SQL condition +func (s *Slices) parseElSE(name string) (res ElseClause) { + slice := s.Current() + res.Cond = slice.Value + res.VarName = name + res.Type = slice.Type + for n := s.Next(); s.HasMore(); n = s.Next() { + switch n.Type { + case SQL, DATA, VARIABLE: + res.Value = append(res.Value, s.parseSQL(name)) + case IF: + ifClause, err := s.parseIF() + if err != nil { + return + } + res.Value = append(res.Value, ifClause) + case WHERE: + whereClause, err := s.parseWhere() + if err != nil { + return + } + res.Value = append(res.Value, whereClause) + case SET: + setClause, err := s.parseSet() + if err != nil { + return + } + res.Value = append(res.Value, setClause) + default: + s.SubIndex() + return + } + } + return +} + +// parseWhere parse where clause, the clause' type must be one of if, SQL condition +func (s *Slices) parseWhere() (res WhereClause, err error) { + slice := s.Current() + name := s.GetName(slice.Type) + s.CreateStringSet(name) + + res.VarName = name + res.Type = slice.Type + for s.HasMore() { + n := s.Next() + switch n.Type { + case SQL, DATA, VARIABLE: + strClause := s.parseSQL(name) + res.Value = append(res.Value, strClause) + s.appendSetValue(name, strClause.String()) + case IF: + var ifClause IfClause + ifClause, err = s.parseIF() + if err != nil { + return + } + res.Value = append(res.Value, ifClause) + s.appendSetValue(name, ifClause.String()) + case END: + return + default: + err = fmt.Errorf("unknow clause : %s", n.Origin) + return + } + } + err = fmt.Errorf("incomplete SQL,where not end") + return +} + +// parseSet parse set clause, the clause' type must be one of if, SQL condition +func (s *Slices) parseSet() (res SetClause, err error) { + slice := s.Current() + name := s.GetName(slice.Type) + s.CreateStringSet(name) + + res.VarName = name + res.Type = slice.Type + for s.HasMore() { + n := s.Next() + switch n.Type { + case SQL, DATA, VARIABLE: + strClause := s.parseSQL(name) + res.Value = append(res.Value, strClause) + s.appendSetValue(name, strClause.String()) + case IF: + var ifClause IfClause + ifClause, err = s.parseIF() + if err != nil { + return + } + res.Value = append(res.Value, ifClause) + s.appendSetValue(name, ifClause.String()) + case END: + return + default: + err = fmt.Errorf("unknow clause : %s", n.Origin) + return + } + } + err = fmt.Errorf("incomplete SQL,set not end") + return +} + +// parseSQL parse sql condition, the clause' type must be one of SQL condition, VARIABLE, Data +func (s *Slices) parseSQL(name string) (res SQLClause) { + res.VarName = name + res.Type = SQL + for slice := s.Current(); ; slice = s.Next() { + switch slice.Type { + case SQL, VARIABLE, DATA: + res.Value = append(res.Value, slice.Value) + default: + s.SubIndex() + return + } + + if !s.HasMore() { + return + } + } +} + +// sql fragment +type fragment struct { + Type Status + value string +} + +func checkFragment(s string, params []parser.Param) (f fragment, err error) { + f = fragment{Type: UNKNOWN, value: strings.Trim(s, " ")} + str := strings.ToLower(strings.Trim(s, " ")) + switch str { + case "&&", "||": + f.Type = LOGICAL + return + case ">", "<", ">=", "<=", "==", "!=": + f.Type = EXPRESSION + return + case "end": + f.Type = END + return + case "if": + f.Type = IF + return + case "set": + f.Type = SET + return + case "else": + f.Type = ELSE + return + case "where": + f.Type = WHERE + return + case "true", "false": + f.Type = BOOL + return + case "nil": + f.Type = OTHER + return + default: + if isDigit(str) { + f.Type = INT + return + } + + f.fragmentByParams(params) + if f.Type != UNKNOWN { + return + } + } + // TODO double check + return f, fmt.Errorf("unknow parameter: %s", s) +} + +func (f *fragment) fragmentByParams(params []parser.Param) { + for _, param := range params { + if param.Name == f.value { + switch param.Type { + case "bool": + f.Type = BOOL + return + case "int": + f.Type = INT + return + case "string": + f.Type = STRING + return + case "Time": + f.Type = TIME + default: + f.Type = OTHER + } + } + } +} + +func splitTemplate(tmpl string, params []parser.Param) (newList []fragment, err error) { + tmpl += " " + var out bytes.Buffer + var t fragment + for i := 0; i < len(tmpl); i++ { + switch tmpl[i] { + case '"': + for { + out.WriteByte(tmpl[i]) + if !stringHasMore(i, tmpl) { + err = fmt.Errorf("incomplete code:%s", tmpl) + return + } + i++ + if tmpl[i] == '"' && tmpl[i-1] != '\\' { + out.WriteByte(tmpl[i]) + newList = append(newList, fragment{Type: STRING, value: out.String()}) + out.Reset() + break + } + } + continue + case ' ': + t, err = checkFragment(out.String(), params) + if err != nil { + return + } + if t.value != "" { + newList = append(newList, t) + } + out.Reset() + case '>', '<', '=', '!': + t, err = checkFragment(out.String(), params) + if err != nil { + return + } + if t.value != "" { + newList = append(newList, t) + } + out.Reset() + + out.WriteByte(tmpl[i]) + if tmpl[i+1] == '=' { + out.WriteByte(tmpl[i+1]) + i++ + } + t, err = checkFragment(out.String(), params) + if err != nil { + return + } + if t.value != "" { + newList = append(newList, t) + } + out.Reset() + continue + case '&', '|': + if tmpl[i+1] == tmpl[i] { + t, err = checkFragment(out.String(), params) + if err != nil { + return + } + if t.value != "" { + newList = append(newList, t) + } + out.Reset() + out.WriteString(tmpl[i : i+2]) + t, err = checkFragment(out.String(), params) + if err != nil { + return + } + if t.value != "" { + newList = append(newList, t) + } + out.Reset() + i++ + continue + } + + } + + out.WriteByte(tmpl[i]) + } + t, err = checkFragment(out.String(), params) + if err != nil { + return + } + if t.value != "" { + newList = append(newList, t) + } + // TODO check if verbose? + if len(newList) == 0 { + return + } + return +} + +// check validition of clause's value +func checkTempleFragmentValid(list []fragment) error { + for i := 1; i < len(list); i++ { + switch list[i].Type { + case IF, ELSE, END, BOOL, LOGICAL, WHERE, SET: + continue + case INT, STRING, OTHER, TIME: + if i+2 < len(list) { + if list[i+1].Type == EXPRESSION && list[i+2].Type == list[i].Type { + i += 2 + } else { + return fmt.Errorf("condition type not match:%s", fragmentToString(list[i:i+2])) + } + } + default: + return fmt.Errorf("unknow fragment : %s ", list[i].value) + } + } + return nil +} + +func fragmentToString(list []fragment) string { + var values []string + + if len(list) == 0 { + return "" + } + for _, t := range list { + values = append(values, t.value) + } + return strings.Join(values, " ") +} + +func fragmentToSLice(list []fragment) (part slice, err error) { + var values []string + + if len(list) == 0 { + return + } + for _, t := range list { + values = append(values, t.value) + } + part.Origin = strings.Join(values, " ") + switch strings.ToLower(values[0]) { + case "if": + if len(values) > 1 { + part.Type = IF + part.Value = strings.Join(values[1:], " ") + return + } + case "else": + if len(values) == 1 { + part.Type = ELSE + return + } else { + if strings.ToLower(values[1]) == "if" && len(values) > 2 { + part.Value = strings.Join(values[2:], " ") + part.Type = ELSEIF + return + } + } + case "where": + part.Type = WHERE + return + case "set": + part.Type = SET + return + case "end": + part.Type = END + return + } + + err = fmt.Errorf("syntax error:%s", strings.Join(values, " ")) + return +} diff --git a/internal/check/export.go b/internal/check/export.go new file mode 100644 index 00000000..c9111370 --- /dev/null +++ b/internal/check/export.go @@ -0,0 +1,70 @@ +package check + +import ( + "fmt" + "reflect" + "strings" + + "gorm.io/gorm" + + "gorm.io/gen/internal/parser" +) + +// CheckStructs check the legitimacy of structures +func CheckStructs(db *gorm.DB, structs ...interface{}) (bases []*BaseStruct, err error) { + if isDBUndefined(db) { + return nil, fmt.Errorf("gen config db is undefined") + } + + for _, st := range structs { + structType := reflect.TypeOf(st) + base := &BaseStruct{ + S: GetSimpleName(structType.Name()), + StructName: structType.Name(), + NewStructName: strings.ToLower(structType.Name()), + StructInfo: parser.Param{Type: structType.Name(), Package: getPackageName(structType.String())}, + db: db, + } + base.getMembers(st) + base.getTableName(st) + if e := base.checkStructAndMembers(); e != nil { + continue + } + + bases = append(bases, base) + } + return +} + +// CheckInterface check the legitimacy of interfaces +func CheckInterface(f *parser.InterfaceSet, s *BaseStruct) (checkResult []*InterfaceMethod, err error) { + for _, interfaceInfo := range f.Interfaces { + for _, method := range interfaceInfo.Methods { + t := &InterfaceMethod{ + S: s.S, + MethodStruct: s.NewStructName, + OriginStruct: s.StructInfo, + MethodName: method.MethodName, + Params: method.Params, + Doc: method.Doc, + ExecuteResult: "_", + Table: s.TableName, + InterfaceName: interfaceInfo.Name, + } + err = t.checkParams(method.Params) + if err != nil { + return + } + err = t.checkResult(method.Result) + if err != nil { + return + } + err = t.checkSQL() + if err != nil { + return + } + checkResult = append(checkResult, t) + } + } + return +} diff --git a/internal/check/gen_structs.go b/internal/check/gen_structs.go new file mode 100644 index 00000000..3c0e9172 --- /dev/null +++ b/internal/check/gen_structs.go @@ -0,0 +1,125 @@ +package check + +import ( + "fmt" + "regexp" + "strings" + + "gorm.io/driver/mysql" + "gorm.io/gorm" + + "gorm.io/gen/internal/parser" +) + +const ( + ModelPkg = "model" + + //query table structure + columnQuery = "SELECT COLUMN_NAME ,COLUMN_COMMENT ,DATA_TYPE ,IS_NULLABLE ,COLUMN_KEY,COLUMN_TYPE,EXTRA" + + " FROM information_schema.columns WHERE table_schema = ? AND table_name =?" +) + +var dataType = map[string]string{ + "smallint": "int32", + "smallint unsigned": "int32", + "int": "int32", + "int unsigned": "int32", + "bigint": "int64", + "bigint unsigned": "int64", + "varchar": "string", + "char": "string", + "date": "time.Time", + "datetime": "time.Time", + "bit(1)": "[]uint8", + "tinyint": "int32", + "tinyint unsigned": "int32", + "tinyint(1)": "bool", + "tinyint(1) unsigned": "bool", + "json": "string", + "text": "string", + "timestamp": "time.Time", + "double": "float64", + "decimal": "float64", + "mediumtext": "string", + "longtext": "string", + "float": "float32", + "float unsigned": "float32", + "tinytext": "string", + "enum": "string", + "time": "time.Time", + "tinyblob": "[]byte", + "blob": "[]byte", + "mediumblob": "[]byte", + "longblob": "[]byte", + "integer": "int32", +} + +// GenBaseStructs generate db model by table name +func GenBaseStructs(db *gorm.DB, pkg string, tableName ...string) (bases []*BaseStruct, err error) { + if isDBUndefined(db) { + return nil, fmt.Errorf("gen config db is undefined") + } + if pkg == "" { + pkg = ModelPkg + } + dbName := getSchemaName(db) + for _, tb := range tableName { + columns, err := getTbColumns(db, dbName, tb) + if err != nil { + return nil, err + } + var base BaseStruct + base.GenBaseStruct = true + base.TableName = tb + base.StructName = nameToCamelCase(tb) + base.StructInfo = parser.Param{Type: base.StructName, Package: pkg} + for _, field := range columns { + mt := dataType[field.DataType] + base.Members = append(base.Members, &Member{ + Name: nameToCamelCase(field.ColumnName), + Type: mt, + ModelType: mt, + ColumnName: field.ColumnName, + ColumnComment: field.ColumnComment, + }) + } + + base.NewStructName = strings.ToLower(base.StructName) + base.S = string(base.NewStructName[0]) + _ = base.checkStructAndMembers() + bases = append(bases, &base) + } + return +} + +//Mysql +func getTbColumns(db *gorm.DB, schemaName string, tableName string) (result []*Column, err error) { + err = db.Raw(columnQuery, schemaName, tableName).Scan(&result).Error + return +} + +// get mysql db' name +var dbNameReg = regexp.MustCompile(`/\w+\?`) + +func getSchemaName(db *gorm.DB) string { + if db == nil || db.Dialector == nil { + return "" + } + myDia, ok := db.Dialector.(*mysql.Dialector) + if !ok || myDia == nil || myDia.Config == nil { + return "" + } + dbName := dbNameReg.FindString(myDia.DSN) + if len(dbName) < 3 { + return "" + } + return dbName[1 : len(dbName)-1] +} + +// convert Table name or column name to camel case +func nameToCamelCase(name string) string { + if name == "" { + return name + } + return strings.ReplaceAll(strings.Title(strings.ReplaceAll(name, "_", " ")), " ", "") +} diff --git a/internal/check/utils.go b/internal/check/utils.go new file mode 100644 index 00000000..9bb737bd --- /dev/null +++ b/internal/check/utils.go @@ -0,0 +1,80 @@ +package check + +import ( + "strings" + "unicode" + + "gorm.io/gorm" +) + +func isCapitalize(s string) bool { + if len(s) < 1 { + return false + } + b := s[0] + if b >= 'A' && b <= 'Z' { + return true + } + return false +} + +func isStringEnd(b byte) bool { + switch { + case b >= 'a' && b <= 'z': + return false + case b >= 'A' && b <= 'Z': + return false + case b >= '0' && b <= '9': + return false + case b == '-' || b == '_' || b == '.': + return false + default: + return true + } +} + +func isDBUndefined(db *gorm.DB) bool { + return db == nil +} + +func getPackageName(fullName string) string { + return strings.Split(fullName, ".")[0] +} + +func isDigit(str string) bool { + for _, x := range str { + if !unicode.IsDigit(x) { + return false + } + } + return true +} + +func allowType(typ string) bool { + switch typ { + case "string", "bytes": + return true + case "int", "int8", "int16", "int32", "int64", "uint", "uint8", "uint16", "uint32", "uint64": + return true + case "float64", "float32": + return true + case "bool": + return true + case "time.Time": + return true + default: + return false + } +} + +func stringHasMore(i int, str string) bool { + return i < len(str)-1 +} + +func DelPointer(name string) string { + return strings.TrimLeft(name, "*") +} + +func GetSimpleName(s string) string { + return string(strings.ToLower(s)[0]) +} diff --git a/internal/parser/export.go b/internal/parser/export.go new file mode 100644 index 00000000..abebaf60 --- /dev/null +++ b/internal/parser/export.go @@ -0,0 +1,73 @@ +package parser + +import ( + "fmt" + "go/build" + "os" + "reflect" + "runtime" + "strings" +) + +type InterfacePath struct { + Name string + FullName string + Files []string +} + +// GetInterfacePath get interface's directory path and all files it contains +func GetInterfacePath(v interface{}) (paths []*InterfacePath, err error) { + value := reflect.ValueOf(v) + if value.Kind() != reflect.Func { + err = fmt.Errorf("model param is not function:%s", value.String()) + return + } + + for i := 0; i < value.Type().NumIn(); i++ { + var path InterfacePath + arg := value.Type().In(i) + path.FullName = arg.String() + + // keep the last model + for _, n := range strings.Split(arg.String(), ".") { + path.Name = n + } + + if strings.Split(arg.String(), ".")[0] == "main" { + _, file, _, ok := runtime.Caller(2) + if ok { + path.Files = append(path.Files, file) + } + paths = append(paths, &path) + continue + } + + ctx := build.Default + var p *build.Package + p, err = ctx.Import(arg.PkgPath(), "", build.ImportComment) + if err != nil { + return + } + + for _, file := range p.GoFiles { + goFile := fmt.Sprintf("%s/%s", p.Dir, file) + if fileExists(goFile) { + path.Files = append(path.Files, goFile) + } + } + + if len(path.Files) == 0 { + err = fmt.Errorf("interface file not found:%s", value.String()) + return + } + + paths = append(paths, &path) + } + + return +} + +func fileExists(path string) bool { + _, err := os.Stat(path) + return err == nil +} diff --git a/internal/parser/parser.go b/internal/parser/parser.go new file mode 100644 index 00000000..522a92f7 --- /dev/null +++ b/internal/parser/parser.go @@ -0,0 +1,179 @@ +package parser + +import ( + "fmt" + "go/ast" + "go/parser" + "go/token" + "path/filepath" +) + +// InterfaceSet ... +type InterfaceSet struct { + Interfaces []InterfaceInfo +} + +// InterfaceInfo ... +type InterfaceInfo struct { + Name string + Doc string + Methods []*Method +} + +// Method interface's method +type Method struct { + MethodName string + Doc string + Params []Param + Result []Param +} + +// ParseFile get interface's info from source file +func (i *InterfaceSet) ParseFile(paths []*InterfacePath) error { + for _, path := range paths { + for _, file := range path.Files { + absFilePath, err := filepath.Abs(file) + if err != nil { + return fmt.Errorf("file not found:%s", file) + } + + err = i.getInterfaceFromFile(absFilePath, path.Name) + if err != nil { + return fmt.Errorf("can't get interface from %s:%s", path.FullName, err) + } + } + } + return nil +} + +// Visit ast visit function +func (i *InterfaceSet) Visit(n ast.Node) (w ast.Visitor) { + switch n := n.(type) { + case *ast.TypeSpec: + if data, ok := n.Type.(*ast.InterfaceType); ok { + r := InterfaceInfo{ + Methods: []*Method{}, + } + methods := data.Methods.List + r.Name = n.Name.Name + r.Doc = n.Doc.Text() + for _, m := range methods { + for _, name := range m.Names { + r.Methods = append(r.Methods, &Method{ + MethodName: name.Name, + Doc: m.Doc.Text(), + Params: getParamList(m.Type.(*ast.FuncType).Params), + Result: getParamList(m.Type.(*ast.FuncType).Results), + }) + } + + } + i.Interfaces = append(i.Interfaces, r) + } + } + return i +} + +// getInterfaceFromFile get interfaces +// get all interfaces from file and compare with specified name +func (i *InterfaceSet) getInterfaceFromFile(filename string, name string) error { + fileset := token.NewFileSet() + f, err := parser.ParseFile(fileset, filename, nil, parser.ParseComments) + if err != nil { + return fmt.Errorf("can't parse file %q: %s", filename, err) + } + + astResult := new(InterfaceSet) + ast.Walk(astResult, f) + + for _, info := range astResult.Interfaces { + if name == info.Name { + i.Interfaces = append(i.Interfaces, info) + } + } + + return nil +} + +// Param parameters in method +type Param struct { // (user model.User) + Package string // package's name: model + Name string // param's name: user + Type string // param's type: User + IsArray bool // is array or not + IsPointer bool // is pointer or not +} + +func (p *Param) Eq(q Param) bool { + return p.Package == q.Package && p.Type == q.Type +} + +func (p *Param) IsError() bool { + return p.Type == "error" +} + +func (p *Param) IsGenT() bool { + return p.Package == "gen" && p.Type == "T" +} + +func (p *Param) IsNull() bool { + return p.Package == "" && p.Type == "" && p.Name == "" +} + +func (p *Param) IsTime() bool { + return p.Package == "time" && p.Type == "Time" +} + +func (p *Param) SetName(name string) { + p.Name = name +} + +func (p *Param) AllowType() bool { + switch p.Type { + case "string", "bytes": + return true + case "int", "int8", "int16", "int32", "int64", "uint", "uint8", "uint16", "uint32", "uint64": + return true + case "float64", "float32": + return true + case "bool": + return true + case "time.Time": + return true + default: + return false + } +} + +func (p *Param) astGetParamType(param *ast.Field) { + switch v := param.Type.(type) { + case *ast.Ident: + p.Type = v.Name + if v.Obj != nil { + p.Package = "UNDEFINED" // set a placeholder + } + case *ast.SelectorExpr: + p.astGetEltType(v) + case *ast.ArrayType: + p.astGetEltType(v.Elt) + p.IsArray = true + case *ast.Ellipsis: + p.astGetEltType(v.Elt) + p.IsArray = true + } +} + +func (p *Param) astGetEltType(expr ast.Expr) string { + switch v := expr.(type) { + case *ast.Ident: + p.Type = v.Name + if v.Obj != nil { + p.Package = "UNDEFINED" + } + case *ast.SelectorExpr: + temp := new(Param) + p.Type = v.Sel.Name + p.Package = temp.astGetEltType(v.X) + } + return p.Type +} diff --git a/internal/parser/utils.go b/internal/parser/utils.go new file mode 100644 index 00000000..05dccd7d --- /dev/null +++ b/internal/parser/utils.go @@ -0,0 +1,30 @@ +package parser + +import "go/ast" + +func getParamList(field *ast.FieldList) []Param { + if field == nil { + return nil + } + var pars []Param + if len(field.List) < 1 { + return nil + } + for _, field := range field.List { + if field.Names == nil { + par := Param{} + par.astGetParamType(field) + pars = append(pars, par) + continue + } + for _, name := range field.Names { + par := Param{ + Name: name.Name, + } + par.astGetParamType(field) + pars = append(pars, par) + continue + } + } + return pars +} diff --git a/internal/template/tmpl.go b/internal/template/tmpl.go new file mode 100644 index 00000000..51b7c6c3 --- /dev/null +++ b/internal/template/tmpl.go @@ -0,0 +1,218 @@ +package template + +const HeaderTmpl = ` +// Code generated by gorm/gen. DO NOT EDIT. +// Code generated by gorm/gen. DO NOT EDIT. +// Code generated by gorm/gen. DO NOT EDIT. + +package {{.}} + +import( + "gorm.io/gorm" + + "gorm.io/gorm/gen/field" + "gorm.io/gorm/gen/helper" +) +` + +const FuncTmpl = ` +/* +{{.Doc}}*/ +func ({{.S}} {{.MethodStruct}}){{.MethodName}}({{range $index,$params:=.Params}}{{if ne $index 0}},{{end}}{{$params.Name}} {{if ne $params.Package ""}}{{$params.Package}}.{{end}}{{$params.Type}}{{end}})({{range $index,$params:=.Result}}{{if ne $index 0}},{{end}}{{$params.Name}} {{if $params.IsArray}}[]{{end}}{{if $params.IsPointer}}*{{end}}{{if ne $params.Package ""}}{{$params.Package}}.{{end}}{{$params.Type}}{{end}}){ + {{if .HasSqlData}}params := map[string]interface{}{ {{range $index,$data:=.SqlData}} + "{{$data}}":{{$data}},{{end}} + } + {{end}} + {{if eq .Table "_"}}table:={{.S}}.UnderlyingDB().Statement.Table{{end}} + + var generateSQL string + {{range $line:=.SqlList}}{{$line}} + {{end}} + + {{if .HasNeedNewResult}}result =new({{if ne .ResultData.Package ""}}{{.ResultData.Package}}.{{end}}{{.ResultData.Type}}){{end}} + {{.ExecuteResult}} = {{.S}}.UnderlyingDB().{{.GormOption}}(generateSQL{{if .HasSqlData}},params{{end}}){{if not .ResultData.IsNull}}.Find({{if .HasGotPoint}}&{{end}}{{.ResultData.Name}}){{end}}.Error + return +} + +` + +// TODO fix New methond, initialize fields with table name +const BaseStruct = ` +type {{.NewStructName}} struct { + gen.DO + + {{range $p :=.Members}}{{$p.Name}} field.{{$p.NewType}} + {{end}} +} + +func New{{.StructName}}(db *gorm.DB) *{{.NewStructName}} { + _{{.NewStructName}} := &{{.NewStructName}}{ + {{range $p :=.Members}}{{$p.Name}}: field.New{{$p.NewType}}("{{$p.ColumnName}}"), + {{end}} + } + _{{.NewStructName}}.UseDB(db) + _{{.NewStructName}}.UseModel({{.StructInfo.Package}}.{{.StructInfo.Type}}{}) + return _{{.NewStructName}} +} + +` + +const BaseGormFunc = ` +func ({{.S}} {{.NewStructName}}) Not(conds ...gen.Condition) *{{.NewStructName}} { + next := {{.S}} + next.DO = *{{.S}}.DO.Not(conds...).(*gen.DO) + return &next +} + +func ({{.S}} {{.NewStructName}}) Or(conds ...gen.Condition) *{{.NewStructName}} { + next := {{.S}} + next.DO = *{{.S}}.DO.Or(conds...).(*gen.DO) + return &next +} + +func ({{.S}} {{.NewStructName}}) Select(conds ...field.Expr) *{{.NewStructName}} { + next := {{.S}} + next.DO = *{{.S}}.DO.Select(conds...).(*gen.DO) + return &next +} + +func ({{.S}} {{.NewStructName}}) Where(conds ...gen.Condition) *{{.NewStructName}} { + next := {{.S}} + next.DO = *{{.S}}.DO.Where(conds...).(*gen.DO) + return &next +} + +func ({{.S}} {{.NewStructName}}) Order(conds ...field.Expr) *{{.NewStructName}} { + next := {{.S}} + next.DO = *{{.S}}.DO.Order(conds...).(*gen.DO) + return &next +} + +func ({{.S}} {{.NewStructName}}) Take() (*{{.StructInfo.Package}}.{{.StructInfo.Type}}, error) { + result := new({{.StructInfo.Package}}.{{.StructInfo.Type}}) + if err := {{.S}}.DO.Take(result); err != nil { + return nil, err + } + return result, nil +} + +func ({{.S}} {{.NewStructName}}) First() (*{{.StructInfo.Package}}.{{.StructInfo.Type}}, error) { + result := new({{.StructInfo.Package}}.{{.StructInfo.Type}}) + if err := {{.S}}.DO.First(result); err != nil { + return nil, err + } + return result, nil +} + +func ({{.S}} {{.NewStructName}}) Last() (*{{.StructInfo.Package}}.{{.StructInfo.Type}}, error) { + result := new({{.StructInfo.Package}}.{{.StructInfo.Type}}) + if err := {{.S}}.DO.Last(result); err != nil { + return nil, err + } + return result, nil +} + +func ({{.S}} {{.NewStructName}}) Find() (result []*{{.StructInfo.Package}}.{{.StructInfo.Type}},err error) { + return result, {{.S}}.DO.Find(&result) +} + + +func ({{.S}} {{.NewStructName}}) Create(info *{{.StructInfo.Package}}.{{.StructInfo.Type}}) error { + return {{.S}}.DO.Create(info) +} + +func ({{.S}} {{.NewStructName}}) BathCreate(infos []*{{.StructInfo.Package}}.{{.StructInfo.Type}}) error { + return {{.S}}.DO.CreateInBatches(infos, len(infos)) +} + +func ({{.S}} {{.NewStructName}}) Update(updates map[string]interface{}) error { + return {{.S}}.DO.Updates(updates) +} + +func ({{.S}} {{.NewStructName}}) FindByPage(offset int, limit int) (result []*{{.StructInfo.Package}}.{{.StructInfo.Type}}, count int64, err error) { + err = {{.S}}.DO.Count(&count) + if err != nil { + return + } + err = {{.S}}.DO.Offset(offset).Limit(limit).Find(&result) + return +} + +func ({{.S}} {{.NewStructName}}) Delete(conds ...field.Expr) error { + result := new({{.StructInfo.Package}}.{{.StructInfo.Type}}) + return {{.S}}.DO.Delete(result, conds...) +} +` + +const UseTmpl = ` +type DB struct{ + db *gorm.DB + + {{range $name,$d :=.Data}}{{$d.StructName}} *{{$name}} + {{end}} +} + +func (d *DB) Transaction(fc func(db *DB) error, opts ...*sql.TxOptions) error { + return d.db.Transaction(func(tx *gorm.DB) error { return fc(d.withTx(tx)) }, opts...) +} + +func (d *DB) Begin(opts ...*sql.TxOptions) *DB { + d.db = d.db.Begin(opts...) + return d +} + +func (d *DB) Commit() *DB { + d.db = d.db.Commit() + return d +} + +func (d *DB) Rollback() *DB { + d.db = d.db.Rollback() + return d +} + +func (d *DB) SavePoint(name string) *DB { + d.db = d.db.SavePoint(name) + return d +} + +func (d *DB) RollbackTo(name string) *DB { + d.db = d.db.RollbackTo(name) + return d +} + +func (d *DB) withTx(tx *gorm.DB) *DB { + newDB := *d + newDB.db = tx + return &newDB +} + +func Use(db *gorm.DB) *DB { + return &DB{ + db: db, + {{range $name,$d :=.Data}}{{$d.StructName}}: New{{$d.StructName}}(db), + {{end}} + } +} +` + +// ModelTemplate used as a variable because it cannot load template file after packed, params still can pass file +const ModelTemplate = ` +package {{.StructInfo.Package}} + +import "time" + +const TableName{{.StructName}} = "{{.TableName}}" + +// {{.TableName}} +type {{.StructName}} struct { + {{range .Members}} + {{.Name}} {{.ModelType}} ` + "`json:\"{{.ColumnName}}\" gorm:\"column:{{.ColumnName}}\"` // {{.ColumnComment}}" + + `{{end}} +} + +// TableName . +func (*{{.StructName}}) TableName() string { + return TableName{{.StructName}} +} +` diff --git a/log/log.go b/log/log.go new file mode 100644 index 00000000..64f32a8d --- /dev/null +++ b/log/log.go @@ -0,0 +1,78 @@ +package log + +import ( + golog "log" + "os" +) + +var loggers = []Logger{golog.New(os.Stderr, "", golog.LstdFlags)} + +func UseLogger(l Logger) { + loggers = append([]Logger{l}, loggers...) +} + +type Logger interface { + Print(v ...interface{}) + Printf(format string, v ...interface{}) + Println(v ...interface{}) + Fatal(v ...interface{}) + Fatalf(format string, v ...interface{}) + Fatalln(v ...interface{}) + Panic(v ...interface{}) + Panicf(format string, v ...interface{}) + Panicln(v ...interface{}) +} + +func Print(v ...interface{}) { + for _, l := range loggers { + l.Print(v...) + } +} + +func Printf(format string, v ...interface{}) { + for _, l := range loggers { + l.Printf(format, v...) + } +} + +func Println(v ...interface{}) { + for _, l := range loggers { + l.Println(v...) + } +} + +func Fatal(v ...interface{}) { + for _, l := range loggers { + l.Fatal(v...) + } +} + +func Fatalf(format string, v ...interface{}) { + for _, l := range loggers { + l.Fatalf(format, v...) + } +} + +func Fatalln(v ...interface{}) { + for _, l := range loggers { + l.Fatalln(v...) + } +} + +func Panic(v ...interface{}) { + for _, l := range loggers { + l.Panic(v...) + } +} + +func Panicf(format string, v ...interface{}) { + for _, l := range loggers { + l.Panicf(format, v...) + } +} + +func Panicln(v ...interface{}) { + for _, l := range loggers { + l.Panicln(v...) + } +} diff --git a/metric.go b/metric.go index aa5adb78..8623f9d6 100644 --- a/metric.go +++ b/metric.go @@ -5,7 +5,6 @@ package gen type BasicMethod uint const ( - // 用户自定义方法 methodDiy BasicMethod = iota methodSelect From 3bd5acb825a795147354c671135a1662d35eec2b Mon Sep 17 00:00:00 2001 From: riverchu Date: Tue, 27 Jul 2021 16:58:08 +0800 Subject: [PATCH 02/19] style: update comment --- do.go | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/do.go b/do.go index 16145105..40ac806e 100644 --- a/do.go +++ b/do.go @@ -68,7 +68,7 @@ func (s *DO) buildWhere() []clause.Expression { type stmtOpt func(*gorm.Statement) *gorm.Statement var ( - // withFROM + // withFROM add FROM clause withFROM stmtOpt = func(stmt *gorm.Statement) *gorm.Statement { if stmt.Table == "" { _ = stmt.Parse(stmt.Model) @@ -77,7 +77,7 @@ var ( return stmt } - // // withSELECT 增加SELECT子句 + // // withSELECT add SELECT clause // withSELECT stmtOpt = func(stmt *gorm.Statement) *gorm.Statement { // if _, ok := stmt.Clauses["SELECT"]; !ok { // stmt.AddClause(clause.Select{}) @@ -111,12 +111,12 @@ func (s *DO) buildStmt(opts ...stmtOpt) *gorm.Statement { // return clause.Expr{SQL: "(" + stmt.SQL.String() + ")", Vars: stmt.Vars} // } -// As 指定的值不可继承,因此需要在结尾使用 +// As alias cannot be heired, As must used on tail func (s *DO) As(alias string) Dao { return &DO{db: s.db, alias: alias} } -// ======================== 逻辑操作 ======================== +// ======================== chainable api ======================== func (s *DO) Not(conds ...Condition) Dao { return NewDO(s.db.Clauses(clause.Where{Exprs: []clause.Expression{clause.Not(condToExpression(conds...)...)}})) } @@ -125,7 +125,6 @@ func (s *DO) Or(conds ...Condition) Dao { return NewDO(s.db.Clauses(clause.Where{Exprs: []clause.Expression{clause.Or(clause.And(condToExpression(conds...)...))}})) } -// ======================== chainable api ======================== func (s *DO) Select(columns ...field.Expr) Dao { Emit(methodSelect) if len(columns) == 0 { @@ -396,8 +395,8 @@ func toInterfaceSlice(value interface{}) []interface{} { } } -// ======================== 临时数据结构 ======================== -// 逗号分割的表达式 +// ======================== temporary ======================== +// CommaExpression comma expression type CommaExpression struct { Exprs []clause.Expression } From 57560c60208c7bf1ac754f65d9ceef8d22e9d2ae Mon Sep 17 00:00:00 2001 From: riverchu Date: Tue, 27 Jul 2021 17:15:23 +0800 Subject: [PATCH 03/19] feat: recv struct pointer --- internal/check/checkstruct.go | 17 ++++------------- internal/check/export.go | 11 ++++++----- internal/check/gen_structs.go | 2 +- internal/check/utils.go | 14 +++++++++++--- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/internal/check/checkstruct.go b/internal/check/checkstruct.go index 08cb4cce..9a0e21a6 100644 --- a/internal/check/checkstruct.go +++ b/internal/check/checkstruct.go @@ -2,7 +2,6 @@ package check import ( "fmt" - "strings" "gorm.io/gorm" @@ -30,7 +29,7 @@ func (b *BaseStruct) getMembers(st interface{}) { for _, field := range stmt.Schema.Fields { b.Members = append(b.Members, &Member{ Name: field.Name, - Type: DelPointer(field.FieldType.String()), + Type: DelPointerSym(field.FieldType.String()), ColumnName: field.DBName, }) } @@ -43,8 +42,8 @@ func (b *BaseStruct) getTableName(st interface{}) { b.TableName = stmt.Table } -// checkStructAndMembers check if struct is exportable and if member's type is regular -func (b *BaseStruct) checkStructAndMembers() (err error) { +// check if struct is exportable and if member's type is regular +func (b *BaseStruct) check() (err error) { if !isCapitalize(b.StructName) { err = fmt.Errorf("ignoring non exportable struct name:%s", b.NewStructName) log.Println(err) @@ -54,15 +53,7 @@ func (b *BaseStruct) checkStructAndMembers() (err error) { if !allowType(m.Type) { b.Members[index].Type = "field" } - b.Members[index].NewType = getNewType(m.Type) + b.Members[index].NewType = getTypeName(m.Type) } return nil } - -func getNewType(t string) string { - var newType string - for _, s := range strings.Split(t, ".") { - newType = s - } - return strings.Title(newType) -} diff --git a/internal/check/export.go b/internal/check/export.go index c9111370..77cb91fe 100644 --- a/internal/check/export.go +++ b/internal/check/export.go @@ -18,16 +18,17 @@ func CheckStructs(db *gorm.DB, structs ...interface{}) (bases []*BaseStruct, err for _, st := range structs { structType := reflect.TypeOf(st) + name := getTypeName(structType.String()) base := &BaseStruct{ - S: GetSimpleName(structType.Name()), - StructName: structType.Name(), - NewStructName: strings.ToLower(structType.Name()), - StructInfo: parser.Param{Type: structType.Name(), Package: getPackageName(structType.String())}, + S: GetSimpleName(name), + StructName: name, + NewStructName: strings.ToLower(name), + StructInfo: parser.Param{Type: name, Package: getPackageName(structType.String())}, db: db, } base.getMembers(st) base.getTableName(st) - if e := base.checkStructAndMembers(); e != nil { + if e := base.check(); e != nil { continue } diff --git a/internal/check/gen_structs.go b/internal/check/gen_structs.go index 3c0e9172..c0f729ca 100644 --- a/internal/check/gen_structs.go +++ b/internal/check/gen_structs.go @@ -86,7 +86,7 @@ func GenBaseStructs(db *gorm.DB, pkg string, tableName ...string) (bases []*Base base.NewStructName = strings.ToLower(base.StructName) base.S = string(base.NewStructName[0]) - _ = base.checkStructAndMembers() + _ = base.check() bases = append(bases, &base) } return diff --git a/internal/check/utils.go b/internal/check/utils.go index 9bb737bd..81d3edfb 100644 --- a/internal/check/utils.go +++ b/internal/check/utils.go @@ -38,7 +38,7 @@ func isDBUndefined(db *gorm.DB) bool { } func getPackageName(fullName string) string { - return strings.Split(fullName, ".")[0] + return strings.Split(DelPointerSym(fullName), ".")[0] } func isDigit(str string) bool { @@ -71,10 +71,18 @@ func stringHasMore(i int, str string) bool { return i < len(str)-1 } -func DelPointer(name string) string { +func DelPointerSym(name string) string { return strings.TrimLeft(name, "*") } func GetSimpleName(s string) string { - return string(strings.ToLower(s)[0]) + return string(strings.ToLower(DelPointerSym(s))[0]) +} + +func getTypeName(t string) string { + var res string + for _, s := range strings.Split(t, ".") { + res = s + } + return strings.Title(res) } From 82bbae619942998459204e3ae9e8d2c85f8f6d7f Mon Sep 17 00:00:00 2001 From: riverchu Date: Tue, 27 Jul 2021 17:25:12 +0800 Subject: [PATCH 04/19] fix: add pre check --- internal/check/clause.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/internal/check/clause.go b/internal/check/clause.go index 94490ae6..55c58c99 100644 --- a/internal/check/clause.go +++ b/internal/check/clause.go @@ -275,6 +275,10 @@ func (s *Slices) parseElSE(name string) (res ElseClause) { res.Cond = slice.Value res.VarName = name res.Type = slice.Type + + if !s.HasMore() { + return + } for n := s.Next(); s.HasMore(); n = s.Next() { switch n.Type { case SQL, DATA, VARIABLE: From 09f1c1e93acd33912033c8a36129797a177118cd Mon Sep 17 00:00:00 2001 From: riverchu Date: Wed, 28 Jul 2021 14:01:14 +0800 Subject: [PATCH 05/19] feat: improve automaton --- internal/check/checkinterface.go | 92 +++++------ internal/check/clause.go | 251 ++++++++++++++++--------------- internal/check/export.go | 13 +- internal/check/utils.go | 6 +- internal/template/tmpl.go | 2 +- 5 files changed, 179 insertions(+), 185 deletions(-) diff --git a/internal/check/checkinterface.go b/internal/check/checkinterface.go index 04ff58d7..1615e4c8 100644 --- a/internal/check/checkinterface.go +++ b/internal/check/checkinterface.go @@ -26,7 +26,7 @@ type InterfaceMethod struct { Result []parser.Param ResultData parser.Param ExecuteResult string - SqlList []string + SqlTmplList []string SqlData []string SqlString string GormOption string @@ -64,7 +64,7 @@ func (f *InterfaceMethod) checkParams(params []parser.Param) (err error) { // checkResult check all parameters and replace gen.T by target structure. Parameters must be one of int/string/struct func (f *InterfaceMethod) checkResult(result []parser.Param) (err error) { - retList := make([]parser.Param, len(result)) + resList := make([]parser.Param, len(result)) for i, param := range result { if param.Package == "UNDEFINED" { param.Package = f.OriginStruct.Package @@ -74,20 +74,20 @@ func (f *InterfaceMethod) checkResult(result []parser.Param) (err error) { param.SetName("err") f.ExecuteResult = "err" case param.Eq(f.OriginStruct) || param.IsGenT(): + param.SetName("result") param.Type = f.OriginStruct.Type param.Package = f.OriginStruct.Package - param.SetName("result") param.IsPointer = true f.ResultData = param case param.AllowType(), param.IsTime(): param.SetName("result") f.ResultData = param default: - return fmt.Errorf("illegal parameter:%s.%s on struct %s.%s generated method %s \n ", param.Package, param.Type, f.OriginStruct.Package, f.OriginStruct.Type, f.MethodName) + return fmt.Errorf("illegal parameter:%s.%s on struct %s.%s generated method %s", param.Package, param.Type, f.OriginStruct.Package, f.OriginStruct.Type, f.MethodName) } - retList[i] = param + resList[i] = param } - f.Result = retList + f.Result = resList return } @@ -137,23 +137,20 @@ func (s *sql) WriteSql(b byte) { default: _ = s.WriteByte(b) } - } // sqlStateCheck check sql with an adeterministic finite automaton -func (f *InterfaceMethod) sqlStateCheck() (err error) { - sqlString := f.SqlString + " " +func (f *InterfaceMethod) sqlStateCheck() error { + sqlString := f.SqlString result := NewSlices() var out sql - - for i := 0; i < len(sqlString); i++ { + for i := 0; !strOutrange(i, sqlString); i++ { b := sqlString[i] switch b { case '"': _ = out.WriteByte(sqlString[i]) - for { - i++ - if !stringHasMore(i, sqlString) { + for i++; ; i++ { + if strOutrange(i, sqlString) { return fmt.Errorf("incomplete SQL:%s", sqlString) } _ = out.WriteByte(sqlString[i]) @@ -161,105 +158,98 @@ func (f *InterfaceMethod) sqlStateCheck() (err error) { break } } - case '{', '@': - sqlClause := out.String() - if strings.TrimSpace(sqlClause) != "" { + if sqlClause := out.String(); strings.TrimSpace(sqlClause) != "" { result.slices = append(result.slices, slice{ Type: SQL, - Value: strconv.Quote(out.String()), + Value: strconv.Quote(sqlClause), }) - } out.Reset() - if !stringHasMore(i+1, sqlString) { + if strOutrange(i+1, sqlString) { return fmt.Errorf("incomplete SQL:%s", sqlString) } if b == '{' && sqlString[i+1] == '{' { - i += 2 - for { - if !stringHasMore(i, sqlString) { + for i += 2; ; i++ { + if strOutrange(i, sqlString) { return fmt.Errorf("incomplete SQL:%s", sqlString) } if sqlString[i] == '"' { _ = out.WriteByte(sqlString[i]) - for { - i++ - if !stringHasMore(i, sqlString) { + for i++; ; i++ { + if strOutrange(i, sqlString) { return fmt.Errorf("incomplete SQL:%s", sqlString) } _ = out.WriteByte(sqlString[i]) if sqlString[i] == '"' && sqlString[i-1] != '\\' { - i++ break } } + i++ + } + if strOutrange(i+1, sqlString) { + return fmt.Errorf("incomplete SQL:%s", sqlString) } if sqlString[i] == '}' && sqlString[i+1] == '}' { + i++ + part, err := checkTemplate(out.String(), f.Params) if err != nil { - err := fmt.Errorf("sql [%s] dynamic template %s err:%s ", sqlString, out.String(), err) - return err + return fmt.Errorf("sql [%s] dynamic template %s err:%w", sqlString, out.String(), err) } result.slices = append(result.slices, part) - i++ out.Reset() break } out.WriteSql(sqlString[i]) - i++ - } - } if b == '@' { - t := DATA i++ + status := DATA if sqlString[i] == '@' { - t = VARIABLE i++ + status = VARIABLE } - for { - if i == len(sqlString) || isStringEnd(sqlString[i]) { + for ; ; i++ { + if strOutrange(i, sqlString) || isEnd(sqlString[i]) { varString := out.String() - s, err := f.isParamInMethod(varString, t) + out.Reset() + + params, err := f.methodParams(varString, status) if err != nil { return fmt.Errorf("sql [%s] varable %s err:%s", sqlString, varString, err) } - - result.slices = append(result.slices, s) - out.Reset() + result.slices = append(result.slices, params) i-- break } - out.WriteSql(sqlString[i]) - i++ } } default: out.WriteSql(b) } } - if strings.Trim(out.String(), " ") != "" { + if sqlClause := out.String(); strings.TrimSpace(sqlClause) != "" { result.slices = append(result.slices, slice{ Type: SQL, - Value: strconv.Quote(out.String()), + Value: strconv.Quote(sqlClause), }) } - _, err = result.parse() + _, err := result.parse() if err != nil { - return fmt.Errorf("sql [%s] parser err:%s", sqlString, err) + return fmt.Errorf("sql [%s] parser err:%w", sqlString, err) } - f.SqlList = result.tmpl - return + f.SqlTmplList = result.tmpl + return nil } -// isParamInMethod if sql's param is not external(except table), generate by gorm -func (f *InterfaceMethod) isParamInMethod(param string, s Status) (result slice, err error) { +// methodParams return extrenal parameters, table name +func (f *InterfaceMethod) methodParams(param string, s Status) (result slice, err error) { for _, p := range f.Params { if p.Name == param { var str string diff --git a/internal/check/clause.go b/internal/check/clause.go index 55c58c99..a1f8dce9 100644 --- a/internal/check/clause.go +++ b/internal/check/clause.go @@ -13,11 +13,23 @@ type Clause interface { String() string } -// SQLClause sql condition clause -type SQLClause struct { +var ( + _ Clause = new(SQLClause) + _ Clause = new(IfClause) + _ Clause = new(ElseClause) + _ Clause = new(WhereClause) + _ Clause = new(SetClause) +) + +type clause struct { VarName string Type Status - Value []string +} + +// SQLClause sql condition clause +type SQLClause struct { + clause + Value []string } func (s SQLClause) String() string { @@ -26,9 +38,8 @@ func (s SQLClause) String() string { // IfClause if clause type IfClause struct { - VarName string + clause Cond string - Type Status Value []Clause Else []Clause } @@ -39,25 +50,23 @@ func (i IfClause) String() string { // ElseClause else clause type ElseClause struct { - VarName string - Cond string - Type Status - Value []Clause + clause + Cond string + Value []Clause } func (e ElseClause) String() (res string) { - strList := make([]string, len(e.Value)) + condList := make([]string, len(e.Value)) for i, v := range e.Value { - strList[i] = v.String() + condList[i] = v.String() } - return strings.ReplaceAll(strings.Join(strList, "+"), `"+"`, "") + return strings.ReplaceAll(strings.Join(condList, "+"), `"+"`, "") } // WhereClause where clause type WhereClause struct { - VarName string - Type Status - Value []Clause + clause + Value []Clause } func (w WhereClause) String() string { @@ -66,9 +75,8 @@ func (w WhereClause) String() string { // SetClause set clause type SetClause struct { - VarName string - Type Status - Value []Clause + clause + Value []Clause } func (w SetClause) String() string { @@ -94,6 +102,11 @@ func NewSlices() *Slices { } } +// Len return length of s.slices +func (s *Slices) Len() int { + return len(s.slices) +} + // Next return next slice and increase index by 1 func (s *Slices) Next() slice { s.currentIndex++ @@ -156,12 +169,13 @@ func (s *Slices) CreateStringSet(name string) { } // parse slice and append result to tmpl, return a Clause array -func (s *Slices) parse() (res []Clause, err error) { +func (s *Slices) parse() ([]Clause, error) { if s.IsNull() { - err = fmt.Errorf("sql is null") - return + return nil, fmt.Errorf("sql is null") } + name := "generateSQL" + res := make([]Clause, 0, s.Len()) for slice := s.Current(); ; slice = s.Next() { s.tmpl = append(s.tmpl, "") switch slice.Type { @@ -170,39 +184,36 @@ func (s *Slices) parse() (res []Clause, err error) { res = append(res, sqlClause) s.tmpl = append(s.tmpl, fmt.Sprintf("%s+=%s", name, sqlClause.String())) case IF: - var ifClause IfClause - ifClause, err = s.parseIF() + ifClause, err := s.parseIF() if err != nil { - return + return nil, err } res = append(res, ifClause) s.tmpl = append(s.tmpl, fmt.Sprintf("%s+=helper.IfClause(%s)", name, ifClause.VarName)) case WHERE: - var whereClause WhereClause - whereClause, err = s.parseWhere() + whereClause, err := s.parseWhere() if err != nil { - return + return nil, err } res = append(res, whereClause) s.tmpl = append(s.tmpl, fmt.Sprintf("%s+=helper.WhereClause(%s)", name, whereClause.VarName)) case SET: - var setClause SetClause - setClause, err = s.parseSet() + setClause, err := s.parseSet() if err != nil { - return + return nil, err } res = append(res, setClause) s.tmpl = append(s.tmpl, fmt.Sprintf("%s+=helper.SetClause(%s)", name, setClause.VarName)) case END: default: - err = fmt.Errorf("unknow clause:%s", slice.Origin) - return + return nil, fmt.Errorf("unknow clause:%s", slice.Origin) } if !s.HasMore() { - return + break } } + return res, nil } // parseIF parse if clause @@ -399,58 +410,52 @@ func (s *Slices) parseSQL(name string) (res SQLClause) { // sql fragment type fragment struct { Type Status - value string + Value string } func checkFragment(s string, params []parser.Param) (f fragment, err error) { - f = fragment{Type: UNKNOWN, value: strings.Trim(s, " ")} + digital := func(str string) string { + if isDigit(str) { + return "" + } + return str + } + + f = fragment{Type: UNKNOWN, Value: strings.Trim(s, " ")} str := strings.ToLower(strings.Trim(s, " ")) - switch str { + switch digital(str) { + case "": + f.Type = INT case "&&", "||": f.Type = LOGICAL - return case ">", "<", ">=", "<=", "==", "!=": f.Type = EXPRESSION - return case "end": f.Type = END - return case "if": f.Type = IF - return case "set": f.Type = SET - return case "else": f.Type = ELSE - return case "where": f.Type = WHERE - return case "true", "false": f.Type = BOOL - return case "nil": f.Type = OTHER - return default: - if isDigit(str) { - f.Type = INT - return - } - f.fragmentByParams(params) - if f.Type != UNKNOWN { - return + if f.Type == UNKNOWN { + err = fmt.Errorf("unknow parameter: %s", s) } } - // TODO double check - return f, fmt.Errorf("unknow parameter: %s", s) + return } func (f *fragment) fragmentByParams(params []parser.Param) { for _, param := range params { - if param.Name == f.value { + if param.Name == f.Value { switch param.Type { case "bool": f.Type = BOOL @@ -470,100 +475,102 @@ func (f *fragment) fragmentByParams(params []parser.Param) { } } -func splitTemplate(tmpl string, params []parser.Param) (newList []fragment, err error) { - tmpl += " " +func splitTemplate(tmpl string, params []parser.Param) (fragList []fragment, err error) { var out bytes.Buffer - var t fragment - for i := 0; i < len(tmpl); i++ { + // TODO add dump func to out + var f fragment + for i := 0; !strOutrange(i, tmpl); i++ { switch tmpl[i] { case '"': - for { - out.WriteByte(tmpl[i]) - if !stringHasMore(i, tmpl) { - err = fmt.Errorf("incomplete code:%s", tmpl) - return + out.WriteByte(tmpl[i]) + for i++; ; i++ { + if strOutrange(i, tmpl) { + return nil, fmt.Errorf("incomplete code:%s", tmpl) } - i++ + out.WriteByte(tmpl[i]) + if tmpl[i] == '"' && tmpl[i-1] != '\\' { - out.WriteByte(tmpl[i]) - newList = append(newList, fragment{Type: STRING, value: out.String()}) + fragList = append(fragList, fragment{Type: STRING, Value: out.String()}) out.Reset() break } } - continue case ' ': - t, err = checkFragment(out.String(), params) - if err != nil { - return - } - if t.value != "" { - newList = append(newList, t) - } + sqlClause := out.String() out.Reset() - case '>', '<', '=', '!': - t, err = checkFragment(out.String(), params) - if err != nil { - return - } - if t.value != "" { - newList = append(newList, t) + if sqlClause != "" { + f, err = checkFragment(sqlClause, params) + if err != nil { + return nil, err + } + fragList = append(fragList, f) } + case '>', '<', '=', '!': + sqlClause := out.String() out.Reset() + if sqlClause != "" { + f, err = checkFragment(sqlClause, params) + if err != nil { + return nil, err + } + fragList = append(fragList, f) + } out.WriteByte(tmpl[i]) + + if strOutrange(i+1, tmpl) { + return nil, fmt.Errorf("incomplete code:%s", tmpl) + } if tmpl[i+1] == '=' { out.WriteByte(tmpl[i+1]) i++ } - t, err = checkFragment(out.String(), params) + + f, err = checkFragment(out.String(), params) if err != nil { - return - } - if t.value != "" { - newList = append(newList, t) + return nil, err } + fragList = append(fragList, f) out.Reset() - continue case '&', '|': + if strOutrange(i+1, tmpl) { + return nil, fmt.Errorf("incomplete code:%s", tmpl) + } + if tmpl[i+1] == tmpl[i] { - t, err = checkFragment(out.String(), params) - if err != nil { - return - } - if t.value != "" { - newList = append(newList, t) - } + i++ + + sqlClause := out.String() out.Reset() - out.WriteString(tmpl[i : i+2]) - t, err = checkFragment(out.String(), params) - if err != nil { - return + if sqlClause != "" { + f, err = checkFragment(out.String(), params) + if err != nil { + return + } + fragList = append(fragList, f) } - if t.value != "" { - newList = append(newList, t) - } - out.Reset() - i++ - continue - } + // write && or || + fragList = append(fragList, fragment{ + Type: LOGICAL, + Value: tmpl[i-1 : i+1], + }) + } + default: + out.WriteByte(tmpl[i]) } - - out.WriteByte(tmpl[i]) - } - t, err = checkFragment(out.String(), params) - if err != nil { - return } - if t.value != "" { - newList = append(newList, t) - } - // TODO check if verbose? - if len(newList) == 0 { - return + + sqlClause := out.String() + out.Reset() + if sqlClause != "" { + f, err = checkFragment(out.String(), params) + if err != nil { + return + } + fragList = append(fragList, f) } - return + return fragList, nil } // check validition of clause's value @@ -581,7 +588,7 @@ func checkTempleFragmentValid(list []fragment) error { } } default: - return fmt.Errorf("unknow fragment : %s ", list[i].value) + return fmt.Errorf("unknow fragment : %s ", list[i].Value) } } return nil @@ -594,7 +601,7 @@ func fragmentToString(list []fragment) string { return "" } for _, t := range list { - values = append(values, t.value) + values = append(values, t.Value) } return strings.Join(values, " ") } @@ -606,7 +613,7 @@ func fragmentToSLice(list []fragment) (part slice, err error) { return } for _, t := range list { - values = append(values, t.value) + values = append(values, t.Value) } part.Origin = strings.Join(values, " ") switch strings.ToLower(values[0]) { diff --git a/internal/check/export.go b/internal/check/export.go index 77cb91fe..75c0874e 100644 --- a/internal/check/export.go +++ b/internal/check/export.go @@ -38,7 +38,7 @@ func CheckStructs(db *gorm.DB, structs ...interface{}) (bases []*BaseStruct, err } // CheckInterface check the legitimacy of interfaces -func CheckInterface(f *parser.InterfaceSet, s *BaseStruct) (checkResult []*InterfaceMethod, err error) { +func CheckInterface(f *parser.InterfaceSet, s *BaseStruct) (checkResults []*InterfaceMethod, err error) { for _, interfaceInfo := range f.Interfaces { for _, method := range interfaceInfo.Methods { t := &InterfaceMethod{ @@ -52,19 +52,16 @@ func CheckInterface(f *parser.InterfaceSet, s *BaseStruct) (checkResult []*Inter Table: s.TableName, InterfaceName: interfaceInfo.Name, } - err = t.checkParams(method.Params) - if err != nil { + if err = t.checkParams(method.Params); err != nil { return } - err = t.checkResult(method.Result) - if err != nil { + if err = t.checkResult(method.Result); err != nil { return } - err = t.checkSQL() - if err != nil { + if err = t.checkSQL(); err != nil { return } - checkResult = append(checkResult, t) + checkResults = append(checkResults, t) } } return diff --git a/internal/check/utils.go b/internal/check/utils.go index 81d3edfb..255a60eb 100644 --- a/internal/check/utils.go +++ b/internal/check/utils.go @@ -18,7 +18,7 @@ func isCapitalize(s string) bool { return false } -func isStringEnd(b byte) bool { +func isEnd(b byte) bool { switch { case b >= 'a' && b <= 'z': return false @@ -67,8 +67,8 @@ func allowType(typ string) bool { } } -func stringHasMore(i int, str string) bool { - return i < len(str)-1 +func strOutrange(index int, str string) bool { + return index >= len(str) } func DelPointerSym(name string) string { diff --git a/internal/template/tmpl.go b/internal/template/tmpl.go index 51b7c6c3..3e592946 100644 --- a/internal/template/tmpl.go +++ b/internal/template/tmpl.go @@ -26,7 +26,7 @@ func ({{.S}} {{.MethodStruct}}){{.MethodName}}({{range $index,$params:=.Params}} {{if eq .Table "_"}}table:={{.S}}.UnderlyingDB().Statement.Table{{end}} var generateSQL string - {{range $line:=.SqlList}}{{$line}} + {{range $line:=.SqlTmplList}}{{$line}} {{end}} {{if .HasNeedNewResult}}result =new({{if ne .ResultData.Package ""}}{{.ResultData.Package}}.{{end}}{{.ResultData.Type}}){{end}} From 59d169ea58948025da6011b8158bea5db4553f83 Mon Sep 17 00:00:00 2001 From: riverchu Date: Wed, 28 Jul 2021 18:18:19 +0800 Subject: [PATCH 06/19] feat: implement Dump --- helper/quote.go | 2 +- internal/check/base.go | 20 +++++++++++++ internal/check/checkinterface.go | 45 +++++++++------------------- internal/check/clause.go | 50 ++++++++++++-------------------- 4 files changed, 54 insertions(+), 63 deletions(-) diff --git a/helper/quote.go b/helper/quote.go index 5f6e987f..f76a2843 100644 --- a/helper/quote.go +++ b/helper/quote.go @@ -10,7 +10,7 @@ func Quote(data string) string { } func escapeBackticks(data string) string { - buf := bytes.NewBuffer(nil) + var buf bytes.Buffer for _, c := range data { if c == '`' { buf.WriteByte('`') diff --git a/internal/check/base.go b/internal/check/base.go index b598a0e5..bd144a6e 100644 --- a/internal/check/base.go +++ b/internal/check/base.go @@ -1,5 +1,7 @@ package check +import "bytes" + type Status int const ( @@ -42,3 +44,21 @@ type Column struct { ColumnType string `gorm:"column:COLUMN_TYPE"` Extra string `gorm:"column:EXTRA"` } + +type sql struct{ bytes.Buffer } + +func (s *sql) WriteSql(b byte) { + switch b { + case '\n', '\t', ' ': + if s.Len() == 0 || s.Bytes()[s.Len()-1] != ' ' { + _ = s.WriteByte(' ') + } + default: + _ = s.WriteByte(b) + } +} + +func (s *sql) Dump() string { + defer s.Reset() + return s.String() +} diff --git a/internal/check/checkinterface.go b/internal/check/checkinterface.go index 1615e4c8..05d05979 100644 --- a/internal/check/checkinterface.go +++ b/internal/check/checkinterface.go @@ -1,7 +1,6 @@ package check import ( - "bytes" "fmt" "strconv" "strings" @@ -126,46 +125,32 @@ func (f *InterfaceMethod) parseDocString() string { return docString } -type sql struct{ bytes.Buffer } - -func (s *sql) WriteSql(b byte) { - switch b { - case '\n', '\t', ' ': - if s.Len() == 0 || s.Bytes()[s.Len()-1] != ' ' { - _ = s.WriteByte(' ') - } - default: - _ = s.WriteByte(b) - } -} - // sqlStateCheck check sql with an adeterministic finite automaton func (f *InterfaceMethod) sqlStateCheck() error { sqlString := f.SqlString result := NewSlices() - var out sql + var buf sql for i := 0; !strOutrange(i, sqlString); i++ { b := sqlString[i] switch b { case '"': - _ = out.WriteByte(sqlString[i]) + _ = buf.WriteByte(sqlString[i]) for i++; ; i++ { if strOutrange(i, sqlString) { return fmt.Errorf("incomplete SQL:%s", sqlString) } - _ = out.WriteByte(sqlString[i]) + _ = buf.WriteByte(sqlString[i]) if sqlString[i] == '"' && sqlString[i-1] != '\\' { break } } case '{', '@': - if sqlClause := out.String(); strings.TrimSpace(sqlClause) != "" { + if sqlClause := buf.Dump(); strings.TrimSpace(sqlClause) != "" { result.slices = append(result.slices, slice{ Type: SQL, Value: strconv.Quote(sqlClause), }) } - out.Reset() if strOutrange(i+1, sqlString) { return fmt.Errorf("incomplete SQL:%s", sqlString) @@ -176,12 +161,12 @@ func (f *InterfaceMethod) sqlStateCheck() error { return fmt.Errorf("incomplete SQL:%s", sqlString) } if sqlString[i] == '"' { - _ = out.WriteByte(sqlString[i]) + _ = buf.WriteByte(sqlString[i]) for i++; ; i++ { if strOutrange(i, sqlString) { return fmt.Errorf("incomplete SQL:%s", sqlString) } - _ = out.WriteByte(sqlString[i]) + _ = buf.WriteByte(sqlString[i]) if sqlString[i] == '"' && sqlString[i-1] != '\\' { break } @@ -195,15 +180,15 @@ func (f *InterfaceMethod) sqlStateCheck() error { if sqlString[i] == '}' && sqlString[i+1] == '}' { i++ - part, err := checkTemplate(out.String(), f.Params) + sqlClause := buf.Dump() + part, err := checkTemplate(sqlClause, f.Params) if err != nil { - return fmt.Errorf("sql [%s] dynamic template %s err:%w", sqlString, out.String(), err) + return fmt.Errorf("sql [%s] dynamic template %s err:%w", sqlString, sqlClause, err) } result.slices = append(result.slices, part) - out.Reset() break } - out.WriteSql(sqlString[i]) + buf.WriteSql(sqlString[i]) } } if b == '@' { @@ -215,9 +200,7 @@ func (f *InterfaceMethod) sqlStateCheck() error { } for ; ; i++ { if strOutrange(i, sqlString) || isEnd(sqlString[i]) { - varString := out.String() - out.Reset() - + varString := buf.Dump() params, err := f.methodParams(varString, status) if err != nil { return fmt.Errorf("sql [%s] varable %s err:%s", sqlString, varString, err) @@ -226,14 +209,14 @@ func (f *InterfaceMethod) sqlStateCheck() error { i-- break } - out.WriteSql(sqlString[i]) + buf.WriteSql(sqlString[i]) } } default: - out.WriteSql(b) + buf.WriteSql(b) } } - if sqlClause := out.String(); strings.TrimSpace(sqlClause) != "" { + if sqlClause := buf.Dump(); strings.TrimSpace(sqlClause) != "" { result.slices = append(result.slices, slice{ Type: SQL, Value: strconv.Quote(sqlClause), diff --git a/internal/check/clause.go b/internal/check/clause.go index a1f8dce9..336e7441 100644 --- a/internal/check/clause.go +++ b/internal/check/clause.go @@ -1,7 +1,6 @@ package check import ( - "bytes" "fmt" "strings" @@ -39,9 +38,9 @@ func (s SQLClause) String() string { // IfClause if clause type IfClause struct { clause - Cond string - Value []Clause - Else []Clause + Cond string + Value []Clause + Else []Clause } func (i IfClause) String() string { @@ -476,29 +475,25 @@ func (f *fragment) fragmentByParams(params []parser.Param) { } func splitTemplate(tmpl string, params []parser.Param) (fragList []fragment, err error) { - var out bytes.Buffer - // TODO add dump func to out + var buf sql var f fragment for i := 0; !strOutrange(i, tmpl); i++ { switch tmpl[i] { case '"': - out.WriteByte(tmpl[i]) + buf.WriteByte(tmpl[i]) for i++; ; i++ { if strOutrange(i, tmpl) { return nil, fmt.Errorf("incomplete code:%s", tmpl) } - out.WriteByte(tmpl[i]) + buf.WriteByte(tmpl[i]) if tmpl[i] == '"' && tmpl[i-1] != '\\' { - fragList = append(fragList, fragment{Type: STRING, Value: out.String()}) - out.Reset() + fragList = append(fragList, fragment{Type: STRING, Value: buf.Dump()}) break } } case ' ': - sqlClause := out.String() - out.Reset() - if sqlClause != "" { + if sqlClause := buf.Dump(); sqlClause != "" { f, err = checkFragment(sqlClause, params) if err != nil { return nil, err @@ -506,9 +501,7 @@ func splitTemplate(tmpl string, params []parser.Param) (fragList []fragment, err fragList = append(fragList, f) } case '>', '<', '=', '!': - sqlClause := out.String() - out.Reset() - if sqlClause != "" { + if sqlClause := buf.Dump(); sqlClause != "" { f, err = checkFragment(sqlClause, params) if err != nil { return nil, err @@ -516,22 +509,21 @@ func splitTemplate(tmpl string, params []parser.Param) (fragList []fragment, err fragList = append(fragList, f) } - out.WriteByte(tmpl[i]) + buf.WriteByte(tmpl[i]) if strOutrange(i+1, tmpl) { return nil, fmt.Errorf("incomplete code:%s", tmpl) } if tmpl[i+1] == '=' { - out.WriteByte(tmpl[i+1]) + buf.WriteByte(tmpl[i+1]) i++ } - f, err = checkFragment(out.String(), params) + f, err = checkFragment(buf.Dump(), params) if err != nil { return nil, err } fragList = append(fragList, f) - out.Reset() case '&', '|': if strOutrange(i+1, tmpl) { return nil, fmt.Errorf("incomplete code:%s", tmpl) @@ -540,12 +532,10 @@ func splitTemplate(tmpl string, params []parser.Param) (fragList []fragment, err if tmpl[i+1] == tmpl[i] { i++ - sqlClause := out.String() - out.Reset() - if sqlClause != "" { - f, err = checkFragment(out.String(), params) + if sqlClause := buf.Dump(); sqlClause != "" { + f, err = checkFragment(sqlClause, params) if err != nil { - return + return nil, err } fragList = append(fragList, f) } @@ -557,16 +547,14 @@ func splitTemplate(tmpl string, params []parser.Param) (fragList []fragment, err }) } default: - out.WriteByte(tmpl[i]) + buf.WriteByte(tmpl[i]) } } - sqlClause := out.String() - out.Reset() - if sqlClause != "" { - f, err = checkFragment(out.String(), params) + if sqlClause := buf.Dump(); sqlClause != "" { + f, err = checkFragment(sqlClause, params) if err != nil { - return + return nil, err } fragList = append(fragList, f) } From 2efd756f86149b2432aac60d98a0721341c42ea1 Mon Sep 17 00:00:00 2001 From: riverchu Date: Wed, 28 Jul 2021 18:33:13 +0800 Subject: [PATCH 07/19] feat: add doOptions when UseDB --- do.go | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/do.go b/do.go index 40ac806e..11faaf3b 100644 --- a/do.go +++ b/do.go @@ -26,9 +26,20 @@ type DO struct { alias string // for subquery } +type doOptions func(*gorm.DB) *gorm.DB + +var ( + // Debug use DB in debug mode + Debug = func(db *gorm.DB) *gorm.DB { return db.Debug() } +) + // UseDB specify a db connection(*gorm.DB) -func (s *DO) UseDB(db *gorm.DB) { - s.db = db.Session(new(gorm.Session)) +func (s *DO) UseDB(db *gorm.DB, opts ...doOptions) { + db = db.Session(new(gorm.Session)) + for _, opt := range opts { + db = opt(db) + } + s.db = db } // UseModel specify a data model structure as a source for table name From 93919199b99c65a67c20682be0c86133fdf3eeb4 Mon Sep 17 00:00:00 2001 From: riverchu Date: Wed, 28 Jul 2021 19:37:14 +0800 Subject: [PATCH 08/19] feat: update NewStructName template --- internal/template/tmpl.go | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/internal/template/tmpl.go b/internal/template/tmpl.go index 3e592946..e54d3ccb 100644 --- a/internal/template/tmpl.go +++ b/internal/template/tmpl.go @@ -36,7 +36,6 @@ func ({{.S}} {{.MethodStruct}}){{.MethodName}}({{range $index,$params:=.Params}} ` -// TODO fix New methond, initialize fields with table name const BaseStruct = ` type {{.NewStructName}} struct { gen.DO @@ -46,12 +45,17 @@ type {{.NewStructName}} struct { } func New{{.StructName}}(db *gorm.DB) *{{.NewStructName}} { - _{{.NewStructName}} := &{{.NewStructName}}{ - {{range $p :=.Members}}{{$p.Name}}: field.New{{$p.NewType}}("{{$p.ColumnName}}"), - {{end}} - } + _{{.NewStructName}} := new({{.NewStructName}}) + _{{.NewStructName}}.UseDB(db) _{{.NewStructName}}.UseModel({{.StructInfo.Package}}.{{.StructInfo.Type}}{}) + + + tableName := _{{.NewStructName}}.Table() + {{range $p :=.Members}} + _{{.NewStructName}}.{{$p.Name}} = field.New{{$p.NewType}}(tableName, "{{$p.ColumnName}}"), + {{end}} + return _{{.NewStructName}} } From 7afba4bdd8cb2ac93e419291866cb7d695399553 Mon Sep 17 00:00:00 2001 From: riverchu Date: Fri, 30 Jul 2021 17:46:33 +0800 Subject: [PATCH 09/19] feat: rename config's field --- generator.go | 31 ++++++++++--------------------- 1 file changed, 10 insertions(+), 21 deletions(-) diff --git a/generator.go b/generator.go index 49379351..8bd7e582 100644 --- a/generator.go +++ b/generator.go @@ -26,8 +26,8 @@ type T interface{} // NewGenerator create a new generator func NewGenerator(cfg Config) *Generator { - if cfg.modelPkgName == "" { - cfg.modelPkgName = check.ModelPkg + if cfg.ModelPkgName == "" { + cfg.ModelPkgName = check.ModelPkg } return &Generator{ Config: cfg, @@ -41,21 +41,10 @@ type Config struct { OutPath string OutFile string - pkgName string - modelPkgName string //default model - db *gorm.DB //nolint -} - -func (c *Config) SetModelPkg(name string) { - c.modelPkgName = name -} - -func (c *Config) SetPkg(name string) { - c.pkgName = name -} + QueryPkgName string // generated query code's package name + ModelPkgName string // generated model code's package name -func (c *Config) GetPkg() string { - return c.pkgName + db *gorm.DB //nolint } // genInfo info about generated code @@ -93,7 +82,7 @@ func (g *Generator) Tables(models ...interface{}) { // TableNames collect table names func (g *Generator) TableNames(names ...string) { - structs, err := check.GenBaseStructs(g.db, g.Config.modelPkgName, names...) + structs, err := check.GenBaseStructs(g.db, g.Config.ModelPkgName, names...) if err != nil { log.Fatalf("check struct error: %s", err) } @@ -154,7 +143,7 @@ func (g *Generator) ApplyByModel(model interface{}, fc interface{}) { // ApplyByTable specifies table by table names // eg: g.ApplyByTable(func(model.Model){}, "user", "role") func (g *Generator) ApplyByTable(fc interface{}, tableNames ...string) { - structs, err := check.GenBaseStructs(g.db, g.Config.modelPkgName, tableNames...) + structs, err := check.GenBaseStructs(g.db, g.Config.ModelPkgName, tableNames...) if err != nil { log.Fatalf("gen struct error: %s", err) } @@ -175,7 +164,7 @@ func (g *Generator) Execute() { log.Fatalf("mkdir failed: %s", err) } } - g.SetPkg(filepath.Base(g.OutPath)) + g.QueryPkgName = filepath.Base(g.OutPath) err = g.generatedBaseStruct() if err != nil { @@ -202,7 +191,7 @@ func (g *Generator) generatedToOutFile() (err error) { return t.Execute(wr, data) } - err = render(tmpl.HeaderTmpl, &buf, g.GetPkg()) + err = render(tmpl.HeaderTmpl, &buf, g.QueryPkgName) if err != nil { return err } @@ -249,7 +238,7 @@ func (g *Generator) generatedBaseStruct() (err error) { if err != nil { return err } - pkg := g.modelPkgName + pkg := g.ModelPkgName if pkg == "" { pkg = check.ModelPkg } From 0727020fea1222df851dd16de36f4d3e8ce47d8c Mon Sep 17 00:00:00 2001 From: riverchu Date: Fri, 30 Jul 2021 18:16:35 +0800 Subject: [PATCH 10/19] style: add git igonre --- .gitignore | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..05dd93d0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +*.o +*.a +*.so +_obj +_test +*.[568vq] +[568vq].out +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* +_testmain.go +*.exe +*.exe~ +*.test +*.prof +*.rar +*.zip +*.gz +*.psd +*.bmd +*.cfg +*.pptx +*.log +*nohup.out +*settings.pyc +*.sublime-project +*.sublime-workspace +!.gitkeep +.DS_Store +/.idea +/.vscode \ No newline at end of file From 0e758b41f97d32221fbc40bb75326c56e84f69d3 Mon Sep 17 00:00:00 2001 From: riverchu Date: Fri, 30 Jul 2021 18:24:17 +0800 Subject: [PATCH 11/19] feat: unexport queryPkgName --- generator.go | 12 ++++++------ generator_test.go | 16 ++++++++++++++++ 2 files changed, 22 insertions(+), 6 deletions(-) create mode 100644 generator_test.go diff --git a/generator.go b/generator.go index 8bd7e582..0c3d5b1c 100644 --- a/generator.go +++ b/generator.go @@ -38,13 +38,13 @@ func NewGenerator(cfg Config) *Generator { // Config generator's basic configuration type Config struct { - OutPath string - OutFile string + db *gorm.DB //nolint - QueryPkgName string // generated query code's package name + OutPath string + OutFile string ModelPkgName string // generated model code's package name - db *gorm.DB //nolint + queryPkgName string // generated query code's package name } // genInfo info about generated code @@ -164,7 +164,7 @@ func (g *Generator) Execute() { log.Fatalf("mkdir failed: %s", err) } } - g.QueryPkgName = filepath.Base(g.OutPath) + g.queryPkgName = filepath.Base(g.OutPath) err = g.generatedBaseStruct() if err != nil { @@ -191,7 +191,7 @@ func (g *Generator) generatedToOutFile() (err error) { return t.Execute(wr, data) } - err = render(tmpl.HeaderTmpl, &buf, g.QueryPkgName) + err = render(tmpl.HeaderTmpl, &buf, g.queryPkgName) if err != nil { return err } diff --git a/generator_test.go b/generator_test.go new file mode 100644 index 00000000..bc480037 --- /dev/null +++ b/generator_test.go @@ -0,0 +1,16 @@ +package gen + +import "testing" + +func TestConfig(t *testing.T) { + _ = &Config{ + db: nil, + + OutPath: "path", + OutFile: "", + + ModelPkgName: "models", + + queryPkgName: "query", + } +} From eeef0cfb5d23c6d2588785b01f2f046aa3a85c20 Mon Sep 17 00:00:00 2001 From: riverchu Date: Fri, 30 Jul 2021 18:37:33 +0800 Subject: [PATCH 12/19] style: format import --- generator.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generator.go b/generator.go index 0c3d5b1c..a37e5f56 100644 --- a/generator.go +++ b/generator.go @@ -10,9 +10,9 @@ import ( "strings" "text/template" + "golang.org/x/tools/imports" "gorm.io/gorm" - "golang.org/x/tools/imports" "gorm.io/gen/internal/check" "gorm.io/gen/internal/parser" tmpl "gorm.io/gen/internal/template" From de1ab6d11f15d1a9b3da8adad769df8e979dcd3c Mon Sep 17 00:00:00 2001 From: riverchu Date: Fri, 30 Jul 2021 18:52:10 +0800 Subject: [PATCH 13/19] fix: fix wrong tmql import path --- internal/template/tmpl.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/template/tmpl.go b/internal/template/tmpl.go index e54d3ccb..ab9147a5 100644 --- a/internal/template/tmpl.go +++ b/internal/template/tmpl.go @@ -10,8 +10,8 @@ package {{.}} import( "gorm.io/gorm" - "gorm.io/gorm/gen/field" - "gorm.io/gorm/gen/helper" + "gorm.io/gen/field" + "gorm.io/gen/helper" ) ` From fb22f9de3dd00921dcf95d75893c906378229713 Mon Sep 17 00:00:00 2001 From: wusongyuan Date: Fri, 30 Jul 2021 19:16:26 +0800 Subject: [PATCH 14/19] feat: join --- .gitignore | 3 +- do.go | 52 +++++++++- go.mod | 2 + go.sum | 210 ++++++++++++++++++++++++++++++++++++++ internal/template/tmpl.go | 26 ++++- 5 files changed, 286 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index 05dd93d0..e6e8d3ad 100644 --- a/.gitignore +++ b/.gitignore @@ -30,4 +30,5 @@ _testmain.go !.gitkeep .DS_Store /.idea -/.vscode \ No newline at end of file +/.vscode +/test/ diff --git a/do.go b/do.go index 11faaf3b..877a0bca 100644 --- a/do.go +++ b/do.go @@ -6,6 +6,7 @@ import ( "gorm.io/gorm" "gorm.io/gorm/clause" + "gorm.io/gorm/schema" "gorm.io/gen/field" ) @@ -54,7 +55,7 @@ func (s *DO) UseTable(tableName string) { } // Table return table name -func (s *DO) Table() string { +func (s *DO) TableName() string { return s.db.Statement.Table } @@ -207,6 +208,55 @@ func (s *DO) Unscoped() Dao { return NewDO(s.db.Unscoped()) } +func (s *DO) Join(table schema.Tabler, conds ...Condition) Dao { + return s.join(table, clause.InnerJoin, conds...) +} + +func (s *DO) LeftJoin(table schema.Tabler, conds ...Condition) Dao { + return s.join(table, clause.LeftJoin, conds...) +} + +func (s *DO) RightJoin(table schema.Tabler, conds ...Condition) Dao { + return s.join(table, clause.RightJoin, conds...) +} + +func (s *DO) join(table schema.Tabler, joinType clause.JoinType, conds ...Condition) Dao { + Emit(methodJoin) + var exprs = make([]clause.Expression, 0, len(conds)) + for _, cond := range conds { + switch cond := cond.(type) { + case *DO: + exprs = append(exprs, cond.buildWhere()...) + default: + exprs = append(exprs, cond) + } + } + + join := clause.Join{Type: joinType, Table: clause.Table{Name: table.TableName()}, ON: clause.Where{ + Exprs: exprs, + }} + from := getFromClause(s.db) + if from == nil { + from = &clause.From{} + } + from.Joins = append(from.Joins, join) + return NewDO(s.db.Clauses(from)) +} + +func getFromClause(db *gorm.DB) *clause.From { + if db == nil { + return nil + } + c, ok := db.Statement.Clauses[clause.From{}.Name()] + if !ok || c.Expression == nil { + return nil + } + if from, ok := c.Expression.(clause.From); ok { + return &from + } + return nil +} + // ======================== finisher api ======================== func (s *DO) Create(value interface{}) error { Emit(methodCreate) diff --git a/go.mod b/go.mod index 16482d02..c3d083e2 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,9 @@ module gorm.io/gen go 1.16 require ( + code.byted.org/gopkg/env v1.4.0 golang.org/x/tools v0.1.5 gorm.io/driver/mysql v1.1.1 gorm.io/gorm v1.21.12 + gorm.io/plugin/dbresolver v1.1.0 ) diff --git a/go.sum b/go.sum index 337243ec..d09857bf 100644 --- a/go.sum +++ b/go.sum @@ -1,38 +1,248 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +code.byted.org/bytedtrace/interface-go v1.0.8/go.mod h1:ClHuh9Jy+R0XN+ocPOE4JJ23xlifYTi+ju8GdsAioIM= +code.byted.org/bytedtrace/interface-go v1.0.15 h1:ASE9WtQ7KiVe69Ub3ja+3jPKlLm6jBk5k1H0zL+2+Cg= +code.byted.org/bytedtrace/interface-go v1.0.15/go.mod h1:b5dUY1vcys9UDUdLbg0FKhqRC8z7kQqdF+g6OOBkCH8= +code.byted.org/gopkg/asyncache v0.0.0-20190823054814-0ab65910ff7f/go.mod h1:UozdttZn5Y/z84K0T+RCgCd8+uJ8laG6czmwPPcxVtE= +code.byted.org/gopkg/asyncache v0.0.0-20210129072708-1df5611dba17 h1:ITqPXvO+6b/Ry5oFkCMv6PJqLTSWygEzXrCEiqxWKls= +code.byted.org/gopkg/asyncache v0.0.0-20210129072708-1df5611dba17/go.mod h1:UozdttZn5Y/z84K0T+RCgCd8+uJ8laG6czmwPPcxVtE= +code.byted.org/gopkg/bytedmysql v1.1.4 h1:VeaorsqEAZDCGSSab60Eqzab2tfG1xHrFIXRtf0v6L8= +code.byted.org/gopkg/bytedmysql v1.1.4/go.mod h1:P5qs3M9kwlNNwyi8k0BWgSoVI60wZLnE4OTzpCkTZUA= +code.byted.org/gopkg/consul v1.1.9/go.mod h1:TALNl7RlbbVsO+79vrr4IymlAYgIHzjkZao97jeAJog= +code.byted.org/gopkg/consul v1.1.13 h1:HEiJGw1o9Bgt6sV1gHq2cHsvBSQuPoDTc6R1dTLz39U= +code.byted.org/gopkg/consul v1.1.13/go.mod h1:TALNl7RlbbVsO+79vrr4IymlAYgIHzjkZao97jeAJog= +code.byted.org/gopkg/ctxvalues v0.2.0/go.mod h1:xaQkBQksiY6rtaDilHDy1yYvvOARMdOIPf1BvimjfGE= +code.byted.org/gopkg/ctxvalues v0.4.0 h1:31pwEthLdrjbn/vmq0AgehFHvH1QlMSBca+KFvfL2uY= +code.byted.org/gopkg/ctxvalues v0.4.0/go.mod h1:xaQkBQksiY6rtaDilHDy1yYvvOARMdOIPf1BvimjfGE= +code.byted.org/gopkg/env v1.2.4/go.mod h1:PLRgKZpOvrV1gh7u2OqJXfDyvbn4ocFVyB3m30lVMTU= +code.byted.org/gopkg/env v1.2.10/go.mod h1:gGi633mn6glSlyBw2pe7fbMti2HsjgVFaQMKTAAPt3A= +code.byted.org/gopkg/env v1.3.4/go.mod h1:gGi633mn6glSlyBw2pe7fbMti2HsjgVFaQMKTAAPt3A= +code.byted.org/gopkg/env v1.3.8/go.mod h1:gGi633mn6glSlyBw2pe7fbMti2HsjgVFaQMKTAAPt3A= +code.byted.org/gopkg/env v1.3.14/go.mod h1:gGi633mn6glSlyBw2pe7fbMti2HsjgVFaQMKTAAPt3A= +code.byted.org/gopkg/env v1.4.0 h1:x8R0ikg9b7jFJVxHB3VeFHE8wAOXQOdqEEZwANmM6S0= +code.byted.org/gopkg/env v1.4.0/go.mod h1:gGi633mn6glSlyBw2pe7fbMti2HsjgVFaQMKTAAPt3A= +code.byted.org/gopkg/logs v1.1.7/go.mod h1:aaEoYCgO37JgO7ZJmB1a97C/CIeRUjgQ3oH8GBtat0c= +code.byted.org/gopkg/logs v1.1.12 h1:YPsM0rHiT7hQDYhKrI0jGASciK3hlMg2iZfuwisAFEk= +code.byted.org/gopkg/logs v1.1.12/go.mod h1:JPSK2oqotOEW8PS1lsdkNVAX0T4MBs6EmsWeYZvlgWU= +code.byted.org/gopkg/logs/v2 v2.0.20 h1:UfMoMJlKBApQA0o2/XE4y8cI4YVtmeI403aQCc3+UxI= +code.byted.org/gopkg/logs/v2 v2.0.20/go.mod h1:jZGyk9C8HyhyQiWPg9wJY+/jhR1h+Qikko9CH8Z7mpw= +code.byted.org/gopkg/metainfo v0.1.0 h1:goep91o1Gz/4Ut4xAfmHTSGdG8cd9PeArBqptFi/WfE= +code.byted.org/gopkg/metainfo v0.1.0/go.mod h1:Su1Ncd0Wotgry8E2XIrUEvEe+ukacn45SBYlQ34i99Y= +code.byted.org/gopkg/metrics v1.4.1/go.mod h1:TA4ZhaTyRREDldJOHSIkPTf5AHVkEHd6FgmB59GYfT0= +code.byted.org/gopkg/metrics v1.4.5/go.mod h1:BbVL8NRam9VwmPYh7zVIx1EKjjmbKNF5nb+yZdcyZLo= +code.byted.org/gopkg/metrics v1.4.6 h1:+yK8Vz0kpGEFfyc7WDbykKegxrPsnkmZbvVTZLjv6Ig= +code.byted.org/gopkg/metrics v1.4.6/go.mod h1:BbVL8NRam9VwmPYh7zVIx1EKjjmbKNF5nb+yZdcyZLo= +code.byted.org/gopkg/metrics/v3 v3.1.1/go.mod h1:NhefMVKiYOoTwNiUYxQhv5ynjXwmLniPsVl4Q+1hHYg= +code.byted.org/gopkg/metrics/v3 v3.1.8 h1:MQgZ09Vn1VP/biOZuB7Oj+0vE1+qisUvZ37Fe5kmDcs= +code.byted.org/gopkg/metrics/v3 v3.1.8/go.mod h1:NhefMVKiYOoTwNiUYxQhv5ynjXwmLniPsVl4Q+1hHYg= +code.byted.org/gopkg/net2 v0.0.0-20191121100702-3595b1b9c967/go.mod h1:RDo4suupud1KOGkXqZ887RNeQzNz4xIL89/DqViVObU= +code.byted.org/gopkg/net2 v1.0.0/go.mod h1:RDo4suupud1KOGkXqZ887RNeQzNz4xIL89/DqViVObU= +code.byted.org/gopkg/net2 v1.1.0/go.mod h1:R+TvSEn+fkrfLgVwQ7KtlssZ5bZ2Vcew9pyhL7LrlkU= +code.byted.org/gopkg/net2 v1.2.0 h1:Bxc8ixC/rOWNha1XXbkzHs+y60hWPNPtCuojCZbkg5o= +code.byted.org/gopkg/net2 v1.2.0/go.mod h1:R+TvSEn+fkrfLgVwQ7KtlssZ5bZ2Vcew9pyhL7LrlkU= +code.byted.org/gorm/bytedgorm v0.5.3 h1:3GPlFqNN1j/HS8TcUBjcdd2tQmtN4WXMkMMLTVlcpYU= +code.byted.org/gorm/bytedgorm v0.5.3/go.mod h1:uP2tan+NOUyocAVoJCZXetw/cY7+I+D0zbq93qqUl8k= +code.byted.org/gorm/gen v0.0.22 h1:CyOgw8rTzfyD0nWp2O49dUn+fdeqiCu9jh8YsRkA3Pw= +code.byted.org/gorm/gen v0.0.22/go.mod h1:1S3UsLwpFlC0+JtBlw4zin1H1AeMTHv3ak1LfbAaJLU= +code.byted.org/inf/infsecc v0.0.0-20190725031222-8b1edbee7d9f/go.mod h1:6OWOcSHg5lXhPgXGnnKSH4AN4OJnjcVqlvKCODqWuHM= +code.byted.org/inf/infsecc v1.0.2 h1:yzaa52/aB4z56SDGPWLpQsc7s5IYAup5FmdIEGKl+7k= +code.byted.org/inf/infsecc v1.0.2/go.mod h1:6OWOcSHg5lXhPgXGnnKSH4AN4OJnjcVqlvKCODqWuHM= +code.byted.org/log_market/gosdk v0.0.0-20191220060055-c0c7ac29c131/go.mod h1:NRonQUBJ+OqGoS6IVxqB4ojuDXuOAi76zVArL+OpIYI= +code.byted.org/log_market/gosdk v0.0.0-20200901112613-614e08663524 h1:2soAsSZZF4exqIuf4BbVJCjnBFRTDLE6+sm2QRxQo5g= +code.byted.org/log_market/gosdk v0.0.0-20200901112613-614e08663524/go.mod h1:NRonQUBJ+OqGoS6IVxqB4ojuDXuOAi76zVArL+OpIYI= +code.byted.org/log_market/ttlogagent_gosdk v0.0.0-20191023050331-0a8ada385fd9/go.mod h1:ejG16d0ZmWBszOqrLxCdk8Uu8yAaxn2yathGQPcD6bU= +code.byted.org/log_market/ttlogagent_gosdk v0.0.1/go.mod h1:jNrmqvpOnyfxbfikIUT/XRflAmioz/y4J+119Yy0tiI= +code.byted.org/log_market/ttlogagent_gosdk v0.0.2 h1:H9wvrQS5bwQfvX/ALrjrUKY23vDWxIUeon8p+j3Qp6I= +code.byted.org/log_market/ttlogagent_gosdk v0.0.2/go.mod h1:jNrmqvpOnyfxbfikIUT/XRflAmioz/y4J+119Yy0tiI= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/agiledragon/gomonkey v2.0.2+incompatible h1:eXKi9/piiC3cjJD1658mEE2o3NjkJ5vDLgYjCQu0Xlw= +github.com/agiledragon/gomonkey v2.0.2+incompatible/go.mod h1:2NGfXu1a80LLr2cmWXGBDaHEjb1idR6+FVlX5T3D9hw= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bytedance/gopkg v0.0.0-20210511095255-6a6cce9da51e h1:MGNQ/XDuPui0VUWKDCvRXcroZGWZEbfHavRMo2cgjNc= +github.com/bytedance/gopkg v0.0.0-20210511095255-6a6cce9da51e/go.mod h1:birsdqRCbwnckJbdAvcSao+AzOyibVEoWB55MjpYpB8= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +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/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +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.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0 h1:jlYHihg//f7RRwuPfptm04yp4s7O6Kw8EZiVYIGcH0g= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jinzhu/now v1.1.2 h1:eVKgfIdy9b6zbWBMgFpfDPoAMifwSZagU9HmEU6zgiI= github.com/jinzhu/now v1.1.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/juju/ratelimit v1.0.1 h1:+7AIFJVQ0EQgq/K9+0Krm7m530Du7tIz0METWzN0RgY= +github.com/juju/ratelimit v1.0.1/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSgWNm/qk= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +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/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= +github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mattn/go-sqlite3 v1.14.5 h1:1IdxlwTNazvbKJQSxoJ5/9ECbEeaTTyeU7sEAZ5KKTQ= +github.com/mattn/go-sqlite3 v1.14.5/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI= +github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= +github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= +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_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/vmihailenco/msgpack/v4 v4.3.11/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4= +github.com/vmihailenco/msgpack/v5 v5.0.0-beta.1 h1:d71/KA0LhvkrJ/Ok+Wx9qK7bU8meKA1Hk0jpVI5kJjk= +github.com/vmihailenco/msgpack/v5 v5.0.0-beta.1/go.mod h1:xlngVLeyQ/Qi05oQxhQ+oTuqa03RjMwMfk/7/TCs+QI= +github.com/vmihailenco/tagparser v0.1.1 h1:quXMXlA39OCbd2wAdTsGDlK9RkOk6Wuw+x37wVyIuWY= +github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +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-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +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-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +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-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210415045647-66c3f260301c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/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-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +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.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +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/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/driver/mysql v1.0.3/go.mod h1:twGxftLBlFgNVNakL7F+P/x9oYqoymG3YYT8cAfI9oI= +gorm.io/driver/mysql v1.1.0/go.mod h1:KdrTanmfLPPyAOeYGyG+UpDys7/7eeWT1zCq+oekYnU= gorm.io/driver/mysql v1.1.1 h1:yr1bpyqiwuSPJ4aGGUX9nu46RHXlF8RASQVb1QQNcvo= gorm.io/driver/mysql v1.1.1/go.mod h1:KdrTanmfLPPyAOeYGyG+UpDys7/7eeWT1zCq+oekYnU= +gorm.io/driver/sqlite v1.1.4 h1:PDzwYE+sI6De2+mxAneV9Xs11+ZyKV6oxD3wDGkaNvM= +gorm.io/driver/sqlite v1.1.4/go.mod h1:mJCeTFr7+crvS+TRnWc5Z3UvwxUN1BGBLMrf5LA9DYw= +gorm.io/gorm v1.20.4/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= +gorm.io/gorm v1.20.7/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= +gorm.io/gorm v1.20.11/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= gorm.io/gorm v1.21.9/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0= +gorm.io/gorm v1.21.10/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0= +gorm.io/gorm v1.21.11/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0= gorm.io/gorm v1.21.12 h1:3fQM0Eiz7jcJEhPggHEpoYnsGZqynMzverL77DV40RM= gorm.io/gorm v1.21.12/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0= +gorm.io/plugin/dbresolver v1.1.0 h1:cegr4DeprR6SkLIQlKhJLYxH8muFbJ4SmnojXvoeb00= +gorm.io/plugin/dbresolver v1.1.0/go.mod h1:tpImigFAEejCALOttyhWqsy4vfa2Uh/vAUVnL5IRF7Y= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/internal/template/tmpl.go b/internal/template/tmpl.go index e54d3ccb..fc2bc164 100644 --- a/internal/template/tmpl.go +++ b/internal/template/tmpl.go @@ -10,8 +10,7 @@ package {{.}} import( "gorm.io/gorm" - "gorm.io/gorm/gen/field" - "gorm.io/gorm/gen/helper" + "gorm.io/gen/field" ) ` @@ -51,9 +50,8 @@ func New{{.StructName}}(db *gorm.DB) *{{.NewStructName}} { _{{.NewStructName}}.UseModel({{.StructInfo.Package}}.{{.StructInfo.Type}}{}) - tableName := _{{.NewStructName}}.Table() - {{range $p :=.Members}} - _{{.NewStructName}}.{{$p.Name}} = field.New{{$p.NewType}}(tableName, "{{$p.ColumnName}}"), + tableName := _{{.NewStructName}}.TableName() + {{range $p :=.Members}} _{{$.NewStructName}}.{{$p.Name}} = field.New{{$p.NewType}}(tableName, "{{$p.ColumnName}}") {{end}} return _{{.NewStructName}} @@ -62,6 +60,24 @@ func New{{.StructName}}(db *gorm.DB) *{{.NewStructName}} { ` const BaseGormFunc = ` +func ({{.S}} {{.NewStructName}}) Join(table schema.Tabler, on ...gen.Condition) *{{.NewStructName}} { + next := {{.S}} + next.DO = *{{.S}}.DO.Join(table, on...).(*gen.DO) + return &next +} + +func ({{.S}} {{.NewStructName}}) LeftJoin(table schema.Tabler, on ...gen.Condition) *{{.NewStructName}} { + next := {{.S}} + next.DO = *{{.S}}.DO.Join(table, on...).(*gen.DO) + return &next +} + +func ({{.S}} {{.NewStructName}}) RightJoin(table schema.Tabler, on ...gen.Condition) *{{.NewStructName}} { + next := {{.S}} + next.DO = *{{.S}}.DO.Join(table, on...).(*gen.DO) + return &next +} + func ({{.S}} {{.NewStructName}}) Not(conds ...gen.Condition) *{{.NewStructName}} { next := {{.S}} next.DO = *{{.S}}.DO.Not(conds...).(*gen.DO) From 0ed51de057c2598c35f537cc8a637b4aec8c9292 Mon Sep 17 00:00:00 2001 From: riverchu Date: Fri, 30 Jul 2021 21:45:25 +0800 Subject: [PATCH 15/19] feat: tidy up go modules --- go.mod | 2 - go.sum | 210 --------------------------------------------------------- 2 files changed, 212 deletions(-) diff --git a/go.mod b/go.mod index c3d083e2..16482d02 100644 --- a/go.mod +++ b/go.mod @@ -3,9 +3,7 @@ module gorm.io/gen go 1.16 require ( - code.byted.org/gopkg/env v1.4.0 golang.org/x/tools v0.1.5 gorm.io/driver/mysql v1.1.1 gorm.io/gorm v1.21.12 - gorm.io/plugin/dbresolver v1.1.0 ) diff --git a/go.sum b/go.sum index d09857bf..337243ec 100644 --- a/go.sum +++ b/go.sum @@ -1,248 +1,38 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -code.byted.org/bytedtrace/interface-go v1.0.8/go.mod h1:ClHuh9Jy+R0XN+ocPOE4JJ23xlifYTi+ju8GdsAioIM= -code.byted.org/bytedtrace/interface-go v1.0.15 h1:ASE9WtQ7KiVe69Ub3ja+3jPKlLm6jBk5k1H0zL+2+Cg= -code.byted.org/bytedtrace/interface-go v1.0.15/go.mod h1:b5dUY1vcys9UDUdLbg0FKhqRC8z7kQqdF+g6OOBkCH8= -code.byted.org/gopkg/asyncache v0.0.0-20190823054814-0ab65910ff7f/go.mod h1:UozdttZn5Y/z84K0T+RCgCd8+uJ8laG6czmwPPcxVtE= -code.byted.org/gopkg/asyncache v0.0.0-20210129072708-1df5611dba17 h1:ITqPXvO+6b/Ry5oFkCMv6PJqLTSWygEzXrCEiqxWKls= -code.byted.org/gopkg/asyncache v0.0.0-20210129072708-1df5611dba17/go.mod h1:UozdttZn5Y/z84K0T+RCgCd8+uJ8laG6czmwPPcxVtE= -code.byted.org/gopkg/bytedmysql v1.1.4 h1:VeaorsqEAZDCGSSab60Eqzab2tfG1xHrFIXRtf0v6L8= -code.byted.org/gopkg/bytedmysql v1.1.4/go.mod h1:P5qs3M9kwlNNwyi8k0BWgSoVI60wZLnE4OTzpCkTZUA= -code.byted.org/gopkg/consul v1.1.9/go.mod h1:TALNl7RlbbVsO+79vrr4IymlAYgIHzjkZao97jeAJog= -code.byted.org/gopkg/consul v1.1.13 h1:HEiJGw1o9Bgt6sV1gHq2cHsvBSQuPoDTc6R1dTLz39U= -code.byted.org/gopkg/consul v1.1.13/go.mod h1:TALNl7RlbbVsO+79vrr4IymlAYgIHzjkZao97jeAJog= -code.byted.org/gopkg/ctxvalues v0.2.0/go.mod h1:xaQkBQksiY6rtaDilHDy1yYvvOARMdOIPf1BvimjfGE= -code.byted.org/gopkg/ctxvalues v0.4.0 h1:31pwEthLdrjbn/vmq0AgehFHvH1QlMSBca+KFvfL2uY= -code.byted.org/gopkg/ctxvalues v0.4.0/go.mod h1:xaQkBQksiY6rtaDilHDy1yYvvOARMdOIPf1BvimjfGE= -code.byted.org/gopkg/env v1.2.4/go.mod h1:PLRgKZpOvrV1gh7u2OqJXfDyvbn4ocFVyB3m30lVMTU= -code.byted.org/gopkg/env v1.2.10/go.mod h1:gGi633mn6glSlyBw2pe7fbMti2HsjgVFaQMKTAAPt3A= -code.byted.org/gopkg/env v1.3.4/go.mod h1:gGi633mn6glSlyBw2pe7fbMti2HsjgVFaQMKTAAPt3A= -code.byted.org/gopkg/env v1.3.8/go.mod h1:gGi633mn6glSlyBw2pe7fbMti2HsjgVFaQMKTAAPt3A= -code.byted.org/gopkg/env v1.3.14/go.mod h1:gGi633mn6glSlyBw2pe7fbMti2HsjgVFaQMKTAAPt3A= -code.byted.org/gopkg/env v1.4.0 h1:x8R0ikg9b7jFJVxHB3VeFHE8wAOXQOdqEEZwANmM6S0= -code.byted.org/gopkg/env v1.4.0/go.mod h1:gGi633mn6glSlyBw2pe7fbMti2HsjgVFaQMKTAAPt3A= -code.byted.org/gopkg/logs v1.1.7/go.mod h1:aaEoYCgO37JgO7ZJmB1a97C/CIeRUjgQ3oH8GBtat0c= -code.byted.org/gopkg/logs v1.1.12 h1:YPsM0rHiT7hQDYhKrI0jGASciK3hlMg2iZfuwisAFEk= -code.byted.org/gopkg/logs v1.1.12/go.mod h1:JPSK2oqotOEW8PS1lsdkNVAX0T4MBs6EmsWeYZvlgWU= -code.byted.org/gopkg/logs/v2 v2.0.20 h1:UfMoMJlKBApQA0o2/XE4y8cI4YVtmeI403aQCc3+UxI= -code.byted.org/gopkg/logs/v2 v2.0.20/go.mod h1:jZGyk9C8HyhyQiWPg9wJY+/jhR1h+Qikko9CH8Z7mpw= -code.byted.org/gopkg/metainfo v0.1.0 h1:goep91o1Gz/4Ut4xAfmHTSGdG8cd9PeArBqptFi/WfE= -code.byted.org/gopkg/metainfo v0.1.0/go.mod h1:Su1Ncd0Wotgry8E2XIrUEvEe+ukacn45SBYlQ34i99Y= -code.byted.org/gopkg/metrics v1.4.1/go.mod h1:TA4ZhaTyRREDldJOHSIkPTf5AHVkEHd6FgmB59GYfT0= -code.byted.org/gopkg/metrics v1.4.5/go.mod h1:BbVL8NRam9VwmPYh7zVIx1EKjjmbKNF5nb+yZdcyZLo= -code.byted.org/gopkg/metrics v1.4.6 h1:+yK8Vz0kpGEFfyc7WDbykKegxrPsnkmZbvVTZLjv6Ig= -code.byted.org/gopkg/metrics v1.4.6/go.mod h1:BbVL8NRam9VwmPYh7zVIx1EKjjmbKNF5nb+yZdcyZLo= -code.byted.org/gopkg/metrics/v3 v3.1.1/go.mod h1:NhefMVKiYOoTwNiUYxQhv5ynjXwmLniPsVl4Q+1hHYg= -code.byted.org/gopkg/metrics/v3 v3.1.8 h1:MQgZ09Vn1VP/biOZuB7Oj+0vE1+qisUvZ37Fe5kmDcs= -code.byted.org/gopkg/metrics/v3 v3.1.8/go.mod h1:NhefMVKiYOoTwNiUYxQhv5ynjXwmLniPsVl4Q+1hHYg= -code.byted.org/gopkg/net2 v0.0.0-20191121100702-3595b1b9c967/go.mod h1:RDo4suupud1KOGkXqZ887RNeQzNz4xIL89/DqViVObU= -code.byted.org/gopkg/net2 v1.0.0/go.mod h1:RDo4suupud1KOGkXqZ887RNeQzNz4xIL89/DqViVObU= -code.byted.org/gopkg/net2 v1.1.0/go.mod h1:R+TvSEn+fkrfLgVwQ7KtlssZ5bZ2Vcew9pyhL7LrlkU= -code.byted.org/gopkg/net2 v1.2.0 h1:Bxc8ixC/rOWNha1XXbkzHs+y60hWPNPtCuojCZbkg5o= -code.byted.org/gopkg/net2 v1.2.0/go.mod h1:R+TvSEn+fkrfLgVwQ7KtlssZ5bZ2Vcew9pyhL7LrlkU= -code.byted.org/gorm/bytedgorm v0.5.3 h1:3GPlFqNN1j/HS8TcUBjcdd2tQmtN4WXMkMMLTVlcpYU= -code.byted.org/gorm/bytedgorm v0.5.3/go.mod h1:uP2tan+NOUyocAVoJCZXetw/cY7+I+D0zbq93qqUl8k= -code.byted.org/gorm/gen v0.0.22 h1:CyOgw8rTzfyD0nWp2O49dUn+fdeqiCu9jh8YsRkA3Pw= -code.byted.org/gorm/gen v0.0.22/go.mod h1:1S3UsLwpFlC0+JtBlw4zin1H1AeMTHv3ak1LfbAaJLU= -code.byted.org/inf/infsecc v0.0.0-20190725031222-8b1edbee7d9f/go.mod h1:6OWOcSHg5lXhPgXGnnKSH4AN4OJnjcVqlvKCODqWuHM= -code.byted.org/inf/infsecc v1.0.2 h1:yzaa52/aB4z56SDGPWLpQsc7s5IYAup5FmdIEGKl+7k= -code.byted.org/inf/infsecc v1.0.2/go.mod h1:6OWOcSHg5lXhPgXGnnKSH4AN4OJnjcVqlvKCODqWuHM= -code.byted.org/log_market/gosdk v0.0.0-20191220060055-c0c7ac29c131/go.mod h1:NRonQUBJ+OqGoS6IVxqB4ojuDXuOAi76zVArL+OpIYI= -code.byted.org/log_market/gosdk v0.0.0-20200901112613-614e08663524 h1:2soAsSZZF4exqIuf4BbVJCjnBFRTDLE6+sm2QRxQo5g= -code.byted.org/log_market/gosdk v0.0.0-20200901112613-614e08663524/go.mod h1:NRonQUBJ+OqGoS6IVxqB4ojuDXuOAi76zVArL+OpIYI= -code.byted.org/log_market/ttlogagent_gosdk v0.0.0-20191023050331-0a8ada385fd9/go.mod h1:ejG16d0ZmWBszOqrLxCdk8Uu8yAaxn2yathGQPcD6bU= -code.byted.org/log_market/ttlogagent_gosdk v0.0.1/go.mod h1:jNrmqvpOnyfxbfikIUT/XRflAmioz/y4J+119Yy0tiI= -code.byted.org/log_market/ttlogagent_gosdk v0.0.2 h1:H9wvrQS5bwQfvX/ALrjrUKY23vDWxIUeon8p+j3Qp6I= -code.byted.org/log_market/ttlogagent_gosdk v0.0.2/go.mod h1:jNrmqvpOnyfxbfikIUT/XRflAmioz/y4J+119Yy0tiI= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/agiledragon/gomonkey v2.0.2+incompatible h1:eXKi9/piiC3cjJD1658mEE2o3NjkJ5vDLgYjCQu0Xlw= -github.com/agiledragon/gomonkey v2.0.2+incompatible/go.mod h1:2NGfXu1a80LLr2cmWXGBDaHEjb1idR6+FVlX5T3D9hw= -github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= -github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bytedance/gopkg v0.0.0-20210511095255-6a6cce9da51e h1:MGNQ/XDuPui0VUWKDCvRXcroZGWZEbfHavRMo2cgjNc= -github.com/bytedance/gopkg v0.0.0-20210511095255-6a6cce9da51e/go.mod h1:birsdqRCbwnckJbdAvcSao+AzOyibVEoWB55MjpYpB8= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -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/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= -github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= -github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= -github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -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.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/mock v1.5.0 h1:jlYHihg//f7RRwuPfptm04yp4s7O6Kw8EZiVYIGcH0g= -github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= -github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jinzhu/now v1.1.2 h1:eVKgfIdy9b6zbWBMgFpfDPoAMifwSZagU9HmEU6zgiI= github.com/jinzhu/now v1.1.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= -github.com/juju/ratelimit v1.0.1 h1:+7AIFJVQ0EQgq/K9+0Krm7m530Du7tIz0METWzN0RgY= -github.com/juju/ratelimit v1.0.1/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSgWNm/qk= -github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= -github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -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/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= -github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/mattn/go-sqlite3 v1.14.5 h1:1IdxlwTNazvbKJQSxoJ5/9ECbEeaTTyeU7sEAZ5KKTQ= -github.com/mattn/go-sqlite3 v1.14.5/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI= -github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= -github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= -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_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/vmihailenco/msgpack/v4 v4.3.11/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4= -github.com/vmihailenco/msgpack/v5 v5.0.0-beta.1 h1:d71/KA0LhvkrJ/Ok+Wx9qK7bU8meKA1Hk0jpVI5kJjk= -github.com/vmihailenco/msgpack/v5 v5.0.0-beta.1/go.mod h1:xlngVLeyQ/Qi05oQxhQ+oTuqa03RjMwMfk/7/TCs+QI= -github.com/vmihailenco/tagparser v0.1.1 h1:quXMXlA39OCbd2wAdTsGDlK9RkOk6Wuw+x37wVyIuWY= -github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -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-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -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-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -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-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210415045647-66c3f260301c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/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-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -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.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -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/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gorm.io/driver/mysql v1.0.3/go.mod h1:twGxftLBlFgNVNakL7F+P/x9oYqoymG3YYT8cAfI9oI= -gorm.io/driver/mysql v1.1.0/go.mod h1:KdrTanmfLPPyAOeYGyG+UpDys7/7eeWT1zCq+oekYnU= gorm.io/driver/mysql v1.1.1 h1:yr1bpyqiwuSPJ4aGGUX9nu46RHXlF8RASQVb1QQNcvo= gorm.io/driver/mysql v1.1.1/go.mod h1:KdrTanmfLPPyAOeYGyG+UpDys7/7eeWT1zCq+oekYnU= -gorm.io/driver/sqlite v1.1.4 h1:PDzwYE+sI6De2+mxAneV9Xs11+ZyKV6oxD3wDGkaNvM= -gorm.io/driver/sqlite v1.1.4/go.mod h1:mJCeTFr7+crvS+TRnWc5Z3UvwxUN1BGBLMrf5LA9DYw= -gorm.io/gorm v1.20.4/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= -gorm.io/gorm v1.20.7/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= -gorm.io/gorm v1.20.11/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= gorm.io/gorm v1.21.9/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0= -gorm.io/gorm v1.21.10/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0= -gorm.io/gorm v1.21.11/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0= gorm.io/gorm v1.21.12 h1:3fQM0Eiz7jcJEhPggHEpoYnsGZqynMzverL77DV40RM= gorm.io/gorm v1.21.12/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0= -gorm.io/plugin/dbresolver v1.1.0 h1:cegr4DeprR6SkLIQlKhJLYxH8muFbJ4SmnojXvoeb00= -gorm.io/plugin/dbresolver v1.1.0/go.mod h1:tpImigFAEejCALOttyhWqsy4vfa2Uh/vAUVnL5IRF7Y= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= From f1ffe107db840cc7253acc926400c315064cefbb Mon Sep 17 00:00:00 2001 From: riverchu Date: Fri, 30 Jul 2021 21:46:08 +0800 Subject: [PATCH 16/19] style: update comments --- do.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/do.go b/do.go index 877a0bca..4cef34f8 100644 --- a/do.go +++ b/do.go @@ -54,7 +54,7 @@ func (s *DO) UseTable(tableName string) { s.db = s.db.Table(tableName).Session(new(gorm.Session)) } -// Table return table name +// TableName return table name func (s *DO) TableName() string { return s.db.Statement.Table } From 1a6f8178c5ade65a0d6eaf6eac8fde1627aeadbf Mon Sep 17 00:00:00 2001 From: riverchu Date: Fri, 30 Jul 2021 21:56:31 +0800 Subject: [PATCH 17/19] feat: optimize getFromClause logic --- do.go | 16 +++++++--------- internal/template/tmpl.go | 1 - 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/do.go b/do.go index 4cef34f8..4dbaa4b8 100644 --- a/do.go +++ b/do.go @@ -236,25 +236,23 @@ func (s *DO) join(table schema.Tabler, joinType clause.JoinType, conds ...Condit Exprs: exprs, }} from := getFromClause(s.db) - if from == nil { - from = &clause.From{} - } from.Joins = append(from.Joins, join) return NewDO(s.db.Clauses(from)) } func getFromClause(db *gorm.DB) *clause.From { - if db == nil { - return nil + if db == nil || db.Statement == nil { + return &clause.From{} } c, ok := db.Statement.Clauses[clause.From{}.Name()] if !ok || c.Expression == nil { - return nil + return &clause.From{} } - if from, ok := c.Expression.(clause.From); ok { - return &from + from, ok := c.Expression.(clause.From) + if !ok { + return &clause.From{} } - return nil + return &from } // ======================== finisher api ======================== diff --git a/internal/template/tmpl.go b/internal/template/tmpl.go index fc2bc164..e4bc8335 100644 --- a/internal/template/tmpl.go +++ b/internal/template/tmpl.go @@ -49,7 +49,6 @@ func New{{.StructName}}(db *gorm.DB) *{{.NewStructName}} { _{{.NewStructName}}.UseDB(db) _{{.NewStructName}}.UseModel({{.StructInfo.Package}}.{{.StructInfo.Type}}{}) - tableName := _{{.NewStructName}}.TableName() {{range $p :=.Members}} _{{$.NewStructName}}.{{$p.Name}} = field.New{{$p.NewType}}(tableName, "{{$p.ColumnName}}") {{end}} From 11e353b33d5dcfb059d6139d94886ec065f2bfc5 Mon Sep 17 00:00:00 2001 From: riverchu Date: Fri, 30 Jul 2021 21:59:15 +0800 Subject: [PATCH 18/19] fix: import helper --- internal/template/tmpl.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/template/tmpl.go b/internal/template/tmpl.go index e4bc8335..6294558e 100644 --- a/internal/template/tmpl.go +++ b/internal/template/tmpl.go @@ -11,6 +11,7 @@ import( "gorm.io/gorm" "gorm.io/gen/field" + "gorm.io/gen/helper" ) ` From a6014756bd0ffed567e9e7dc366aa81ae6759134 Mon Sep 17 00:00:00 2001 From: riverchu Date: Mon, 2 Aug 2021 11:20:34 +0800 Subject: [PATCH 19/19] feat: use CommaExpression from gorm/clause --- do.go | 19 ++----------------- go.mod | 2 +- go.sum | 4 ++-- 3 files changed, 5 insertions(+), 20 deletions(-) diff --git a/do.go b/do.go index 4dbaa4b8..0f4c64b5 100644 --- a/do.go +++ b/do.go @@ -142,7 +142,7 @@ func (s *DO) Select(columns ...field.Expr) Dao { if len(columns) == 0 { return NewDO(s.db.Clauses(clause.Select{})) } - return NewDO(s.db.Clauses(clause.Select{Expression: CommaExpression{Exprs: toExpression(columns...)}})) + return NewDO(s.db.Clauses(clause.Select{Expression: clause.CommaExpression{Exprs: toExpression(columns...)}})) } func (s *DO) Where(conds ...Condition) Dao { @@ -161,7 +161,7 @@ func (s *DO) Where(conds ...Condition) Dao { func (s *DO) Order(columns ...field.Expr) Dao { Emit(methodOrder) - return NewDO(s.db.Clauses(clause.OrderBy{Expression: CommaExpression{Exprs: toExpression(columns...)}})) + return NewDO(s.db.Clauses(clause.OrderBy{Expression: clause.CommaExpression{Exprs: toExpression(columns...)}})) } func (s *DO) Distinct(columns ...field.Expr) Dao { @@ -454,21 +454,6 @@ func toInterfaceSlice(value interface{}) []interface{} { } } -// ======================== temporary ======================== -// CommaExpression comma expression -type CommaExpression struct { - Exprs []clause.Expression -} - -func (comma CommaExpression) Build(builder clause.Builder) { - for idx, expr := range comma.Exprs { - if idx > 0 { - _, _ = builder.WriteString(", ") - } - expr.Build(builder) - } -} - // ======================== New Table ======================== // Table return a new table produced by subquery, diff --git a/go.mod b/go.mod index 16482d02..122016d2 100644 --- a/go.mod +++ b/go.mod @@ -5,5 +5,5 @@ go 1.16 require ( golang.org/x/tools v0.1.5 gorm.io/driver/mysql v1.1.1 - gorm.io/gorm v1.21.12 + gorm.io/gorm v1.21.13-0.20210728110034-7a49629fd1c7 ) diff --git a/go.sum b/go.sum index 337243ec..9ea668d8 100644 --- a/go.sum +++ b/go.sum @@ -34,5 +34,5 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8T gorm.io/driver/mysql v1.1.1 h1:yr1bpyqiwuSPJ4aGGUX9nu46RHXlF8RASQVb1QQNcvo= gorm.io/driver/mysql v1.1.1/go.mod h1:KdrTanmfLPPyAOeYGyG+UpDys7/7eeWT1zCq+oekYnU= gorm.io/gorm v1.21.9/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0= -gorm.io/gorm v1.21.12 h1:3fQM0Eiz7jcJEhPggHEpoYnsGZqynMzverL77DV40RM= -gorm.io/gorm v1.21.12/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0= +gorm.io/gorm v1.21.13-0.20210728110034-7a49629fd1c7 h1:5Mss7ezjcC8lWeoiwwT0+pz51inhy3j0b/nyOpn4SVE= +gorm.io/gorm v1.21.13-0.20210728110034-7a49629fd1c7/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0=