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:
kingxt
2021-02-26 16:11:47 +08:00
committed by GitHub
parent ef146cf5ba
commit e6ef1fca12
104 changed files with 651 additions and 375 deletions

View File

@@ -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)

View File

@@ -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)
}

View File

@@ -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)

View File

@@ -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 {

View File

@@ -1,5 +0,0 @@
package gen
import "errors"
var ErrCircleQuery = errors.New("circle query with other fields")

View File

@@ -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

View File

@@ -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"`

View File

@@ -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相关数据

View File

@@ -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 {

View File

@@ -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
}

View File

@@ -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)

View File

@@ -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`

View File

@@ -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"

View File

@@ -1,3 +1,4 @@
package template
// Field defines a filed template for types
var Field = `{{.name}} {{.type}} {{.tag}} {{if .hasComment}}// {{.comment}}{{end}}`

View File

@@ -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"

View File

@@ -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)`

View File

@@ -1,5 +1,6 @@
package template
// Model defines a template for model
var Model = `package {{.pkg}}
{{.imports}}
{{.vars}}

View File

@@ -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{

View File

@@ -1,3 +1,4 @@
package template
// Tag defines a tag template text
var Tag = "`db:\"{{.field}}\"`"

View File

@@ -1,5 +1,6 @@
package template
// Types defines a template for types in model
var Types = `
type (
{{.upperStartCamelObject}}Model interface{

View File

@@ -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`

View File

@@ -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}}{})

View File

@@ -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)

View File

@@ -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 {

View File

@@ -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
}

View File

@@ -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

View File

@@ -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")
)

View File

@@ -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
}

View File

@@ -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())

View File

@@ -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)

View File

@@ -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 {