#11 code generator
This commit is contained in:
6
cmd/gormgen/README.MD
Normal file
6
cmd/gormgen/README.MD
Normal file
@@ -0,0 +1,6 @@
|
||||
## 执行命令
|
||||
1. 定义生成的表,设置 config 中 cmd.genTables,可以自定义设置多张表,为空表示生成库中所有的表,如果设置多个表可用','分割;
|
||||
1. 在根目录下执行脚本文件:`./scripts/gormgen.sh`;
|
||||
|
||||
## 参考
|
||||
- https://github.com/MohamedBassem/gormgen
|
||||
37
cmd/gormgen/main.go
Normal file
37
cmd/gormgen/main.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/cmd/gormgen/pkg"
|
||||
)
|
||||
|
||||
var (
|
||||
input string
|
||||
structs []string
|
||||
)
|
||||
|
||||
func init() {
|
||||
flagStructs := flag.String("structs", "", "[Required] The name of schema structs to generate structs for, comma seperated\n")
|
||||
flagInput := flag.String("input", "", "[Required] The name of the input file dir\n")
|
||||
flag.Parse()
|
||||
|
||||
if *flagStructs == "" || *flagInput == "" {
|
||||
flag.Usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
structs = strings.Split(*flagStructs, ",")
|
||||
input = *flagInput
|
||||
}
|
||||
|
||||
func main() {
|
||||
gen := pkg.NewGenerator(input)
|
||||
p := pkg.NewParser(input)
|
||||
if err := gen.ParserAST(p, structs).Generate().Format().Flush(); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
}
|
||||
124
cmd/gormgen/pkg/generator.go
Normal file
124
cmd/gormgen/pkg/generator.go
Normal file
@@ -0,0 +1,124 @@
|
||||
package pkg
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"go/format"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
)
|
||||
|
||||
// fieldConfig
|
||||
type fieldConfig struct {
|
||||
FieldName string
|
||||
ColumnName string
|
||||
FieldType string
|
||||
HumpName string
|
||||
}
|
||||
|
||||
// structConfig
|
||||
type structConfig struct {
|
||||
config
|
||||
StructName string
|
||||
OnlyFields []fieldConfig
|
||||
OptionFields []fieldConfig
|
||||
}
|
||||
|
||||
type ImportPkg struct {
|
||||
Pkg string
|
||||
}
|
||||
|
||||
type structHelpers struct {
|
||||
Titelize func(string) string
|
||||
}
|
||||
|
||||
type config struct {
|
||||
PkgName string
|
||||
Helpers structHelpers
|
||||
QueryBuilderName string
|
||||
}
|
||||
|
||||
// The Generator is the one responsible for generating the code, adding the imports, formating, and writing it to the file.
|
||||
type Generator struct {
|
||||
buf map[string]*bytes.Buffer
|
||||
inputFile string
|
||||
config config
|
||||
structConfigs []structConfig
|
||||
}
|
||||
|
||||
// NewGenerator function creates an instance of the generator given the name of the output file as an argument.
|
||||
func NewGenerator(outputFile string) *Generator {
|
||||
return &Generator{
|
||||
buf: map[string]*bytes.Buffer{},
|
||||
inputFile: outputFile,
|
||||
}
|
||||
}
|
||||
|
||||
// ParserAST parse by go file
|
||||
func (g *Generator) ParserAST(p *Parser, structs []string) (ret *Generator) {
|
||||
for _, v := range structs {
|
||||
g.buf[gorm.ToDBName(v)] = new(bytes.Buffer)
|
||||
}
|
||||
g.structConfigs = p.Parse()
|
||||
g.config.PkgName = p.pkg.Name
|
||||
g.config.Helpers = structHelpers{
|
||||
Titelize: strings.Title,
|
||||
}
|
||||
g.config.QueryBuilderName = SQLColumnToHumpStyle(p.pkg.Name) + "QueryBuilder"
|
||||
return g
|
||||
}
|
||||
|
||||
func (g *Generator) checkConfig() (err error) {
|
||||
if len(g.config.PkgName) == 0 {
|
||||
err = errors.New("package name dose'n set")
|
||||
return
|
||||
}
|
||||
for i := 0; i < len(g.structConfigs); i++ {
|
||||
g.structConfigs[i].config = g.config
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Generate executes the template and store it in an internal buffer.
|
||||
func (g *Generator) Generate() *Generator {
|
||||
if err := g.checkConfig(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
for _, v := range g.structConfigs {
|
||||
if _, ok := g.buf[gorm.ToDBName(v.StructName)]; !ok {
|
||||
continue
|
||||
}
|
||||
if err := outputTemplate.Execute(g.buf[gorm.ToDBName(v.StructName)], v); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
return g
|
||||
}
|
||||
|
||||
// Format function formats the output of the generation.
|
||||
func (g *Generator) Format() *Generator {
|
||||
for k := range g.buf {
|
||||
formattedOutput, err := format.Source(g.buf[k].Bytes())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
g.buf[k] = bytes.NewBuffer(formattedOutput)
|
||||
}
|
||||
return g
|
||||
}
|
||||
|
||||
// Flush function writes the output to the output file.
|
||||
func (g *Generator) Flush() error {
|
||||
for k := range g.buf {
|
||||
filename := g.inputFile + "/gen_" + strings.ToLower(k) + ".go"
|
||||
if err := ioutil.WriteFile(filename, g.buf[k].Bytes(), 0777); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
120
cmd/gormgen/pkg/parser.go
Normal file
120
cmd/gormgen/pkg/parser.go
Normal file
@@ -0,0 +1,120 @@
|
||||
package pkg
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/build"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
)
|
||||
|
||||
// The Parser is used to parse a directory and expose information about the structs defined in the files of this directory.
|
||||
type Parser struct {
|
||||
dir string
|
||||
pkg *build.Package
|
||||
parsedFiles []*ast.File
|
||||
}
|
||||
|
||||
// NewParser create a new parser instance.
|
||||
func NewParser(dir string) *Parser {
|
||||
return &Parser{
|
||||
dir: dir,
|
||||
}
|
||||
}
|
||||
|
||||
// getPackage parse dir get go file and package
|
||||
func (p *Parser) getPackage() {
|
||||
pkg, err := build.Default.ImportDir(p.dir, build.ImportComment)
|
||||
if err != nil {
|
||||
log.Fatalf("cannot process directory %s: %s", p.dir, err)
|
||||
}
|
||||
p.pkg = pkg
|
||||
|
||||
}
|
||||
|
||||
// parseGoFiles parse go file
|
||||
func (p *Parser) parseGoFiles() {
|
||||
var parsedFiles []*ast.File
|
||||
fs := token.NewFileSet()
|
||||
for _, file := range p.pkg.GoFiles {
|
||||
file = p.dir + "/" + file
|
||||
parsedFile, err := parser.ParseFile(fs, file, nil, 0)
|
||||
if err != nil {
|
||||
log.Fatalf("parsing package: %s: %s\n", file, err)
|
||||
}
|
||||
parsedFiles = append(parsedFiles, parsedFile)
|
||||
}
|
||||
p.parsedFiles = parsedFiles
|
||||
}
|
||||
|
||||
// parseTypes parse type of struct
|
||||
func (p *Parser) parseTypes(file *ast.File) (ret []structConfig) {
|
||||
ast.Inspect(file, func(n ast.Node) bool {
|
||||
decl, ok := n.(*ast.GenDecl)
|
||||
if !ok || decl.Tok != token.TYPE {
|
||||
return true
|
||||
}
|
||||
|
||||
for _, spec := range decl.Specs {
|
||||
var (
|
||||
data structConfig
|
||||
)
|
||||
typeSpec, _ok := spec.(*ast.TypeSpec)
|
||||
if !_ok {
|
||||
continue
|
||||
}
|
||||
// We only care about struct declaration (for now)
|
||||
var structType *ast.StructType
|
||||
if structType, ok = typeSpec.Type.(*ast.StructType); !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
data.StructName = typeSpec.Name.Name
|
||||
for _, v := range structType.Fields.List {
|
||||
var (
|
||||
optionField fieldConfig
|
||||
)
|
||||
|
||||
// type is ident, get onlyField type
|
||||
if t, _ok := v.Type.(*ast.Ident); _ok {
|
||||
optionField.FieldType = t.String()
|
||||
} else {
|
||||
if v.Tag != nil {
|
||||
if strings.Contains(v.Tag.Value, "gorm") && strings.Contains(v.Tag.Value, "time") {
|
||||
optionField.FieldType = "time.Time"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// get file name
|
||||
if len(v.Names) > 0 {
|
||||
optionField.FieldName = v.Names[0].String()
|
||||
optionField.ColumnName = gorm.ToDBName(optionField.FieldName)
|
||||
optionField.HumpName = SQLColumnToHumpStyle(optionField.ColumnName)
|
||||
}
|
||||
|
||||
data.OptionFields = append(data.OptionFields, optionField)
|
||||
}
|
||||
|
||||
ret = append(ret, data)
|
||||
}
|
||||
return true
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Parse should be called before any type querying for the parser. It takes the directory to be parsed and extracts all the structs defined in this directory.
|
||||
func (p *Parser) Parse() (ret []structConfig) {
|
||||
var (
|
||||
data []structConfig
|
||||
)
|
||||
p.getPackage()
|
||||
p.parseGoFiles()
|
||||
for _, f := range p.parsedFiles {
|
||||
data = append(data, p.parseTypes(f)...)
|
||||
}
|
||||
return data
|
||||
}
|
||||
149
cmd/gormgen/pkg/template.go
Normal file
149
cmd/gormgen/pkg/template.go
Normal file
@@ -0,0 +1,149 @@
|
||||
package pkg
|
||||
|
||||
import "text/template"
|
||||
|
||||
// Make sure that the template compiles during package initialization
|
||||
func parseTemplateOrPanic(t string) *template.Template {
|
||||
tpl, err := template.New("output_template").Parse(t)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return tpl
|
||||
}
|
||||
|
||||
var outputTemplate = parseTemplateOrPanic(`
|
||||
///////////////////////////////////////////////////////////
|
||||
// THIS FILE IS AUTO GENERATED by gormgen, DON'T EDIT IT //
|
||||
// ANY CHANGES DONE HERE WILL BE LOST //
|
||||
///////////////////////////////////////////////////////////
|
||||
|
||||
package {{.PkgName}}
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func NewModel() *{{.StructName}} {
|
||||
return new({{.StructName}})
|
||||
}
|
||||
|
||||
func NewQueryBuilder() *{{.QueryBuilderName}} {
|
||||
return new({{.QueryBuilderName}})
|
||||
}
|
||||
|
||||
func (t *{{.StructName}}) Create(db *gorm.DB) (id int32, err error) {
|
||||
if err = db.Create(t).Error; err != nil {
|
||||
return 0, errors.Wrap(err, "create err")
|
||||
}
|
||||
return t.Id, nil
|
||||
}
|
||||
|
||||
func (t *{{.StructName}}) Delete(db *gorm.DB) (err error) {
|
||||
if err = db.Delete(t).Error; err != nil {
|
||||
return errors.Wrap(err, "delete err")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *{{.StructName}}) Updates(db *gorm.DB, m map[string]interface{}) (err error) {
|
||||
if err = db.Model(&UserDemo{}).Where("id = ?", t.Id).Updates(m).Error; err != nil {
|
||||
return errors.Wrap(err, "updates err")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type {{.QueryBuilderName}} struct {
|
||||
order []string
|
||||
where []struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}
|
||||
limit int
|
||||
offset int
|
||||
}
|
||||
|
||||
func (qb *{{.QueryBuilderName}}) buildQuery(db *gorm.DB) *gorm.DB {
|
||||
ret := db
|
||||
for _, where := range qb.where {
|
||||
ret = ret.Where(where.prefix, where.value)
|
||||
}
|
||||
for _, order := range qb.order {
|
||||
ret = ret.Order(order)
|
||||
}
|
||||
ret = ret.Limit(qb.limit).Offset(qb.offset)
|
||||
return ret
|
||||
}
|
||||
|
||||
func (qb *{{.QueryBuilderName}}) Count(db *gorm.DB) (int64, error) {
|
||||
var c int64
|
||||
res := qb.buildQuery(db).Model(&{{.StructName}}{}).Count(&c)
|
||||
if res.Error != nil && res.Error == gorm.ErrRecordNotFound {
|
||||
c = 0
|
||||
}
|
||||
return c, res.Error
|
||||
}
|
||||
|
||||
func (qb *{{.QueryBuilderName}}) First(db *gorm.DB) (*{{.StructName}}, error) {
|
||||
ret := &{{.StructName}}{}
|
||||
res := qb.buildQuery(db).First(ret)
|
||||
if res.Error != nil && res.Error == gorm.ErrRecordNotFound {
|
||||
ret = nil
|
||||
}
|
||||
return ret, res.Error
|
||||
}
|
||||
|
||||
func (qb *{{.QueryBuilderName}}) QueryOne(db *gorm.DB) (*{{.StructName}}, error) {
|
||||
qb.limit = 1
|
||||
ret, err := qb.QueryAll(db)
|
||||
if len(ret) > 0 {
|
||||
return ret[0], err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (qb *{{.QueryBuilderName}}) QueryAll(db *gorm.DB) ([]*{{.StructName}}, error) {
|
||||
var ret []*{{.StructName}}
|
||||
err := qb.buildQuery(db).Find(&ret).Error
|
||||
return ret, err
|
||||
}
|
||||
|
||||
func (qb *{{.QueryBuilderName}}) Limit(limit int) *{{.QueryBuilderName}} {
|
||||
qb.limit = limit
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *{{.QueryBuilderName}}) Offset(offset int) *{{.QueryBuilderName}} {
|
||||
qb.offset = offset
|
||||
return qb
|
||||
}
|
||||
|
||||
{{$queryBuilderName := .QueryBuilderName}}
|
||||
{{range .OptionFields}}
|
||||
func (qb *{{$queryBuilderName}}) Where{{call $.Helpers.Titelize .FieldName}}(p db_repo.Predicate, value {{.FieldType}}) *{{$queryBuilderName}} {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}{
|
||||
fmt.Sprintf("%v %v ?", "{{.ColumnName}}", p),
|
||||
value,
|
||||
})
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *{{$queryBuilderName}}) OrderBy{{call $.Helpers.Titelize .FieldName}}(asc bool) *{{$queryBuilderName}} {
|
||||
order := "DESC"
|
||||
if asc {
|
||||
order = "ASC"
|
||||
}
|
||||
|
||||
qb.order = append(qb.order, "{{.ColumnName}} " + order)
|
||||
return qb
|
||||
}
|
||||
{{end}}
|
||||
`)
|
||||
18
cmd/gormgen/pkg/utils.go
Normal file
18
cmd/gormgen/pkg/utils.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package pkg
|
||||
|
||||
import "strings"
|
||||
|
||||
// SQLColumnToHumpStyle sql转换成驼峰模式
|
||||
func SQLColumnToHumpStyle(in string) (ret string) {
|
||||
for i := 0; i < len(in); i++ {
|
||||
if i > 0 && in[i-1] == '_' && in[i] != '_' {
|
||||
s := strings.ToUpper(string(in[i]))
|
||||
ret += s
|
||||
} else if in[i] == '_' {
|
||||
continue
|
||||
} else {
|
||||
ret += string(in[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
6
cmd/handlergen/README.md
Normal file
6
cmd/handlergen/README.md
Normal file
@@ -0,0 +1,6 @@
|
||||
## 执行命令
|
||||
|
||||
```$xslt
|
||||
// test_handler 为 ./internal/api/controller/ 中的包名
|
||||
./scripts/handlergen.sh test_handler
|
||||
```
|
||||
84
cmd/handlergen/main.go
Normal file
84
cmd/handlergen/main.go
Normal file
@@ -0,0 +1,84 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
var handlerName string
|
||||
|
||||
func init() {
|
||||
handler := flag.String("handler", "", "请输入需要生成的 handler 名称\n")
|
||||
flag.Parse()
|
||||
|
||||
handlerName = strings.ToLower(*handler)
|
||||
}
|
||||
|
||||
func main() {
|
||||
fs := token.NewFileSet()
|
||||
file := fmt.Sprintf("./internal/api/controller/%s/handler.go", handlerName)
|
||||
parsedFile, err := parser.ParseFile(fs, file, nil, 0)
|
||||
if err != nil {
|
||||
log.Fatalf("parsing package: %s: %s\n", file, err)
|
||||
}
|
||||
|
||||
ast.Inspect(parsedFile, func(n ast.Node) bool {
|
||||
decl, ok := n.(*ast.GenDecl)
|
||||
if !ok || decl.Tok != token.TYPE {
|
||||
return true
|
||||
}
|
||||
|
||||
for _, spec := range decl.Specs {
|
||||
typeSpec, _ok := spec.(*ast.TypeSpec)
|
||||
if !_ok {
|
||||
continue
|
||||
}
|
||||
|
||||
var interfaceType *ast.InterfaceType
|
||||
if interfaceType, ok = typeSpec.Type.(*ast.InterfaceType); !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, v := range interfaceType.Methods.List {
|
||||
if len(v.Names) > 0 {
|
||||
if v.Names[0].String() == "i" {
|
||||
continue
|
||||
}
|
||||
|
||||
filepath := "./internal/api/controller/" + handlerName
|
||||
filename := fmt.Sprintf("%s/func_%s.go", filepath, strings.ToLower(v.Names[0].String()))
|
||||
funcFile, err := os.OpenFile(filename, os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0766)
|
||||
if err != nil {
|
||||
fmt.Printf("create and open func file error %v\n", err.Error())
|
||||
}
|
||||
|
||||
funcContent := fmt.Sprintf("package %s\n\n", handlerName)
|
||||
funcContent += "import (\n"
|
||||
funcContent += `"github.com/xinliangnote/go-gin-api/internal/pkg/core"`
|
||||
funcContent += "\n)\n\n"
|
||||
funcContent += fmt.Sprintf("\n\ntype %sRequest struct {}\n\n", Lcfirst(v.Names[0].String()))
|
||||
funcContent += fmt.Sprintf("type %sResponse struct {}\n\n", Lcfirst(v.Names[0].String()))
|
||||
funcContent += fmt.Sprintf("func (h *handler) %s() core.HandlerFunc { \n return func(c core.Context) {\n\n}}", v.Names[0].String())
|
||||
|
||||
funcFile.WriteString(funcContent)
|
||||
funcFile.Close()
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
func Lcfirst(str string) string {
|
||||
for i, v := range str {
|
||||
return string(unicode.ToLower(v)) + str[i+1:]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
289
cmd/mysqlmd/main.go
Normal file
289
cmd/mysqlmd/main.go
Normal file
@@ -0,0 +1,289 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/configs"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/db"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/env"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/logger"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type tableInfo struct {
|
||||
Name string `db:"table_name"` // name
|
||||
Comment sql.NullString `db:"table_comment"` // comment
|
||||
}
|
||||
|
||||
type tableColumn struct {
|
||||
OrdinalPosition uint16 `db:"ORDINAL_POSITION"` // position
|
||||
ColumnName string `db:"COLUMN_NAME"` // name
|
||||
ColumnType string `db:"COLUMN_TYPE"` // column_type
|
||||
DataType string `db:"DATA_TYPE"` // data_type
|
||||
ColumnKey sql.NullString `db:"COLUMN_KEY"` // key
|
||||
IsNullable string `db:"IS_NULLABLE"` // nullable
|
||||
Extra sql.NullString `db:"EXTRA"` // extra
|
||||
ColumnComment sql.NullString `db:"COLUMN_COMMENT"` // comment
|
||||
ColumnDefault sql.NullString `db:"COLUMN_DEFAULT"` // default value
|
||||
}
|
||||
|
||||
func main() {
|
||||
// 初始化 logger
|
||||
loggers, err := logger.NewJSONLogger(
|
||||
logger.WithField("domain", fmt.Sprintf("%s[%s]", configs.ProjectName(), env.Active().Value())),
|
||||
logger.WithTimeLayout("2006-01-02 15:04:05"),
|
||||
logger.WithFileP(configs.ProjectLogFile()),
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer loggers.Sync()
|
||||
|
||||
// 初始化 DB
|
||||
dbRepo, err := db.New()
|
||||
if err != nil {
|
||||
loggers.Fatal("new db err", zap.Error(err))
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err := dbRepo.DbWClose(); err != nil {
|
||||
loggers.Error("dbw close err", zap.Error(err))
|
||||
}
|
||||
|
||||
if err := dbRepo.DbRClose(); err != nil {
|
||||
loggers.Error("dbr close err", zap.Error(err))
|
||||
}
|
||||
}()
|
||||
|
||||
dbName := configs.Get().MySQL.Read.Name
|
||||
genTables := configs.Get().Cmd.GenTables
|
||||
tables, err := queryTables(dbRepo.GetDbR(), dbName, genTables)
|
||||
if err != nil {
|
||||
loggers.Error("query tables of database err", zap.Error(err))
|
||||
return
|
||||
}
|
||||
|
||||
for _, table := range tables {
|
||||
|
||||
filepath := "./internal/api/repository/db_repo/" + table.Name + "_repo"
|
||||
_ = os.Mkdir(filepath, 0766)
|
||||
|
||||
mdName := fmt.Sprintf("%s/gen_table.md", filepath)
|
||||
mdFile, err := os.OpenFile(mdName, os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0766)
|
||||
if err != nil {
|
||||
fmt.Printf("create and open markdown file error %v\n", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
modelName := fmt.Sprintf("%s/gen_model.go", filepath)
|
||||
modelFile, err := os.OpenFile(modelName, os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0766)
|
||||
if err != nil {
|
||||
fmt.Printf("create and open model file error %v\n", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
modelContent := fmt.Sprintf("package %s%s\n", table.Name, "_repo")
|
||||
modelContent += fmt.Sprintf(`import "time"`)
|
||||
modelContent += fmt.Sprintf("\n\n// %s \n", table.Comment.String)
|
||||
modelContent += fmt.Sprintf("//go:generate gormgen -structs %s -input . \n", capitalize(table.Name))
|
||||
modelContent += fmt.Sprintf("type %s struct {\n", capitalize(table.Name))
|
||||
|
||||
tableContent := fmt.Sprintf("#### %s.%s \n", dbName, table.Name)
|
||||
if table.Comment.String != "" {
|
||||
tableContent += table.Comment.String + "\n"
|
||||
}
|
||||
tableContent += "\n" +
|
||||
"| 序号 | 名称 | 描述 | 类型 | 键 | 为空 | 额外 | 默认值 |\n" +
|
||||
"| :--: | :--: | :--: | :--: | :--: | :--: | :--: | :--: |\n"
|
||||
|
||||
columnInfo, columnInfoErr := queryTableColumn(dbRepo.GetDbR(), dbName, table.Name)
|
||||
if columnInfoErr != nil {
|
||||
continue
|
||||
}
|
||||
for _, info := range columnInfo {
|
||||
tableContent += fmt.Sprintf(
|
||||
"| %d | %s | %s | %s | %s | %s | %s | %s |\n",
|
||||
info.OrdinalPosition,
|
||||
info.ColumnName,
|
||||
strings.ReplaceAll(strings.ReplaceAll(info.ColumnComment.String, "|", "\\|"), "\n", ""),
|
||||
info.ColumnType,
|
||||
info.ColumnKey.String,
|
||||
info.IsNullable,
|
||||
info.Extra.String,
|
||||
info.ColumnDefault.String,
|
||||
)
|
||||
|
||||
if textType(info.DataType) == "time.Time" {
|
||||
modelContent += fmt.Sprintf("%s %s `%s` // %s\n", capitalize(info.ColumnName), textType(info.DataType), "gorm:\"time\"", info.ColumnComment.String)
|
||||
} else {
|
||||
modelContent += fmt.Sprintf("%s %s // %s\n", capitalize(info.ColumnName), textType(info.DataType), info.ColumnComment.String)
|
||||
}
|
||||
}
|
||||
|
||||
mdFile.WriteString(tableContent)
|
||||
mdFile.Close()
|
||||
|
||||
modelContent += "}\n"
|
||||
modelFile.WriteString(modelContent)
|
||||
modelFile.Close()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func queryTables(db *gorm.DB, dbName string, tableName string) ([]tableInfo, error) {
|
||||
var tableCollect []tableInfo
|
||||
var tableArray []string
|
||||
var commentArray []sql.NullString
|
||||
|
||||
sqlTables := fmt.Sprintf("SELECT `table_name`,`table_comment` FROM `information_schema`.`tables` WHERE `table_schema`= '%s'", dbName)
|
||||
rows, err := db.Raw(sqlTables).Rows()
|
||||
if err != nil {
|
||||
return tableCollect, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
for rows.Next() {
|
||||
var info tableInfo
|
||||
err = rows.Scan(&info.Name, &info.Comment)
|
||||
if err != nil {
|
||||
fmt.Printf("execute query tables action error,had ignored, detail is [%v]\n", err.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
tableCollect = append(tableCollect, info)
|
||||
tableArray = append(tableArray, info.Name)
|
||||
commentArray = append(commentArray, info.Comment)
|
||||
}
|
||||
|
||||
// filter tables when specified tables params
|
||||
if tableName != "" {
|
||||
tableCollect = nil
|
||||
chooseTables := strings.Split(tableName, ",")
|
||||
indexMap := make(map[int]int)
|
||||
for _, item := range chooseTables {
|
||||
subIndexMap := getTargetIndexMap(tableArray, item)
|
||||
for k, v := range subIndexMap {
|
||||
if _, ok := indexMap[k]; ok {
|
||||
continue
|
||||
}
|
||||
indexMap[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
if len(indexMap) != 0 {
|
||||
for _, v := range indexMap {
|
||||
var info tableInfo
|
||||
info.Name = tableArray[v]
|
||||
info.Comment = commentArray[v]
|
||||
tableCollect = append(tableCollect, info)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return tableCollect, err
|
||||
}
|
||||
|
||||
func queryTableColumn(db *gorm.DB, dbName string, tableName string) ([]tableColumn, error) {
|
||||
// 定义承载列信息的切片
|
||||
var columns []tableColumn
|
||||
|
||||
sqlTableColumn := fmt.Sprintf("SELECT `ORDINAL_POSITION`,`COLUMN_NAME`,`COLUMN_TYPE`,`DATA_TYPE`,`COLUMN_KEY`,`IS_NULLABLE`,`EXTRA`,`COLUMN_COMMENT`,`COLUMN_DEFAULT` FROM `information_schema`.`columns` WHERE `table_schema`= '%s' AND `table_name`= '%s' ORDER BY `ORDINAL_POSITION` ASC",
|
||||
dbName, tableName)
|
||||
|
||||
rows, err := db.Raw(sqlTableColumn).Rows()
|
||||
if err != nil {
|
||||
fmt.Printf("execute query table column action error, detail is [%v]\n", err.Error())
|
||||
return columns, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
for rows.Next() {
|
||||
var column tableColumn
|
||||
err = rows.Scan(
|
||||
&column.OrdinalPosition,
|
||||
&column.ColumnName,
|
||||
&column.ColumnType,
|
||||
&column.DataType,
|
||||
&column.ColumnKey,
|
||||
&column.IsNullable,
|
||||
&column.Extra,
|
||||
&column.ColumnComment,
|
||||
&column.ColumnDefault)
|
||||
if err != nil {
|
||||
fmt.Printf("query table column scan error, detail is [%v]\n", err.Error())
|
||||
return columns, err
|
||||
}
|
||||
columns = append(columns, column)
|
||||
}
|
||||
|
||||
return columns, err
|
||||
}
|
||||
|
||||
func getTargetIndexMap(tableNameArr []string, item string) map[int]int {
|
||||
indexMap := make(map[int]int)
|
||||
for i := 0; i < len(tableNameArr); i++ {
|
||||
if match, _ := regexp.MatchString(item, tableNameArr[i]); match {
|
||||
if _, ok := indexMap[i]; ok {
|
||||
continue
|
||||
}
|
||||
indexMap[i] = i
|
||||
}
|
||||
}
|
||||
return indexMap
|
||||
}
|
||||
|
||||
func capitalize(s string) string {
|
||||
var upperStr string
|
||||
chars := strings.Split(s, "_")
|
||||
for _, val := range chars {
|
||||
vv := []rune(val)
|
||||
for i := 0; i < len(vv); i++ {
|
||||
if i == 0 {
|
||||
if vv[i] >= 97 && vv[i] <= 122 {
|
||||
vv[i] -= 32
|
||||
upperStr += string(vv[i])
|
||||
}
|
||||
} else {
|
||||
upperStr += string(vv[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
return upperStr
|
||||
}
|
||||
|
||||
func textType(s string) string {
|
||||
var mysqlTypeToGoType = map[string]string{
|
||||
"tinyint": "int32",
|
||||
"smallint": "int32",
|
||||
"mediumint": "int32",
|
||||
"int": "int32",
|
||||
"integer": "int64",
|
||||
"bigint": "int64",
|
||||
"float": "float64",
|
||||
"double": "float64",
|
||||
"decimal": "float64",
|
||||
"date": "string",
|
||||
"time": "string",
|
||||
"year": "string",
|
||||
"datetime": "time.Time",
|
||||
"timestamp": "time.Time",
|
||||
"char": "string",
|
||||
"varchar": "string",
|
||||
"tinyblob": "string",
|
||||
"tinytext": "string",
|
||||
"blob": "string",
|
||||
"text": "string",
|
||||
"mediumblob": "string",
|
||||
"mediumtext": "string",
|
||||
"longblob": "string",
|
||||
"longtext": "string",
|
||||
}
|
||||
return mysqlTypeToGoType[s]
|
||||
}
|
||||
@@ -63,6 +63,10 @@ type Config struct {
|
||||
Private string `toml:"private"`
|
||||
Public string `toml:"public"`
|
||||
} `toml:"rsa"`
|
||||
|
||||
Cmd struct {
|
||||
GenTables string `toml:"genTables"`
|
||||
} `toml:"cmd"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
@@ -77,3 +77,5 @@ xLYEFN9h2MWYgxLm9Z0rLMrWwMM+E2rCs8tsxAD5sO9RZMJPl1C0FIsMR53ngqbz
|
||||
owIDAQAB
|
||||
-----END PUBLIC KEY-----'
|
||||
|
||||
[cmd]
|
||||
genTables = 'user_demo'
|
||||
@@ -169,7 +169,7 @@ var doc = `{
|
||||
},
|
||||
"/user/delete/{id}": {
|
||||
"patch": {
|
||||
"description": "删除用户 - 更新 is_deleted = 1",
|
||||
"description": "删除用户",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
@@ -179,7 +179,7 @@ var doc = `{
|
||||
"tags": [
|
||||
"User"
|
||||
],
|
||||
"summary": "删除用户 - 更新 is_deleted = 1",
|
||||
"summary": "删除用户",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
|
||||
@@ -152,7 +152,7 @@
|
||||
},
|
||||
"/user/delete/{id}": {
|
||||
"patch": {
|
||||
"description": "删除用户 - 更新 is_deleted = 1",
|
||||
"description": "删除用户",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
@@ -162,7 +162,7 @@
|
||||
"tags": [
|
||||
"User"
|
||||
],
|
||||
"summary": "删除用户 - 更新 is_deleted = 1",
|
||||
"summary": "删除用户",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
|
||||
@@ -176,7 +176,7 @@ paths:
|
||||
patch:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 删除用户 - 更新 is_deleted = 1
|
||||
description: 删除用户
|
||||
parameters:
|
||||
- description: 用户ID
|
||||
in: path
|
||||
@@ -203,7 +203,7 @@ paths:
|
||||
description: Unauthorized
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
summary: 删除用户 - 更新 is_deleted = 1
|
||||
summary: 删除用户
|
||||
tags:
|
||||
- User
|
||||
/user/info/{username}:
|
||||
|
||||
1
go.mod
1
go.mod
@@ -12,6 +12,7 @@ require (
|
||||
github.com/go-redis/redis/v7 v7.4.0
|
||||
github.com/golang/protobuf v1.4.3
|
||||
github.com/google/go-cmp v0.5.4 // indirect
|
||||
github.com/jinzhu/gorm v1.9.16
|
||||
github.com/onsi/ginkgo v1.14.2 // indirect
|
||||
github.com/onsi/gomega v1.10.4 // indirect
|
||||
github.com/pkg/errors v0.9.1
|
||||
|
||||
20
go.sum
20
go.sum
@@ -19,6 +19,7 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym
|
||||
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
|
||||
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
|
||||
github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
|
||||
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
@@ -33,6 +34,7 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ=
|
||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
||||
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
|
||||
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q=
|
||||
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
@@ -58,6 +60,8 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6ROGeiHFAP8WJdI2RoxALQYgdllERc3N5N2DM=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
@@ -65,6 +69,8 @@ github.com/dgryski/trifles v0.0.0-20190318185328-a8d75aae118c h1:TUuUh0Xgj97tLMN
|
||||
github.com/dgryski/trifles v0.0.0-20190318185328-a8d75aae118c/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA=
|
||||
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/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y=
|
||||
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
@@ -123,6 +129,8 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me
|
||||
github.com/gogo/protobuf v1.0.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
@@ -192,8 +200,11 @@ github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0m
|
||||
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
|
||||
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/jinzhu/gorm v1.9.16 h1:+IyIjPEABKRpsu/F8OvDPy9fyQlgsg2luMV2ZIH5i5o=
|
||||
github.com/jinzhu/gorm v1.9.16/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs=
|
||||
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.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/jinzhu/now v1.1.1 h1:g39TucaRWyV3dwDO++eEc6qf8TVIQ/Da48WmqjZ3i7E=
|
||||
github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
@@ -220,6 +231,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
|
||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||
github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4=
|
||||
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
||||
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
|
||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
@@ -237,6 +250,8 @@ github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-sqlite3 v1.14.0 h1:mLyGNKR8+Vv9CAU7PphKa2hkEqxxhn8i32J6FPj1/QA=
|
||||
github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
@@ -381,9 +396,11 @@ go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
|
||||
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=
|
||||
@@ -409,6 +426,7 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.0 h1:8pl+sMODzuvGJkmj2W4kZihvVb5mKm8pB/X44PIQHv8=
|
||||
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -428,6 +446,8 @@ golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLL
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
|
||||
@@ -18,7 +18,7 @@ type createRequest struct {
|
||||
}
|
||||
|
||||
type createResponse struct {
|
||||
Id uint `json:"id"` // 主键ID
|
||||
Id int32 `json:"id"` // 主键ID
|
||||
}
|
||||
|
||||
// 创建用户
|
||||
|
||||
@@ -9,16 +9,16 @@ import (
|
||||
)
|
||||
|
||||
type deleteRequest struct {
|
||||
Id uint `uri:"id"` // 用户ID
|
||||
Id int32 `uri:"id"` // 用户ID
|
||||
}
|
||||
|
||||
type deleteResponse struct {
|
||||
Id uint `json:"id"` // 用户主键ID
|
||||
Id int32 `json:"id"` // 用户主键ID
|
||||
}
|
||||
|
||||
// 删除用户 - 更新 is_deleted = 1
|
||||
// @Summary 删除用户 - 更新 is_deleted = 1
|
||||
// @Description 删除用户 - 更新 is_deleted = 1
|
||||
// 删除用户
|
||||
// @Summary 删除用户
|
||||
// @Description 删除用户
|
||||
// @Tags User
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
|
||||
@@ -14,7 +14,7 @@ type detailRequest struct {
|
||||
}
|
||||
|
||||
type detailResponse struct {
|
||||
Id uint `json:"id"` // 用户主键ID
|
||||
Id int32 `json:"id"` // 用户主键ID
|
||||
UserName string `json:"user_name"` // 用户名
|
||||
NickName string `json:"nick_name"` // 昵称
|
||||
Mobile ddm.Mobile `json:"mobile"` // 手机号(脱敏)
|
||||
|
||||
@@ -9,12 +9,12 @@ import (
|
||||
)
|
||||
|
||||
type updateNickNameByIDRequest struct {
|
||||
Id uint `json:"id"` // 用户主键ID
|
||||
Id int32 `json:"id"` // 用户主键ID
|
||||
NickName string `json:"nick_name"` // 昵称
|
||||
}
|
||||
|
||||
type updateNickNameByIDResponse struct {
|
||||
Id uint `json:"id"` // 用户主键ID
|
||||
Id int32 `json:"id"` // 用户主键ID
|
||||
}
|
||||
|
||||
// 编辑用户 - 通过用户主键ID更新用户昵称
|
||||
|
||||
@@ -18,7 +18,7 @@ type Handler interface {
|
||||
Create() core.HandlerFunc
|
||||
// UpdateNickNameByID 编辑用户 - 通过主键ID更新用户昵称
|
||||
UpdateNickNameByID() core.HandlerFunc
|
||||
// Delete 删除用户 - 通过主键ID更新 is_deleted = 1
|
||||
// Delete 删除用户
|
||||
Delete() core.HandlerFunc
|
||||
// Detail 用户详情
|
||||
Detail() core.HandlerFunc
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
## repository
|
||||
|
||||
数据访问层。
|
||||
#### 数据访问层。
|
||||
|
||||
- `./db_repo` 访问 DB 数据
|
||||
- `./cache_repo` 访问 Cache 数据
|
||||
- `./third_party_request` 访问外部 HTTP 接口数据。
|
||||
|
||||
SQL 建议:
|
||||
- 禁止使用 SQL k v 拼接,好处是避免 SQL 注入;
|
||||
- 禁止使用连表查询,好处是易扩展,比如分库分表;
|
||||
- 禁止使用万能方法,好处是便于后期维护,比如字段调整;
|
||||
- 禁止使用删除方法,好处是避免数据丢失;
|
||||
#### SQL 建议:
|
||||
- 建议每张表需包含字段:主键(id)、标记删除(is_deteled)、创建时间(created_at)、更新时间(updated_at)
|
||||
|
||||
```mysql
|
||||
@@ -19,11 +15,18 @@ SQL 建议:
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
```
|
||||
什么是万能方法?
|
||||
|
||||
指的是特别灵活的查询,比如通过非固定的参数返回全部字段,建议做到需要什么返回什么,不要返回大而全的数据,更新时也不能传递什么参数更新什么参数,更新字段要提前约定好。
|
||||
|
||||
命名规范:
|
||||
#### 命名规范:
|
||||
|
||||
- 包名应以 `_repo` 结尾;
|
||||
- `./db_repo` 目录下的包名以 `数据表名`+ `_repo` 命名;
|
||||
|
||||
#### 脚本生成 MySQL CURD
|
||||
|
||||
1. 定义生成的表,设置 config 中 cmd.genTables,可以自定义设置多张表,为空表示生成库中所有的表,如果设置多个表可用','分割;
|
||||
1. 在根目录下执行脚本文件:`./scripts/gormgen.sh`;
|
||||
|
||||
以用户表(user_demo)为例:
|
||||
- 结构体文件:user_demo_repo/gen_model.go;
|
||||
- CURD 方法文件:user_demo_repo/gen_user_demo.go;
|
||||
- 表结构 MD 文件:user_demo_repo/gen_table.md;
|
||||
|
||||
14
internal/api/repository/db_repo/db.go
Normal file
14
internal/api/repository/db_repo/db.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package db_repo
|
||||
|
||||
// Predicate is a string that acts as a condition in the where clause
|
||||
type Predicate string
|
||||
|
||||
var (
|
||||
EqualPredicate = Predicate("=")
|
||||
NotEqualPredicate = Predicate("<>")
|
||||
GreaterThanPredicate = Predicate(">")
|
||||
GreaterThanOrEqualPredicate = Predicate(">=")
|
||||
SmallerThanPredicate = Predicate("<")
|
||||
SmallerThanOrEqualPredicate = Predicate("<=")
|
||||
LikePredicate = Predicate("LIKE")
|
||||
)
|
||||
15
internal/api/repository/db_repo/user_demo_repo/gen_model.go
Executable file
15
internal/api/repository/db_repo/user_demo_repo/gen_model.go
Executable file
@@ -0,0 +1,15 @@
|
||||
package user_demo_repo
|
||||
|
||||
import "time"
|
||||
|
||||
// 用户Demo表
|
||||
//go:generate gormgen -structs UserDemo -input .
|
||||
type UserDemo struct {
|
||||
Id int32 // 主键
|
||||
UserName string // 用户名
|
||||
NickName string // 昵称
|
||||
Mobile string // 手机号
|
||||
IsDeleted int32 // 是否删除 1:是 -1:否
|
||||
CreatedAt time.Time `gorm:"time"` // 创建时间
|
||||
UpdatedAt time.Time `gorm:"time"` // 更新时间
|
||||
}
|
||||
12
internal/api/repository/db_repo/user_demo_repo/gen_table.md
Executable file
12
internal/api/repository/db_repo/user_demo_repo/gen_table.md
Executable file
@@ -0,0 +1,12 @@
|
||||
#### xin_ceshi.user_demo
|
||||
用户Demo表
|
||||
|
||||
| 序号 | 名称 | 描述 | 类型 | 键 | 为空 | 额外 | 默认值 |
|
||||
| :--: | :--: | :--: | :--: | :--: | :--: | :--: | :--: |
|
||||
| 1 | id | 主键 | int(11) unsigned | PRI | NO | auto_increment | |
|
||||
| 2 | user_name | 用户名 | varchar(32) | | NO | | |
|
||||
| 3 | nick_name | 昵称 | varchar(100) | | NO | | |
|
||||
| 4 | mobile | 手机号 | varchar(20) | | NO | | |
|
||||
| 5 | is_deleted | 是否删除 1:是 -1:否 | tinyint(1) | | NO | | -1 |
|
||||
| 6 | created_at | 创建时间 | timestamp | | NO | | CURRENT_TIMESTAMP |
|
||||
| 7 | updated_at | 更新时间 | timestamp | | NO | on update CURRENT_TIMESTAMP | CURRENT_TIMESTAMP |
|
||||
257
internal/api/repository/db_repo/user_demo_repo/gen_user_demo.go
Executable file
257
internal/api/repository/db_repo/user_demo_repo/gen_user_demo.go
Executable file
@@ -0,0 +1,257 @@
|
||||
///////////////////////////////////////////////////////////
|
||||
// THIS FILE IS AUTO GENERATED by gormgen, DON'T EDIT IT //
|
||||
// ANY CHANGES DONE HERE WILL BE LOST //
|
||||
///////////////////////////////////////////////////////////
|
||||
|
||||
package user_demo_repo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func NewModel() *UserDemo {
|
||||
return new(UserDemo)
|
||||
}
|
||||
|
||||
func NewQueryBuilder() *userDemoRepoQueryBuilder {
|
||||
return new(userDemoRepoQueryBuilder)
|
||||
}
|
||||
|
||||
func (t *UserDemo) Create(db *gorm.DB) (id int32, err error) {
|
||||
if err = db.Create(t).Error; err != nil {
|
||||
return 0, errors.Wrap(err, "create err")
|
||||
}
|
||||
return t.Id, nil
|
||||
}
|
||||
|
||||
func (t *UserDemo) Delete(db *gorm.DB) (err error) {
|
||||
if err = db.Delete(t).Error; err != nil {
|
||||
return errors.Wrap(err, "delete err")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *UserDemo) Updates(db *gorm.DB, m map[string]interface{}) (err error) {
|
||||
if err = db.Model(&UserDemo{}).Where("id = ?", t.Id).Updates(m).Error; err != nil {
|
||||
return errors.Wrap(err, "updates err")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type userDemoRepoQueryBuilder struct {
|
||||
order []string
|
||||
where []struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}
|
||||
limit int
|
||||
offset int
|
||||
}
|
||||
|
||||
func (qb *userDemoRepoQueryBuilder) buildQuery(db *gorm.DB) *gorm.DB {
|
||||
ret := db
|
||||
for _, where := range qb.where {
|
||||
ret = ret.Where(where.prefix, where.value)
|
||||
}
|
||||
for _, order := range qb.order {
|
||||
ret = ret.Order(order)
|
||||
}
|
||||
ret = ret.Limit(qb.limit).Offset(qb.offset)
|
||||
return ret
|
||||
}
|
||||
|
||||
func (qb *userDemoRepoQueryBuilder) Count(db *gorm.DB) (int64, error) {
|
||||
var c int64
|
||||
res := qb.buildQuery(db).Model(&UserDemo{}).Count(&c)
|
||||
if res.Error != nil && res.Error == gorm.ErrRecordNotFound {
|
||||
c = 0
|
||||
}
|
||||
return c, res.Error
|
||||
}
|
||||
|
||||
func (qb *userDemoRepoQueryBuilder) First(db *gorm.DB) (*UserDemo, error) {
|
||||
ret := &UserDemo{}
|
||||
res := qb.buildQuery(db).First(ret)
|
||||
if res.Error != nil && res.Error == gorm.ErrRecordNotFound {
|
||||
ret = nil
|
||||
}
|
||||
return ret, res.Error
|
||||
}
|
||||
|
||||
func (qb *userDemoRepoQueryBuilder) QueryOne(db *gorm.DB) (*UserDemo, error) {
|
||||
qb.limit = 1
|
||||
ret, err := qb.QueryAll(db)
|
||||
if len(ret) > 0 {
|
||||
return ret[0], err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (qb *userDemoRepoQueryBuilder) QueryAll(db *gorm.DB) ([]*UserDemo, error) {
|
||||
var ret []*UserDemo
|
||||
err := qb.buildQuery(db).Find(&ret).Error
|
||||
return ret, err
|
||||
}
|
||||
|
||||
func (qb *userDemoRepoQueryBuilder) Limit(limit int) *userDemoRepoQueryBuilder {
|
||||
qb.limit = limit
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *userDemoRepoQueryBuilder) Offset(offset int) *userDemoRepoQueryBuilder {
|
||||
qb.offset = offset
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *userDemoRepoQueryBuilder) WhereId(p db_repo.Predicate, value int32) *userDemoRepoQueryBuilder {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}{
|
||||
fmt.Sprintf("%v %v ?", "id", p),
|
||||
value,
|
||||
})
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *userDemoRepoQueryBuilder) OrderById(asc bool) *userDemoRepoQueryBuilder {
|
||||
order := "DESC"
|
||||
if asc {
|
||||
order = "ASC"
|
||||
}
|
||||
|
||||
qb.order = append(qb.order, "id "+order)
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *userDemoRepoQueryBuilder) WhereUserName(p db_repo.Predicate, value string) *userDemoRepoQueryBuilder {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}{
|
||||
fmt.Sprintf("%v %v ?", "user_name", p),
|
||||
value,
|
||||
})
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *userDemoRepoQueryBuilder) OrderByUserName(asc bool) *userDemoRepoQueryBuilder {
|
||||
order := "DESC"
|
||||
if asc {
|
||||
order = "ASC"
|
||||
}
|
||||
|
||||
qb.order = append(qb.order, "user_name "+order)
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *userDemoRepoQueryBuilder) WhereNickName(p db_repo.Predicate, value string) *userDemoRepoQueryBuilder {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}{
|
||||
fmt.Sprintf("%v %v ?", "nick_name", p),
|
||||
value,
|
||||
})
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *userDemoRepoQueryBuilder) OrderByNickName(asc bool) *userDemoRepoQueryBuilder {
|
||||
order := "DESC"
|
||||
if asc {
|
||||
order = "ASC"
|
||||
}
|
||||
|
||||
qb.order = append(qb.order, "nick_name "+order)
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *userDemoRepoQueryBuilder) WhereMobile(p db_repo.Predicate, value string) *userDemoRepoQueryBuilder {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}{
|
||||
fmt.Sprintf("%v %v ?", "mobile", p),
|
||||
value,
|
||||
})
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *userDemoRepoQueryBuilder) OrderByMobile(asc bool) *userDemoRepoQueryBuilder {
|
||||
order := "DESC"
|
||||
if asc {
|
||||
order = "ASC"
|
||||
}
|
||||
|
||||
qb.order = append(qb.order, "mobile "+order)
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *userDemoRepoQueryBuilder) WhereIsDeleted(p db_repo.Predicate, value int32) *userDemoRepoQueryBuilder {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}{
|
||||
fmt.Sprintf("%v %v ?", "is_deleted", p),
|
||||
value,
|
||||
})
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *userDemoRepoQueryBuilder) OrderByIsDeleted(asc bool) *userDemoRepoQueryBuilder {
|
||||
order := "DESC"
|
||||
if asc {
|
||||
order = "ASC"
|
||||
}
|
||||
|
||||
qb.order = append(qb.order, "is_deleted "+order)
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *userDemoRepoQueryBuilder) WhereCreatedAt(p db_repo.Predicate, value time.Time) *userDemoRepoQueryBuilder {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}{
|
||||
fmt.Sprintf("%v %v ?", "created_at", p),
|
||||
value,
|
||||
})
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *userDemoRepoQueryBuilder) OrderByCreatedAt(asc bool) *userDemoRepoQueryBuilder {
|
||||
order := "DESC"
|
||||
if asc {
|
||||
order = "ASC"
|
||||
}
|
||||
|
||||
qb.order = append(qb.order, "created_at "+order)
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *userDemoRepoQueryBuilder) WhereUpdatedAt(p db_repo.Predicate, value time.Time) *userDemoRepoQueryBuilder {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}{
|
||||
fmt.Sprintf("%v %v ?", "updated_at", p),
|
||||
value,
|
||||
})
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *userDemoRepoQueryBuilder) OrderByUpdatedAt(asc bool) *userDemoRepoQueryBuilder {
|
||||
order := "DESC"
|
||||
if asc {
|
||||
order = "ASC"
|
||||
}
|
||||
|
||||
qb.order = append(qb.order, "updated_at "+order)
|
||||
return qb
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package user_demo_repo
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// 用户Demo表
|
||||
type UserDemo struct {
|
||||
Id uint `gorm:"column:id;primary_key;AUTO_INCREMENT"` // 主键
|
||||
UserName string `gorm:"column:user_name;NOT NULL"` // 用户名
|
||||
NickName string `gorm:"column:nick_name;NOT NULL"` // 昵称
|
||||
Mobile string `gorm:"column:mobile;NOT NULL"` // 手机号
|
||||
IsDeleted int `gorm:"column:is_deleted;default:-1;NOT NULL"` // 是否删除 1:是 -1:否
|
||||
CreatedAt time.Time `gorm:"column:created_at;default:CURRENT_TIMESTAMP;NOT NULL"` // 创建时间
|
||||
UpdatedAt time.Time `gorm:"column:updated_at;default:CURRENT_TIMESTAMP;NOT NULL"` // 更新时间
|
||||
}
|
||||
|
||||
func (m *UserDemo) TableName() string {
|
||||
return "user_demo"
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
package user_demo_repo
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/db"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
var _ UserRepo = (*userRepo)(nil)
|
||||
|
||||
type UserRepo interface {
|
||||
// i 为了避免被其他包实现
|
||||
i()
|
||||
Create(ctx core.Context, user UserDemo) (id uint, err error)
|
||||
UpdateNickNameByID(ctx core.Context, id uint, username string) (err error)
|
||||
GetUserByUserName(ctx core.Context, username string) (*UserDemo, error)
|
||||
Delete(ctx core.Context, id uint) (err error)
|
||||
getUserByID(ctx core.Context, id uint) (*UserDemo, error)
|
||||
}
|
||||
|
||||
type userRepo struct {
|
||||
db db.Repo
|
||||
}
|
||||
|
||||
func NewUserRepo(db db.Repo) UserRepo {
|
||||
return &userRepo{
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
||||
func (u *userRepo) i() {}
|
||||
|
||||
func (u *userRepo) Create(ctx core.Context, user UserDemo) (id uint, err error) {
|
||||
err = u.db.GetDbW().WithContext(ctx.RequestContext()).Create(&user).Error
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "[user_repo] create user err")
|
||||
}
|
||||
return user.Id, nil
|
||||
}
|
||||
|
||||
func (u *userRepo) getUserByID(ctx core.Context, id uint) (*UserDemo, error) {
|
||||
data := new(UserDemo)
|
||||
err := u.db.GetDbR().
|
||||
WithContext(ctx.RequestContext()).First(data, id).Where("is_deleted = ?", -1).Error
|
||||
if err != nil && err != gorm.ErrRecordNotFound {
|
||||
return nil, errors.Wrap(err, "[user_demo] get user data err")
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func (u *userRepo) UpdateNickNameByID(ctx core.Context, id uint, nickname string) (err error) {
|
||||
user, err := u.getUserByID(ctx, id)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "[user_demo] get user data err")
|
||||
}
|
||||
return u.db.GetDbW().WithContext(ctx.RequestContext()).Model(user).Update("nick_name", nickname).Error
|
||||
}
|
||||
|
||||
func (u *userRepo) Delete(ctx core.Context, id uint) (err error) {
|
||||
user, err := u.getUserByID(ctx, id)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "[user_demo] get user data err")
|
||||
}
|
||||
return u.db.GetDbW().WithContext(ctx.RequestContext()).Model(user).Update("is_deleted", 1).Error
|
||||
}
|
||||
|
||||
func (u *userRepo) GetUserByUserName(ctx core.Context, username string) (*UserDemo, error) {
|
||||
data := new(UserDemo)
|
||||
err := u.db.GetDbR().
|
||||
WithContext(ctx.RequestContext()).
|
||||
Select([]string{"id", "user_name", "nick_name", "mobile"}).
|
||||
Where("user_name = ? and is_deleted = ?", username, -1).
|
||||
First(data).Error
|
||||
if err != nil && err != gorm.ErrRecordNotFound {
|
||||
return nil, errors.Wrap(err, "[user_demo] get user data err")
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
@@ -11,14 +11,13 @@ type CreateUserInfo struct {
|
||||
Mobile string `json:"mobile"` // 手机号
|
||||
}
|
||||
|
||||
func (u *userSer) Create(ctx core.Context, user *CreateUserInfo) (id uint, err error) {
|
||||
create := user_demo_repo.UserDemo{
|
||||
UserName: user.UserName,
|
||||
NickName: user.NickName,
|
||||
Mobile: user.Mobile,
|
||||
}
|
||||
func (u *userSer) Create(ctx core.Context, user *CreateUserInfo) (id int32, err error) {
|
||||
model := user_demo_repo.NewModel()
|
||||
model.UserName = user.UserName
|
||||
model.NickName = user.NickName
|
||||
model.Mobile = user.Mobile
|
||||
|
||||
id, err = u.userRepo.Create(ctx, create)
|
||||
id, err = model.Create(u.db.GetDbW().WithContext(ctx.RequestContext()))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
package user_service
|
||||
|
||||
import "github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo/user_demo_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
)
|
||||
|
||||
func (u *userSer) Delete(ctx core.Context, id uint) (err error) {
|
||||
err = u.userRepo.Delete(ctx, id)
|
||||
func (u *userSer) Delete(ctx core.Context, id int32) (err error) {
|
||||
model := user_demo_repo.NewModel()
|
||||
model.Id = id
|
||||
err = model.Delete(u.db.GetDbW().WithContext(ctx.RequestContext()))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,14 +1,23 @@
|
||||
package user_service
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo/user_demo_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
)
|
||||
|
||||
func (u *userSer) GetUserByUserName(ctx core.Context, username string) (user *user_demo_repo.UserDemo, err error) {
|
||||
user, err = u.userRepo.GetUserByUserName(ctx, username)
|
||||
user, err = user_demo_repo.NewQueryBuilder().
|
||||
WhereUserName(db_repo.EqualPredicate, username).
|
||||
QueryOne(u.db.GetDbR().WithContext(ctx.RequestContext()))
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return user, err
|
||||
}
|
||||
|
||||
if user == nil {
|
||||
user = user_demo_repo.NewModel()
|
||||
}
|
||||
|
||||
return user, nil
|
||||
}
|
||||
|
||||
@@ -1,11 +1,22 @@
|
||||
package user_service
|
||||
|
||||
import "github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo/user_demo_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
)
|
||||
|
||||
func (u *userSer) UpdateNickNameByID(ctx core.Context, id uint, username string) (err error) {
|
||||
err = u.userRepo.UpdateNickNameByID(ctx, id, username)
|
||||
if err != nil {
|
||||
return nil
|
||||
func (u *userSer) UpdateNickNameByID(ctx core.Context, id int32, nickname string) (err error) {
|
||||
model := user_demo_repo.NewModel()
|
||||
model.Id = id
|
||||
|
||||
data := map[string]interface{}{
|
||||
"nick_name": nickname,
|
||||
}
|
||||
|
||||
err = model.Updates(u.db.GetDbW().WithContext(ctx.RequestContext()), data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -13,24 +13,21 @@ type UserService interface {
|
||||
// i 为了避免被其他包实现
|
||||
i()
|
||||
|
||||
Create(ctx core.Context, user *CreateUserInfo) (id uint, err error)
|
||||
UpdateNickNameByID(ctx core.Context, id uint, username string) (err error)
|
||||
Create(ctx core.Context, user *CreateUserInfo) (id int32, err error)
|
||||
UpdateNickNameByID(ctx core.Context, id int32, username string) (err error)
|
||||
GetUserByUserName(ctx core.Context, username string) (user *user_demo_repo.UserDemo, err error)
|
||||
Delete(ctx core.Context, id uint) (err error)
|
||||
Delete(ctx core.Context, id int32) (err error)
|
||||
}
|
||||
|
||||
type userSer struct {
|
||||
db db.Repo
|
||||
cache cache.Repo
|
||||
userRepo user_demo_repo.UserRepo
|
||||
db db.Repo
|
||||
cache cache.Repo
|
||||
}
|
||||
|
||||
func NewUserService(db db.Repo, cache cache.Repo) UserService {
|
||||
userRepo := user_demo_repo.NewUserRepo(db)
|
||||
return &userSer{
|
||||
db: db,
|
||||
cache: cache,
|
||||
userRepo: userRepo,
|
||||
db: db,
|
||||
cache: cache,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
"gorm.io/driver/mysql"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/schema"
|
||||
)
|
||||
|
||||
var _ Repo = (*dbRepo)(nil)
|
||||
@@ -80,6 +81,9 @@ func dbConnect(user, pass, addr, dbName string) (*gorm.DB, error) {
|
||||
"Local")
|
||||
|
||||
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
|
||||
NamingStrategy: schema.NamingStrategy{
|
||||
SingularTable: true,
|
||||
},
|
||||
//Logger: logger.Default.LogMode(logger.Info), // 日志配置
|
||||
})
|
||||
|
||||
|
||||
14
scripts/gormgen.sh
Executable file
14
scripts/gormgen.sh
Executable file
@@ -0,0 +1,14 @@
|
||||
#!/bin/bash
|
||||
printf "\nRegenerating mysql file\n\n"
|
||||
time go run -v ./cmd/mysqlmd/main.go -env fat
|
||||
|
||||
printf "\nRegenerating code\n\n"
|
||||
time go build -o gormgen ./cmd/gormgen/main.go
|
||||
mv gormgen $GOPATH/bin
|
||||
|
||||
go generate ./...
|
||||
|
||||
printf "\nFormatting code\n\n"
|
||||
time go run -v github.com/koketama/mfmt
|
||||
|
||||
printf "\nDone.\n\n"
|
||||
8
scripts/handlergen.sh
Executable file
8
scripts/handlergen.sh
Executable file
@@ -0,0 +1,8 @@
|
||||
#!/bin/bash
|
||||
printf "\nRegenerating handler file\n\n"
|
||||
time go run -v ./cmd/handlergen/main.go -handler $1
|
||||
|
||||
printf "\nFormatting code\n\n"
|
||||
time go run -v github.com/koketama/mfmt
|
||||
|
||||
printf "\nDone.\n\n"
|
||||
Reference in New Issue
Block a user