mirror of
https://gitee.com/johng/gf.git
synced 2024-11-29 18:57:44 +08:00
add ut cases for command gen dao
(#2958)
This commit is contained in:
parent
5059abd88e
commit
5219c5c37e
6
.github/workflows/build_and_test.sh
vendored
6
.github/workflows/build_and_test.sh
vendored
@ -1,9 +1,15 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# find all path that contains go.mod.
|
||||
for file in `find . -name go.mod`; do
|
||||
dirpath=$(dirname $file)
|
||||
echo $dirpath
|
||||
|
||||
if [[ $file =~ "/testdata/" ]]; then
|
||||
echo "ignore testdata path $file"
|
||||
continue 1
|
||||
fi
|
||||
|
||||
# package kuhecm needs golang >= v1.18
|
||||
if [ "kubecm" = $(basename $dirpath) ]; then
|
||||
if ! go version|grep -q "1.19"; then
|
||||
|
@ -1,7 +1,12 @@
|
||||
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/v2/test/gtest"
|
||||
@ -10,11 +15,10 @@ import (
|
||||
func Test_Fix_doFixV25Content(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
content = gtest.DataContent(`fix25_content.go.txt`)
|
||||
content = gtest.DataContent(`fix`, `fix25_content.go`)
|
||||
f = cFix{}
|
||||
)
|
||||
newContent, err := f.doFixV25Content(content)
|
||||
_, err := f.doFixV25Content(content)
|
||||
t.AssertNil(err)
|
||||
fmt.Println(newContent)
|
||||
})
|
||||
}
|
||||
|
229
cmd/gf/internal/cmd/cmd_gen_dao_test.go
Normal file
229
cmd/gf/internal/cmd/cmd_gen_dao_test.go
Normal file
@ -0,0 +1,229 @@
|
||||
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/cmd/gendao"
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/test/gtest"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/guid"
|
||||
"github.com/gogf/gf/v2/util/gutil"
|
||||
)
|
||||
|
||||
var ctx = context.Background()
|
||||
|
||||
func dropTableWithDb(db gdb.DB, table string) {
|
||||
dropTableStmt := fmt.Sprintf("DROP TABLE IF EXISTS `%s`", table)
|
||||
if _, err := db.Exec(ctx, dropTableStmt); err != nil {
|
||||
gtest.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Gen_Dao_Default(t *testing.T) {
|
||||
link := "mysql:root:12345678@tcp(127.0.0.1:3306)/test?loc=Local&parseTime=true"
|
||||
db, err := gdb.New(gdb.ConfigNode{
|
||||
Link: link,
|
||||
})
|
||||
gtest.AssertNil(err)
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
table = "table_user"
|
||||
sqlContent = fmt.Sprintf(
|
||||
gtest.DataContent(`gendao`, `user.tpl.sql`),
|
||||
table,
|
||||
)
|
||||
)
|
||||
dropTableWithDb(db, table)
|
||||
array := gstr.SplitAndTrim(sqlContent, ";")
|
||||
for _, v := range array {
|
||||
if _, err = db.Exec(ctx, v); err != nil {
|
||||
t.AssertNil(err)
|
||||
}
|
||||
}
|
||||
defer dropTableWithDb(db, table)
|
||||
|
||||
var (
|
||||
path = gfile.Temp(guid.S())
|
||||
group = "test"
|
||||
in = gendao.CGenDaoInput{
|
||||
Path: path,
|
||||
Link: link,
|
||||
Tables: "",
|
||||
TablesEx: "",
|
||||
Group: group,
|
||||
Prefix: "",
|
||||
RemovePrefix: "",
|
||||
JsonCase: "SnakeScreaming",
|
||||
ImportPrefix: "",
|
||||
DaoPath: "",
|
||||
DoPath: "",
|
||||
EntityPath: "",
|
||||
TplDaoIndexPath: "",
|
||||
TplDaoInternalPath: "",
|
||||
TplDaoDoPath: "",
|
||||
TplDaoEntityPath: "",
|
||||
StdTime: false,
|
||||
WithTime: false,
|
||||
GJsonSupport: false,
|
||||
OverwriteDao: false,
|
||||
DescriptionTag: false,
|
||||
NoJsonTag: false,
|
||||
NoModelComment: false,
|
||||
Clear: false,
|
||||
TypeMapping: nil,
|
||||
}
|
||||
)
|
||||
err = gutil.FillStructWithDefault(&in)
|
||||
t.AssertNil(err)
|
||||
|
||||
err = gfile.Mkdir(path)
|
||||
t.AssertNil(err)
|
||||
|
||||
// for go mod import path auto retrieve.
|
||||
err = gfile.Copy(
|
||||
gtest.DataPath("gendao", "go.mod.txt"),
|
||||
gfile.Join(path, "go.mod"),
|
||||
)
|
||||
t.AssertNil(err)
|
||||
|
||||
_, err = gendao.CGenDao{}.Dao(ctx, in)
|
||||
t.AssertNil(err)
|
||||
defer gfile.Remove(path)
|
||||
|
||||
// files
|
||||
files, err := gfile.ScanDir(path, "*.go", true)
|
||||
t.AssertNil(err)
|
||||
t.Assert(files, []string{
|
||||
path + "/dao/internal/table_user.go",
|
||||
path + "/dao/table_user.go",
|
||||
path + "/model/do/table_user.go",
|
||||
path + "/model/entity/table_user.go",
|
||||
})
|
||||
// content
|
||||
testPath := gtest.DataPath("gendao", "generated_user")
|
||||
expectFiles := []string{
|
||||
testPath + "/dao/internal/table_user.go",
|
||||
testPath + "/dao/table_user.go",
|
||||
testPath + "/model/do/table_user.go",
|
||||
testPath + "/model/entity/table_user.go",
|
||||
}
|
||||
for i, _ := range files {
|
||||
t.Assert(gfile.GetContents(files[i]), gfile.GetContents(expectFiles[i]))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Gen_Dao_TypeMapping(t *testing.T) {
|
||||
link := "mysql:root:12345678@tcp(127.0.0.1:3306)/test?loc=Local&parseTime=true"
|
||||
db, err := gdb.New(gdb.ConfigNode{
|
||||
Link: link,
|
||||
})
|
||||
gtest.AssertNil(err)
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
table = "table_user"
|
||||
sqlContent = fmt.Sprintf(
|
||||
gtest.DataContent(`gendao`, `user.tpl.sql`),
|
||||
table,
|
||||
)
|
||||
)
|
||||
defer dropTableWithDb(db, table)
|
||||
array := gstr.SplitAndTrim(sqlContent, ";")
|
||||
for _, v := range array {
|
||||
if _, err = db.Exec(ctx, v); err != nil {
|
||||
t.AssertNil(err)
|
||||
}
|
||||
}
|
||||
defer dropTableWithDb(db, table)
|
||||
|
||||
var (
|
||||
path = gfile.Temp(guid.S())
|
||||
group = "test"
|
||||
in = gendao.CGenDaoInput{
|
||||
Path: path,
|
||||
Link: link,
|
||||
Tables: "",
|
||||
TablesEx: "",
|
||||
Group: group,
|
||||
Prefix: "",
|
||||
RemovePrefix: "",
|
||||
JsonCase: "",
|
||||
ImportPrefix: "",
|
||||
DaoPath: "",
|
||||
DoPath: "",
|
||||
EntityPath: "",
|
||||
TplDaoIndexPath: "",
|
||||
TplDaoInternalPath: "",
|
||||
TplDaoDoPath: "",
|
||||
TplDaoEntityPath: "",
|
||||
StdTime: false,
|
||||
WithTime: false,
|
||||
GJsonSupport: false,
|
||||
OverwriteDao: false,
|
||||
DescriptionTag: false,
|
||||
NoJsonTag: false,
|
||||
NoModelComment: false,
|
||||
Clear: false,
|
||||
TypeMapping: map[gendao.DBFieldTypeName]gendao.CustomAttributeType{
|
||||
"int": {
|
||||
Type: "int64",
|
||||
Import: "",
|
||||
},
|
||||
"decimal": {
|
||||
Type: "decimal.Decimal",
|
||||
Import: "github.com/shopspring/decimal",
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
err = gutil.FillStructWithDefault(&in)
|
||||
t.AssertNil(err)
|
||||
|
||||
err = gfile.Mkdir(path)
|
||||
t.AssertNil(err)
|
||||
|
||||
// for go mod import path auto retrieve.
|
||||
err = gfile.Copy(
|
||||
gtest.DataPath("gendao", "go.mod.txt"),
|
||||
gfile.Join(path, "go.mod"),
|
||||
)
|
||||
t.AssertNil(err)
|
||||
|
||||
_, err = gendao.CGenDao{}.Dao(ctx, in)
|
||||
t.AssertNil(err)
|
||||
defer gfile.Remove(path)
|
||||
|
||||
// files
|
||||
files, err := gfile.ScanDir(path, "*.go", true)
|
||||
t.AssertNil(err)
|
||||
t.Assert(files, []string{
|
||||
path + "/dao/internal/table_user.go",
|
||||
path + "/dao/table_user.go",
|
||||
path + "/model/do/table_user.go",
|
||||
path + "/model/entity/table_user.go",
|
||||
})
|
||||
// content
|
||||
testPath := gtest.DataPath("gendao", "generated_user_type_mapping")
|
||||
expectFiles := []string{
|
||||
testPath + "/dao/internal/table_user.go",
|
||||
testPath + "/dao/table_user.go",
|
||||
testPath + "/model/do/table_user.go",
|
||||
testPath + "/model/entity/table_user.go",
|
||||
}
|
||||
for i, _ := range files {
|
||||
t.Assert(gfile.GetContents(files[i]), gfile.GetContents(expectFiles[i]))
|
||||
}
|
||||
})
|
||||
}
|
@ -115,7 +115,7 @@ generated json tag case for model struct, cases are as follows:
|
||||
|
||||
var (
|
||||
createdAt = gtime.Now()
|
||||
defaultTypeMapping = map[string]TypeMapping{
|
||||
defaultTypeMapping = map[DBFieldTypeName]CustomAttributeType{
|
||||
"decimal": {
|
||||
Type: "float64",
|
||||
},
|
||||
@ -172,31 +172,32 @@ type (
|
||||
CGenDao struct{}
|
||||
CGenDaoInput struct {
|
||||
g.Meta `name:"dao" config:"{CGenDaoConfig}" usage:"{CGenDaoUsage}" brief:"{CGenDaoBrief}" eg:"{CGenDaoEg}" ad:"{CGenDaoAd}"`
|
||||
Path string `name:"path" short:"p" brief:"{CGenDaoBriefPath}" d:"internal"`
|
||||
Link string `name:"link" short:"l" brief:"{CGenDaoBriefLink}"`
|
||||
Tables string `name:"tables" short:"t" brief:"{CGenDaoBriefTables}"`
|
||||
TablesEx string `name:"tablesEx" short:"x" brief:"{CGenDaoBriefTablesEx}"`
|
||||
Group string `name:"group" short:"g" brief:"{CGenDaoBriefGroup}" d:"default"`
|
||||
Prefix string `name:"prefix" short:"f" brief:"{CGenDaoBriefPrefix}"`
|
||||
RemovePrefix string `name:"removePrefix" short:"r" brief:"{CGenDaoBriefRemovePrefix}"`
|
||||
JsonCase string `name:"jsonCase" short:"j" brief:"{CGenDaoBriefJsonCase}" d:"CamelLower"`
|
||||
ImportPrefix string `name:"importPrefix" short:"i" brief:"{CGenDaoBriefImportPrefix}"`
|
||||
DaoPath string `name:"daoPath" short:"d" brief:"{CGenDaoBriefDaoPath}" d:"dao"`
|
||||
DoPath string `name:"doPath" short:"o" brief:"{CGenDaoBriefDoPath}" d:"model/do"`
|
||||
EntityPath string `name:"entityPath" short:"e" brief:"{CGenDaoBriefEntityPath}" d:"model/entity"`
|
||||
TplDaoIndexPath string `name:"tplDaoIndexPath" short:"t1" brief:"{CGenDaoBriefTplDaoIndexPath}"`
|
||||
TplDaoInternalPath string `name:"tplDaoInternalPath" short:"t2" brief:"{CGenDaoBriefTplDaoInternalPath}"`
|
||||
TplDaoDoPath string `name:"tplDaoDoPath" short:"t3" brief:"{CGenDaoBriefTplDaoDoPathPath}"`
|
||||
TplDaoEntityPath string `name:"tplDaoEntityPath" short:"t4" brief:"{CGenDaoBriefTplDaoEntityPath}"`
|
||||
StdTime bool `name:"stdTime" short:"s" brief:"{CGenDaoBriefStdTime}" orphan:"true"`
|
||||
WithTime bool `name:"withTime" short:"w" brief:"{CGenDaoBriefWithTime}" orphan:"true"`
|
||||
GJsonSupport bool `name:"gJsonSupport" short:"n" brief:"{CGenDaoBriefGJsonSupport}" orphan:"true"`
|
||||
OverwriteDao bool `name:"overwriteDao" short:"v" brief:"{CGenDaoBriefOverwriteDao}" orphan:"true"`
|
||||
DescriptionTag bool `name:"descriptionTag" short:"c" brief:"{CGenDaoBriefDescriptionTag}" orphan:"true"`
|
||||
NoJsonTag bool `name:"noJsonTag" short:"k" brief:"{CGenDaoBriefNoJsonTag}" orphan:"true"`
|
||||
NoModelComment bool `name:"noModelComment" short:"m" brief:"{CGenDaoBriefNoModelComment}" orphan:"true"`
|
||||
Clear bool `name:"clear" short:"a" brief:"{CGenDaoBriefClear}" orphan:"true"`
|
||||
TypeMapping map[string]TypeMapping `name:"typeMapping" short:"y" brief:"{CGenDaoBriefTypeMapping}" orphan:"true"`
|
||||
Path string `name:"path" short:"p" brief:"{CGenDaoBriefPath}" d:"internal"`
|
||||
Link string `name:"link" short:"l" brief:"{CGenDaoBriefLink}"`
|
||||
Tables string `name:"tables" short:"t" brief:"{CGenDaoBriefTables}"`
|
||||
TablesEx string `name:"tablesEx" short:"x" brief:"{CGenDaoBriefTablesEx}"`
|
||||
Group string `name:"group" short:"g" brief:"{CGenDaoBriefGroup}" d:"default"`
|
||||
Prefix string `name:"prefix" short:"f" brief:"{CGenDaoBriefPrefix}"`
|
||||
RemovePrefix string `name:"removePrefix" short:"r" brief:"{CGenDaoBriefRemovePrefix}"`
|
||||
JsonCase string `name:"jsonCase" short:"j" brief:"{CGenDaoBriefJsonCase}" d:"CamelLower"`
|
||||
ImportPrefix string `name:"importPrefix" short:"i" brief:"{CGenDaoBriefImportPrefix}"`
|
||||
DaoPath string `name:"daoPath" short:"d" brief:"{CGenDaoBriefDaoPath}" d:"dao"`
|
||||
DoPath string `name:"doPath" short:"o" brief:"{CGenDaoBriefDoPath}" d:"model/do"`
|
||||
EntityPath string `name:"entityPath" short:"e" brief:"{CGenDaoBriefEntityPath}" d:"model/entity"`
|
||||
TplDaoIndexPath string `name:"tplDaoIndexPath" short:"t1" brief:"{CGenDaoBriefTplDaoIndexPath}"`
|
||||
TplDaoInternalPath string `name:"tplDaoInternalPath" short:"t2" brief:"{CGenDaoBriefTplDaoInternalPath}"`
|
||||
TplDaoDoPath string `name:"tplDaoDoPath" short:"t3" brief:"{CGenDaoBriefTplDaoDoPathPath}"`
|
||||
TplDaoEntityPath string `name:"tplDaoEntityPath" short:"t4" brief:"{CGenDaoBriefTplDaoEntityPath}"`
|
||||
StdTime bool `name:"stdTime" short:"s" brief:"{CGenDaoBriefStdTime}" orphan:"true"`
|
||||
WithTime bool `name:"withTime" short:"w" brief:"{CGenDaoBriefWithTime}" orphan:"true"`
|
||||
GJsonSupport bool `name:"gJsonSupport" short:"n" brief:"{CGenDaoBriefGJsonSupport}" orphan:"true"`
|
||||
OverwriteDao bool `name:"overwriteDao" short:"v" brief:"{CGenDaoBriefOverwriteDao}" orphan:"true"`
|
||||
DescriptionTag bool `name:"descriptionTag" short:"c" brief:"{CGenDaoBriefDescriptionTag}" orphan:"true"`
|
||||
NoJsonTag bool `name:"noJsonTag" short:"k" brief:"{CGenDaoBriefNoJsonTag}" orphan:"true"`
|
||||
NoModelComment bool `name:"noModelComment" short:"m" brief:"{CGenDaoBriefNoModelComment}" orphan:"true"`
|
||||
Clear bool `name:"clear" short:"a" brief:"{CGenDaoBriefClear}" orphan:"true"`
|
||||
|
||||
TypeMapping map[DBFieldTypeName]CustomAttributeType `name:"typeMapping" short:"y" brief:"{CGenDaoBriefTypeMapping}" orphan:"true"`
|
||||
}
|
||||
CGenDaoOutput struct{}
|
||||
|
||||
@ -207,7 +208,8 @@ type (
|
||||
NewTableNames []string
|
||||
}
|
||||
|
||||
TypeMapping struct {
|
||||
DBFieldTypeName = string
|
||||
CustomAttributeType struct {
|
||||
Type string `brief:"custom attribute type name"`
|
||||
Import string `brief:"custom import for this type"`
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ func generateStructFieldDefinition(
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
localTypeNameStr = string(localTypeName)
|
||||
switch localTypeName {
|
||||
case gdb.LocalTypeDate, gdb.LocalTypeDatetime:
|
||||
if in.StdTime {
|
||||
|
@ -27,4 +27,4 @@ func Test_Router_Hook_Multi(t *testing.T) {
|
||||
r.Response.Write("2")
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
85
cmd/gf/internal/cmd/testdata/gendao/generated_user/dao/internal/table_user.go
vendored
Normal file
85
cmd/gf/internal/cmd/testdata/gendao/generated_user/dao/internal/table_user.go
vendored
Normal file
@ -0,0 +1,85 @@
|
||||
// ==========================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// ==========================================================================
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// TableUserDao is the data access object for table table_user.
|
||||
type TableUserDao struct {
|
||||
table string // table is the underlying table name of the DAO.
|
||||
group string // group is the database configuration group name of current DAO.
|
||||
columns TableUserColumns // columns contains all the column names of Table for convenient usage.
|
||||
}
|
||||
|
||||
// TableUserColumns defines and stores column names for table table_user.
|
||||
type TableUserColumns struct {
|
||||
Id string // User ID
|
||||
Passport string // User Passport
|
||||
Password string // User Password
|
||||
Nickname string // User Nickname
|
||||
Score string // Total score amount.
|
||||
CreateAt string // Created Time
|
||||
UpdateAt string // Updated Time
|
||||
}
|
||||
|
||||
// tableUserColumns holds the columns for table table_user.
|
||||
var tableUserColumns = TableUserColumns{
|
||||
Id: "id",
|
||||
Passport: "passport",
|
||||
Password: "password",
|
||||
Nickname: "nickname",
|
||||
Score: "score",
|
||||
CreateAt: "create_at",
|
||||
UpdateAt: "update_at",
|
||||
}
|
||||
|
||||
// NewTableUserDao creates and returns a new DAO object for table data access.
|
||||
func NewTableUserDao() *TableUserDao {
|
||||
return &TableUserDao{
|
||||
group: "test",
|
||||
table: "table_user",
|
||||
columns: tableUserColumns,
|
||||
}
|
||||
}
|
||||
|
||||
// DB retrieves and returns the underlying raw database management object of current DAO.
|
||||
func (dao *TableUserDao) DB() gdb.DB {
|
||||
return g.DB(dao.group)
|
||||
}
|
||||
|
||||
// Table returns the table name of current dao.
|
||||
func (dao *TableUserDao) Table() string {
|
||||
return dao.table
|
||||
}
|
||||
|
||||
// Columns returns all column names of current dao.
|
||||
func (dao *TableUserDao) Columns() TableUserColumns {
|
||||
return dao.columns
|
||||
}
|
||||
|
||||
// Group returns the configuration group name of database of current dao.
|
||||
func (dao *TableUserDao) Group() string {
|
||||
return dao.group
|
||||
}
|
||||
|
||||
// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation.
|
||||
func (dao *TableUserDao) Ctx(ctx context.Context) *gdb.Model {
|
||||
return dao.DB().Model(dao.table).Safe().Ctx(ctx)
|
||||
}
|
||||
|
||||
// Transaction wraps the transaction logic using function f.
|
||||
// It rollbacks the transaction and returns the error from function f if it returns non-nil error.
|
||||
// It commits the transaction and returns nil if function f returns nil.
|
||||
//
|
||||
// Note that, you should not Commit or Rollback the transaction in function f
|
||||
// as it is automatically handled by this function.
|
||||
func (dao *TableUserDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
|
||||
return dao.Ctx(ctx).Transaction(ctx, f)
|
||||
}
|
27
cmd/gf/internal/cmd/testdata/gendao/generated_user/dao/table_user.go
vendored
Normal file
27
cmd/gf/internal/cmd/testdata/gendao/generated_user/dao/table_user.go
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
// =================================================================================
|
||||
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
|
||||
// =================================================================================
|
||||
|
||||
package dao
|
||||
|
||||
import (
|
||||
"for-gendao-test/pkg/dao/internal"
|
||||
)
|
||||
|
||||
// internalTableUserDao is internal type for wrapping internal DAO implements.
|
||||
type internalTableUserDao = *internal.TableUserDao
|
||||
|
||||
// tableUserDao is the data access object for table table_user.
|
||||
// You can define custom methods on it to extend its functionality as you wish.
|
||||
type tableUserDao struct {
|
||||
internalTableUserDao
|
||||
}
|
||||
|
||||
var (
|
||||
// TableUser is globally public accessible object for table table_user operations.
|
||||
TableUser = tableUserDao{
|
||||
internal.NewTableUserDao(),
|
||||
}
|
||||
)
|
||||
|
||||
// Fill with you ideas below.
|
22
cmd/gf/internal/cmd/testdata/gendao/generated_user/model/do/table_user.go
vendored
Normal file
22
cmd/gf/internal/cmd/testdata/gendao/generated_user/model/do/table_user.go
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package do
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// TableUser is the golang structure of table table_user for DAO operations like Where/Data.
|
||||
type TableUser struct {
|
||||
g.Meta `orm:"table:table_user, do:true"`
|
||||
Id interface{} // User ID
|
||||
Passport interface{} // User Passport
|
||||
Password interface{} // User Password
|
||||
Nickname interface{} // User Nickname
|
||||
Score interface{} // Total score amount.
|
||||
CreateAt *gtime.Time // Created Time
|
||||
UpdateAt *gtime.Time // Updated Time
|
||||
}
|
20
cmd/gf/internal/cmd/testdata/gendao/generated_user/model/entity/table_user.go
vendored
Normal file
20
cmd/gf/internal/cmd/testdata/gendao/generated_user/model/entity/table_user.go
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package entity
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// TableUser is the golang structure for table table_user.
|
||||
type TableUser struct {
|
||||
Id uint `json:"ID" ` // User ID
|
||||
Passport string `json:"PASSPORT" ` // User Passport
|
||||
Password string `json:"PASSWORD" ` // User Password
|
||||
Nickname string `json:"NICKNAME" ` // User Nickname
|
||||
Score float64 `json:"SCORE" ` // Total score amount.
|
||||
CreateAt *gtime.Time `json:"CREATE_AT" ` // Created Time
|
||||
UpdateAt *gtime.Time `json:"UPDATE_AT" ` // Updated Time
|
||||
}
|
85
cmd/gf/internal/cmd/testdata/gendao/generated_user_type_mapping/dao/internal/table_user.go
vendored
Normal file
85
cmd/gf/internal/cmd/testdata/gendao/generated_user_type_mapping/dao/internal/table_user.go
vendored
Normal file
@ -0,0 +1,85 @@
|
||||
// ==========================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// ==========================================================================
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// TableUserDao is the data access object for table table_user.
|
||||
type TableUserDao struct {
|
||||
table string // table is the underlying table name of the DAO.
|
||||
group string // group is the database configuration group name of current DAO.
|
||||
columns TableUserColumns // columns contains all the column names of Table for convenient usage.
|
||||
}
|
||||
|
||||
// TableUserColumns defines and stores column names for table table_user.
|
||||
type TableUserColumns struct {
|
||||
Id string // User ID
|
||||
Passport string // User Passport
|
||||
Password string // User Password
|
||||
Nickname string // User Nickname
|
||||
Score string // Total score amount.
|
||||
CreateAt string // Created Time
|
||||
UpdateAt string // Updated Time
|
||||
}
|
||||
|
||||
// tableUserColumns holds the columns for table table_user.
|
||||
var tableUserColumns = TableUserColumns{
|
||||
Id: "id",
|
||||
Passport: "passport",
|
||||
Password: "password",
|
||||
Nickname: "nickname",
|
||||
Score: "score",
|
||||
CreateAt: "create_at",
|
||||
UpdateAt: "update_at",
|
||||
}
|
||||
|
||||
// NewTableUserDao creates and returns a new DAO object for table data access.
|
||||
func NewTableUserDao() *TableUserDao {
|
||||
return &TableUserDao{
|
||||
group: "test",
|
||||
table: "table_user",
|
||||
columns: tableUserColumns,
|
||||
}
|
||||
}
|
||||
|
||||
// DB retrieves and returns the underlying raw database management object of current DAO.
|
||||
func (dao *TableUserDao) DB() gdb.DB {
|
||||
return g.DB(dao.group)
|
||||
}
|
||||
|
||||
// Table returns the table name of current dao.
|
||||
func (dao *TableUserDao) Table() string {
|
||||
return dao.table
|
||||
}
|
||||
|
||||
// Columns returns all column names of current dao.
|
||||
func (dao *TableUserDao) Columns() TableUserColumns {
|
||||
return dao.columns
|
||||
}
|
||||
|
||||
// Group returns the configuration group name of database of current dao.
|
||||
func (dao *TableUserDao) Group() string {
|
||||
return dao.group
|
||||
}
|
||||
|
||||
// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation.
|
||||
func (dao *TableUserDao) Ctx(ctx context.Context) *gdb.Model {
|
||||
return dao.DB().Model(dao.table).Safe().Ctx(ctx)
|
||||
}
|
||||
|
||||
// Transaction wraps the transaction logic using function f.
|
||||
// It rollbacks the transaction and returns the error from function f if it returns non-nil error.
|
||||
// It commits the transaction and returns nil if function f returns nil.
|
||||
//
|
||||
// Note that, you should not Commit or Rollback the transaction in function f
|
||||
// as it is automatically handled by this function.
|
||||
func (dao *TableUserDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
|
||||
return dao.Ctx(ctx).Transaction(ctx, f)
|
||||
}
|
27
cmd/gf/internal/cmd/testdata/gendao/generated_user_type_mapping/dao/table_user.go
vendored
Normal file
27
cmd/gf/internal/cmd/testdata/gendao/generated_user_type_mapping/dao/table_user.go
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
// =================================================================================
|
||||
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
|
||||
// =================================================================================
|
||||
|
||||
package dao
|
||||
|
||||
import (
|
||||
"for-gendao-test/pkg/dao/internal"
|
||||
)
|
||||
|
||||
// internalTableUserDao is internal type for wrapping internal DAO implements.
|
||||
type internalTableUserDao = *internal.TableUserDao
|
||||
|
||||
// tableUserDao is the data access object for table table_user.
|
||||
// You can define custom methods on it to extend its functionality as you wish.
|
||||
type tableUserDao struct {
|
||||
internalTableUserDao
|
||||
}
|
||||
|
||||
var (
|
||||
// TableUser is globally public accessible object for table table_user operations.
|
||||
TableUser = tableUserDao{
|
||||
internal.NewTableUserDao(),
|
||||
}
|
||||
)
|
||||
|
||||
// Fill with you ideas below.
|
22
cmd/gf/internal/cmd/testdata/gendao/generated_user_type_mapping/model/do/table_user.go
vendored
Normal file
22
cmd/gf/internal/cmd/testdata/gendao/generated_user_type_mapping/model/do/table_user.go
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package do
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// TableUser is the golang structure of table table_user for DAO operations like Where/Data.
|
||||
type TableUser struct {
|
||||
g.Meta `orm:"table:table_user, do:true"`
|
||||
Id interface{} // User ID
|
||||
Passport interface{} // User Passport
|
||||
Password interface{} // User Password
|
||||
Nickname interface{} // User Nickname
|
||||
Score interface{} // Total score amount.
|
||||
CreateAt *gtime.Time // Created Time
|
||||
UpdateAt *gtime.Time // Updated Time
|
||||
}
|
21
cmd/gf/internal/cmd/testdata/gendao/generated_user_type_mapping/model/entity/table_user.go
vendored
Normal file
21
cmd/gf/internal/cmd/testdata/gendao/generated_user_type_mapping/model/entity/table_user.go
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package entity
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"github.com/shopspring/decimal"
|
||||
)
|
||||
|
||||
// TableUser is the golang structure for table table_user.
|
||||
type TableUser struct {
|
||||
Id int64 `json:"id" ` // User ID
|
||||
Passport string `json:"passport" ` // User Passport
|
||||
Password string `json:"password" ` // User Password
|
||||
Nickname string `json:"nickname" ` // User Nickname
|
||||
Score decimal.Decimal `json:"score" ` // Total score amount.
|
||||
CreateAt *gtime.Time `json:"createAt" ` // Created Time
|
||||
UpdateAt *gtime.Time `json:"updateAt" ` // Updated Time
|
||||
}
|
32
cmd/gf/internal/cmd/testdata/gendao/go.mod.txt
vendored
Normal file
32
cmd/gf/internal/cmd/testdata/gendao/go.mod.txt
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
module for-gendao-test/pkg
|
||||
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/gogf/gf/v2 v2.5.3
|
||||
github.com/shopspring/decimal v1.3.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/BurntSushi/toml v1.2.0 // indirect
|
||||
github.com/clbanning/mxj/v2 v2.7.0 // indirect
|
||||
github.com/fatih/color v1.15.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||
github.com/go-logr/logr v1.2.4 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/gorilla/websocket v1.5.0 // indirect
|
||||
github.com/grokify/html-strip-tags-go v0.0.1 // indirect
|
||||
github.com/magiconair/properties v1.8.6 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.15 // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||
github.com/rivo/uniseg v0.4.4 // indirect
|
||||
go.opentelemetry.io/otel v1.14.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.14.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.14.0 // indirect
|
||||
golang.org/x/net v0.12.0 // indirect
|
||||
golang.org/x/sys v0.10.0 // indirect
|
||||
golang.org/x/text v0.11.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
10
cmd/gf/internal/cmd/testdata/gendao/user.tpl.sql
vendored
Normal file
10
cmd/gf/internal/cmd/testdata/gendao/user.tpl.sql
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
CREATE TABLE `%s` (
|
||||
`id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'User ID',
|
||||
`passport` varchar(45) NOT NULL COMMENT 'User Passport',
|
||||
`password` varchar(45) NOT NULL COMMENT 'User Password',
|
||||
`nickname` varchar(45) NOT NULL COMMENT 'User Nickname',
|
||||
`score` decimal(10,2) unsigned DEFAULT NULL COMMENT 'Total score amount.',
|
||||
`create_at` datetime DEFAULT NULL COMMENT 'Created Time',
|
||||
`update_at` datetime DEFAULT NULL COMMENT 'Updated Time',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
@ -22,16 +22,25 @@ import (
|
||||
|
||||
func Test_SetSingleCustomListener(t *testing.T) {
|
||||
var (
|
||||
p, _ = gtcp.GetFreePort()
|
||||
ln, _ = net.Listen("tcp", fmt.Sprintf(":%d", p))
|
||||
s = g.Server(guid.S())
|
||||
p1 int
|
||||
ln1 net.Listener
|
||||
)
|
||||
for i := 0; i < 1000; i++ {
|
||||
p1, _ = gtcp.GetFreePort()
|
||||
if ln1 == nil {
|
||||
ln1, _ = net.Listen("tcp", fmt.Sprintf(":%d", p1))
|
||||
}
|
||||
if ln1 != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
s := g.Server(guid.S())
|
||||
s.Group("/", func(group *ghttp.RouterGroup) {
|
||||
group.GET("/test", func(r *ghttp.Request) {
|
||||
r.Response.Write("test")
|
||||
})
|
||||
})
|
||||
err := s.SetListener(ln)
|
||||
err := s.SetListener(ln1)
|
||||
gtest.AssertNil(err)
|
||||
|
||||
s.Start()
|
||||
@ -51,12 +60,25 @@ func Test_SetSingleCustomListener(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_SetMultipleCustomListeners(t *testing.T) {
|
||||
p1, _ := gtcp.GetFreePort()
|
||||
p2, _ := gtcp.GetFreePort()
|
||||
|
||||
ln1, _ := net.Listen("tcp", fmt.Sprintf(":%d", p1))
|
||||
ln2, _ := net.Listen("tcp", fmt.Sprintf(":%d", p2))
|
||||
|
||||
var (
|
||||
p1 int
|
||||
p2 int
|
||||
ln1 net.Listener
|
||||
ln2 net.Listener
|
||||
)
|
||||
for i := 0; i < 1000; i++ {
|
||||
p1, _ = gtcp.GetFreePort()
|
||||
p2, _ = gtcp.GetFreePort()
|
||||
if ln1 == nil {
|
||||
ln1, _ = net.Listen("tcp", fmt.Sprintf(":%d", p1))
|
||||
}
|
||||
if ln2 == nil {
|
||||
ln2, _ = net.Listen("tcp", fmt.Sprintf(":%d", p2))
|
||||
}
|
||||
if ln1 != nil && ln2 != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
s := g.Server(guid.S())
|
||||
s.Group("/", func(group *ghttp.RouterGroup) {
|
||||
group.GET("/test", func(r *ghttp.Request) {
|
||||
|
@ -64,7 +64,7 @@ func Mkdir(path string) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Create creates file with given `path` recursively.
|
||||
// Create creates a file with given `path` recursively.
|
||||
// The parameter `path` is suggested to be absolute path.
|
||||
func Create(path string) (*os.File, error) {
|
||||
dir := Dir(path)
|
||||
|
@ -15,21 +15,74 @@ import (
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
)
|
||||
|
||||
// CopyOption is the option for Copy* functions.
|
||||
type CopyOption struct {
|
||||
Sync bool // Auto call file sync after source file content copied to target file.
|
||||
Mode os.FileMode // Destination created file mode. The default file mode is DefaultPermCopy.
|
||||
}
|
||||
|
||||
// Copy file/directory from `src` to `dst`.
|
||||
//
|
||||
// If `src` is file, it calls CopyFile to implements copy feature,
|
||||
// or else it calls CopyDir.
|
||||
func Copy(src string, dst string) error {
|
||||
//
|
||||
// If `src` is file, but `dst` already exists and is a folder,
|
||||
// it then creates a same name file of `src` in folder `dst`.
|
||||
//
|
||||
// Eg:
|
||||
// Copy("/tmp/file1", "/tmp/file2") => /tmp/file1 copied to /tmp/file2
|
||||
// Copy("/tmp/dir1", "/tmp/dir2") => /tmp/dir1 copied to /tmp/dir2
|
||||
// Copy("/tmp/file1", "/tmp/dir2") => /tmp/file1 copied to /tmp/dir2/file1
|
||||
// Copy("/tmp/dir1", "/tmp/file2") => error
|
||||
func Copy(src string, dst string, option ...CopyOption) error {
|
||||
if src == "" {
|
||||
return gerror.NewCode(gcode.CodeInvalidParameter, "source path cannot be empty")
|
||||
}
|
||||
if dst == "" {
|
||||
return gerror.NewCode(gcode.CodeInvalidParameter, "destination path cannot be empty")
|
||||
}
|
||||
if IsFile(src) {
|
||||
return CopyFile(src, dst)
|
||||
srcStat, srcStatErr := os.Stat(src)
|
||||
if srcStatErr != nil {
|
||||
if os.IsNotExist(srcStatErr) {
|
||||
return gerror.WrapCodef(
|
||||
gcode.CodeInvalidParameter,
|
||||
srcStatErr,
|
||||
`the src path "%s" does not exist`,
|
||||
src,
|
||||
)
|
||||
}
|
||||
return gerror.WrapCodef(
|
||||
gcode.CodeInternalError, srcStatErr, `call os.Stat on "%s" failed`, src,
|
||||
)
|
||||
}
|
||||
return CopyDir(src, dst)
|
||||
dstStat, dstStatErr := os.Stat(dst)
|
||||
if dstStatErr != nil && !os.IsNotExist(dstStatErr) {
|
||||
return gerror.WrapCodef(
|
||||
gcode.CodeInternalError, dstStatErr, `call os.Stat on "%s" failed`, dst)
|
||||
}
|
||||
|
||||
if IsFile(src) {
|
||||
var isDstExist = false
|
||||
if dstStat != nil && !os.IsNotExist(dstStatErr) {
|
||||
isDstExist = true
|
||||
}
|
||||
if isDstExist && dstStat.IsDir() {
|
||||
var (
|
||||
srcName = Basename(src)
|
||||
dstPath = Join(dst, srcName)
|
||||
)
|
||||
return CopyFile(src, dstPath, option...)
|
||||
}
|
||||
return CopyFile(src, dst, option...)
|
||||
}
|
||||
if !srcStat.IsDir() && dstStat != nil && dstStat.IsDir() {
|
||||
return gerror.NewCodef(
|
||||
gcode.CodeInvalidParameter,
|
||||
`Copy failed: the src path "%s" is file, but the dst path "%s" is folder`,
|
||||
src, dst,
|
||||
)
|
||||
}
|
||||
return CopyDir(src, dst, option...)
|
||||
}
|
||||
|
||||
// CopyFile copies the contents of the file named `src` to the file named
|
||||
@ -38,7 +91,8 @@ func Copy(src string, dst string) error {
|
||||
// of the source file. The file mode will be copied from the source and
|
||||
// the copied data is synced/flushed to stable storage.
|
||||
// Thanks: https://gist.github.com/r0l1/92462b38df26839a3ca324697c8cba04
|
||||
func CopyFile(src, dst string) (err error) {
|
||||
func CopyFile(src, dst string, option ...CopyOption) (err error) {
|
||||
var usedOption = getCopyOption(option...)
|
||||
if src == "" {
|
||||
return gerror.NewCode(gcode.CodeInvalidParameter, "source file cannot be empty")
|
||||
}
|
||||
@ -49,6 +103,35 @@ func CopyFile(src, dst string) (err error) {
|
||||
if src == dst {
|
||||
return nil
|
||||
}
|
||||
// file state check.
|
||||
srcStat, srcStatErr := os.Stat(src)
|
||||
if srcStatErr != nil {
|
||||
if os.IsNotExist(srcStatErr) {
|
||||
return gerror.WrapCodef(
|
||||
gcode.CodeInvalidParameter,
|
||||
srcStatErr,
|
||||
`the src path "%s" does not exist`,
|
||||
src,
|
||||
)
|
||||
}
|
||||
return gerror.WrapCodef(
|
||||
gcode.CodeInternalError, srcStatErr, `call os.Stat on "%s" failed`, src,
|
||||
)
|
||||
}
|
||||
dstStat, dstStatErr := os.Stat(dst)
|
||||
if dstStatErr != nil && !os.IsNotExist(dstStatErr) {
|
||||
return gerror.WrapCodef(
|
||||
gcode.CodeInternalError, dstStatErr, `call os.Stat on "%s" failed`, dst,
|
||||
)
|
||||
}
|
||||
if !srcStat.IsDir() && dstStat != nil && dstStat.IsDir() {
|
||||
return gerror.NewCodef(
|
||||
gcode.CodeInvalidParameter,
|
||||
`CopyFile failed: the src path "%s" is file, but the dst path "%s" is folder`,
|
||||
src, dst,
|
||||
)
|
||||
}
|
||||
// copy file logic.
|
||||
var inFile *os.File
|
||||
inFile, err = Open(src)
|
||||
if err != nil {
|
||||
@ -73,11 +156,13 @@ func CopyFile(src, dst string) (err error) {
|
||||
err = gerror.Wrapf(err, `io.Copy failed from "%s" to "%s"`, src, dst)
|
||||
return
|
||||
}
|
||||
if err = outFile.Sync(); err != nil {
|
||||
err = gerror.Wrapf(err, `file sync failed for file "%s"`, dst)
|
||||
return
|
||||
if usedOption.Sync {
|
||||
if err = outFile.Sync(); err != nil {
|
||||
err = gerror.Wrapf(err, `file sync failed for file "%s"`, dst)
|
||||
return
|
||||
}
|
||||
}
|
||||
if err = Chmod(dst, DefaultPermCopy); err != nil {
|
||||
if err = Chmod(dst, usedOption.Mode); err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
@ -86,7 +171,8 @@ func CopyFile(src, dst string) (err error) {
|
||||
// CopyDir recursively copies a directory tree, attempting to preserve permissions.
|
||||
//
|
||||
// Note that, the Source directory must exist and symlinks are ignored and skipped.
|
||||
func CopyDir(src string, dst string) (err error) {
|
||||
func CopyDir(src string, dst string, option ...CopyOption) (err error) {
|
||||
var usedOption = getCopyOption(option...)
|
||||
if src == "" {
|
||||
return gerror.NewCode(gcode.CodeInvalidParameter, "source directory cannot be empty")
|
||||
}
|
||||
@ -107,8 +193,13 @@ func CopyDir(src string, dst string) (err error) {
|
||||
return gerror.NewCode(gcode.CodeInvalidParameter, "source is not a directory")
|
||||
}
|
||||
if !Exists(dst) {
|
||||
if err = os.MkdirAll(dst, DefaultPermCopy); err != nil {
|
||||
err = gerror.Wrapf(err, `create directory failed for path "%s", perm "%s"`, dst, DefaultPermCopy)
|
||||
if err = os.MkdirAll(dst, usedOption.Mode); err != nil {
|
||||
err = gerror.Wrapf(
|
||||
err,
|
||||
`create directory failed for path "%s", perm "%s"`,
|
||||
dst,
|
||||
usedOption.Mode,
|
||||
)
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -129,10 +220,21 @@ func CopyDir(src string, dst string) (err error) {
|
||||
if entry.Type()&os.ModeSymlink != 0 {
|
||||
continue
|
||||
}
|
||||
if err = CopyFile(srcPath, dstPath); err != nil {
|
||||
if err = CopyFile(srcPath, dstPath, option...); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getCopyOption(option ...CopyOption) CopyOption {
|
||||
var usedOption CopyOption
|
||||
if len(option) > 0 {
|
||||
usedOption = option[0]
|
||||
}
|
||||
if usedOption.Mode == 0 {
|
||||
usedOption.Mode = DefaultPermCopy
|
||||
}
|
||||
return usedOption
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"github.com/gogf/gf/v2/test/gtest"
|
||||
"github.com/gogf/gf/v2/util/guid"
|
||||
)
|
||||
|
||||
func Test_Copy(t *testing.T) {
|
||||
@ -33,6 +34,40 @@ func Test_Copy(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Copy_File_To_Dir(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
src = gtest.DataPath("dir1", "file1")
|
||||
dst = gfile.Temp(guid.S(), "dir2")
|
||||
)
|
||||
err := gfile.Mkdir(dst)
|
||||
t.AssertNil(err)
|
||||
defer gfile.Remove(dst)
|
||||
|
||||
err = gfile.Copy(src, dst)
|
||||
t.AssertNil(err)
|
||||
|
||||
expectPath := gfile.Join(dst, "file1")
|
||||
t.Assert(gfile.GetContents(expectPath), gfile.GetContents(src))
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Copy_Dir_To_File(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
src = gtest.DataPath("dir1")
|
||||
dst = gfile.Temp(guid.S(), "file2")
|
||||
)
|
||||
f, err := gfile.Create(dst)
|
||||
t.AssertNil(err)
|
||||
defer f.Close()
|
||||
defer gfile.Remove(dst)
|
||||
|
||||
err = gfile.Copy(src, dst)
|
||||
t.AssertNE(err, nil)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_CopyFile(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
|
1
os/gfile/testdata/dir1/file1
vendored
1
os/gfile/testdata/dir1/file1
vendored
@ -0,0 +1 @@
|
||||
file1
|
1
os/gfile/testdata/dir2/file2
vendored
1
os/gfile/testdata/dir2/file2
vendored
@ -0,0 +1 @@
|
||||
file2
|
@ -9,6 +9,8 @@ package gstructs
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
)
|
||||
|
||||
// Type wraps reflect.Type for additional features.
|
||||
@ -25,13 +27,15 @@ type Field struct {
|
||||
TagName string
|
||||
|
||||
// Retrieved tag value.
|
||||
// There might be more than one tags in the field, but only one can be retrieved according to calling function rules.
|
||||
// There might be more than one tags in the field,
|
||||
// but only one can be retrieved according to calling function rules.
|
||||
TagValue string
|
||||
}
|
||||
|
||||
// FieldsInput is the input parameter struct type for function Fields.
|
||||
type FieldsInput struct {
|
||||
// Pointer should be type of struct/*struct.
|
||||
// TODO this attribute name is not suitable, which would make confuse.
|
||||
Pointer interface{}
|
||||
|
||||
// RecursiveOption specifies the way retrieving the fields recursively if the attribute
|
||||
@ -42,6 +46,7 @@ type FieldsInput struct {
|
||||
// FieldMapInput is the input parameter struct type for function FieldMap.
|
||||
type FieldMapInput struct {
|
||||
// Pointer should be type of struct/*struct.
|
||||
// TODO this attribute name is not suitable, which would make confuse.
|
||||
Pointer interface{}
|
||||
|
||||
// PriorityTagArray specifies the priority tag array for retrieving from high to low.
|
||||
@ -60,3 +65,188 @@ const (
|
||||
RecursiveOptionEmbedded RecursiveOption = 1 // Recursively retrieving fields as map if the field is an embedded struct.
|
||||
RecursiveOptionEmbeddedNoTag RecursiveOption = 2 // Recursively retrieving fields as map if the field is an embedded struct and the field has no tag.
|
||||
)
|
||||
|
||||
// Fields retrieves and returns the fields of `pointer` as slice.
|
||||
func Fields(in FieldsInput) ([]Field, error) {
|
||||
var (
|
||||
ok bool
|
||||
fieldFilterMap = make(map[string]struct{})
|
||||
retrievedFields = make([]Field, 0)
|
||||
currentLevelFieldMap = make(map[string]Field)
|
||||
rangeFields, err = getFieldValues(in.Pointer)
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for index := 0; index < len(rangeFields); index++ {
|
||||
field := rangeFields[index]
|
||||
currentLevelFieldMap[field.Name()] = field
|
||||
}
|
||||
|
||||
for index := 0; index < len(rangeFields); index++ {
|
||||
field := rangeFields[index]
|
||||
if _, ok = fieldFilterMap[field.Name()]; ok {
|
||||
continue
|
||||
}
|
||||
if field.IsEmbedded() {
|
||||
if in.RecursiveOption != RecursiveOptionNone {
|
||||
switch in.RecursiveOption {
|
||||
case RecursiveOptionEmbeddedNoTag:
|
||||
if field.TagStr() != "" {
|
||||
break
|
||||
}
|
||||
fallthrough
|
||||
|
||||
case RecursiveOptionEmbedded:
|
||||
structFields, err := Fields(FieldsInput{
|
||||
Pointer: field.Value,
|
||||
RecursiveOption: in.RecursiveOption,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// The current level fields can overwrite the sub-struct fields with the same name.
|
||||
for i := 0; i < len(structFields); i++ {
|
||||
var (
|
||||
structField = structFields[i]
|
||||
fieldName = structField.Name()
|
||||
)
|
||||
if _, ok = fieldFilterMap[fieldName]; ok {
|
||||
continue
|
||||
}
|
||||
fieldFilterMap[fieldName] = struct{}{}
|
||||
if v, ok := currentLevelFieldMap[fieldName]; !ok {
|
||||
retrievedFields = append(retrievedFields, structField)
|
||||
} else {
|
||||
retrievedFields = append(retrievedFields, v)
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
fieldFilterMap[field.Name()] = struct{}{}
|
||||
retrievedFields = append(retrievedFields, field)
|
||||
}
|
||||
return retrievedFields, nil
|
||||
}
|
||||
|
||||
// FieldMap retrieves and returns struct field as map[name/tag]Field from `pointer`.
|
||||
//
|
||||
// The parameter `pointer` should be type of struct/*struct.
|
||||
//
|
||||
// The parameter `priority` specifies the priority tag array for retrieving from high to low.
|
||||
// If it's given `nil`, it returns map[name]Field, of which the `name` is attribute name.
|
||||
//
|
||||
// The parameter `recursive` specifies whether retrieving the fields recursively if the attribute
|
||||
// is an embedded struct.
|
||||
//
|
||||
// Note that it only retrieves the exported attributes with first letter upper-case from struct.
|
||||
func FieldMap(in FieldMapInput) (map[string]Field, error) {
|
||||
fields, err := getFieldValues(in.Pointer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var (
|
||||
tagValue string
|
||||
mapField = make(map[string]Field)
|
||||
)
|
||||
for _, field := range fields {
|
||||
// Only retrieve exported attributes.
|
||||
if !field.IsExported() {
|
||||
continue
|
||||
}
|
||||
tagValue = ""
|
||||
for _, p := range in.PriorityTagArray {
|
||||
tagValue = field.Tag(p)
|
||||
if tagValue != "" && tagValue != "-" {
|
||||
break
|
||||
}
|
||||
}
|
||||
tempField := field
|
||||
tempField.TagValue = tagValue
|
||||
if tagValue != "" {
|
||||
mapField[tagValue] = tempField
|
||||
} else {
|
||||
if in.RecursiveOption != RecursiveOptionNone && field.IsEmbedded() {
|
||||
switch in.RecursiveOption {
|
||||
case RecursiveOptionEmbeddedNoTag:
|
||||
if field.TagStr() != "" {
|
||||
mapField[field.Name()] = tempField
|
||||
break
|
||||
}
|
||||
fallthrough
|
||||
|
||||
case RecursiveOptionEmbedded:
|
||||
m, err := FieldMap(FieldMapInput{
|
||||
Pointer: field.Value,
|
||||
PriorityTagArray: in.PriorityTagArray,
|
||||
RecursiveOption: in.RecursiveOption,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for k, v := range m {
|
||||
if _, ok := mapField[k]; !ok {
|
||||
tempV := v
|
||||
mapField[k] = tempV
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mapField[field.Name()] = tempField
|
||||
}
|
||||
}
|
||||
}
|
||||
return mapField, nil
|
||||
}
|
||||
|
||||
// StructType retrieves and returns the struct Type of specified struct/*struct.
|
||||
// The parameter `object` should be either type of struct/*struct/[]struct/[]*struct.
|
||||
func StructType(object interface{}) (*Type, error) {
|
||||
var (
|
||||
reflectValue reflect.Value
|
||||
reflectKind reflect.Kind
|
||||
reflectType reflect.Type
|
||||
)
|
||||
if rv, ok := object.(reflect.Value); ok {
|
||||
reflectValue = rv
|
||||
} else {
|
||||
reflectValue = reflect.ValueOf(object)
|
||||
}
|
||||
reflectKind = reflectValue.Kind()
|
||||
for {
|
||||
switch reflectKind {
|
||||
case reflect.Ptr:
|
||||
if !reflectValue.IsValid() || reflectValue.IsNil() {
|
||||
// If pointer is type of *struct and nil, then automatically create a temporary struct.
|
||||
reflectValue = reflect.New(reflectValue.Type().Elem()).Elem()
|
||||
reflectKind = reflectValue.Kind()
|
||||
} else {
|
||||
reflectValue = reflectValue.Elem()
|
||||
reflectKind = reflectValue.Kind()
|
||||
}
|
||||
|
||||
case reflect.Array, reflect.Slice:
|
||||
reflectValue = reflect.New(reflectValue.Type().Elem()).Elem()
|
||||
reflectKind = reflectValue.Kind()
|
||||
|
||||
default:
|
||||
goto exitLoop
|
||||
}
|
||||
}
|
||||
|
||||
exitLoop:
|
||||
if reflectKind != reflect.Struct {
|
||||
return nil, gerror.Newf(
|
||||
`invalid object kind "%s", kind of "struct" is required`,
|
||||
reflectKind,
|
||||
)
|
||||
}
|
||||
reflectType = reflectValue.Type()
|
||||
return &Type{
|
||||
Type: reflectType,
|
||||
}, nil
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ package gstructs
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/gogf/gf/v2/internal/empty"
|
||||
"github.com/gogf/gf/v2/internal/utils"
|
||||
"github.com/gogf/gf/v2/util/gtag"
|
||||
)
|
||||
@ -94,139 +95,12 @@ func (f *Field) OriginalKind() reflect.Kind {
|
||||
return reflectKind
|
||||
}
|
||||
|
||||
// Fields retrieves and returns the fields of `pointer` as slice.
|
||||
func Fields(in FieldsInput) ([]Field, error) {
|
||||
var (
|
||||
ok bool
|
||||
fieldFilterMap = make(map[string]struct{})
|
||||
retrievedFields = make([]Field, 0)
|
||||
currentLevelFieldMap = make(map[string]Field)
|
||||
)
|
||||
rangeFields, err := getFieldValues(in.Pointer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for index := 0; index < len(rangeFields); index++ {
|
||||
field := rangeFields[index]
|
||||
currentLevelFieldMap[field.Name()] = field
|
||||
}
|
||||
|
||||
for index := 0; index < len(rangeFields); index++ {
|
||||
field := rangeFields[index]
|
||||
if _, ok = fieldFilterMap[field.Name()]; ok {
|
||||
continue
|
||||
}
|
||||
if field.IsEmbedded() {
|
||||
if in.RecursiveOption != RecursiveOptionNone {
|
||||
switch in.RecursiveOption {
|
||||
case RecursiveOptionEmbeddedNoTag:
|
||||
if field.TagStr() != "" {
|
||||
break
|
||||
}
|
||||
fallthrough
|
||||
|
||||
case RecursiveOptionEmbedded:
|
||||
structFields, err := Fields(FieldsInput{
|
||||
Pointer: field.Value,
|
||||
RecursiveOption: in.RecursiveOption,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// The current level fields can overwrite the sub-struct fields with the same name.
|
||||
for i := 0; i < len(structFields); i++ {
|
||||
var (
|
||||
structField = structFields[i]
|
||||
fieldName = structField.Name()
|
||||
)
|
||||
if _, ok = fieldFilterMap[fieldName]; ok {
|
||||
continue
|
||||
}
|
||||
fieldFilterMap[fieldName] = struct{}{}
|
||||
if v, ok := currentLevelFieldMap[fieldName]; !ok {
|
||||
retrievedFields = append(retrievedFields, structField)
|
||||
} else {
|
||||
retrievedFields = append(retrievedFields, v)
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
fieldFilterMap[field.Name()] = struct{}{}
|
||||
retrievedFields = append(retrievedFields, field)
|
||||
}
|
||||
return retrievedFields, nil
|
||||
// IsEmpty checks and returns whether the value of this Field is empty.
|
||||
func (f *Field) IsEmpty() bool {
|
||||
return empty.IsEmpty(f.Value)
|
||||
}
|
||||
|
||||
// FieldMap retrieves and returns struct field as map[name/tag]Field from `pointer`.
|
||||
//
|
||||
// The parameter `pointer` should be type of struct/*struct.
|
||||
//
|
||||
// The parameter `priority` specifies the priority tag array for retrieving from high to low.
|
||||
// If it's given `nil`, it returns map[name]Field, of which the `name` is attribute name.
|
||||
//
|
||||
// The parameter `recursive` specifies the whether retrieving the fields recursively if the attribute
|
||||
// is an embedded struct.
|
||||
//
|
||||
// Note that it only retrieves the exported attributes with first letter upper-case from struct.
|
||||
func FieldMap(in FieldMapInput) (map[string]Field, error) {
|
||||
fields, err := getFieldValues(in.Pointer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var (
|
||||
tagValue string
|
||||
mapField = make(map[string]Field)
|
||||
)
|
||||
for _, field := range fields {
|
||||
// Only retrieve exported attributes.
|
||||
if !field.IsExported() {
|
||||
continue
|
||||
}
|
||||
tagValue = ""
|
||||
for _, p := range in.PriorityTagArray {
|
||||
tagValue = field.Tag(p)
|
||||
if tagValue != "" && tagValue != "-" {
|
||||
break
|
||||
}
|
||||
}
|
||||
tempField := field
|
||||
tempField.TagValue = tagValue
|
||||
if tagValue != "" {
|
||||
mapField[tagValue] = tempField
|
||||
} else {
|
||||
if in.RecursiveOption != RecursiveOptionNone && field.IsEmbedded() {
|
||||
switch in.RecursiveOption {
|
||||
case RecursiveOptionEmbeddedNoTag:
|
||||
if field.TagStr() != "" {
|
||||
mapField[field.Name()] = tempField
|
||||
break
|
||||
}
|
||||
fallthrough
|
||||
|
||||
case RecursiveOptionEmbedded:
|
||||
m, err := FieldMap(FieldMapInput{
|
||||
Pointer: field.Value,
|
||||
PriorityTagArray: in.PriorityTagArray,
|
||||
RecursiveOption: in.RecursiveOption,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for k, v := range m {
|
||||
if _, ok := mapField[k]; !ok {
|
||||
tempV := v
|
||||
mapField[k] = tempV
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mapField[field.Name()] = tempField
|
||||
}
|
||||
}
|
||||
}
|
||||
return mapField, nil
|
||||
// IsNil checks and returns whether the value of this Field is nil.
|
||||
func (f *Field) IsNil(traceSource ...bool) bool {
|
||||
return empty.IsNil(f.Value, traceSource...)
|
||||
}
|
||||
|
@ -120,16 +120,16 @@ func TagMapField(object interface{}, priority []string) (map[string]Field, error
|
||||
return tagMap, nil
|
||||
}
|
||||
|
||||
func getFieldValues(value interface{}) ([]Field, error) {
|
||||
func getFieldValues(structObject interface{}) ([]Field, error) {
|
||||
var (
|
||||
reflectValue reflect.Value
|
||||
reflectKind reflect.Kind
|
||||
)
|
||||
if v, ok := value.(reflect.Value); ok {
|
||||
if v, ok := structObject.(reflect.Value); ok {
|
||||
reflectValue = v
|
||||
reflectKind = reflectValue.Kind()
|
||||
} else {
|
||||
reflectValue = reflect.ValueOf(value)
|
||||
reflectValue = reflect.ValueOf(structObject)
|
||||
reflectKind = reflectValue.Kind()
|
||||
}
|
||||
for {
|
||||
|
@ -6,60 +6,6 @@
|
||||
|
||||
package gstructs
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
)
|
||||
|
||||
// StructType retrieves and returns the struct Type of specified struct/*struct.
|
||||
// The parameter `object` should be either type of struct/*struct/[]struct/[]*struct.
|
||||
func StructType(object interface{}) (*Type, error) {
|
||||
var (
|
||||
reflectValue reflect.Value
|
||||
reflectKind reflect.Kind
|
||||
reflectType reflect.Type
|
||||
)
|
||||
if rv, ok := object.(reflect.Value); ok {
|
||||
reflectValue = rv
|
||||
} else {
|
||||
reflectValue = reflect.ValueOf(object)
|
||||
}
|
||||
reflectKind = reflectValue.Kind()
|
||||
for {
|
||||
switch reflectKind {
|
||||
case reflect.Ptr:
|
||||
if !reflectValue.IsValid() || reflectValue.IsNil() {
|
||||
// If pointer is type of *struct and nil, then automatically create a temporary struct.
|
||||
reflectValue = reflect.New(reflectValue.Type().Elem()).Elem()
|
||||
reflectKind = reflectValue.Kind()
|
||||
} else {
|
||||
reflectValue = reflectValue.Elem()
|
||||
reflectKind = reflectValue.Kind()
|
||||
}
|
||||
|
||||
case reflect.Array, reflect.Slice:
|
||||
reflectValue = reflect.New(reflectValue.Type().Elem()).Elem()
|
||||
reflectKind = reflectValue.Kind()
|
||||
|
||||
default:
|
||||
goto exitLoop
|
||||
}
|
||||
}
|
||||
|
||||
exitLoop:
|
||||
if reflectKind != reflect.Struct {
|
||||
return nil, gerror.Newf(
|
||||
`invalid object kind "%s", kind of "struct" is required`,
|
||||
reflectKind,
|
||||
)
|
||||
}
|
||||
reflectType = reflectValue.Type()
|
||||
return &Type{
|
||||
Type: reflectType,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Signature returns a unique string as this type.
|
||||
func (t Type) Signature() string {
|
||||
return t.PkgPath() + "/" + t.String()
|
||||
|
@ -26,6 +26,25 @@ func Convert(fromValue interface{}, toTypeName string, extraParams ...interface{
|
||||
})
|
||||
}
|
||||
|
||||
// ConvertWithRefer converts the variable `fromValue` to the type referred by value `referValue`.
|
||||
//
|
||||
// The optional parameter `extraParams` is used for additional necessary parameter for this conversion.
|
||||
// It supports common basic types conversion as its conversion based on type name string.
|
||||
func ConvertWithRefer(fromValue interface{}, referValue interface{}, extraParams ...interface{}) interface{} {
|
||||
var referValueRf reflect.Value
|
||||
if v, ok := referValue.(reflect.Value); ok {
|
||||
referValueRf = v
|
||||
} else {
|
||||
referValueRf = reflect.ValueOf(referValue)
|
||||
}
|
||||
return doConvert(doConvertInput{
|
||||
FromValue: fromValue,
|
||||
ToTypeName: referValueRf.Type().String(),
|
||||
ReferValue: referValue,
|
||||
Extra: extraParams,
|
||||
})
|
||||
}
|
||||
|
||||
type doConvertInput struct {
|
||||
FromValue interface{} // Value that is converted from.
|
||||
ToTypeName string // Target value type name in string.
|
||||
|
@ -48,3 +48,13 @@ func Test_Duration(t *testing.T) {
|
||||
t.Assert(d.Nanoseconds(), 1000000000)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_ConvertWithRefer(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
t.AssertEQ(gconv.ConvertWithRefer("1", 100), 1)
|
||||
t.AssertEQ(gconv.ConvertWithRefer("1.01", 1.111), 1.01)
|
||||
t.AssertEQ(gconv.ConvertWithRefer("1.01", "1.111"), "1.01")
|
||||
t.AssertEQ(gconv.ConvertWithRefer("1.01", false), true)
|
||||
t.AssertNE(gconv.ConvertWithRefer("1.01", false), false)
|
||||
})
|
||||
}
|
||||
|
@ -13,8 +13,7 @@ import (
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
type boolStruct struct {
|
||||
}
|
||||
type boolStruct struct{}
|
||||
|
||||
func Test_Bool(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
|
@ -9,6 +9,9 @@ package gutil
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gcode"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/os/gstructs"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
@ -36,3 +39,63 @@ func StructToSlice(data interface{}) []interface{} {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// FillStructWithDefault fills attributes of pointed struct with tag value from `default/d` tag .
|
||||
// The parameter `structPtr` should be either type of *struct/[]*struct.
|
||||
func FillStructWithDefault(structPtr interface{}) error {
|
||||
var (
|
||||
reflectValue reflect.Value
|
||||
)
|
||||
if rv, ok := structPtr.(reflect.Value); ok {
|
||||
reflectValue = rv
|
||||
} else {
|
||||
reflectValue = reflect.ValueOf(structPtr)
|
||||
}
|
||||
switch reflectValue.Kind() {
|
||||
case reflect.Ptr:
|
||||
// Nothing to do.
|
||||
case reflect.Array, reflect.Slice:
|
||||
if reflectValue.Elem().Kind() != reflect.Ptr {
|
||||
return gerror.NewCodef(
|
||||
gcode.CodeInvalidParameter,
|
||||
`invalid parameter "%s", the element of slice should be type of pointer of struct, but given "%s"`,
|
||||
reflectValue.Type().String(), reflectValue.Elem().Type().String(),
|
||||
)
|
||||
}
|
||||
default:
|
||||
return gerror.NewCodef(
|
||||
gcode.CodeInvalidParameter,
|
||||
`invalid parameter "%s", should be type of pointer of struct`,
|
||||
reflectValue.Type().String(),
|
||||
)
|
||||
}
|
||||
if reflectValue.IsNil() {
|
||||
return gerror.NewCode(
|
||||
gcode.CodeInvalidParameter,
|
||||
`the pointed struct object should not be nil`,
|
||||
)
|
||||
}
|
||||
if !reflectValue.Elem().IsValid() {
|
||||
return gerror.NewCode(
|
||||
gcode.CodeInvalidParameter,
|
||||
`the pointed struct object should be valid`,
|
||||
)
|
||||
}
|
||||
fields, err := gstructs.Fields(gstructs.FieldsInput{
|
||||
Pointer: reflectValue,
|
||||
RecursiveOption: gstructs.RecursiveOptionNone,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, field := range fields {
|
||||
if defaultValue := field.TagDefault(); defaultValue != "" {
|
||||
if field.IsEmpty() {
|
||||
field.Value.Set(reflect.ValueOf(
|
||||
gconv.ConvertWithRefer(defaultValue, field.Value),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -36,3 +36,20 @@ func Test_StructToSlice(t *testing.T) {
|
||||
t.Assert(s, nil)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_FillStructWithDefault(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
type A struct {
|
||||
V1 int `d:"1.01"`
|
||||
V2 string `d:"1.01"`
|
||||
V3 float32 `d:"1.01"`
|
||||
}
|
||||
a := A{}
|
||||
err := gutil.FillStructWithDefault(&a)
|
||||
t.AssertNil(err)
|
||||
|
||||
t.Assert(a.V1, `1`)
|
||||
t.Assert(a.V2, `1.01`)
|
||||
t.Assert(a.V3, `1.01`)
|
||||
})
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user