Code optimized (#523)
* optimized markdown generator * optimized markdown generator * optimized markdown generator * add more comment * add comment * add comment * add comments for rpc tool * add comments for model tool * add comments for model tool * add comments for model tool * add comments for config tool * add comments for config tool * add comments * add comments * add comments * add comments * add comment * remove rpc main head info * add comment * optimized Co-authored-by: anqiansong <anqiansong@xiaoheiban.cn>
This commit is contained in:
@@ -9,14 +9,17 @@ import (
|
||||
|
||||
const dbTag = "db"
|
||||
|
||||
// NewEq wraps builder.Eq
|
||||
func NewEq(in interface{}) builder.Eq {
|
||||
return builder.Eq(ToMap(in))
|
||||
}
|
||||
|
||||
// NewGt wraps builder.Gt
|
||||
func NewGt(in interface{}) builder.Gt {
|
||||
return builder.Gt(ToMap(in))
|
||||
}
|
||||
|
||||
// ToMap converts interface into map
|
||||
func ToMap(in interface{}) map[string]interface{} {
|
||||
out := make(map[string]interface{})
|
||||
v := reflect.ValueOf(in)
|
||||
@@ -76,6 +79,7 @@ func FieldNames(in interface{}) []string {
|
||||
return out
|
||||
}
|
||||
|
||||
// RawFieldNames converts golang struct field into slice string
|
||||
func RawFieldNames(in interface{}) []string {
|
||||
out := make([]string, 0)
|
||||
v := reflect.ValueOf(in)
|
||||
|
||||
@@ -10,12 +10,12 @@ import (
|
||||
|
||||
type mockedUser struct {
|
||||
// 自增id
|
||||
Id string `db:"id" json:"id,omitempty"`
|
||||
ID string `db:"id" json:"id,omitempty"`
|
||||
// 姓名
|
||||
UserName string `db:"user_name" json:"userName,omitempty"`
|
||||
// 1男,2女
|
||||
Sex int `db:"sex" json:"sex,omitempty"`
|
||||
Uuid string `db:"uuid" uuid:"uuid,omitempty"`
|
||||
UUID string `db:"uuid" uuid:"uuid,omitempty"`
|
||||
Age int `db:"age" json:"age"`
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ func TestFieldNames(t *testing.T) {
|
||||
|
||||
func TestNewEq(t *testing.T) {
|
||||
u := &mockedUser{
|
||||
Id: "123456",
|
||||
ID: "123456",
|
||||
UserName: "wahaha",
|
||||
}
|
||||
out := NewEq(u)
|
||||
@@ -54,16 +54,16 @@ func TestNewEq(t *testing.T) {
|
||||
// @see https://github.com/go-xorm/builder
|
||||
func TestBuilderSql(t *testing.T) {
|
||||
u := &mockedUser{
|
||||
Id: "123123",
|
||||
ID: "123123",
|
||||
}
|
||||
fields := RawFieldNames(u)
|
||||
eq := NewEq(u)
|
||||
sql, args, err := builder.Select(fields...).From("user").Where(eq).ToSQL()
|
||||
fmt.Println(sql, args, err)
|
||||
|
||||
actualSql := "SELECT `id`,`user_name`,`sex`,`uuid`,`age` FROM user WHERE id=?"
|
||||
actualSQL := "SELECT `id`,`user_name`,`sex`,`uuid`,`age` FROM user WHERE id=?"
|
||||
actualArgs := []interface{}{"123123"}
|
||||
assert.Equal(t, sql, actualSql)
|
||||
assert.Equal(t, sql, actualSQL)
|
||||
assert.Equal(t, args, actualArgs)
|
||||
}
|
||||
|
||||
@@ -76,9 +76,9 @@ func TestBuildSqlDefaultValue(t *testing.T) {
|
||||
sql, args, err := builder.Select(userFieldsWithRawStringQuote...).From("user").Where(eq).ToSQL()
|
||||
fmt.Println(sql, args, err)
|
||||
|
||||
actualSql := "SELECT `id`,`user_name`,`sex`,`uuid`,`age` FROM user WHERE age=? AND user_name=?"
|
||||
actualSQL := "SELECT `id`,`user_name`,`sex`,`uuid`,`age` FROM user WHERE age=? AND user_name=?"
|
||||
actualArgs := []interface{}{0, ""}
|
||||
assert.Equal(t, sql, actualSql)
|
||||
assert.Equal(t, sql, actualSQL)
|
||||
assert.Equal(t, args, actualArgs)
|
||||
})
|
||||
|
||||
@@ -86,9 +86,9 @@ func TestBuildSqlDefaultValue(t *testing.T) {
|
||||
sql, args, err := builder.Select(userFieldsWithoutRawStringQuote...).From("user").Where(eq).ToSQL()
|
||||
fmt.Println(sql, args, err)
|
||||
|
||||
actualSql := "SELECT id,user_name,sex,uuid,age FROM user WHERE age=? AND user_name=?"
|
||||
actualSQL := "SELECT id,user_name,sex,uuid,age FROM user WHERE age=? AND user_name=?"
|
||||
actualArgs := []interface{}{0, ""}
|
||||
assert.Equal(t, sql, actualSql)
|
||||
assert.Equal(t, sql, actualSQL)
|
||||
assert.Equal(t, args, actualArgs)
|
||||
})
|
||||
}
|
||||
@@ -102,9 +102,9 @@ func TestBuilderSqlIn(t *testing.T) {
|
||||
sql, args, err := builder.Select(userFieldsWithRawStringQuote...).From("user").Where(in).And(gtU).ToSQL()
|
||||
fmt.Println(sql, args, err)
|
||||
|
||||
actualSql := "SELECT `id`,`user_name`,`sex`,`uuid`,`age` FROM user WHERE id IN (?,?,?) AND age>?"
|
||||
actualSQL := "SELECT `id`,`user_name`,`sex`,`uuid`,`age` FROM user WHERE id IN (?,?,?) AND age>?"
|
||||
actualArgs := []interface{}{"1", "2", "3", 18}
|
||||
assert.Equal(t, sql, actualSql)
|
||||
assert.Equal(t, sql, actualSQL)
|
||||
assert.Equal(t, args, actualArgs)
|
||||
}
|
||||
|
||||
@@ -113,8 +113,8 @@ func TestBuildSqlLike(t *testing.T) {
|
||||
sql, args, err := builder.Select(userFieldsWithRawStringQuote...).From("user").Where(like).ToSQL()
|
||||
fmt.Println(sql, args, err)
|
||||
|
||||
actualSql := "SELECT `id`,`user_name`,`sex`,`uuid`,`age` FROM user WHERE name LIKE ?"
|
||||
actualSQL := "SELECT `id`,`user_name`,`sex`,`uuid`,`age` FROM user WHERE name LIKE ?"
|
||||
actualArgs := []interface{}{"%wang%"}
|
||||
assert.Equal(t, sql, actualSql)
|
||||
assert.Equal(t, sql, actualSQL)
|
||||
assert.Equal(t, args, actualArgs)
|
||||
}
|
||||
|
||||
@@ -22,13 +22,14 @@ const (
|
||||
flagDir = "dir"
|
||||
flagCache = "cache"
|
||||
flagIdea = "idea"
|
||||
flagUrl = "url"
|
||||
flagURL = "url"
|
||||
flagTable = "table"
|
||||
flagStyle = "style"
|
||||
)
|
||||
|
||||
var errNotMatched = errors.New("sql not matched")
|
||||
|
||||
// MysqlDDL generates model code from ddl
|
||||
func MysqlDDL(ctx *cli.Context) error {
|
||||
src := ctx.String(flagSrc)
|
||||
dir := ctx.String(flagDir)
|
||||
@@ -43,8 +44,9 @@ func MysqlDDL(ctx *cli.Context) error {
|
||||
return fromDDl(src, dir, cfg, cache, idea)
|
||||
}
|
||||
|
||||
// MyDataSource generates model code from datasource
|
||||
func MyDataSource(ctx *cli.Context) error {
|
||||
url := strings.TrimSpace(ctx.String(flagUrl))
|
||||
url := strings.TrimSpace(ctx.String(flagURL))
|
||||
dir := strings.TrimSpace(ctx.String(flagDir))
|
||||
cache := ctx.Bool(flagCache)
|
||||
idea := ctx.Bool(flagIdea)
|
||||
|
||||
@@ -39,6 +39,7 @@ var commonMysqlDataTypeMap = map[string]string{
|
||||
"json": "string",
|
||||
}
|
||||
|
||||
// ConvertDataType converts mysql column type into golang type
|
||||
func ConvertDataType(dataBaseType string, isDefaultNull bool) (string, error) {
|
||||
tp, ok := commonMysqlDataTypeMap[strings.ToLower(dataBaseType)]
|
||||
if !ok {
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
package gen
|
||||
|
||||
import "errors"
|
||||
|
||||
var ErrCircleQuery = errors.New("circle query with other fields")
|
||||
@@ -33,6 +33,7 @@ type (
|
||||
cfg *config.Config
|
||||
}
|
||||
|
||||
// Option defines a function with argument defaultGenerator
|
||||
Option func(generator *defaultGenerator)
|
||||
|
||||
code struct {
|
||||
@@ -48,6 +49,7 @@ type (
|
||||
}
|
||||
)
|
||||
|
||||
// NewDefaultGenerator creates an instance for defaultGenerator
|
||||
func NewDefaultGenerator(dir string, cfg *config.Config, opt ...Option) (*defaultGenerator, error) {
|
||||
if dir == "" {
|
||||
dir = pwd
|
||||
@@ -75,6 +77,7 @@ func NewDefaultGenerator(dir string, cfg *config.Config, opt ...Option) (*defaul
|
||||
return generator, nil
|
||||
}
|
||||
|
||||
// WithConsoleOption creates a console option
|
||||
func WithConsoleOption(c console.Console) Option {
|
||||
return func(generator *defaultGenerator) {
|
||||
generator.Console = c
|
||||
@@ -189,6 +192,7 @@ func (g *defaultGenerator) genFromDDL(source string, withCache bool) (map[string
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// Table defines mysql table
|
||||
type Table struct {
|
||||
parser.Table
|
||||
CacheKey map[string]Key
|
||||
|
||||
@@ -94,7 +94,7 @@ func TestWrapWithRawString(t *testing.T) {
|
||||
|
||||
func TestFields(t *testing.T) {
|
||||
type Student struct {
|
||||
Id int64 `db:"id"`
|
||||
ID int64 `db:"id"`
|
||||
Name string `db:"name"`
|
||||
Age sql.NullInt64 `db:"age"`
|
||||
Score sql.NullFloat64 `db:"score"`
|
||||
|
||||
@@ -8,17 +8,22 @@ import (
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util/stringx"
|
||||
)
|
||||
|
||||
// tableName:user
|
||||
// {{prefix}}=cache
|
||||
// key:id
|
||||
// Key defines cache key variable for generating code
|
||||
type Key struct {
|
||||
VarExpression string // cacheUserIdPrefix = "cache#User#id#"
|
||||
Left string // cacheUserIdPrefix
|
||||
Right string // cache#user#id#
|
||||
Variable string // userIdKey
|
||||
KeyExpression string // userIdKey: = fmt.Sprintf("cache#user#id#%v", userId)
|
||||
DataKeyExpression string // userIdKey: = fmt.Sprintf("cache#user#id#%v", data.userId)
|
||||
RespKeyExpression string // userIdKey: = fmt.Sprintf("cache#user#id#%v", resp.userId)
|
||||
// VarExpression likes cacheUserIdPrefix = "cache#User#id#"
|
||||
VarExpression string
|
||||
// Left likes cacheUserIdPrefix
|
||||
Left string
|
||||
// Right likes cache#user#id#
|
||||
Right string
|
||||
// Variable likes userIdKey
|
||||
Variable string
|
||||
// KeyExpression likes userIdKey: = fmt.Sprintf("cache#user#id#%v", userId)
|
||||
KeyExpression string
|
||||
// DataKeyExpression likes userIdKey: = fmt.Sprintf("cache#user#id#%v", data.userId)
|
||||
DataKeyExpression string
|
||||
// RespKeyExpression likes userIdKey: = fmt.Sprintf("cache#user#id#%v", resp.userId)
|
||||
RespKeyExpression string
|
||||
}
|
||||
|
||||
// key-数据库原始字段名,value-缓存key相关数据
|
||||
|
||||
@@ -54,18 +54,22 @@ var templates = map[string]string{
|
||||
errTemplateFile: template.Error,
|
||||
}
|
||||
|
||||
// Category returns model const value
|
||||
func Category() string {
|
||||
return category
|
||||
}
|
||||
|
||||
// Clean deletes all template files
|
||||
func Clean() error {
|
||||
return util.Clean(category)
|
||||
}
|
||||
|
||||
// GenTemplates creates template files if not exists
|
||||
func GenTemplates(_ *cli.Context) error {
|
||||
return util.InitTemplates(category, templates)
|
||||
}
|
||||
|
||||
// RevertTemplate recovers the delete template files
|
||||
func RevertTemplate(name string) error {
|
||||
content, ok := templates[name]
|
||||
if !ok {
|
||||
@@ -75,6 +79,7 @@ func RevertTemplate(name string) error {
|
||||
return util.CreateTemplate(category, name, content)
|
||||
}
|
||||
|
||||
// Update provides template clean and init
|
||||
func Update() error {
|
||||
err := Clean()
|
||||
if err != nil {
|
||||
|
||||
@@ -3,10 +3,12 @@ package model
|
||||
import "github.com/tal-tech/go-zero/core/stores/sqlx"
|
||||
|
||||
type (
|
||||
// InformationSchemaModel defines information schema model
|
||||
InformationSchemaModel struct {
|
||||
conn sqlx.SqlConn
|
||||
}
|
||||
|
||||
// Column defines column in table
|
||||
Column struct {
|
||||
Name string `db:"COLUMN_NAME"`
|
||||
DataType string `db:"DATA_TYPE"`
|
||||
@@ -18,10 +20,12 @@ type (
|
||||
}
|
||||
)
|
||||
|
||||
// NewInformationSchemaModel creates an instance for InformationSchemaModel
|
||||
func NewInformationSchemaModel(conn sqlx.SqlConn) *InformationSchemaModel {
|
||||
return &InformationSchemaModel{conn: conn}
|
||||
}
|
||||
|
||||
// GetAllTables selects all tables from TABLE_SCHEMA
|
||||
func (m *InformationSchemaModel) GetAllTables(database string) ([]string, error) {
|
||||
query := `select TABLE_NAME from TABLES where TABLE_SCHEMA = ?`
|
||||
var tables []string
|
||||
@@ -33,9 +37,10 @@ func (m *InformationSchemaModel) GetAllTables(database string) ([]string, error)
|
||||
return tables, nil
|
||||
}
|
||||
|
||||
// FindByTableName finds out the target table by name
|
||||
func (m *InformationSchemaModel) FindByTableName(db, table string) ([]*Column, error) {
|
||||
querySql := `select COLUMN_NAME,COLUMN_DEFAULT,IS_NULLABLE,DATA_TYPE,COLUMN_KEY,EXTRA,COLUMN_COMMENT from COLUMNS where TABLE_SCHEMA = ? and TABLE_NAME = ?`
|
||||
querySQL := `select COLUMN_NAME,COLUMN_DEFAULT,IS_NULLABLE,DATA_TYPE,COLUMN_KEY,EXTRA,COLUMN_COMMENT from COLUMNS where TABLE_SCHEMA = ? and TABLE_NAME = ?`
|
||||
var reply []*Column
|
||||
err := m.conn.QueryRows(&reply, querySql, db, table)
|
||||
err := m.conn.QueryRows(&reply, querySQL, db, table)
|
||||
return reply, err
|
||||
}
|
||||
|
||||
@@ -21,17 +21,20 @@ const (
|
||||
const timeImport = "time.Time"
|
||||
|
||||
type (
|
||||
// Table describes a mysql table
|
||||
Table struct {
|
||||
Name stringx.String
|
||||
PrimaryKey Primary
|
||||
Fields []Field
|
||||
}
|
||||
|
||||
// Primary describes a primary key
|
||||
Primary struct {
|
||||
Field
|
||||
AutoIncrement bool
|
||||
}
|
||||
|
||||
// Field describes a table field
|
||||
Field struct {
|
||||
Name stringx.String
|
||||
DataBaseType string
|
||||
@@ -41,9 +44,11 @@ type (
|
||||
Comment string
|
||||
}
|
||||
|
||||
// KeyType types alias of int
|
||||
KeyType int
|
||||
)
|
||||
|
||||
// Parse parses ddl into golang structure
|
||||
func Parse(ddl string) (*Table, error) {
|
||||
stmt, err := sqlparser.ParseStrictDDL(ddl)
|
||||
if err != nil {
|
||||
@@ -169,6 +174,7 @@ func getIndexKeyType(indexes []*sqlparser.IndexDefinition) (map[string]KeyType,
|
||||
return keyMap, nil
|
||||
}
|
||||
|
||||
// ContainsTime determines whether the table field contains time.Time
|
||||
func (t *Table) ContainsTime() bool {
|
||||
for _, item := range t.Fields {
|
||||
if item.DataType == timeImport {
|
||||
@@ -178,6 +184,7 @@ func (t *Table) ContainsTime() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// ConvertColumn provides type conversion for mysql clolumn, primary key lookup
|
||||
func ConvertColumn(db, table string, in []*model.Column) (*Table, error) {
|
||||
var reply Table
|
||||
reply.Name = stringx.From(table)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package template
|
||||
|
||||
// Delete defines a delete template
|
||||
var Delete = `
|
||||
func (m *default{{.upperStartCamelObject}}Model) Delete({{.lowerStartCamelPrimaryKey}} {{.dataType}}) error {
|
||||
{{if .withCache}}{{if .containsIndexCache}}data, err:=m.FindOne({{.lowerStartCamelPrimaryKey}})
|
||||
@@ -17,4 +18,5 @@ func (m *default{{.upperStartCamelObject}}Model) Delete({{.lowerStartCamelPrimar
|
||||
}
|
||||
`
|
||||
|
||||
// DeleteMethod defines a delete template for interface method
|
||||
var DeleteMethod = `Delete({{.lowerStartCamelPrimaryKey}} {{.dataType}}) error`
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package template
|
||||
|
||||
// Error defines an error template
|
||||
var Error = `package {{.pkg}}
|
||||
|
||||
import "github.com/tal-tech/go-zero/core/stores/sqlx"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
package template
|
||||
|
||||
// Field defines a filed template for types
|
||||
var Field = `{{.name}} {{.type}} {{.tag}} {{if .hasComment}}// {{.comment}}{{end}}`
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package template
|
||||
|
||||
var (
|
||||
// Imports defines a import template for model in cache case
|
||||
Imports = `import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
@@ -14,6 +15,7 @@ var (
|
||||
"github.com/tal-tech/go-zero/tools/goctl/model/sql/builderx"
|
||||
)
|
||||
`
|
||||
// ImportsNoCache defines a import template for model in normal case
|
||||
ImportsNoCache = `import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package template
|
||||
|
||||
// Insert defines a template for insert code in model
|
||||
var Insert = `
|
||||
func (m *default{{.upperStartCamelObject}}Model) Insert(data {{.upperStartCamelObject}}) (sql.Result,error) {
|
||||
{{if .withCache}}{{if .containsIndexCache}}{{.keys}}
|
||||
@@ -14,4 +15,5 @@ func (m *default{{.upperStartCamelObject}}Model) Insert(data {{.upperStartCamelO
|
||||
}
|
||||
`
|
||||
|
||||
// InsertMethod defines a interface method template for insert code in model
|
||||
var InsertMethod = `Insert(data {{.upperStartCamelObject}}) (sql.Result,error)`
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package template
|
||||
|
||||
// Model defines a template for model
|
||||
var Model = `package {{.pkg}}
|
||||
{{.imports}}
|
||||
{{.vars}}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package template
|
||||
|
||||
// New defines an template for creating model instance
|
||||
var New = `
|
||||
func New{{.upperStartCamelObject}}Model(conn sqlx.SqlConn{{if .withCache}}, c cache.CacheConf{{end}}) {{.upperStartCamelObject}}Model {
|
||||
return &default{{.upperStartCamelObject}}Model{
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
package template
|
||||
|
||||
// Tag defines a tag template text
|
||||
var Tag = "`db:\"{{.field}}\"`"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package template
|
||||
|
||||
// Types defines a template for types in model
|
||||
var Types = `
|
||||
type (
|
||||
{{.upperStartCamelObject}}Model interface{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package template
|
||||
|
||||
// Update defines a template for generating update codes
|
||||
var Update = `
|
||||
func (m *default{{.upperStartCamelObject}}Model) Update(data {{.upperStartCamelObject}}) error {
|
||||
{{if .withCache}}{{.primaryCacheKey}}
|
||||
@@ -12,4 +13,5 @@ func (m *default{{.upperStartCamelObject}}Model) Update(data {{.upperStartCamelO
|
||||
}
|
||||
`
|
||||
|
||||
// UpdateMethod defines an interface method template for generating update codes
|
||||
var UpdateMethod = `Update(data {{.upperStartCamelObject}}) error`
|
||||
|
||||
@@ -2,6 +2,7 @@ package template
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Vars defines a template for var block in model
|
||||
var Vars = fmt.Sprintf(`
|
||||
var (
|
||||
{{.lowerStartCamelObject}}FieldNames = builderx.RawFieldNames(&{{.upperStartCamelObject}}{})
|
||||
|
||||
@@ -20,11 +20,11 @@ func TestStudentModel(t *testing.T) {
|
||||
testTable = "`student`"
|
||||
testUpdateName = "gozero1"
|
||||
testRowsAffected int64 = 1
|
||||
testInsertId int64 = 1
|
||||
testInsertID int64 = 1
|
||||
)
|
||||
|
||||
var data Student
|
||||
data.Id = testInsertId
|
||||
data.ID = testInsertID
|
||||
data.Name = "gozero"
|
||||
data.Age = sql.NullInt64{
|
||||
Int64: 1,
|
||||
@@ -43,14 +43,14 @@ func TestStudentModel(t *testing.T) {
|
||||
err := mockStudent(func(mock sqlmock.Sqlmock) {
|
||||
mock.ExpectExec(fmt.Sprintf("insert into %s", testTable)).
|
||||
WithArgs(data.Name, data.Age, data.Score).
|
||||
WillReturnResult(sqlmock.NewResult(testInsertId, testRowsAffected))
|
||||
WillReturnResult(sqlmock.NewResult(testInsertID, testRowsAffected))
|
||||
}, func(m StudentModel) {
|
||||
r, err := m.Insert(data)
|
||||
assert.Nil(t, err)
|
||||
|
||||
lastInsertId, err := r.LastInsertId()
|
||||
lastInsertID, err := r.LastInsertId()
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, testInsertId, lastInsertId)
|
||||
assert.Equal(t, testInsertID, lastInsertID)
|
||||
|
||||
rowsAffected, err := r.RowsAffected()
|
||||
assert.Nil(t, err)
|
||||
@@ -60,17 +60,17 @@ func TestStudentModel(t *testing.T) {
|
||||
|
||||
err = mockStudent(func(mock sqlmock.Sqlmock) {
|
||||
mock.ExpectQuery(fmt.Sprintf("select (.+) from %s", testTable)).
|
||||
WithArgs(testInsertId).
|
||||
WillReturnRows(sqlmock.NewRows([]string{"id", "name", "age", "score", "create_time", "update_time"}).AddRow(testInsertId, data.Name, data.Age, data.Score, testTimeValue, testTimeValue))
|
||||
WithArgs(testInsertID).
|
||||
WillReturnRows(sqlmock.NewRows([]string{"id", "name", "age", "score", "create_time", "update_time"}).AddRow(testInsertID, data.Name, data.Age, data.Score, testTimeValue, testTimeValue))
|
||||
}, func(m StudentModel) {
|
||||
result, err := m.FindOne(testInsertId)
|
||||
result, err := m.FindOne(testInsertID)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, *result, data)
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
|
||||
err = mockStudent(func(mock sqlmock.Sqlmock) {
|
||||
mock.ExpectExec(fmt.Sprintf("update %s", testTable)).WithArgs(testUpdateName, data.Age, data.Score, testInsertId).WillReturnResult(sqlmock.NewResult(testInsertId, testRowsAffected))
|
||||
mock.ExpectExec(fmt.Sprintf("update %s", testTable)).WithArgs(testUpdateName, data.Age, data.Score, testInsertID).WillReturnResult(sqlmock.NewResult(testInsertID, testRowsAffected))
|
||||
}, func(m StudentModel) {
|
||||
data.Name = testUpdateName
|
||||
err := m.Update(data)
|
||||
@@ -80,19 +80,19 @@ func TestStudentModel(t *testing.T) {
|
||||
|
||||
err = mockStudent(func(mock sqlmock.Sqlmock) {
|
||||
mock.ExpectQuery(fmt.Sprintf("select (.+) from %s ", testTable)).
|
||||
WithArgs(testInsertId).
|
||||
WillReturnRows(sqlmock.NewRows([]string{"id", "name", "age", "score", "create_time", "update_time"}).AddRow(testInsertId, data.Name, data.Age, data.Score, testTimeValue, testTimeValue))
|
||||
WithArgs(testInsertID).
|
||||
WillReturnRows(sqlmock.NewRows([]string{"id", "name", "age", "score", "create_time", "update_time"}).AddRow(testInsertID, data.Name, data.Age, data.Score, testTimeValue, testTimeValue))
|
||||
}, func(m StudentModel) {
|
||||
result, err := m.FindOne(testInsertId)
|
||||
result, err := m.FindOne(testInsertID)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, *result, data)
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
|
||||
err = mockStudent(func(mock sqlmock.Sqlmock) {
|
||||
mock.ExpectExec(fmt.Sprintf("delete from %s where `id` = ?", testTable)).WithArgs(testInsertId).WillReturnResult(sqlmock.NewResult(testInsertId, testRowsAffected))
|
||||
mock.ExpectExec(fmt.Sprintf("delete from %s where `id` = ?", testTable)).WithArgs(testInsertID).WillReturnResult(sqlmock.NewResult(testInsertID, testRowsAffected))
|
||||
}, func(m StudentModel) {
|
||||
err := m.Delete(testInsertId)
|
||||
err := m.Delete(testInsertID)
|
||||
assert.Nil(t, err)
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
@@ -109,11 +109,11 @@ func TestUserModel(t *testing.T) {
|
||||
testGender = "男"
|
||||
testNickname = "test_nickname"
|
||||
testRowsAffected int64 = 1
|
||||
testInsertId int64 = 1
|
||||
testInsertID int64 = 1
|
||||
)
|
||||
|
||||
var data User
|
||||
data.Id = testInsertId
|
||||
data.ID = testInsertID
|
||||
data.User = testUser
|
||||
data.Name = "gozero"
|
||||
data.Password = testPassword
|
||||
@@ -126,14 +126,14 @@ func TestUserModel(t *testing.T) {
|
||||
err := mockUser(func(mock sqlmock.Sqlmock) {
|
||||
mock.ExpectExec(fmt.Sprintf("insert into %s", testTable)).
|
||||
WithArgs(data.User, data.Name, data.Password, data.Mobile, data.Gender, data.Nickname).
|
||||
WillReturnResult(sqlmock.NewResult(testInsertId, testRowsAffected))
|
||||
WillReturnResult(sqlmock.NewResult(testInsertID, testRowsAffected))
|
||||
}, func(m UserModel) {
|
||||
r, err := m.Insert(data)
|
||||
assert.Nil(t, err)
|
||||
|
||||
lastInsertId, err := r.LastInsertId()
|
||||
lastInsertID, err := r.LastInsertId()
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, testInsertId, lastInsertId)
|
||||
assert.Equal(t, testInsertID, lastInsertID)
|
||||
|
||||
rowsAffected, err := r.RowsAffected()
|
||||
assert.Nil(t, err)
|
||||
@@ -143,17 +143,17 @@ func TestUserModel(t *testing.T) {
|
||||
|
||||
err = mockUser(func(mock sqlmock.Sqlmock) {
|
||||
mock.ExpectQuery(fmt.Sprintf("select (.+) from %s", testTable)).
|
||||
WithArgs(testInsertId).
|
||||
WillReturnRows(sqlmock.NewRows([]string{"id", "user", "name", "password", "mobile", "gender", "nickname", "create_time", "update_time"}).AddRow(testInsertId, data.User, data.Name, data.Password, data.Mobile, data.Gender, data.Nickname, testTimeValue, testTimeValue))
|
||||
WithArgs(testInsertID).
|
||||
WillReturnRows(sqlmock.NewRows([]string{"id", "user", "name", "password", "mobile", "gender", "nickname", "create_time", "update_time"}).AddRow(testInsertID, data.User, data.Name, data.Password, data.Mobile, data.Gender, data.Nickname, testTimeValue, testTimeValue))
|
||||
}, func(m UserModel) {
|
||||
result, err := m.FindOne(testInsertId)
|
||||
result, err := m.FindOne(testInsertID)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, *result, data)
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
|
||||
err = mockUser(func(mock sqlmock.Sqlmock) {
|
||||
mock.ExpectExec(fmt.Sprintf("update %s", testTable)).WithArgs(data.User, testUpdateName, data.Password, data.Mobile, data.Gender, data.Nickname, testInsertId).WillReturnResult(sqlmock.NewResult(testInsertId, testRowsAffected))
|
||||
mock.ExpectExec(fmt.Sprintf("update %s", testTable)).WithArgs(data.User, testUpdateName, data.Password, data.Mobile, data.Gender, data.Nickname, testInsertID).WillReturnResult(sqlmock.NewResult(testInsertID, testRowsAffected))
|
||||
}, func(m UserModel) {
|
||||
data.Name = testUpdateName
|
||||
err := m.Update(data)
|
||||
@@ -163,19 +163,19 @@ func TestUserModel(t *testing.T) {
|
||||
|
||||
err = mockUser(func(mock sqlmock.Sqlmock) {
|
||||
mock.ExpectQuery(fmt.Sprintf("select (.+) from %s ", testTable)).
|
||||
WithArgs(testInsertId).
|
||||
WillReturnRows(sqlmock.NewRows([]string{"id", "user", "name", "password", "mobile", "gender", "nickname", "create_time", "update_time"}).AddRow(testInsertId, data.User, data.Name, data.Password, data.Mobile, data.Gender, data.Nickname, testTimeValue, testTimeValue))
|
||||
WithArgs(testInsertID).
|
||||
WillReturnRows(sqlmock.NewRows([]string{"id", "user", "name", "password", "mobile", "gender", "nickname", "create_time", "update_time"}).AddRow(testInsertID, data.User, data.Name, data.Password, data.Mobile, data.Gender, data.Nickname, testTimeValue, testTimeValue))
|
||||
}, func(m UserModel) {
|
||||
result, err := m.FindOne(testInsertId)
|
||||
result, err := m.FindOne(testInsertID)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, *result, data)
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
|
||||
err = mockUser(func(mock sqlmock.Sqlmock) {
|
||||
mock.ExpectExec(fmt.Sprintf("delete from %s where `id` = ?", testTable)).WithArgs(testInsertId).WillReturnResult(sqlmock.NewResult(testInsertId, testRowsAffected))
|
||||
mock.ExpectExec(fmt.Sprintf("delete from %s where `id` = ?", testTable)).WithArgs(testInsertID).WillReturnResult(sqlmock.NewResult(testInsertID, testRowsAffected))
|
||||
}, func(m UserModel) {
|
||||
err := m.Delete(testInsertId)
|
||||
err := m.Delete(testInsertID)
|
||||
assert.Nil(t, err)
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
|
||||
@@ -19,10 +19,11 @@ var (
|
||||
studentRowsExpectAutoSet = strings.Join(stringx.Remove(studentFieldNames, "`id`", "`create_time`", "`update_time`"), ",")
|
||||
studentRowsWithPlaceHolder = strings.Join(stringx.Remove(studentFieldNames, "`id`", "`create_time`", "`update_time`"), "=?,") + "=?"
|
||||
|
||||
cacheStudentIdPrefix = "cache#Student#id#"
|
||||
cacheStudentIDPrefix = "cache#Student#id#"
|
||||
)
|
||||
|
||||
type (
|
||||
// StudentModel defines a model for Student
|
||||
StudentModel interface {
|
||||
Insert(data Student) (sql.Result, error)
|
||||
FindOne(id int64) (*Student, error)
|
||||
@@ -35,8 +36,9 @@ type (
|
||||
table string
|
||||
}
|
||||
|
||||
// Student defines an data structure for mysql
|
||||
Student struct {
|
||||
Id int64 `db:"id"`
|
||||
ID int64 `db:"id"`
|
||||
Name string `db:"name"`
|
||||
Age sql.NullInt64 `db:"age"`
|
||||
Score sql.NullFloat64 `db:"score"`
|
||||
@@ -45,6 +47,7 @@ type (
|
||||
}
|
||||
)
|
||||
|
||||
// NewStudentModel creates an instance for StudentModel
|
||||
func NewStudentModel(conn sqlx.SqlConn, c cache.CacheConf) StudentModel {
|
||||
return &defaultStudentModel{
|
||||
CachedConn: sqlc.NewConn(conn, c),
|
||||
@@ -60,9 +63,9 @@ func (m *defaultStudentModel) Insert(data Student) (sql.Result, error) {
|
||||
}
|
||||
|
||||
func (m *defaultStudentModel) FindOne(id int64) (*Student, error) {
|
||||
studentIdKey := fmt.Sprintf("%s%v", cacheStudentIdPrefix, id)
|
||||
studentIDKey := fmt.Sprintf("%s%v", cacheStudentIDPrefix, id)
|
||||
var resp Student
|
||||
err := m.QueryRow(&resp, studentIdKey, func(conn sqlx.SqlConn, v interface{}) error {
|
||||
err := m.QueryRow(&resp, studentIDKey, func(conn sqlx.SqlConn, v interface{}) error {
|
||||
query := fmt.Sprintf("select %s from %s where `id` = ? limit 1", studentRows, m.table)
|
||||
return conn.QueryRow(v, query, id)
|
||||
})
|
||||
@@ -77,26 +80,26 @@ func (m *defaultStudentModel) FindOne(id int64) (*Student, error) {
|
||||
}
|
||||
|
||||
func (m *defaultStudentModel) Update(data Student) error {
|
||||
studentIdKey := fmt.Sprintf("%s%v", cacheStudentIdPrefix, data.Id)
|
||||
studentIDKey := fmt.Sprintf("%s%v", cacheStudentIDPrefix, data.ID)
|
||||
_, err := m.Exec(func(conn sqlx.SqlConn) (result sql.Result, err error) {
|
||||
query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, studentRowsWithPlaceHolder)
|
||||
return conn.Exec(query, data.Name, data.Age, data.Score, data.Id)
|
||||
}, studentIdKey)
|
||||
return conn.Exec(query, data.Name, data.Age, data.Score, data.ID)
|
||||
}, studentIDKey)
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *defaultStudentModel) Delete(id int64) error {
|
||||
|
||||
studentIdKey := fmt.Sprintf("%s%v", cacheStudentIdPrefix, id)
|
||||
studentIDKey := fmt.Sprintf("%s%v", cacheStudentIDPrefix, id)
|
||||
_, err := m.Exec(func(conn sqlx.SqlConn) (result sql.Result, err error) {
|
||||
query := fmt.Sprintf("delete from %s where `id` = ?", m.table)
|
||||
return conn.Exec(query, id)
|
||||
}, studentIdKey)
|
||||
}, studentIDKey)
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *defaultStudentModel) formatPrimary(primary interface{}) string {
|
||||
return fmt.Sprintf("%s%v", cacheStudentIdPrefix, primary)
|
||||
return fmt.Sprintf("%s%v", cacheStudentIDPrefix, primary)
|
||||
}
|
||||
|
||||
func (m *defaultStudentModel) queryPrimary(conn sqlx.SqlConn, v, primary interface{}) error {
|
||||
|
||||
@@ -20,6 +20,7 @@ var (
|
||||
)
|
||||
|
||||
type (
|
||||
// UserModel defines a model for user
|
||||
UserModel interface {
|
||||
Insert(data User) (sql.Result, error)
|
||||
FindOne(id int64) (*User, error)
|
||||
@@ -35,8 +36,9 @@ type (
|
||||
table string
|
||||
}
|
||||
|
||||
// User defines an data structure for mysql
|
||||
User struct {
|
||||
Id int64 `db:"id"`
|
||||
ID int64 `db:"id"`
|
||||
User string `db:"user"` // 用户
|
||||
Name string `db:"name"` // 用户名称
|
||||
Password string `db:"password"` // 用户密码
|
||||
@@ -48,6 +50,7 @@ type (
|
||||
}
|
||||
)
|
||||
|
||||
// NewUserModel creates an instance for UserModel
|
||||
func NewUserModel(conn sqlx.SqlConn) UserModel {
|
||||
return &defaultUserModel{
|
||||
conn: conn,
|
||||
@@ -119,7 +122,7 @@ func (m *defaultUserModel) FindOneByMobile(mobile string) (*User, error) {
|
||||
|
||||
func (m *defaultUserModel) Update(data User) error {
|
||||
query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, userRowsWithPlaceHolder)
|
||||
_, err := m.conn.Exec(query, data.User, data.Name, data.Password, data.Mobile, data.Gender, data.Nickname, data.Id)
|
||||
_, err := m.conn.Exec(query, data.User, data.Name, data.Password, data.Mobile, data.Gender, data.Nickname, data.ID)
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -2,4 +2,5 @@ package model
|
||||
|
||||
import "github.com/tal-tech/go-zero/core/stores/sqlx"
|
||||
|
||||
// ErrNotFound types an alias for sqlx.ErrNotFound
|
||||
var ErrNotFound = sqlx.ErrNotFound
|
||||
|
||||
@@ -13,9 +13,13 @@ import (
|
||||
const tagName = "db"
|
||||
|
||||
var (
|
||||
ErrNotMatchDestination = errors.New("not matching destination to scan")
|
||||
ErrNotReadableValue = errors.New("value not addressable or interfaceable")
|
||||
ErrNotSettable = errors.New("passed in variable is not settable")
|
||||
// ErrNotMatchDestination defines an error for mismatching case
|
||||
ErrNotMatchDestination = errors.New("not matching destination to scan")
|
||||
// ErrNotReadableValue defines an error for the value is not addressable or interfaceable
|
||||
ErrNotReadableValue = errors.New("value not addressable or interfaceable")
|
||||
// ErrNotSettable defines an error for the variable is not settable
|
||||
ErrNotSettable = errors.New("passed in variable is not settable")
|
||||
// ErrUnsupportedValueType deinfes an error for unsupported unmarshal type
|
||||
ErrUnsupportedValueType = errors.New("unsupported unmarshal type")
|
||||
)
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
)
|
||||
|
||||
type (
|
||||
// MockConn defines a mock connection instance for mysql
|
||||
MockConn struct {
|
||||
db *sql.DB
|
||||
}
|
||||
@@ -17,43 +18,51 @@ type (
|
||||
}
|
||||
)
|
||||
|
||||
// NewMockConn creates an instance for MockConn
|
||||
func NewMockConn(db *sql.DB) *MockConn {
|
||||
return &MockConn{db: db}
|
||||
}
|
||||
|
||||
// Exec executes sql and returns the result
|
||||
func (conn *MockConn) Exec(query string, args ...interface{}) (sql.Result, error) {
|
||||
return exec(conn.db, query, args...)
|
||||
}
|
||||
|
||||
// Prepare executes sql by sql.DB
|
||||
func (conn *MockConn) Prepare(query string) (sqlx.StmtSession, error) {
|
||||
st, err := conn.db.Prepare(query)
|
||||
return statement{stmt: st}, err
|
||||
}
|
||||
|
||||
// QueryRow executes sql and returns a query row
|
||||
func (conn *MockConn) QueryRow(v interface{}, q string, args ...interface{}) error {
|
||||
return query(conn.db, func(rows *sql.Rows) error {
|
||||
return unmarshalRow(v, rows, true)
|
||||
}, q, args...)
|
||||
}
|
||||
|
||||
// QueryRowPartial executes sql and returns a partial query row
|
||||
func (conn *MockConn) QueryRowPartial(v interface{}, q string, args ...interface{}) error {
|
||||
return query(conn.db, func(rows *sql.Rows) error {
|
||||
return unmarshalRow(v, rows, false)
|
||||
}, q, args...)
|
||||
}
|
||||
|
||||
// QueryRows executes sql and returns query rows
|
||||
func (conn *MockConn) QueryRows(v interface{}, q string, args ...interface{}) error {
|
||||
return query(conn.db, func(rows *sql.Rows) error {
|
||||
return unmarshalRows(v, rows, true)
|
||||
}, q, args...)
|
||||
}
|
||||
|
||||
// QueryRowsPartial executes sql and returns partial query rows
|
||||
func (conn *MockConn) QueryRowsPartial(v interface{}, q string, args ...interface{}) error {
|
||||
return query(conn.db, func(rows *sql.Rows) error {
|
||||
return unmarshalRows(v, rows, false)
|
||||
}, q, args...)
|
||||
}
|
||||
|
||||
// Transact is the implemention of sqlx.SqlConn, nothing to do
|
||||
func (conn *MockConn) Transact(func(session sqlx.Session) error) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -94,11 +94,6 @@ func format(query string, args ...interface{}) (string, error) {
|
||||
return b.String(), nil
|
||||
}
|
||||
|
||||
func logInstanceError(datasource string, err error) {
|
||||
datasource = desensitize(datasource)
|
||||
logx.Errorf("Error on getting sql instance of %s: %v", datasource, err)
|
||||
}
|
||||
|
||||
func logSqlError(stmt string, err error) {
|
||||
if err != nil && err != ErrNotFound {
|
||||
logx.Errorf("stmt: %s, error: %s", stmt, err.Error())
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// expression: globbing patterns
|
||||
// MatchFiles returns the match values by globbing patterns
|
||||
func MatchFiles(in string) ([]string, error) {
|
||||
dir, pattern := filepath.Split(in)
|
||||
abs, err := filepath.Abs(dir)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package util
|
||||
|
||||
// TrimStringSlice returns a copy slice without empty string item
|
||||
func TrimStringSlice(list []string) []string {
|
||||
var out []string
|
||||
for _, item := range list {
|
||||
|
||||
Reference in New Issue
Block a user