mirror of
https://gitee.com/johng/gf.git
synced 2024-12-02 12:17:53 +08:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
a7c4597c97
@ -60,6 +60,7 @@ const (
|
||||
OrmTagForWith = "with"
|
||||
OrmTagForWithWhere = "where"
|
||||
OrmTagForWithOrder = "order"
|
||||
OrmTagForDto = "dto"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -70,9 +71,25 @@ var (
|
||||
structTagPriority = append([]string{OrmTagForStruct}, gconv.StructTagPriority...)
|
||||
)
|
||||
|
||||
// isForDaoModel checks and returns whether given type is for dao model.
|
||||
func isForDaoModel(t reflect.Type) bool {
|
||||
return gstr.HasSuffix(t.String(), modelForDaoSuffix)
|
||||
// isDtoStruct checks and returns whether given type is a DTO struct.
|
||||
func isDtoStruct(object interface{}) bool {
|
||||
// It checks by struct name like "XxxForDao", to be compatible with old version.
|
||||
// TODO remove this compatible codes in future.
|
||||
reflectType := reflect.TypeOf(object)
|
||||
if gstr.HasSuffix(reflectType.String(), modelForDaoSuffix) {
|
||||
return true
|
||||
}
|
||||
// It checks by struct meta for DTO struct in version.
|
||||
if ormTag := gmeta.Get(object, OrmTagForStruct); !ormTag.IsEmpty() {
|
||||
match, _ := gregex.MatchString(
|
||||
fmt.Sprintf(`%s\s*:\s*([^,]+)`, OrmTagForDto),
|
||||
ormTag.String(),
|
||||
)
|
||||
if len(match) > 1 {
|
||||
return gconv.Bool(match[1])
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// getTableNameFromOrmTag retrieves and returns the table name from struct object.
|
||||
@ -424,7 +441,7 @@ func formatWhereHolder(db DB, in formatWhereHolderInput) (newWhere string, newAr
|
||||
case reflect.Struct:
|
||||
// If the `where` parameter is defined like `xxxForDao`, it then adds `OmitNil` option for this condition,
|
||||
// which will filter all nil parameters in `where`.
|
||||
if isForDaoModel(reflect.TypeOf(in.Where)) {
|
||||
if isDtoStruct(in.Where) {
|
||||
in.OmitNil = true
|
||||
}
|
||||
// If `where` struct implements iIterator interface,
|
||||
|
@ -73,10 +73,10 @@ func (m *Model) Data(data ...interface{}) *Model {
|
||||
switch reflectInfo.OriginKind {
|
||||
case reflect.Slice, reflect.Array:
|
||||
if reflectInfo.OriginValue.Len() > 0 {
|
||||
// If the `data` parameter is defined like `xxxForDao`,
|
||||
// If the `data` parameter is a DTO struct,
|
||||
// it then adds `OmitNilData` option for this condition,
|
||||
// which will filter all nil parameters in `data`.
|
||||
if isForDaoModel(reflectInfo.OriginValue.Index(0).Elem().Type()) {
|
||||
if isDtoStruct(reflectInfo.OriginValue.Index(0).Interface()) {
|
||||
model = model.OmitNilData()
|
||||
model.option |= optionOmitNilDataInternal
|
||||
}
|
||||
@ -88,10 +88,10 @@ func (m *Model) Data(data ...interface{}) *Model {
|
||||
model.data = list
|
||||
|
||||
case reflect.Struct:
|
||||
// If the `data` parameter is defined like `xxxForDao`,
|
||||
// If the `data` parameter is a DTO struct,
|
||||
// it then adds `OmitNilData` option for this condition,
|
||||
// which will filter all nil parameters in `data`.
|
||||
if isForDaoModel(reflect.TypeOf(value)) {
|
||||
if isDtoStruct(value) {
|
||||
model = model.OmitNilData()
|
||||
}
|
||||
if v, ok := data[0].(iInterfaces); ok {
|
||||
|
@ -13,6 +13,144 @@ import (
|
||||
"github.com/gogf/gf/v2/test/gtest"
|
||||
)
|
||||
|
||||
func Test_Model_Insert_Data_DTO(t *testing.T) {
|
||||
table := createTable()
|
||||
defer dropTable(table)
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
type User struct {
|
||||
g.Meta `orm:"dto:true"`
|
||||
Id interface{}
|
||||
Passport interface{}
|
||||
Password interface{}
|
||||
Nickname interface{}
|
||||
CreateTime interface{}
|
||||
}
|
||||
data := User{
|
||||
Id: 1,
|
||||
Passport: "user_1",
|
||||
Password: "pass_1",
|
||||
}
|
||||
result, err := db.Model(table).Data(data).Insert()
|
||||
t.AssertNil(err)
|
||||
n, _ := result.LastInsertId()
|
||||
t.Assert(n, 1)
|
||||
|
||||
one, err := db.Model(table).WherePri(1).One()
|
||||
t.AssertNil(err)
|
||||
t.Assert(one[`id`], `1`)
|
||||
t.Assert(one[`passport`], `user_1`)
|
||||
t.Assert(one[`password`], `pass_1`)
|
||||
t.Assert(one[`nickname`], ``)
|
||||
t.Assert(one[`create_time`], ``)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Model_Insert_Data_LIst_DTO(t *testing.T) {
|
||||
table := createTable()
|
||||
defer dropTable(table)
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
type User struct {
|
||||
g.Meta `orm:"dto:true"`
|
||||
Id interface{}
|
||||
Passport interface{}
|
||||
Password interface{}
|
||||
Nickname interface{}
|
||||
CreateTime interface{}
|
||||
}
|
||||
data := g.Slice{
|
||||
User{
|
||||
Id: 1,
|
||||
Passport: "user_1",
|
||||
Password: "pass_1",
|
||||
},
|
||||
User{
|
||||
Id: 2,
|
||||
Passport: "user_2",
|
||||
Password: "pass_2",
|
||||
},
|
||||
}
|
||||
result, err := db.Model(table).Data(data).Insert()
|
||||
t.AssertNil(err)
|
||||
n, _ := result.LastInsertId()
|
||||
t.Assert(n, 2)
|
||||
|
||||
one, err := db.Model(table).WherePri(1).One()
|
||||
t.AssertNil(err)
|
||||
t.Assert(one[`id`], `1`)
|
||||
t.Assert(one[`passport`], `user_1`)
|
||||
t.Assert(one[`password`], `pass_1`)
|
||||
t.Assert(one[`nickname`], ``)
|
||||
t.Assert(one[`create_time`], ``)
|
||||
|
||||
one, err = db.Model(table).WherePri(2).One()
|
||||
t.AssertNil(err)
|
||||
t.Assert(one[`id`], `2`)
|
||||
t.Assert(one[`passport`], `user_2`)
|
||||
t.Assert(one[`password`], `pass_2`)
|
||||
t.Assert(one[`nickname`], ``)
|
||||
t.Assert(one[`create_time`], ``)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Model_Update_Data_DTO(t *testing.T) {
|
||||
table := createInitTable()
|
||||
defer dropTable(table)
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
type User struct {
|
||||
g.Meta `orm:"dto:true"`
|
||||
Id interface{}
|
||||
Passport interface{}
|
||||
Password interface{}
|
||||
Nickname interface{}
|
||||
CreateTime interface{}
|
||||
}
|
||||
data := User{
|
||||
Id: 1,
|
||||
Passport: "user_100",
|
||||
Password: "pass_100",
|
||||
}
|
||||
_, err := db.Model(table).Data(data).WherePri(1).Update()
|
||||
t.AssertNil(err)
|
||||
|
||||
one, err := db.Model(table).WherePri(1).One()
|
||||
t.AssertNil(err)
|
||||
t.Assert(one[`id`], `1`)
|
||||
t.Assert(one[`passport`], `user_100`)
|
||||
t.Assert(one[`password`], `pass_100`)
|
||||
t.Assert(one[`nickname`], `name_1`)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Model_Where_DTO(t *testing.T) {
|
||||
table := createInitTable()
|
||||
defer dropTable(table)
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
type User struct {
|
||||
g.Meta `orm:"dto:true"`
|
||||
Id interface{}
|
||||
Passport interface{}
|
||||
Password interface{}
|
||||
Nickname interface{}
|
||||
CreateTime interface{}
|
||||
}
|
||||
where := User{
|
||||
Id: 1,
|
||||
Passport: "user_1",
|
||||
Password: "pass_1",
|
||||
}
|
||||
one, err := db.Model(table).Where(where).One()
|
||||
t.AssertNil(err)
|
||||
t.Assert(one[`id`], `1`)
|
||||
t.Assert(one[`passport`], `user_1`)
|
||||
t.Assert(one[`password`], `pass_1`)
|
||||
t.Assert(one[`nickname`], `name_1`)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Model_Insert_Data_ForDao(t *testing.T) {
|
||||
table := createTable()
|
||||
defer dropTable(table)
|
@ -65,16 +65,17 @@ func (c *Command) Print() {
|
||||
}
|
||||
}
|
||||
for _, cmd := range c.commands {
|
||||
brief := gstr.Replace(cmd.Brief, "\n", "")
|
||||
// Add "..." to brief for those commands that also have sub-commands.
|
||||
if len(cmd.commands) > 0 {
|
||||
cmd.Brief = gstr.TrimRight(cmd.Brief, ".") + "..."
|
||||
brief = gstr.TrimRight(brief, ".") + "..."
|
||||
}
|
||||
var (
|
||||
spaceLength = maxSpaceLength - len(cmd.Name)
|
||||
wordwrapPrefix = gstr.Repeat(" ", len(prefix+cmd.Name)+spaceLength+4)
|
||||
lineStr = fmt.Sprintf(
|
||||
"%s%s%s%s\n",
|
||||
prefix, cmd.Name, gstr.Repeat(" ", spaceLength+4), gstr.Trim(cmd.Brief),
|
||||
prefix, cmd.Name, gstr.Repeat(" ", spaceLength+4), gstr.Trim(brief),
|
||||
)
|
||||
)
|
||||
lineStr = gstr.WordWrap(lineStr, maxLineChars, "\n"+wordwrapPrefix)
|
||||
@ -102,11 +103,12 @@ func (c *Command) Print() {
|
||||
continue
|
||||
}
|
||||
var (
|
||||
brief = gstr.Trim(gstr.Replace(arg.Brief, "\n", ""))
|
||||
spaceLength = maxSpaceLength - len(arg.Name)
|
||||
wordwrapPrefix = gstr.Repeat(" ", len(prefix+arg.Name)+spaceLength+4)
|
||||
lineStr = fmt.Sprintf(
|
||||
"%s%s%s%s\n",
|
||||
prefix, arg.Name, gstr.Repeat(" ", spaceLength+4), gstr.Trim(arg.Brief),
|
||||
prefix, arg.Name, gstr.Repeat(" ", spaceLength+4), brief,
|
||||
)
|
||||
)
|
||||
lineStr = gstr.WordWrap(lineStr, maxLineChars, "\n"+wordwrapPrefix)
|
||||
@ -145,11 +147,12 @@ func (c *Command) Print() {
|
||||
nameStr = fmt.Sprintf("-/--%s", arg.Name)
|
||||
}
|
||||
var (
|
||||
brief = gstr.Trim(gstr.Replace(arg.Brief, "\n", ""))
|
||||
spaceLength = maxSpaceLength - len(nameStr)
|
||||
wordwrapPrefix = gstr.Repeat(" ", len(prefix+nameStr)+spaceLength+4)
|
||||
lineStr = fmt.Sprintf(
|
||||
"%s%s%s%s\n",
|
||||
prefix, nameStr, gstr.Repeat(" ", spaceLength+4), gstr.Trim(arg.Brief),
|
||||
prefix, nameStr, gstr.Repeat(" ", spaceLength+4), brief,
|
||||
)
|
||||
)
|
||||
lineStr = gstr.WordWrap(lineStr, maxLineChars, "\n"+wordwrapPrefix)
|
||||
|
@ -86,15 +86,21 @@ PLATFORMS
|
||||
plan9 386
|
||||
plan9 amd64
|
||||
solaris amd64
|
||||
`
|
||||
commandBuildBriefPack = `
|
||||
destination file path for packed file. if extension of the filename is ".go" and "-n" option is given,
|
||||
it enables packing SRC to go file, or else it packs SRC into a binary file.
|
||||
|
||||
`
|
||||
)
|
||||
|
||||
func init() {
|
||||
gtag.Sets(map[string]string{
|
||||
`commandBuildBrief`: commandBuildBrief,
|
||||
`commandBuildDc`: commandBuildDc,
|
||||
`commandBuildEg`: commandBuildEg,
|
||||
`commandBuildAd`: commandBuildAd,
|
||||
`commandBuildBrief`: commandBuildBrief,
|
||||
`commandBuildDc`: commandBuildDc,
|
||||
`commandBuildEg`: commandBuildEg,
|
||||
`commandBuildAd`: commandBuildAd,
|
||||
`commandBuildBriefPack`: commandBuildBriefPack,
|
||||
})
|
||||
}
|
||||
|
||||
@ -109,7 +115,7 @@ type commandBuildInput struct {
|
||||
Extra string `short:"e" name:"extra" brief:"extra custom \"go build\" options"`
|
||||
Mod string `short:"m" name:"mod" brief:"like \"-mod\" option of \"go build\", use \"-m none\" to disable go module"`
|
||||
Cgo bool `short:"c" name:"cgo" brief:"enable or disable cgo feature, it's disabled in default" orphan:"true"`
|
||||
Pack string `name:"pack" brief:"pack specified folder into temporary go file before building and removes it after built"`
|
||||
Pack string `name:"pack" brief:"{commandBuildBriefPack}"`
|
||||
}
|
||||
type commandBuildOutput struct{}
|
||||
|
||||
|
@ -103,7 +103,7 @@ func ShellRun(cmd string) error {
|
||||
}
|
||||
|
||||
// ShellExec executes given command `cmd` synchronously and returns the command result.
|
||||
func ShellExec(cmd string, environment ...[]string) (string, error) {
|
||||
func ShellExec(cmd string, environment ...[]string) (result string, err error) {
|
||||
var (
|
||||
buf = bytes.NewBuffer(nil)
|
||||
p = NewProcess(
|
||||
@ -114,7 +114,9 @@ func ShellExec(cmd string, environment ...[]string) (string, error) {
|
||||
)
|
||||
p.Stdout = buf
|
||||
p.Stderr = buf
|
||||
return buf.String(), p.Run()
|
||||
err = p.Run()
|
||||
result = buf.String()
|
||||
return
|
||||
}
|
||||
|
||||
// parseCommand parses command `cmd` into slice arguments.
|
||||
|
29
os/gproc/gproc_z_unit_test.go
Normal file
29
os/gproc/gproc_z_unit_test.go
Normal file
@ -0,0 +1,29 @@
|
||||
// Copyright GoFrame 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.
|
||||
|
||||
// go test *.go -bench=".*" -benchmem
|
||||
|
||||
package gproc_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/v2/os/gproc"
|
||||
"github.com/gogf/gf/v2/test/gtest"
|
||||
)
|
||||
|
||||
func Test_ShellExec(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
s, err := gproc.ShellExec(`echo 123`)
|
||||
t.AssertNil(err)
|
||||
t.Assert(s, "123\n")
|
||||
})
|
||||
// error
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
_, err := gproc.ShellExec(`NoneExistCommandCall`)
|
||||
t.AssertNE(err, nil)
|
||||
})
|
||||
}
|
@ -77,6 +77,11 @@ func ScanDirFile(path string, pattern string, recursive ...bool) []*File {
|
||||
return defaultResource.ScanDirFile(path, pattern, recursive...)
|
||||
}
|
||||
|
||||
// Export exports and saves specified path `src` and all its sub files to specified system path `dst` recursively.
|
||||
func Export(src, dst string, option ...ExportOption) error {
|
||||
return defaultResource.Export(src, dst, option...)
|
||||
}
|
||||
|
||||
// Dump prints the files of the default resource object.
|
||||
func Dump() {
|
||||
defaultResource.Dump()
|
||||
|
@ -17,6 +17,7 @@ import (
|
||||
"github.com/gogf/gf/v2/internal/intlog"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
)
|
||||
|
||||
type Resource struct {
|
||||
@ -224,12 +225,56 @@ func (r *Resource) doScanDir(path string, pattern string, recursive bool, onlyFi
|
||||
return files
|
||||
}
|
||||
|
||||
// ExportOption is the option for function Export.
|
||||
type ExportOption struct {
|
||||
RemovePrefix string // Remove the prefix of file name from resource.
|
||||
}
|
||||
|
||||
// Export exports and saves specified path `srcPath` and all its sub files to specified system path `dstPath` recursively.
|
||||
func (r *Resource) Export(src, dst string, option ...ExportOption) error {
|
||||
var (
|
||||
err error
|
||||
name string
|
||||
path string
|
||||
exportOption ExportOption
|
||||
files = r.doScanDir(src, "*", true, false)
|
||||
)
|
||||
if len(option) > 0 {
|
||||
exportOption = option[0]
|
||||
}
|
||||
for _, file := range files {
|
||||
name = file.Name()
|
||||
if exportOption.RemovePrefix != "" {
|
||||
name = gstr.TrimLeftStr(name, exportOption.RemovePrefix)
|
||||
}
|
||||
name = gstr.Trim(name, `\/`)
|
||||
if name == "" {
|
||||
continue
|
||||
}
|
||||
path = gfile.Join(dst, name)
|
||||
if file.FileInfo().IsDir() {
|
||||
err = gfile.Mkdir(path)
|
||||
} else {
|
||||
err = gfile.PutBytes(path, file.Content())
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Dump prints the files of current resource object.
|
||||
func (r *Resource) Dump() {
|
||||
var info os.FileInfo
|
||||
r.tree.Iterator(func(key, value interface{}) bool {
|
||||
info = value.(*File).FileInfo()
|
||||
fmt.Printf("%v %7s %s\n", gtime.New(info.ModTime()).ISO8601(), gfile.FormatSize(info.Size()), key)
|
||||
fmt.Printf(
|
||||
"%v %7s %s\n",
|
||||
gtime.New(info.ModTime()).ISO8601(),
|
||||
gfile.FormatSize(info.Size()),
|
||||
key,
|
||||
)
|
||||
return true
|
||||
})
|
||||
fmt.Printf("TOTAL FILES: %d\n", r.tree.Size())
|
||||
|
@ -7,11 +7,11 @@
|
||||
package gres_test
|
||||
|
||||
import (
|
||||
_ "github.com/gogf/gf/v2/os/gres/testdata/data"
|
||||
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
_ "github.com/gogf/gf/v2/os/gres/testdata/data"
|
||||
|
||||
"github.com/gogf/gf/v2/debug/gdebug"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
@ -231,3 +231,40 @@ func Test_ScanDirFile(t *testing.T) {
|
||||
t.Assert(files[0].Content(), "sub-test2 content")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Export(t *testing.T) {
|
||||
gres.Dump()
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
src = `template`
|
||||
dst = gfile.TempDir(gtime.TimestampNanoStr())
|
||||
err = gres.Export(src, dst)
|
||||
)
|
||||
defer gfile.Remove(dst)
|
||||
t.AssertNil(err)
|
||||
files, err := gfile.ScanDir(dst, "*", true)
|
||||
t.AssertNil(err)
|
||||
t.Assert(len(files), 14)
|
||||
|
||||
name := `template/index.html`
|
||||
t.Assert(gfile.GetContents(gfile.Join(dst, name)), gres.GetContent(name))
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
src = `template`
|
||||
dst = gfile.TempDir(gtime.TimestampNanoStr())
|
||||
err = gres.Export(src, dst, gres.ExportOption{
|
||||
RemovePrefix: `template`,
|
||||
})
|
||||
)
|
||||
defer gfile.Remove(dst)
|
||||
t.AssertNil(err)
|
||||
files, err := gfile.ScanDir(dst, "*", true)
|
||||
t.AssertNil(err)
|
||||
t.Assert(len(files), 13)
|
||||
|
||||
nameInRes := `template/index.html`
|
||||
nameInSys := `index.html`
|
||||
t.Assert(gfile.GetContents(gfile.Join(dst, nameInSys)), gres.GetContent(nameInRes))
|
||||
})
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user