mirror of
https://gitee.com/johng/gf
synced 2026-06-10 03:23:59 +08:00
Compare commits
18 Commits
contrib/dr
...
v2.6.1
| Author | SHA1 | Date | |
|---|---|---|---|
| 85d95e3e27 | |||
| 4cce8557e6 | |||
| d60d7674d7 | |||
| 7f9467d1f8 | |||
| d08e3ef838 | |||
| 645c5ff5b5 | |||
| 7975e391f0 | |||
| 565790036e | |||
| 44819b135e | |||
| bb19877430 | |||
| fc02e06423 | |||
| dd8a5dcf32 | |||
| 33584506ab | |||
| ee2cf92479 | |||
| 0b6dd6fb13 | |||
| 993467bb3c | |||
| c7c9f0011a | |||
| 9aa872e705 |
2
.github/workflows/golangci-lint.yml
vendored
2
.github/workflows/golangci-lint.yml
vendored
@ -36,7 +36,7 @@ jobs:
|
||||
golangci:
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [ '1.18','1.19','1.20','1.21' ]
|
||||
go-version: [ '1.18','1.19','1.20','1.21.4' ]
|
||||
name: golangci-lint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
@ -9,6 +9,15 @@
|
||||
[](https://codecov.io/gh/gogf/gf)
|
||||
[](https://github.com/gogf/gf)
|
||||
[](https://github.com/gogf/gf)
|
||||
|
||||
[](https://github.com/gogf/gf/releases)
|
||||
[](https://github.com/gogf/gf/pulls)
|
||||
[](https://github.com/gogf/gf/pulls?q=is%3Apr+is%3Aclosed)
|
||||
[](https://github.com/gogf/gf/issues)
|
||||
[](https://github.com/gogf/gf/issues?q=is%3Aissue+is%3Aclosed)
|
||||

|
||||

|
||||
|
||||
</div>
|
||||
|
||||
`GoFrame` is a modular, powerful, high-performance and enterprise-class application development framework of Golang.
|
||||
|
||||
@ -7,20 +7,21 @@
|
||||
package gfcmd
|
||||
|
||||
import (
|
||||
_ "github.com/gogf/gf/cmd/gf/v2/internal/packed"
|
||||
"context"
|
||||
"runtime"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gcode"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/cmd"
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/allyes"
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gcfg"
|
||||
"github.com/gogf/gf/v2/os/gcmd"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/cmd"
|
||||
_ "github.com/gogf/gf/cmd/gf/v2/internal/packed"
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/allyes"
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -99,6 +100,9 @@ func GetCommand(ctx context.Context) (*Command, error) {
|
||||
|
||||
// zsh alias "git fetch" conflicts checks.
|
||||
func handleZshAlias() {
|
||||
if runtime.GOOS == "windows" {
|
||||
return
|
||||
}
|
||||
if home, err := gfile.Home(); err == nil {
|
||||
zshPath := gfile.Join(home, ".zshrc")
|
||||
if gfile.Exists(zshPath) {
|
||||
|
||||
@ -3,14 +3,14 @@ module github.com/gogf/gf/cmd/gf/v2
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/gogf/gf/contrib/drivers/clickhouse/v2 v2.5.7
|
||||
github.com/gogf/gf/contrib/drivers/mssql/v2 v2.5.7
|
||||
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.5.7
|
||||
github.com/gogf/gf/contrib/drivers/oracle/v2 v2.5.7
|
||||
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.5.7
|
||||
github.com/gogf/gf/contrib/drivers/sqlite/v2 v2.5.7
|
||||
github.com/gogf/gf/v2 v2.5.7
|
||||
github.com/minio/selfupdate v0.6.0
|
||||
github.com/gogf/gf/contrib/drivers/clickhouse/v2 v2.6.1
|
||||
github.com/gogf/gf/contrib/drivers/mssql/v2 v2.6.1
|
||||
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.6.1
|
||||
github.com/gogf/gf/contrib/drivers/oracle/v2 v2.6.1
|
||||
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.6.1
|
||||
github.com/gogf/gf/contrib/drivers/sqlite/v2 v2.6.1
|
||||
github.com/gogf/gf/v2 v2.6.1
|
||||
github.com/gogf/selfupdate v0.0.0-20231215043001-5c48c528462f
|
||||
github.com/olekukonko/tablewriter v0.0.5
|
||||
golang.org/x/mod v0.9.0
|
||||
golang.org/x/tools v0.7.0
|
||||
|
||||
@ -38,20 +38,8 @@ github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiU
|
||||
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
|
||||
github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
||||
github.com/gogf/gf/contrib/drivers/clickhouse/v2 v2.5.6 h1:yziPSf9AycEWphv9WiNjcRAVPOJtUauMMvP6pHQB4jY=
|
||||
github.com/gogf/gf/contrib/drivers/clickhouse/v2 v2.5.6/go.mod h1:yOlpwhFXgW+P2sf4goA20PUtxdVLliBx4dJRyJeOtto=
|
||||
github.com/gogf/gf/contrib/drivers/mssql/v2 v2.5.6 h1:LGQIe5IvYVr4hZ/vUAFiqWssxE7QeILyVPJ9swo1Cmk=
|
||||
github.com/gogf/gf/contrib/drivers/mssql/v2 v2.5.6/go.mod h1:EcF8v8jqCV61/YqN6DXxdo3kh8waGmEj6WpFqbLkkrM=
|
||||
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.5.6 h1:oR9F4LVoKa/fjf/o6Y/CQRNiYy35Bszo07WwvMWYMxo=
|
||||
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.5.6/go.mod h1:gvHSRqCpv2c+N0gDHsEldHgU/yM9tcCBdIEKZ32/TaE=
|
||||
github.com/gogf/gf/contrib/drivers/oracle/v2 v2.5.6 h1:3Y3lEoO9SoG1AmfaKjgTsDt93+T2q/qTMog8wBvIIGM=
|
||||
github.com/gogf/gf/contrib/drivers/oracle/v2 v2.5.6/go.mod h1:cR3lFoU6ZtSaMQ3DpCJwWnYW6EvHPYGGeqv/kzgH4gw=
|
||||
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.5.6 h1:0WHVzqITqIBu/NNPXt3tN2eiWAGiNjs9sg6wh+WbUvY=
|
||||
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.5.6/go.mod h1:qZCTNQ0n2gHcuBwM9wUl3pelync3xK0gTnChJZD6f0I=
|
||||
github.com/gogf/gf/contrib/drivers/sqlite/v2 v2.5.6 h1:6clfLvFoHXHdw+skmXg4yxw+cLwgAG8gRiS/6f9Y9Xc=
|
||||
github.com/gogf/gf/contrib/drivers/sqlite/v2 v2.5.6/go.mod h1:QV6Rrj+4G4OaJVkP9XXRZ1LWL+ls6qH7ebeMcxsulqA=
|
||||
github.com/gogf/gf/v2 v2.5.6 h1:a1UK1yUP3s+l+vPxmV91+8gTarAP9b1IEOw0W7LNl6E=
|
||||
github.com/gogf/gf/v2 v2.5.6/go.mod h1:17K/gBYrp0bHGC3XYC7bSPoywmZ6MrZHrZakTfh4eIQ=
|
||||
github.com/gogf/selfupdate v0.0.0-20231215043001-5c48c528462f h1:7xfXR/BhG3JDqO1s45n65Oyx9t4E/UqDOXep6jXdLCM=
|
||||
github.com/gogf/selfupdate v0.0.0-20231215043001-5c48c528462f/go.mod h1:HnYoio6S7VaFJdryKcD/r9HgX+4QzYfr00XiXUo/xz0=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||
@ -87,8 +75,6 @@ github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m
|
||||
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
||||
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/minio/selfupdate v0.6.0 h1:i76PgT0K5xO9+hjzKcacQtO7+MjJ4JKA8Ak8XQ9DDwU=
|
||||
github.com/minio/selfupdate v0.6.0/go.mod h1:bO02GTIPCMQFTEvE5h4DjYB58bCoZ35XLeBf0buTDdM=
|
||||
github.com/mkevac/debugcharts v0.0.0-20191222103121-ae1c48aa8615/go.mod h1:Ad7oeElCZqA1Ufj0U9/liOF4BtVepxRcTvr2ey7zTvM=
|
||||
github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8=
|
||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||
@ -140,7 +126,6 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20211209193657-4570a0811e8b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||
|
||||
@ -82,11 +82,11 @@ func init() {
|
||||
type (
|
||||
cRunInput struct {
|
||||
g.Meta `name:"run"`
|
||||
File string `name:"FILE" arg:"true" brief:"{cRunFileBrief}" v:"required"`
|
||||
Path string `name:"path" short:"p" brief:"{cRunPathBrief}" d:"./"`
|
||||
Extra string `name:"extra" short:"e" brief:"{cRunExtraBrief}"`
|
||||
Args string `name:"args" short:"a" brief:"{cRunArgsBrief}"`
|
||||
WatchPaths string `name:"watchPaths" short:"w" brief:"{cRunWatchPathsBrief}"`
|
||||
File string `name:"FILE" arg:"true" brief:"{cRunFileBrief}" v:"required"`
|
||||
Path string `name:"path" short:"p" brief:"{cRunPathBrief}" d:"./"`
|
||||
Extra string `name:"extra" short:"e" brief:"{cRunExtraBrief}"`
|
||||
Args string `name:"args" short:"a" brief:"{cRunArgsBrief}"`
|
||||
WatchPaths []string `name:"watchPaths" short:"w" brief:"{cRunWatchPathsBrief}"`
|
||||
}
|
||||
cRunOutput struct{}
|
||||
)
|
||||
@ -97,12 +97,16 @@ func (c cRun) Index(ctx context.Context, in cRunInput) (out *cRunOutput, err err
|
||||
mlog.Fatalf(`command "go" not found in your environment, please install golang first to proceed this command`)
|
||||
}
|
||||
|
||||
if len(in.WatchPaths) == 1 {
|
||||
in.WatchPaths = strings.Split(in.WatchPaths[0], ",")
|
||||
}
|
||||
|
||||
app := &cRunApp{
|
||||
File: in.File,
|
||||
Path: in.Path,
|
||||
Options: in.Extra,
|
||||
Args: in.Args,
|
||||
WatchPaths: strings.Split(in.WatchPaths, ","),
|
||||
WatchPaths: in.WatchPaths,
|
||||
}
|
||||
dirty := gtype.NewBool()
|
||||
_, err = gfsnotify.Add(gfile.RealPath("."), func(event *gfsnotify.Event) {
|
||||
|
||||
@ -11,7 +11,7 @@ import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
|
||||
"github.com/minio/selfupdate"
|
||||
"github.com/gogf/selfupdate"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils"
|
||||
|
||||
@ -6,6 +6,33 @@
|
||||
|
||||
package cmd
|
||||
|
||||
import "context"
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
var ctx = context.Background()
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/test/gtest"
|
||||
)
|
||||
|
||||
var (
|
||||
ctx = context.Background()
|
||||
testDB gdb.DB
|
||||
link = "mysql:root:12345678@tcp(127.0.0.1:3306)/test?loc=Local&parseTime=true"
|
||||
)
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
testDB, err = gdb.New(gdb.ConfigNode{
|
||||
Link: link,
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,7 +12,6 @@ import (
|
||||
"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"
|
||||
@ -20,22 +19,11 @@ import (
|
||||
"github.com/gogf/gf/v2/util/gutil"
|
||||
)
|
||||
|
||||
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 (
|
||||
err error
|
||||
db = testDB
|
||||
table = "table_user"
|
||||
sqlContent = fmt.Sprintf(
|
||||
gtest.DataContent(`gendao`, `user.tpl.sql`),
|
||||
@ -123,14 +111,10 @@ func Test_Gen_Dao_Default(t *testing.T) {
|
||||
}
|
||||
|
||||
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 (
|
||||
err error
|
||||
db = testDB
|
||||
table = "table_user"
|
||||
sqlContent = fmt.Sprintf(
|
||||
gtest.DataContent(`gendao`, `user.tpl.sql`),
|
||||
|
||||
70
cmd/gf/internal/cmd/cmd_z_unit_gen_pbentity_test.go
Normal file
70
cmd/gf/internal/cmd/cmd_z_unit_gen_pbentity_test.go
Normal file
@ -0,0 +1,70 @@
|
||||
// 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"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/v2/os/gcmd"
|
||||
"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"
|
||||
)
|
||||
|
||||
func Test_Gen_Pbentity_NameCase(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
err error
|
||||
db = testDB
|
||||
table = "table_user"
|
||||
sqlContent = fmt.Sprintf(
|
||||
gtest.DataContent(`genpbentity`, `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())
|
||||
err = gfile.Mkdir(path)
|
||||
t.AssertNil(err)
|
||||
defer gfile.Remove(path)
|
||||
|
||||
root, err := gcmd.NewFromObject(GF)
|
||||
t.AssertNil(err)
|
||||
err = root.AddObject(
|
||||
Gen,
|
||||
)
|
||||
t.AssertNil(err)
|
||||
os.Args = []string{"gf", "gen", "pbentity", "-l", link, "-p", path, "-package=unittest", "-nameCase=SnakeScreaming"}
|
||||
|
||||
err = root.RunWithError(ctx)
|
||||
t.AssertNil(err)
|
||||
|
||||
files := []string{
|
||||
filepath.FromSlash(path + "/table_user.proto"),
|
||||
}
|
||||
|
||||
testPath := gtest.DataPath("genpbentity", "generated_user")
|
||||
expectFiles := []string{
|
||||
filepath.FromSlash(testPath + "/table_user.proto"),
|
||||
}
|
||||
// check files content
|
||||
for i := range files {
|
||||
t.Assert(gfile.GetContents(files[i]), gfile.GetContents(expectFiles[i]))
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -74,7 +74,7 @@ type (
|
||||
SdkStdVersion bool `short:"v" name:"sdkStdVersion" brief:"{CGenCtrlBriefSdkStdVersion}" orphan:"true"`
|
||||
SdkNoV1 bool `short:"n" name:"sdkNoV1" brief:"{CGenCtrlBriefSdkNoV1}" orphan:"true"`
|
||||
Clear bool `short:"c" name:"clear" brief:"{CGenCtrlBriefClear}" orphan:"true"`
|
||||
Merge bool `short:"m" name:"merge" brief:"{CGenCtrlControllerMerge}" orphan:"true"`
|
||||
Merge bool `short:"m" name:"merge" brief:"{CGenCtrlControllerMerge}" orphan:"true"`
|
||||
}
|
||||
CGenCtrlOutput struct{}
|
||||
)
|
||||
|
||||
@ -59,28 +59,29 @@ CONFIGURATION SUPPORT
|
||||
numeric:
|
||||
type: string
|
||||
`
|
||||
CGenDaoBriefPath = `directory path for generated files`
|
||||
CGenDaoBriefLink = `database configuration, the same as the ORM configuration of GoFrame`
|
||||
CGenDaoBriefTables = `generate models only for given tables, multiple table names separated with ','`
|
||||
CGenDaoBriefTablesEx = `generate models excluding given tables, multiple table names separated with ','`
|
||||
CGenDaoBriefPrefix = `add prefix for all table of specified link/database tables`
|
||||
CGenDaoBriefRemovePrefix = `remove specified prefix of the table, multiple prefix separated with ','`
|
||||
CGenDaoBriefStdTime = `use time.Time from stdlib instead of gtime.Time for generated time/date fields of tables`
|
||||
CGenDaoBriefWithTime = `add created time for auto produced go files`
|
||||
CGenDaoBriefGJsonSupport = `use gJsonSupport to use *gjson.Json instead of string for generated json fields of tables`
|
||||
CGenDaoBriefImportPrefix = `custom import prefix for generated go files`
|
||||
CGenDaoBriefDaoPath = `directory path for storing generated dao files under path`
|
||||
CGenDaoBriefDoPath = `directory path for storing generated do files under path`
|
||||
CGenDaoBriefEntityPath = `directory path for storing generated entity files under path`
|
||||
CGenDaoBriefOverwriteDao = `overwrite all dao files both inside/outside internal folder`
|
||||
CGenDaoBriefModelFile = `custom file name for storing generated model content`
|
||||
CGenDaoBriefModelFileForDao = `custom file name generating model for DAO operations like Where/Data. It's empty in default`
|
||||
CGenDaoBriefDescriptionTag = `add comment to description tag for each field`
|
||||
CGenDaoBriefNoJsonTag = `no json tag will be added for each field`
|
||||
CGenDaoBriefNoModelComment = `no model comment will be added for each field`
|
||||
CGenDaoBriefClear = `delete all generated go files that do not exist in database`
|
||||
CGenDaoBriefTypeMapping = `custom local type mapping for generated struct attributes relevant to fields of table`
|
||||
CGenDaoBriefGroup = `
|
||||
CGenDaoBriefPath = `directory path for generated files`
|
||||
CGenDaoBriefLink = `database configuration, the same as the ORM configuration of GoFrame`
|
||||
CGenDaoBriefTables = `generate models only for given tables, multiple table names separated with ','`
|
||||
CGenDaoBriefTablesEx = `generate models excluding given tables, multiple table names separated with ','`
|
||||
CGenDaoBriefPrefix = `add prefix for all table of specified link/database tables`
|
||||
CGenDaoBriefRemovePrefix = `remove specified prefix of the table, multiple prefix separated with ','`
|
||||
CGenDaoBriefRemoveFieldPrefix = `remove specified prefix of the field, multiple prefix separated with ','`
|
||||
CGenDaoBriefStdTime = `use time.Time from stdlib instead of gtime.Time for generated time/date fields of tables`
|
||||
CGenDaoBriefWithTime = `add created time for auto produced go files`
|
||||
CGenDaoBriefGJsonSupport = `use gJsonSupport to use *gjson.Json instead of string for generated json fields of tables`
|
||||
CGenDaoBriefImportPrefix = `custom import prefix for generated go files`
|
||||
CGenDaoBriefDaoPath = `directory path for storing generated dao files under path`
|
||||
CGenDaoBriefDoPath = `directory path for storing generated do files under path`
|
||||
CGenDaoBriefEntityPath = `directory path for storing generated entity files under path`
|
||||
CGenDaoBriefOverwriteDao = `overwrite all dao files both inside/outside internal folder`
|
||||
CGenDaoBriefModelFile = `custom file name for storing generated model content`
|
||||
CGenDaoBriefModelFileForDao = `custom file name generating model for DAO operations like Where/Data. It's empty in default`
|
||||
CGenDaoBriefDescriptionTag = `add comment to description tag for each field`
|
||||
CGenDaoBriefNoJsonTag = `no json tag will be added for each field`
|
||||
CGenDaoBriefNoModelComment = `no model comment will be added for each field`
|
||||
CGenDaoBriefClear = `delete all generated go files that do not exist in database`
|
||||
CGenDaoBriefTypeMapping = `custom local type mapping for generated struct attributes relevant to fields of table`
|
||||
CGenDaoBriefGroup = `
|
||||
specifying the configuration group name of database for generated ORM instance,
|
||||
it's not necessary and the default value is "default"
|
||||
`
|
||||
@ -145,6 +146,7 @@ func init() {
|
||||
`CGenDaoBriefTablesEx`: CGenDaoBriefTablesEx,
|
||||
`CGenDaoBriefPrefix`: CGenDaoBriefPrefix,
|
||||
`CGenDaoBriefRemovePrefix`: CGenDaoBriefRemovePrefix,
|
||||
`CGenDaoBriefRemoveFieldPrefix`: CGenDaoBriefRemoveFieldPrefix,
|
||||
`CGenDaoBriefStdTime`: CGenDaoBriefStdTime,
|
||||
`CGenDaoBriefWithTime`: CGenDaoBriefWithTime,
|
||||
`CGenDaoBriefDaoPath`: CGenDaoBriefDaoPath,
|
||||
@ -180,6 +182,7 @@ type (
|
||||
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}"`
|
||||
RemoveFieldPrefix string `name:"removeFieldPrefix" short:"rf" brief:"{CGenDaoBriefRemoveFieldPrefix}"`
|
||||
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"`
|
||||
|
||||
@ -138,6 +138,7 @@ type generateDaoInternalInput struct {
|
||||
|
||||
func generateDaoInternal(in generateDaoInternalInput) {
|
||||
path := filepath.FromSlash(gfile.Join(in.DirPathDaoInternal, in.FileName+".go"))
|
||||
removeFieldPrefixArray := gstr.SplitAndTrim(in.RemoveFieldPrefix, ",")
|
||||
modelContent := gstr.ReplaceByMap(
|
||||
getTemplateFromPathOrDefault(in.TplDaoInternalPath, consts.TemplateGenDaoInternalContent),
|
||||
g.MapStrStr{
|
||||
@ -146,8 +147,8 @@ func generateDaoInternal(in generateDaoInternalInput) {
|
||||
tplVarGroupName: in.Group,
|
||||
tplVarTableNameCamelCase: in.TableNameCamelCase,
|
||||
tplVarTableNameCamelLowerCase: in.TableNameCamelLowerCase,
|
||||
tplVarColumnDefine: gstr.Trim(generateColumnDefinitionForDao(in.FieldMap)),
|
||||
tplVarColumnNames: gstr.Trim(generateColumnNamesForDao(in.FieldMap)),
|
||||
tplVarColumnDefine: gstr.Trim(generateColumnDefinitionForDao(in.FieldMap, removeFieldPrefixArray)),
|
||||
tplVarColumnNames: gstr.Trim(generateColumnNamesForDao(in.FieldMap, removeFieldPrefixArray)),
|
||||
})
|
||||
modelContent = replaceDefaultVar(in.CGenDaoInternalInput, modelContent)
|
||||
if err := gfile.PutContents(path, strings.TrimSpace(modelContent)); err != nil {
|
||||
@ -160,16 +161,23 @@ func generateDaoInternal(in generateDaoInternalInput) {
|
||||
|
||||
// generateColumnNamesForDao generates and returns the column names assignment content of column struct
|
||||
// for specified table.
|
||||
func generateColumnNamesForDao(fieldMap map[string]*gdb.TableField) string {
|
||||
func generateColumnNamesForDao(fieldMap map[string]*gdb.TableField, removeFieldPrefixArray []string) string {
|
||||
var (
|
||||
buffer = bytes.NewBuffer(nil)
|
||||
array = make([][]string, len(fieldMap))
|
||||
names = sortFieldKeyForDao(fieldMap)
|
||||
)
|
||||
|
||||
for index, name := range names {
|
||||
field := fieldMap[name]
|
||||
|
||||
newFiledName := field.Name
|
||||
for _, v := range removeFieldPrefixArray {
|
||||
newFiledName = gstr.TrimLeftStr(newFiledName, v, 1)
|
||||
}
|
||||
|
||||
array[index] = []string{
|
||||
" #" + gstr.CaseCamel(field.Name) + ":",
|
||||
" #" + gstr.CaseCamel(newFiledName) + ":",
|
||||
fmt.Sprintf(` #"%s",`, field.Name),
|
||||
}
|
||||
}
|
||||
@ -189,12 +197,13 @@ func generateColumnNamesForDao(fieldMap map[string]*gdb.TableField) string {
|
||||
}
|
||||
|
||||
// generateColumnDefinitionForDao generates and returns the column names definition for specified table.
|
||||
func generateColumnDefinitionForDao(fieldMap map[string]*gdb.TableField) string {
|
||||
func generateColumnDefinitionForDao(fieldMap map[string]*gdb.TableField, removeFieldPrefixArray []string) string {
|
||||
var (
|
||||
buffer = bytes.NewBuffer(nil)
|
||||
array = make([][]string, len(fieldMap))
|
||||
names = sortFieldKeyForDao(fieldMap)
|
||||
)
|
||||
|
||||
for index, name := range names {
|
||||
var (
|
||||
field = fieldMap[name]
|
||||
@ -203,8 +212,12 @@ func generateColumnDefinitionForDao(fieldMap map[string]*gdb.TableField) string
|
||||
"\r", " ",
|
||||
}))
|
||||
)
|
||||
newFiledName := field.Name
|
||||
for _, v := range removeFieldPrefixArray {
|
||||
newFiledName = gstr.TrimLeftStr(newFiledName, v, 1)
|
||||
}
|
||||
array[index] = []string{
|
||||
" #" + gstr.CaseCamel(field.Name),
|
||||
" #" + gstr.CaseCamel(newFiledName),
|
||||
" # " + "string",
|
||||
" #" + fmt.Sprintf(`// %s`, comment),
|
||||
}
|
||||
|
||||
@ -126,8 +126,13 @@ func generateStructFieldDefinition(
|
||||
tagKey = "`"
|
||||
descriptionTag = gstr.Replace(formatComment(field.Comment), `"`, `\"`)
|
||||
)
|
||||
removeFieldPrefixArray := gstr.SplitAndTrim(in.RemoveFieldPrefix, ",")
|
||||
newFiledName := field.Name
|
||||
for _, v := range removeFieldPrefixArray {
|
||||
newFiledName = gstr.TrimLeftStr(newFiledName, v, 1)
|
||||
}
|
||||
attrLines = []string{
|
||||
" #" + gstr.CaseCamel(field.Name),
|
||||
" #" + gstr.CaseCamel(newFiledName),
|
||||
" #" + localTypeNameStr,
|
||||
}
|
||||
attrLines = append(attrLines, " #"+fmt.Sprintf(tagKey+`json:"%s"`, jsonTag))
|
||||
|
||||
@ -31,16 +31,17 @@ import (
|
||||
type (
|
||||
CGenPbEntity struct{}
|
||||
CGenPbEntityInput struct {
|
||||
g.Meta `name:"pbentity" config:"{CGenPbEntityConfig}" brief:"{CGenPbEntityBrief}" eg:"{CGenPbEntityEg}" ad:"{CGenPbEntityAd}"`
|
||||
Path string `name:"path" short:"p" brief:"{CGenPbEntityBriefPath}" d:"manifest/protobuf/pbentity"`
|
||||
Package string `name:"package" short:"k" brief:"{CGenPbEntityBriefPackage}"`
|
||||
Link string `name:"link" short:"l" brief:"{CGenPbEntityBriefLink}"`
|
||||
Tables string `name:"tables" short:"t" brief:"{CGenPbEntityBriefTables}"`
|
||||
Prefix string `name:"prefix" short:"f" brief:"{CGenPbEntityBriefPrefix}"`
|
||||
RemovePrefix string `name:"removePrefix" short:"r" brief:"{CGenPbEntityBriefRemovePrefix}"`
|
||||
NameCase string `name:"nameCase" short:"n" brief:"{CGenPbEntityBriefNameCase}" d:"Camel"`
|
||||
JsonCase string `name:"jsonCase" short:"j" brief:"{CGenPbEntityBriefJsonCase}" d:"CamelLower"`
|
||||
Option string `name:"option" short:"o" brief:"{CGenPbEntityBriefOption}"`
|
||||
g.Meta `name:"pbentity" config:"{CGenPbEntityConfig}" brief:"{CGenPbEntityBrief}" eg:"{CGenPbEntityEg}" ad:"{CGenPbEntityAd}"`
|
||||
Path string `name:"path" short:"p" brief:"{CGenPbEntityBriefPath}" d:"manifest/protobuf/pbentity"`
|
||||
Package string `name:"package" short:"k" brief:"{CGenPbEntityBriefPackage}"`
|
||||
Link string `name:"link" short:"l" brief:"{CGenPbEntityBriefLink}"`
|
||||
Tables string `name:"tables" short:"t" brief:"{CGenPbEntityBriefTables}"`
|
||||
Prefix string `name:"prefix" short:"f" brief:"{CGenPbEntityBriefPrefix}"`
|
||||
RemovePrefix string `name:"removePrefix" short:"r" brief:"{CGenPbEntityBriefRemovePrefix}"`
|
||||
RemoveFieldPrefix string `name:"removeFieldPrefix" short:"rf" brief:"{CGenPbEntityBriefRemoveFieldPrefix}"`
|
||||
NameCase string `name:"nameCase" short:"n" brief:"{CGenPbEntityBriefNameCase}" d:"Camel"`
|
||||
JsonCase string `name:"jsonCase" short:"j" brief:"{CGenPbEntityBriefJsonCase}" d:"none"`
|
||||
Option string `name:"option" short:"o" brief:"{CGenPbEntityBriefOption}"`
|
||||
}
|
||||
CGenPbEntityOutput struct{}
|
||||
|
||||
@ -87,14 +88,15 @@ CONFIGURATION SUPPORT
|
||||
option java_package = "protobuf/demos";
|
||||
option php_namespace = "protobuf/demos";
|
||||
`
|
||||
CGenPbEntityBriefPath = `directory path for generated files storing`
|
||||
CGenPbEntityBriefPackage = `package path for all entity proto files`
|
||||
CGenPbEntityBriefLink = `database configuration, the same as the ORM configuration of GoFrame`
|
||||
CGenPbEntityBriefTables = `generate models only for given tables, multiple table names separated with ','`
|
||||
CGenPbEntityBriefPrefix = `add specified prefix for all entity names and entity proto files`
|
||||
CGenPbEntityBriefRemovePrefix = `remove specified prefix of the table, multiple prefix separated with ','`
|
||||
CGenPbEntityBriefOption = `extra protobuf options`
|
||||
CGenPbEntityBriefGroup = `
|
||||
CGenPbEntityBriefPath = `directory path for generated files storing`
|
||||
CGenPbEntityBriefPackage = `package path for all entity proto files`
|
||||
CGenPbEntityBriefLink = `database configuration, the same as the ORM configuration of GoFrame`
|
||||
CGenPbEntityBriefTables = `generate models only for given tables, multiple table names separated with ','`
|
||||
CGenPbEntityBriefPrefix = `add specified prefix for all entity names and entity proto files`
|
||||
CGenPbEntityBriefRemovePrefix = `remove specified prefix of the table, multiple prefix separated with ','`
|
||||
CGenPbEntityBriefRemoveFieldPrefix = `remove specified prefix of the field, multiple prefix separated with ','`
|
||||
CGenPbEntityBriefOption = `extra protobuf options`
|
||||
CGenPbEntityBriefGroup = `
|
||||
specifying the configuration group name of database for generated ORM instance,
|
||||
it's not necessary and the default value is "default"
|
||||
`
|
||||
@ -120,20 +122,21 @@ set it to "none" to ignore json tag generating.
|
||||
|
||||
func init() {
|
||||
gtag.Sets(g.MapStrStr{
|
||||
`CGenPbEntityConfig`: CGenPbEntityConfig,
|
||||
`CGenPbEntityBrief`: CGenPbEntityBrief,
|
||||
`CGenPbEntityEg`: CGenPbEntityEg,
|
||||
`CGenPbEntityAd`: CGenPbEntityAd,
|
||||
`CGenPbEntityBriefPath`: CGenPbEntityBriefPath,
|
||||
`CGenPbEntityBriefPackage`: CGenPbEntityBriefPackage,
|
||||
`CGenPbEntityBriefLink`: CGenPbEntityBriefLink,
|
||||
`CGenPbEntityBriefTables`: CGenPbEntityBriefTables,
|
||||
`CGenPbEntityBriefPrefix`: CGenPbEntityBriefPrefix,
|
||||
`CGenPbEntityBriefRemovePrefix`: CGenPbEntityBriefRemovePrefix,
|
||||
`CGenPbEntityBriefGroup`: CGenPbEntityBriefGroup,
|
||||
`CGenPbEntityBriefNameCase`: CGenPbEntityBriefNameCase,
|
||||
`CGenPbEntityBriefJsonCase`: CGenPbEntityBriefJsonCase,
|
||||
`CGenPbEntityBriefOption`: CGenPbEntityBriefOption,
|
||||
`CGenPbEntityConfig`: CGenPbEntityConfig,
|
||||
`CGenPbEntityBrief`: CGenPbEntityBrief,
|
||||
`CGenPbEntityEg`: CGenPbEntityEg,
|
||||
`CGenPbEntityAd`: CGenPbEntityAd,
|
||||
`CGenPbEntityBriefPath`: CGenPbEntityBriefPath,
|
||||
`CGenPbEntityBriefPackage`: CGenPbEntityBriefPackage,
|
||||
`CGenPbEntityBriefLink`: CGenPbEntityBriefLink,
|
||||
`CGenPbEntityBriefTables`: CGenPbEntityBriefTables,
|
||||
`CGenPbEntityBriefPrefix`: CGenPbEntityBriefPrefix,
|
||||
`CGenPbEntityBriefRemovePrefix`: CGenPbEntityBriefRemovePrefix,
|
||||
`CGenPbEntityBriefRemoveFieldPrefix`: CGenPbEntityBriefRemoveFieldPrefix,
|
||||
`CGenPbEntityBriefGroup`: CGenPbEntityBriefGroup,
|
||||
`CGenPbEntityBriefNameCase`: CGenPbEntityBriefNameCase,
|
||||
`CGenPbEntityBriefJsonCase`: CGenPbEntityBriefJsonCase,
|
||||
`CGenPbEntityBriefOption`: CGenPbEntityBriefOption,
|
||||
})
|
||||
}
|
||||
|
||||
@ -339,6 +342,7 @@ func generateMessageFieldForPbEntity(index int, field *gdb.TableField, in CGenPb
|
||||
comment = gstr.Replace(comment, `\n`, " ")
|
||||
comment, _ = gregex.ReplaceString(`\s{2,}`, ` `, comment)
|
||||
if jsonTagName := formatCase(field.Name, in.JsonCase); jsonTagName != "" {
|
||||
jsonTagStr = fmt.Sprintf(`[json_name = "%s"]`, jsonTagName)
|
||||
// beautiful indent.
|
||||
if index < 10 {
|
||||
// 3 spaces
|
||||
@ -351,9 +355,16 @@ func generateMessageFieldForPbEntity(index int, field *gdb.TableField, in CGenPb
|
||||
jsonTagStr = " " + jsonTagStr
|
||||
}
|
||||
}
|
||||
|
||||
removeFieldPrefixArray := gstr.SplitAndTrim(in.RemoveFieldPrefix, ",")
|
||||
newFiledName := field.Name
|
||||
for _, v := range removeFieldPrefixArray {
|
||||
newFiledName = gstr.TrimLeftStr(newFiledName, v, 1)
|
||||
}
|
||||
|
||||
return []string{
|
||||
" #" + localTypeNameStr,
|
||||
" #" + formatCase(field.Name, in.NameCase),
|
||||
" #" + formatCase(newFiledName, in.NameCase),
|
||||
" #= " + gconv.String(index) + jsonTagStr + ";",
|
||||
" #" + fmt.Sprintf(`// %s`, comment),
|
||||
}
|
||||
@ -368,32 +379,10 @@ func getTplPbEntityContent(tplEntityPath string) string {
|
||||
|
||||
// formatCase call gstr.Case* function to convert the s to specified case.
|
||||
func formatCase(str, caseStr string) string {
|
||||
switch gstr.ToLower(caseStr) {
|
||||
case gstr.ToLower("Camel"):
|
||||
return gstr.CaseCamel(str)
|
||||
|
||||
case gstr.ToLower("CamelLower"):
|
||||
return gstr.CaseCamelLower(str)
|
||||
|
||||
case gstr.ToLower("Kebab"):
|
||||
return gstr.CaseKebab(str)
|
||||
|
||||
case gstr.ToLower("KebabScreaming"):
|
||||
return gstr.CaseKebabScreaming(str)
|
||||
|
||||
case gstr.ToLower("Snake"):
|
||||
return gstr.CaseSnake(str)
|
||||
|
||||
case gstr.ToLower("SnakeFirstUpper"):
|
||||
return gstr.CaseSnakeFirstUpper(str)
|
||||
|
||||
case gstr.ToLower("SnakeScreaming"):
|
||||
return gstr.CaseSnakeScreaming(str)
|
||||
|
||||
case "none":
|
||||
if caseStr == "none" {
|
||||
return ""
|
||||
}
|
||||
return str
|
||||
return gstr.CaseConvert(str, gstr.CaseTypeMatch(caseStr))
|
||||
}
|
||||
|
||||
func sortFieldKeyForPbEntity(fieldMap map[string]*gdb.TableField) []string {
|
||||
|
||||
21
cmd/gf/internal/cmd/testdata/genpbentity/generated_user/table_user.proto
vendored
Normal file
21
cmd/gf/internal/cmd/testdata/genpbentity/generated_user/table_user.proto
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
// ==========================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// ==========================================================================
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package unittest;
|
||||
|
||||
option go_package = "unittest";
|
||||
|
||||
import "google/protobuf/timestamp.proto";
|
||||
|
||||
message TableUser {
|
||||
uint32 ID = 1; // User ID
|
||||
string PASSPORT = 2; // User Passport
|
||||
string PASSWORD = 3; // User Password
|
||||
string NICKNAME = 4; // User Nickname
|
||||
string SCORE = 5; // Total score amount.
|
||||
google.protobuf.Timestamp CREATE_AT = 6; // Created Time
|
||||
google.protobuf.Timestamp UPDATE_AT = 7; // Updated Time
|
||||
}
|
||||
10
cmd/gf/internal/cmd/testdata/genpbentity/user.tpl.sql
vendored
Normal file
10
cmd/gf/internal/cmd/testdata/genpbentity/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;
|
||||
@ -24,15 +24,19 @@ var (
|
||||
)
|
||||
|
||||
func init() {
|
||||
logger.SetStack(false)
|
||||
if genv.Get(headerPrintEnvName).String() == "1" {
|
||||
logger.SetHeaderPrint(true)
|
||||
} else {
|
||||
logger.SetHeaderPrint(false)
|
||||
}
|
||||
|
||||
if gcmd.GetOpt("debug") != nil || gcmd.GetOpt("gf.debug") != nil {
|
||||
logger.SetHeaderPrint(true)
|
||||
logger.SetStackSkip(4)
|
||||
logger.SetFlags(logger.GetFlags() | glog.F_FILE_LONG)
|
||||
logger.SetDebug(true)
|
||||
} else {
|
||||
logger.SetStack(false)
|
||||
logger.SetDebug(false)
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,24 +8,27 @@ package gvar
|
||||
|
||||
import "github.com/gogf/gf/v2/util/gconv"
|
||||
|
||||
// MapOption specifies the option for map converting.
|
||||
type MapOption = gconv.MapOption
|
||||
|
||||
// Map converts and returns `v` as map[string]interface{}.
|
||||
func (v *Var) Map(tags ...string) map[string]interface{} {
|
||||
return gconv.Map(v.Val(), tags...)
|
||||
func (v *Var) Map(option ...MapOption) map[string]interface{} {
|
||||
return gconv.Map(v.Val(), option...)
|
||||
}
|
||||
|
||||
// MapStrAny is like function Map, but implements the interface of MapStrAny.
|
||||
func (v *Var) MapStrAny() map[string]interface{} {
|
||||
return v.Map()
|
||||
func (v *Var) MapStrAny(option ...MapOption) map[string]interface{} {
|
||||
return v.Map(option...)
|
||||
}
|
||||
|
||||
// MapStrStr converts and returns `v` as map[string]string.
|
||||
func (v *Var) MapStrStr(tags ...string) map[string]string {
|
||||
return gconv.MapStrStr(v.Val(), tags...)
|
||||
func (v *Var) MapStrStr(option ...MapOption) map[string]string {
|
||||
return gconv.MapStrStr(v.Val(), option...)
|
||||
}
|
||||
|
||||
// MapStrVar converts and returns `v` as map[string]Var.
|
||||
func (v *Var) MapStrVar(tags ...string) map[string]*Var {
|
||||
m := v.Map(tags...)
|
||||
func (v *Var) MapStrVar(option ...MapOption) map[string]*Var {
|
||||
m := v.Map(option...)
|
||||
if len(m) > 0 {
|
||||
vMap := make(map[string]*Var, len(m))
|
||||
for k, v := range m {
|
||||
@ -37,16 +40,19 @@ func (v *Var) MapStrVar(tags ...string) map[string]*Var {
|
||||
}
|
||||
|
||||
// MapDeep converts and returns `v` as map[string]interface{} recursively.
|
||||
// Deprecated: used Map instead.
|
||||
func (v *Var) MapDeep(tags ...string) map[string]interface{} {
|
||||
return gconv.MapDeep(v.Val(), tags...)
|
||||
}
|
||||
|
||||
// MapStrStrDeep converts and returns `v` as map[string]string recursively.
|
||||
// Deprecated: used MapStrStr instead.
|
||||
func (v *Var) MapStrStrDeep(tags ...string) map[string]string {
|
||||
return gconv.MapStrStrDeep(v.Val(), tags...)
|
||||
}
|
||||
|
||||
// MapStrVarDeep converts and returns `v` as map[string]*Var recursively.
|
||||
// Deprecated: used MapStrVar instead.
|
||||
func (v *Var) MapStrVarDeep(tags ...string) map[string]*Var {
|
||||
m := v.MapDeep(tags...)
|
||||
if len(m) > 0 {
|
||||
@ -61,12 +67,12 @@ func (v *Var) MapStrVarDeep(tags ...string) map[string]*Var {
|
||||
|
||||
// Maps converts and returns `v` as map[string]string.
|
||||
// See gconv.Maps.
|
||||
func (v *Var) Maps(tags ...string) []map[string]interface{} {
|
||||
return gconv.Maps(v.Val(), tags...)
|
||||
func (v *Var) Maps(option ...MapOption) []map[string]interface{} {
|
||||
return gconv.Maps(v.Val(), option...)
|
||||
}
|
||||
|
||||
// MapsDeep converts `value` to []map[string]interface{} recursively.
|
||||
// See gconv.MapsDeep.
|
||||
// Deprecated: used Maps instead.
|
||||
func (v *Var) MapsDeep(tags ...string) []map[string]interface{} {
|
||||
return gconv.MapsDeep(v.Val(), tags...)
|
||||
}
|
||||
|
||||
@ -4,7 +4,7 @@ go 1.18
|
||||
|
||||
require (
|
||||
github.com/apolloconfig/agollo/v4 v4.3.1
|
||||
github.com/gogf/gf/v2 v2.5.7
|
||||
github.com/gogf/gf/v2 v2.6.1
|
||||
)
|
||||
|
||||
require (
|
||||
|
||||
@ -3,7 +3,7 @@ module github.com/gogf/gf/contrib/config/consul/v2
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
github.com/gogf/gf/v2 v2.5.7
|
||||
github.com/gogf/gf/v2 v2.6.1
|
||||
github.com/hashicorp/consul/api v1.24.0
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2
|
||||
)
|
||||
|
||||
@ -3,7 +3,7 @@ module github.com/gogf/gf/contrib/config/kubecm/v2
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
github.com/gogf/gf/v2 v2.5.7
|
||||
github.com/gogf/gf/v2 v2.6.1
|
||||
k8s.io/api v0.27.4
|
||||
k8s.io/apimachinery v0.27.4
|
||||
k8s.io/client-go v0.27.4
|
||||
|
||||
@ -3,7 +3,7 @@ module github.com/gogf/gf/contrib/config/nacos/v2
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/gogf/gf/v2 v2.5.7
|
||||
github.com/gogf/gf/v2 v2.6.1
|
||||
github.com/nacos-group/nacos-sdk-go v1.1.4
|
||||
)
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@ module github.com/gogf/gf/contrib/config/polaris/v2
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/gogf/gf/v2 v2.5.7
|
||||
github.com/gogf/gf/v2 v2.6.1
|
||||
github.com/polarismesh/polaris-go v1.5.5
|
||||
)
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@ go 1.18
|
||||
|
||||
require (
|
||||
github.com/ClickHouse/clickhouse-go/v2 v2.0.15
|
||||
github.com/gogf/gf/v2 v2.5.7
|
||||
github.com/gogf/gf/v2 v2.6.1
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/shopspring/decimal v1.3.1
|
||||
)
|
||||
|
||||
@ -74,9 +74,16 @@ func (d *Driver) Open(config *gdb.ConfigNode) (db *sql.DB, err error) {
|
||||
}
|
||||
// Data Source Name of DM8:
|
||||
// dm://userName:password@ip:port/dbname
|
||||
// dm://userName:password@DW/dbname?DW=(192.168.1.1:5236,192.168.1.2:5236)
|
||||
var domain string
|
||||
if config.Port != "" {
|
||||
domain = fmt.Sprintf("%s:%s", config.Host, config.Port)
|
||||
} else {
|
||||
domain = config.Host
|
||||
}
|
||||
source = fmt.Sprintf(
|
||||
"dm://%s:%s@%s:%s/%s?charset=%s&schema=%s",
|
||||
config.User, config.Pass, config.Host, config.Port, config.Name, config.Charset, config.Name,
|
||||
"dm://%s:%s@%s/%s?charset=%s&schema=%s",
|
||||
config.User, config.Pass, domain, config.Name, config.Charset, config.Name,
|
||||
)
|
||||
// Demo of timezone setting:
|
||||
// &loc=Asia/Shanghai
|
||||
@ -210,7 +217,11 @@ func (d *Driver) DoFilter(ctx context.Context, link gdb.Link, sql string, args [
|
||||
// TODO The current approach is too rough. We should deal with the GROUP_CONCAT function and the parsing of the index field from within the select from match.
|
||||
// (GROUP_CONCAT DM does not approve; index cannot be used as a query column name, and security characters need to be added, such as "index")
|
||||
l, r := d.GetChars()
|
||||
newSql = gstr.ReplaceI(newSql, "INDEX", l+"INDEX"+r)
|
||||
if strings.Contains(newSql, "INDEX") || strings.Contains(newSql, "index") {
|
||||
if !(strings.Contains(newSql, "_INDEX") || strings.Contains(newSql, "_index")) {
|
||||
newSql = gstr.ReplaceI(newSql, "INDEX", l+"INDEX"+r)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO i tried to do but it never work:
|
||||
// array, err := gregex.MatchAllString(`SELECT (.*INDEX.*) FROM .*`, newSql)
|
||||
|
||||
@ -21,38 +21,44 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
db gdb.DB
|
||||
dblink gdb.DB
|
||||
dbErr gdb.DB
|
||||
ctx context.Context
|
||||
)
|
||||
|
||||
const (
|
||||
db gdb.DB
|
||||
dblink gdb.DB
|
||||
dbErr gdb.DB
|
||||
ctx context.Context
|
||||
TableSize = 10
|
||||
|
||||
// TableName = "inf_group"
|
||||
// TableNamePrefix = "t_"
|
||||
// TestSchema = "SYSDBADP"
|
||||
)
|
||||
|
||||
const (
|
||||
TestDbIP = "127.0.0.1"
|
||||
TestDbPort = "5236"
|
||||
TestDbUser = "SYSDBA"
|
||||
TestDbPass = "SYSDBA001"
|
||||
TestDbName = "SYSDBA"
|
||||
TestDbType = "dm"
|
||||
TestDBHost = "127.0.0.1"
|
||||
TestDBPort = "5236"
|
||||
TestDBUser = "SYSDBA"
|
||||
TestDBPass = "SYSDBA001"
|
||||
TestDBName = "SYSDBA"
|
||||
TestDBType = "dm"
|
||||
TestCharset = "utf8"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
ID int64 `orm:"id"`
|
||||
AccountName string `orm:"account_name"`
|
||||
PwdReset int64 `orm:"pwd_reset"`
|
||||
AttrIndex int64 `orm:"attr_index"`
|
||||
Enabled int64 `orm:"enabled"`
|
||||
Deleted int64 `orm:"deleted"`
|
||||
CreatedBy string `orm:"created_by"`
|
||||
CreatedTime time.Time `orm:"created_time"`
|
||||
UpdatedBy string `orm:"updated_by"`
|
||||
UpdatedTime time.Time `orm:"updated_time"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
node := gdb.ConfigNode{
|
||||
Host: TestDbIP,
|
||||
Port: TestDbPort,
|
||||
User: TestDbUser,
|
||||
Pass: TestDbPass,
|
||||
Name: TestDbName,
|
||||
Type: TestDbType,
|
||||
Host: TestDBHost,
|
||||
Port: TestDBPort,
|
||||
User: TestDBUser,
|
||||
Pass: TestDBPass,
|
||||
Name: TestDBName,
|
||||
Type: TestDBType,
|
||||
Role: "master",
|
||||
Charset: TestCharset,
|
||||
Weight: 1,
|
||||
@ -62,22 +68,23 @@ func init() {
|
||||
UpdatedAt: "updated_time",
|
||||
}
|
||||
|
||||
// todo
|
||||
nodeLink := gdb.ConfigNode{
|
||||
Type: TestDbType,
|
||||
Name: TestDbName,
|
||||
Type: TestDBType,
|
||||
Name: TestDBName,
|
||||
Link: fmt.Sprintf(
|
||||
"dm:%s:%s@tcp(%s:%s)/%s?charset=%s",
|
||||
TestDbUser, TestDbPass, TestDbIP, TestDbPort, TestDbName, TestCharset,
|
||||
TestDBUser, TestDBPass, TestDBHost, TestDBPort, TestDBName, TestCharset,
|
||||
),
|
||||
}
|
||||
|
||||
nodeErr := gdb.ConfigNode{
|
||||
Host: TestDbIP,
|
||||
Port: TestDbPort,
|
||||
User: TestDbUser,
|
||||
Host: TestDBHost,
|
||||
Port: TestDBPort,
|
||||
User: TestDBUser,
|
||||
Pass: "1234",
|
||||
Name: TestDbName,
|
||||
Type: TestDbType,
|
||||
Name: TestDBName,
|
||||
Type: TestDBType,
|
||||
Role: "master",
|
||||
Charset: TestCharset,
|
||||
Weight: 1,
|
||||
@ -107,6 +114,23 @@ func init() {
|
||||
ctx = context.Background()
|
||||
}
|
||||
|
||||
func dropTable(table string) {
|
||||
count, err := db.GetCount(
|
||||
ctx,
|
||||
"SELECT COUNT(*) FROM all_tables WHERE owner = ? And table_name= ?", TestDBName, strings.ToUpper(table),
|
||||
)
|
||||
if err != nil {
|
||||
gtest.Fatal(err)
|
||||
}
|
||||
|
||||
if count == 0 {
|
||||
return
|
||||
}
|
||||
if _, err := db.Exec(ctx, fmt.Sprintf("DROP TABLE %s", table)); err != nil {
|
||||
gtest.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func createTable(table ...string) (name string) {
|
||||
if len(table) > 0 {
|
||||
name = table[0]
|
||||
@ -124,6 +148,7 @@ func createTable(table ...string) (name string) {
|
||||
"PWD_RESET" TINYINT DEFAULT 0 NOT NULL,
|
||||
"ENABLED" INT DEFAULT 1 NOT NULL,
|
||||
"DELETED" INT DEFAULT 0 NOT NULL,
|
||||
"ATTR_INDEX" INT DEFAULT 0 ,
|
||||
"CREATED_BY" VARCHAR(32) DEFAULT '' NOT NULL,
|
||||
"CREATED_TIME" TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP() NOT NULL,
|
||||
"UPDATED_BY" VARCHAR(32) DEFAULT '' NOT NULL,
|
||||
@ -136,18 +161,6 @@ NOT CLUSTER PRIMARY KEY("ID")) STORAGE(ON "MAIN", CLUSTERBTR) ;
|
||||
return
|
||||
}
|
||||
|
||||
type User struct {
|
||||
ID int64 `orm:"id"`
|
||||
AccountName string `orm:"account_name"`
|
||||
PwdReset int64 `orm:"pwd_reset"`
|
||||
Enabled int64 `orm:"enabled"`
|
||||
Deleted int64 `orm:"deleted"`
|
||||
CreatedBy string `orm:"created_by"`
|
||||
CreatedTime time.Time `orm:"created_time"`
|
||||
UpdatedBy string `orm:"updated_by"`
|
||||
UpdatedTime time.Time `orm:"updated_time"`
|
||||
}
|
||||
|
||||
func createInitTable(table ...string) (name string) {
|
||||
name = createTable(table...)
|
||||
array := garray.New(true)
|
||||
@ -156,10 +169,11 @@ func createInitTable(table ...string) (name string) {
|
||||
"id": i,
|
||||
"account_name": fmt.Sprintf(`name_%d`, i),
|
||||
"pwd_reset": 0,
|
||||
"attr_index": i,
|
||||
"create_time": gtime.Now().String(),
|
||||
})
|
||||
}
|
||||
result, err := db.Schema(TestDbName).Insert(context.Background(), name, array.Slice())
|
||||
result, err := db.Schema(TestDBName).Insert(context.Background(), name, array.Slice())
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
n, e := result.RowsAffected()
|
||||
@ -168,19 +182,34 @@ func createInitTable(table ...string) (name string) {
|
||||
return
|
||||
}
|
||||
|
||||
func dropTable(table string) {
|
||||
count, err := db.GetCount(
|
||||
ctx,
|
||||
"SELECT COUNT(*) FROM USER_TABLES WHERE TABLE_NAME = ?", strings.ToUpper(table),
|
||||
)
|
||||
if err != nil {
|
||||
gtest.Fatal(err)
|
||||
func createTableFalse(table ...string) (name string, err error) {
|
||||
if len(table) > 0 {
|
||||
name = table[0]
|
||||
} else {
|
||||
name = fmt.Sprintf("random_%d", gtime.Timestamp())
|
||||
}
|
||||
|
||||
if count == 0 {
|
||||
return
|
||||
}
|
||||
if _, err := db.Exec(ctx, fmt.Sprintf("DROP TABLE %s", table)); err != nil {
|
||||
gtest.Fatal(err)
|
||||
dropTable(name)
|
||||
|
||||
if _, err := db.Exec(ctx, fmt.Sprintf(`
|
||||
CREATE TABLE "%s"
|
||||
(
|
||||
"ID" BIGINT NOT NULL,
|
||||
"ACCOUNT_NAME" VARCHAR(128) DEFAULT '' NOT NULL,
|
||||
"PWD_RESET" TINYINT DEFAULT 0 NOT NULL,
|
||||
"ENABLED" INT DEFAULT 1 NOT NULL,
|
||||
"DELETED" INT DEFAULT 0 NOT NULL,
|
||||
"INDEX" INT DEFAULT 0 ,
|
||||
"ATTR_INDEX" INT DEFAULT 0 ,
|
||||
"CREATED_BY" VARCHAR(32) DEFAULT '' NOT NULL,
|
||||
"CREATED_TIME" TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP() NOT NULL,
|
||||
"UPDATED_BY" VARCHAR(32) DEFAULT '' NOT NULL,
|
||||
"UPDATED_TIME" TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP() NOT NULL,
|
||||
NOT CLUSTER PRIMARY KEY("ID")) STORAGE(ON "MAIN", CLUSTERBTR) ;
|
||||
`, name)); err != nil {
|
||||
// gtest.Fatal(err)
|
||||
return name, fmt.Errorf("createTableFalse")
|
||||
}
|
||||
|
||||
return name, nil
|
||||
}
|
||||
|
||||
@ -27,13 +27,11 @@ func Test_DB_Ping(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestTables(t *testing.T) {
|
||||
tables := []string{"A_tables", "A_tables2"}
|
||||
for _, v := range tables {
|
||||
createInitTable(v)
|
||||
}
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
tables := []string{"A_tables", "A_tables2"}
|
||||
|
||||
for _, v := range tables {
|
||||
createInitTable(v)
|
||||
// createTable(v)
|
||||
}
|
||||
result, err := db.Tables(ctx)
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
@ -63,13 +61,31 @@ func TestTables(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestTableFields(t *testing.T) {
|
||||
// The test scenario index of this test case (exact matching field) is a keyword in the Dameng database and cannot exist as a field name.
|
||||
// If the data structure previously migrated from mysql has an index (completely matching field), it will also be allowed.
|
||||
// However, when processing the index (completely matching field), the adapter will automatically add security character
|
||||
// In principle, such problems will not occur if you directly use Dameng database initialization instead of migrating the data structure from mysql.
|
||||
// If so, the adapter has also taken care of it.
|
||||
func TestTablesFalse(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
tables := []string{"A_tables", "A_tables2"}
|
||||
for _, v := range tables {
|
||||
_, err := createTableFalse(v)
|
||||
gtest.Assert(err, fmt.Errorf("createTableFalse"))
|
||||
// createTable(v)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestTableFields(t *testing.T) {
|
||||
tables := "A_tables"
|
||||
createInitTable(tables)
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
tables := "A_tables"
|
||||
var expect = map[string][]interface{}{
|
||||
"ID": {"BIGINT", false},
|
||||
"ACCOUNT_NAME": {"VARCHAR", false},
|
||||
"PWD_RESET": {"TINYINT", false},
|
||||
"ATTR_INDEX": {"INT", true},
|
||||
"DELETED": {"INT", false},
|
||||
"CREATED_TIME": {"TIMESTAMP", false},
|
||||
}
|
||||
@ -98,8 +114,9 @@ func TestTableFields(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_DB_Query(t *testing.T) {
|
||||
tableName := "A_tables"
|
||||
createInitTable(tableName)
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
tableName := "A_tables"
|
||||
// createTable(tableName)
|
||||
_, err := db.Query(ctx, fmt.Sprintf("SELECT * from %s", tableName))
|
||||
t.AssertNil(err)
|
||||
@ -121,16 +138,18 @@ func Test_DB_Query(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestModelSave(t *testing.T) {
|
||||
table := "A_tables"
|
||||
createInitTable(table)
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
// createTable("A_tables")
|
||||
data := []User{
|
||||
{
|
||||
ID: 100,
|
||||
AccountName: "user_100",
|
||||
AttrIndex: 100,
|
||||
CreatedTime: time.Now(),
|
||||
},
|
||||
}
|
||||
_, err := db.Model("A_tables").Data(data).Save()
|
||||
_, err := db.Model(table).Data(data).Save()
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
data2 := []User{
|
||||
@ -139,7 +158,7 @@ func TestModelSave(t *testing.T) {
|
||||
AccountName: "user_101",
|
||||
},
|
||||
}
|
||||
_, err = db.Model("A_tables").Data(&data2).Save()
|
||||
_, err = db.Model(table).Data(&data2).Save()
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
data3 := []User{
|
||||
@ -149,7 +168,7 @@ func TestModelSave(t *testing.T) {
|
||||
PwdReset: 10,
|
||||
},
|
||||
}
|
||||
_, err = db.Model("A_tables").Save(data3)
|
||||
_, err = db.Model(table).Save(data3)
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
data4 := []User{
|
||||
@ -159,63 +178,68 @@ func TestModelSave(t *testing.T) {
|
||||
CreatedTime: time.Now(),
|
||||
},
|
||||
}
|
||||
_, err = db.Model("A_tables").Save(&data4)
|
||||
_, err = db.Model(table).Save(&data4)
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
// TODO:: Should be Supported 'Replace' Operation
|
||||
// _, err = db.Schema(TestDbName).Replace(ctx, "DoInsert", data, 10)
|
||||
// _, err = db.Schema(TestDBName).Replace(ctx, "DoInsert", data, 10)
|
||||
// gtest.Assert(err, nil)
|
||||
})
|
||||
}
|
||||
|
||||
func TestModelInsert(t *testing.T) {
|
||||
// g.Model.insert not lost default not null coloumn
|
||||
table := "A_tables"
|
||||
createInitTable(table)
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
// createTable("A_tables")
|
||||
i := 200
|
||||
data := User{
|
||||
ID: int64(i),
|
||||
AccountName: fmt.Sprintf(`A%dtwo`, i),
|
||||
PwdReset: 0,
|
||||
AttrIndex: 99,
|
||||
// CreatedTime: time.Now(),
|
||||
UpdatedTime: time.Now(),
|
||||
}
|
||||
// _, err := db.Schema(TestDbName).Model("A_tables").Data(data).Insert()
|
||||
_, err := db.Model("A_tables").Insert(&data)
|
||||
// _, err := db.Schema(TestDBName).Model(table).Data(data).Insert()
|
||||
_, err := db.Model(table).Insert(&data)
|
||||
gtest.Assert(err, nil)
|
||||
})
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
// createTable("A_tables")
|
||||
i := 201
|
||||
data := User{
|
||||
ID: int64(i),
|
||||
AccountName: fmt.Sprintf(`A%dtwoONE`, i),
|
||||
PwdReset: 1,
|
||||
CreatedTime: time.Now(),
|
||||
AttrIndex: 98,
|
||||
// UpdatedTime: time.Now(),
|
||||
}
|
||||
// _, err := db.Schema(TestDbName).Model("A_tables").Data(data).Insert()
|
||||
_, err := db.Model("A_tables").Data(&data).Insert()
|
||||
// _, err := db.Schema(TestDBName).Model(table).Data(data).Insert()
|
||||
_, err := db.Model(table).Data(&data).Insert()
|
||||
gtest.Assert(err, nil)
|
||||
})
|
||||
}
|
||||
|
||||
func TestDBInsert(t *testing.T) {
|
||||
table := "A_tables"
|
||||
createInitTable("A_tables")
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
// createTable("A_tables")
|
||||
i := 300
|
||||
data := g.Map{
|
||||
"ID": i,
|
||||
"ACCOUNT_NAME": fmt.Sprintf(`A%dthress`, i),
|
||||
"PWD_RESET": 3,
|
||||
"ATTR_INDEX": 98,
|
||||
}
|
||||
_, err := db.Insert(ctx, "A_tables", &data)
|
||||
_, err := db.Insert(ctx, table, &data)
|
||||
gtest.Assert(err, nil)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_DB_Exec(t *testing.T) {
|
||||
createInitTable("A_tables")
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
_, err := db.Exec(ctx, "SELECT ? from dual", 1)
|
||||
t.AssertNil(err)
|
||||
@ -226,18 +250,18 @@ func Test_DB_Exec(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_DB_Insert(t *testing.T) {
|
||||
// table := createTable()
|
||||
// defer dropTable(table)
|
||||
table := "A_tables"
|
||||
createInitTable(table)
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
// normal map
|
||||
_, err := db.Insert(ctx, "A_tables", g.Map{
|
||||
_, err := db.Insert(ctx, table, g.Map{
|
||||
"ID": 1000,
|
||||
"ACCOUNT_NAME": "map1",
|
||||
"CREATED_TIME": gtime.Now(),
|
||||
})
|
||||
t.AssertNil(err)
|
||||
|
||||
result, err := db.Insert(ctx, "A_tables", g.Map{
|
||||
result, err := db.Insert(ctx, table, g.Map{
|
||||
"ID": "2000",
|
||||
"ACCOUNT_NAME": "map2",
|
||||
"CREATED_TIME": gtime.Now(),
|
||||
@ -246,7 +270,7 @@ func Test_DB_Insert(t *testing.T) {
|
||||
n, _ := result.RowsAffected()
|
||||
t.Assert(n, 1)
|
||||
|
||||
result, err = db.Insert(ctx, "A_tables", g.Map{
|
||||
result, err = db.Insert(ctx, table, g.Map{
|
||||
"ID": 3000,
|
||||
"ACCOUNT_NAME": "map3",
|
||||
// "CREATED_TIME": gtime.Now(),
|
||||
@ -256,7 +280,7 @@ func Test_DB_Insert(t *testing.T) {
|
||||
t.Assert(n, 1)
|
||||
|
||||
// struct
|
||||
result, err = db.Insert(ctx, "A_tables", User{
|
||||
result, err = db.Insert(ctx, table, User{
|
||||
ID: 4000,
|
||||
AccountName: "struct_4",
|
||||
// CreatedTime: timeStr,
|
||||
@ -266,7 +290,7 @@ func Test_DB_Insert(t *testing.T) {
|
||||
n, _ = result.RowsAffected()
|
||||
t.Assert(n, 1)
|
||||
|
||||
ones, err := db.Model("A_tables").Where("ID", 4000).All()
|
||||
ones, err := db.Model(table).Where("ID", 4000).All()
|
||||
t.AssertNil(err)
|
||||
t.Assert(ones[0]["ID"].Int(), 4000)
|
||||
t.Assert(ones[0]["ACCOUNT_NAME"].String(), "struct_4")
|
||||
@ -276,7 +300,7 @@ func Test_DB_Insert(t *testing.T) {
|
||||
|
||||
// *struct
|
||||
timeStr := time.Now()
|
||||
result, err = db.Insert(ctx, "A_tables", &User{
|
||||
result, err = db.Insert(ctx, table, &User{
|
||||
ID: 5000,
|
||||
AccountName: "struct_5",
|
||||
CreatedTime: timeStr,
|
||||
@ -286,13 +310,13 @@ func Test_DB_Insert(t *testing.T) {
|
||||
n, _ = result.RowsAffected()
|
||||
t.Assert(n, 1)
|
||||
|
||||
one, err := db.Model("A_tables").Where("ID", 5000).One()
|
||||
one, err := db.Model(table).Where("ID", 5000).One()
|
||||
t.AssertNil(err)
|
||||
t.Assert(one["ID"].Int(), 5000)
|
||||
t.Assert(one["ACCOUNT_NAME"].String(), "struct_5")
|
||||
|
||||
// batch with Insert
|
||||
r, err := db.Insert(ctx, "A_tables", g.Slice{
|
||||
r, err := db.Insert(ctx, table, g.Slice{
|
||||
g.Map{
|
||||
"ID": 6000,
|
||||
"ACCOUNT_NAME": "t6000",
|
||||
@ -306,7 +330,7 @@ func Test_DB_Insert(t *testing.T) {
|
||||
n, _ = r.RowsAffected()
|
||||
t.Assert(n, 2)
|
||||
|
||||
one, err = db.Model("A_tables").Where("ID", 6000).One()
|
||||
one, err = db.Model(table).Where("ID", 6000).One()
|
||||
t.AssertNil(err)
|
||||
t.Assert(one["ID"].Int(), 6000)
|
||||
t.Assert(one["ACCOUNT_NAME"].String(), "t6000")
|
||||
@ -314,8 +338,9 @@ func Test_DB_Insert(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_DB_BatchInsert(t *testing.T) {
|
||||
table := "A_tables"
|
||||
createInitTable(table)
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
table := "A_tables"
|
||||
r, err := db.Insert(ctx, table, g.List{
|
||||
{
|
||||
"ID": 400,
|
||||
@ -334,9 +359,6 @@ func Test_DB_BatchInsert(t *testing.T) {
|
||||
})
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
table := "A_tables"
|
||||
// table := createTable()
|
||||
// defer dropTable(table)
|
||||
// []interface{}
|
||||
r, err := db.Insert(ctx, table, g.Slice{
|
||||
g.Map{
|
||||
@ -357,9 +379,6 @@ func Test_DB_BatchInsert(t *testing.T) {
|
||||
|
||||
// batch insert map
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
table := "A_tables"
|
||||
// table := createTable()
|
||||
// defer dropTable(table)
|
||||
result, err := db.Insert(ctx, table, g.Map{
|
||||
"ID": 600,
|
||||
"ACCOUNT_NAME": "600_batch_600",
|
||||
@ -373,10 +392,9 @@ func Test_DB_BatchInsert(t *testing.T) {
|
||||
|
||||
func Test_DB_BatchInsert_Struct(t *testing.T) {
|
||||
// batch insert struct
|
||||
table := "A_tables"
|
||||
createInitTable(table)
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
table := "A_tables"
|
||||
// table := createTable()
|
||||
// defer dropTable(table)
|
||||
user := &User{
|
||||
ID: 700,
|
||||
AccountName: "BatchInsert_Struct_700",
|
||||
@ -391,26 +409,25 @@ func Test_DB_BatchInsert_Struct(t *testing.T) {
|
||||
|
||||
func Test_DB_Update(t *testing.T) {
|
||||
table := "A_tables"
|
||||
// table := createInitTable()
|
||||
createInitTable(table)
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
result, err := db.Update(ctx, table, "pwd_reset=7", "id=700")
|
||||
result, err := db.Update(ctx, table, "pwd_reset=7", "id=7")
|
||||
t.AssertNil(err)
|
||||
n, _ := result.RowsAffected()
|
||||
t.Assert(n, 1)
|
||||
|
||||
one, err := db.Model(table).Where("ID", 700).One()
|
||||
one, err := db.Model(table).Where("ID", 7).One()
|
||||
t.AssertNil(err)
|
||||
t.Assert(one["ID"].Int(), 700)
|
||||
t.Assert(one["ACCOUNT_NAME"].String(), "BatchInsert_Struct_700")
|
||||
t.Assert(one["ID"].Int(), 7)
|
||||
t.Assert(one["ACCOUNT_NAME"].String(), "name_7")
|
||||
t.Assert(one["PWD_RESET"].String(), "7")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_DB_GetAll(t *testing.T) {
|
||||
table := "A_tables"
|
||||
// table := createInitTable()
|
||||
// defer dropTable(table)
|
||||
createInitTable(table)
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
result, err := db.GetAll(ctx, fmt.Sprintf("SELECT * FROM %s WHERE id=?", table), 1)
|
||||
@ -459,41 +476,38 @@ func Test_DB_GetAll(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_DB_GetOne(t *testing.T) {
|
||||
// table := createInitTable()
|
||||
table := "A_tables"
|
||||
createInitTable(table)
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
record, err := db.GetOne(ctx, fmt.Sprintf("SELECT * FROM %s WHERE account_name=?", table), "struct_4")
|
||||
record, err := db.GetOne(ctx, fmt.Sprintf("SELECT * FROM %s WHERE account_name=?", table), "name_4")
|
||||
t.AssertNil(err)
|
||||
t.Assert(record["ACCOUNT_NAME"].String(), "struct_4")
|
||||
t.Assert(record["ACCOUNT_NAME"].String(), "name_4")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_DB_GetValue(t *testing.T) {
|
||||
table := "A_tables"
|
||||
// table := createInitTable()
|
||||
// defer dropTable(table)
|
||||
createInitTable(table)
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
value, err := db.GetValue(ctx, fmt.Sprintf("SELECT id FROM %s WHERE account_name=?", table), "map2")
|
||||
value, err := db.GetValue(ctx, fmt.Sprintf("SELECT id FROM %s WHERE account_name=?", table), "name_2")
|
||||
t.AssertNil(err)
|
||||
t.Assert(value.Int(), 2000)
|
||||
t.Assert(value.Int(), 2)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_DB_GetCount(t *testing.T) {
|
||||
table := "A_tables"
|
||||
// table := createInitTable()
|
||||
// defer dropTable(table)
|
||||
createInitTable(table)
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
count, err := db.GetCount(ctx, fmt.Sprintf("SELECT * FROM %s", table))
|
||||
t.AssertNil(err)
|
||||
t.Assert(count, 28)
|
||||
t.Assert(count, 10)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_DB_GetStruct(t *testing.T) {
|
||||
table := "A_tables"
|
||||
// table := createInitTable()
|
||||
// defer dropTable(table)
|
||||
createInitTable(table)
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
user := new(User)
|
||||
err := db.GetScan(ctx, user, fmt.Sprintf("SELECT * FROM %s WHERE id=?", table), 3)
|
||||
@ -502,33 +516,31 @@ func Test_DB_GetStruct(t *testing.T) {
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
user := new(User)
|
||||
err := db.GetScan(ctx, user, fmt.Sprintf("SELECT * FROM %s WHERE id=?", table), 200)
|
||||
err := db.GetScan(ctx, user, fmt.Sprintf("SELECT * FROM %s WHERE id=?", table), 2)
|
||||
t.AssertNil(err)
|
||||
t.Assert(user.AccountName, "A200two")
|
||||
t.Assert(user.AccountName, "name_2")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_DB_GetStructs(t *testing.T) {
|
||||
table := "A_tables"
|
||||
// table := createInitTable()
|
||||
// defer dropTable(table)
|
||||
createInitTable(table)
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var users []User
|
||||
err := db.GetScan(ctx, &users, fmt.Sprintf("SELECT * FROM %s WHERE id>?", table), 4000)
|
||||
err := db.GetScan(ctx, &users, fmt.Sprintf("SELECT * FROM %s WHERE id>?", table), 4)
|
||||
t.AssertNil(err)
|
||||
t.Assert(users[0].ID, 5000)
|
||||
t.Assert(users[1].ID, 6000)
|
||||
t.Assert(users[2].ID, 6001)
|
||||
t.Assert(users[0].AccountName, "struct_5")
|
||||
t.Assert(users[1].AccountName, "t6000")
|
||||
t.Assert(users[2].AccountName, "t6001")
|
||||
t.Assert(users[0].ID, 5)
|
||||
t.Assert(users[1].ID, 6)
|
||||
t.Assert(users[2].ID, 7)
|
||||
t.Assert(users[0].AccountName, "name_5")
|
||||
t.Assert(users[1].AccountName, "name_6")
|
||||
t.Assert(users[2].AccountName, "name_7")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_DB_GetScan(t *testing.T) {
|
||||
table := "A_tables"
|
||||
// table := createInitTable()
|
||||
// defer dropTable(table)
|
||||
createInitTable(table)
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
user := new(User)
|
||||
err := db.GetScan(ctx, user, fmt.Sprintf("SELECT * FROM %s WHERE id=?", table), 3)
|
||||
@ -555,17 +567,17 @@ func Test_DB_GetScan(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_DB_Delete(t *testing.T) {
|
||||
// table := createInitTable()
|
||||
// defer dropTable(table)
|
||||
table := "A_tables"
|
||||
createInitTable(table)
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
result, err := db.Delete(ctx, "A_tables", "id=32")
|
||||
result, err := db.Delete(ctx, table, "id=32")
|
||||
t.AssertNil(err)
|
||||
n, _ := result.RowsAffected()
|
||||
t.Assert(n, 0)
|
||||
})
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
result, err := db.Model("A_tables").Where("id", 33).Delete()
|
||||
result, err := db.Model(table).Where("id", 33).Delete()
|
||||
t.AssertNil(err)
|
||||
n, _ := result.RowsAffected()
|
||||
t.Assert(n, 0)
|
||||
@ -574,8 +586,7 @@ func Test_DB_Delete(t *testing.T) {
|
||||
|
||||
func Test_Empty_Slice_Argument(t *testing.T) {
|
||||
table := "A_tables"
|
||||
// table := createInitTable()
|
||||
// defer dropTable(table)
|
||||
createInitTable(table)
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
result, err := db.GetAll(ctx, fmt.Sprintf(`select * from %s where id in(?)`, table), g.Slice{})
|
||||
t.AssertNil(err)
|
||||
|
||||
@ -6,7 +6,7 @@ replace github.com/gogf/gf/v2 => ../../../
|
||||
|
||||
require (
|
||||
gitee.com/chunanyong/dm v1.8.12
|
||||
github.com/gogf/gf/v2 v2.5.7
|
||||
github.com/gogf/gf/v2 v2.6.1
|
||||
)
|
||||
|
||||
require (
|
||||
|
||||
@ -4,7 +4,7 @@ go 1.18
|
||||
|
||||
require (
|
||||
github.com/denisenkom/go-mssqldb v0.12.3
|
||||
github.com/gogf/gf/v2 v2.5.7
|
||||
github.com/gogf/gf/v2 v2.6.1
|
||||
)
|
||||
|
||||
require (
|
||||
|
||||
@ -4,7 +4,7 @@ go 1.18
|
||||
|
||||
require (
|
||||
github.com/go-sql-driver/mysql v1.7.1
|
||||
github.com/gogf/gf/v2 v2.5.7
|
||||
github.com/gogf/gf/v2 v2.6.1
|
||||
)
|
||||
|
||||
require (
|
||||
|
||||
@ -55,7 +55,6 @@ func init() {
|
||||
nodeInvalid := gdb.ConfigNode{
|
||||
Link: fmt.Sprintf("mysql:root:%s@tcp(127.0.0.1:3307)/?loc=Local&parseTime=true", TestDbPass),
|
||||
}
|
||||
|
||||
gdb.AddConfigNode("test", nodeDefault)
|
||||
gdb.AddConfigNode("prefix", nodePrefix)
|
||||
gdb.AddConfigNode("nodeinvalid", nodeInvalid)
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
package mysql_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
@ -881,3 +882,120 @@ func Test_Issue3086(t *testing.T) {
|
||||
t.Assert(n, 2)
|
||||
})
|
||||
}
|
||||
|
||||
// https://github.com/gogf/gf/issues/3204
|
||||
func Test_Issue3204(t *testing.T) {
|
||||
table := createInitTable()
|
||||
defer dropTable(table)
|
||||
|
||||
// where
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
type User struct {
|
||||
g.Meta `orm:"do:true"`
|
||||
Id interface{} `orm:"id,omitempty"`
|
||||
Passport interface{} `orm:"passport,omitempty"`
|
||||
Password interface{} `orm:"password,omitempty"`
|
||||
Nickname interface{} `orm:"nickname,omitempty"`
|
||||
CreateTime interface{} `orm:"create_time,omitempty"`
|
||||
}
|
||||
where := User{
|
||||
Id: 2,
|
||||
Passport: "",
|
||||
}
|
||||
all, err := db.Model(table).Where(where).All()
|
||||
t.AssertNil(err)
|
||||
t.Assert(len(all), 1)
|
||||
t.Assert(all[0]["id"], 2)
|
||||
})
|
||||
// data
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
type User struct {
|
||||
g.Meta `orm:"do:true"`
|
||||
Id interface{} `orm:"id,omitempty"`
|
||||
Passport interface{} `orm:"passport,omitempty"`
|
||||
Password interface{} `orm:"password,omitempty"`
|
||||
Nickname interface{} `orm:"nickname,omitempty"`
|
||||
CreateTime interface{} `orm:"create_time,omitempty"`
|
||||
}
|
||||
var (
|
||||
err error
|
||||
sqlArray []string
|
||||
insertId int64
|
||||
data = User{
|
||||
Id: 20,
|
||||
Passport: "passport_20",
|
||||
Password: "",
|
||||
}
|
||||
)
|
||||
sqlArray, err = gdb.CatchSQL(ctx, func(ctx context.Context) error {
|
||||
insertId, err = db.Ctx(ctx).Model(table).Data(data).InsertAndGetId()
|
||||
return err
|
||||
})
|
||||
t.AssertNil(err)
|
||||
t.Assert(insertId, 20)
|
||||
t.Assert(
|
||||
gstr.Contains(sqlArray[len(sqlArray)-1], "(`id`,`passport`) VALUES(20,'passport_20')"),
|
||||
true,
|
||||
)
|
||||
})
|
||||
// update data
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
type User struct {
|
||||
g.Meta `orm:"do:true"`
|
||||
Id interface{} `orm:"id,omitempty"`
|
||||
Passport interface{} `orm:"passport,omitempty"`
|
||||
Password interface{} `orm:"password,omitempty"`
|
||||
Nickname interface{} `orm:"nickname,omitempty"`
|
||||
CreateTime interface{} `orm:"create_time,omitempty"`
|
||||
}
|
||||
var (
|
||||
err error
|
||||
sqlArray []string
|
||||
data = User{
|
||||
Passport: "passport_1",
|
||||
Password: "",
|
||||
Nickname: "",
|
||||
}
|
||||
)
|
||||
sqlArray, err = gdb.CatchSQL(ctx, func(ctx context.Context) error {
|
||||
_, err = db.Ctx(ctx).Model(table).Data(data).WherePri(1).Update()
|
||||
return err
|
||||
})
|
||||
t.AssertNil(err)
|
||||
t.Assert(
|
||||
gstr.Contains(sqlArray[len(sqlArray)-1], "SET `passport`='passport_1' WHERE `id`=1"),
|
||||
true,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
// https://github.com/gogf/gf/issues/3218
|
||||
func Test_Issue3218(t *testing.T) {
|
||||
table := "issue3218_sys_config"
|
||||
array := gstr.SplitAndTrim(gtest.DataContent(`issue3218.sql`), ";")
|
||||
for _, v := range array {
|
||||
if _, err := db.Exec(ctx, v); err != nil {
|
||||
gtest.Error(err)
|
||||
}
|
||||
}
|
||||
defer dropTable(table)
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
type SysConfigInfo struct {
|
||||
Name string `json:"name"`
|
||||
Value map[string]string `json:"value"`
|
||||
}
|
||||
var configData *SysConfigInfo
|
||||
err := db.Model(table).Scan(&configData)
|
||||
t.AssertNil(err)
|
||||
t.Assert(configData, &SysConfigInfo{
|
||||
Name: "site",
|
||||
Value: map[string]string{
|
||||
"fixed_page": "",
|
||||
"site_name": "22",
|
||||
"version": "22",
|
||||
"banned_ip": "22",
|
||||
"filings": "2222",
|
||||
},
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
14
contrib/drivers/mysql/testdata/issue3218.sql
vendored
Normal file
14
contrib/drivers/mysql/testdata/issue3218.sql
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
CREATE TABLE `issue3218_sys_config` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '配置名称',
|
||||
`value` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '配置值',
|
||||
`created_at` timestamp NULL DEFAULT NULL COMMENT '创建时间',
|
||||
`updated_at` timestamp NULL DEFAULT NULL COMMENT '更新时间',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
UNIQUE INDEX `name`(`name`(191)) USING BTREE
|
||||
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of sys_config
|
||||
-- ----------------------------
|
||||
INSERT INTO `issue3218_sys_config` VALUES (49, 'site', '{\"banned_ip\":\"22\",\"filings\":\"2222\",\"fixed_page\":\"\",\"site_name\":\"22\",\"version\":\"22\"}', '2023-12-19 14:08:25', '2023-12-19 14:08:25');
|
||||
@ -3,7 +3,7 @@ module github.com/gogf/gf/contrib/drivers/oracle/v2
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/gogf/gf/v2 v2.5.7
|
||||
github.com/gogf/gf/v2 v2.6.1
|
||||
github.com/sijms/go-ora/v2 v2.7.10
|
||||
)
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@ module github.com/gogf/gf/contrib/drivers/pgsql/v2
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/gogf/gf/v2 v2.5.7
|
||||
github.com/gogf/gf/v2 v2.6.1
|
||||
github.com/lib/pq v1.10.9
|
||||
)
|
||||
|
||||
|
||||
@ -15,6 +15,7 @@ import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
_ "github.com/lib/pq"
|
||||
@ -237,6 +238,12 @@ func (d *Driver) Tables(ctx context.Context, schema ...string) (tables []string,
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
useRelpartbound := ""
|
||||
if gstr.CompareVersion(d.version(ctx, link), "10") >= 0 {
|
||||
useRelpartbound = "AND c.relpartbound IS NULL"
|
||||
}
|
||||
|
||||
var query = fmt.Sprintf(`
|
||||
SELECT
|
||||
c.relname
|
||||
@ -247,10 +254,11 @@ INNER JOIN pg_namespace n ON
|
||||
WHERE
|
||||
n.nspname = '%s'
|
||||
AND c.relkind IN ('r', 'p')
|
||||
AND c.relpartbound IS NULL
|
||||
%s
|
||||
ORDER BY
|
||||
c.relname`,
|
||||
usedSchema,
|
||||
useRelpartbound,
|
||||
)
|
||||
|
||||
query, _ = gregex.ReplaceString(`[\n\r\s]+`, " ", gstr.Trim(query))
|
||||
@ -266,6 +274,23 @@ ORDER BY
|
||||
return
|
||||
}
|
||||
|
||||
// version checks and returns the database version.
|
||||
func (d *Driver) version(ctx context.Context, link gdb.Link) string {
|
||||
result, err := d.DoSelect(ctx, link, "SELECT version();")
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
if len(result) > 0 {
|
||||
if v, ok := result[0]["version"]; ok {
|
||||
matches := regexp.MustCompile(`PostgreSQL (\d+\.\d+)`).FindStringSubmatch(v.String())
|
||||
if len(matches) >= 2 {
|
||||
return matches[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// TableFields retrieves and returns the fields' information of specified table of current schema.
|
||||
func (d *Driver) TableFields(ctx context.Context, table string, schema ...string) (fields map[string]*gdb.TableField, err error) {
|
||||
var (
|
||||
|
||||
@ -4,7 +4,7 @@ go 1.18
|
||||
|
||||
require (
|
||||
github.com/glebarez/go-sqlite v1.21.2
|
||||
github.com/gogf/gf/v2 v2.5.7
|
||||
github.com/gogf/gf/v2 v2.6.1
|
||||
)
|
||||
|
||||
require (
|
||||
|
||||
@ -3,7 +3,7 @@ module github.com/gogf/gf/contrib/drivers/sqlitecgo/v2
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/gogf/gf/v2 v2.5.7
|
||||
github.com/gogf/gf/v2 v2.6.1
|
||||
github.com/mattn/go-sqlite3 v1.14.17
|
||||
)
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@ module github.com/gogf/gf/contrib/nosql/redis/v2
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/gogf/gf/v2 v2.5.7
|
||||
github.com/gogf/gf/v2 v2.6.1
|
||||
github.com/redis/go-redis/v9 v9.2.1
|
||||
go.opentelemetry.io/otel v1.14.0
|
||||
go.opentelemetry.io/otel/trace v1.14.0
|
||||
|
||||
@ -3,7 +3,7 @@ module github.com/gogf/gf/contrib/registry/etcd/v2
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/gogf/gf/v2 v2.5.7
|
||||
github.com/gogf/gf/v2 v2.6.1
|
||||
go.etcd.io/etcd/client/v3 v3.5.7
|
||||
)
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@ module github.com/gogf/gf/contrib/registry/file/v2
|
||||
|
||||
go 1.18
|
||||
|
||||
require github.com/gogf/gf/v2 v2.5.7
|
||||
require github.com/gogf/gf/v2 v2.6.1
|
||||
|
||||
require (
|
||||
github.com/BurntSushi/toml v1.2.0 // indirect
|
||||
|
||||
@ -3,7 +3,7 @@ module github.com/gogf/gf/contrib/registry/nacos/v2
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/gogf/gf/v2 v2.5.7
|
||||
github.com/gogf/gf/v2 v2.6.1
|
||||
github.com/joy999/nacos-sdk-go v0.0.0-20231120071639-10a34b3e7288
|
||||
)
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@ module github.com/gogf/gf/contrib/registry/polaris/v2
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/gogf/gf/v2 v2.5.7
|
||||
github.com/gogf/gf/v2 v2.6.1
|
||||
github.com/polarismesh/polaris-go v1.5.5
|
||||
)
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@ go 1.18
|
||||
|
||||
require (
|
||||
github.com/go-zookeeper/zk v1.0.3
|
||||
github.com/gogf/gf/v2 v2.5.7
|
||||
github.com/gogf/gf/v2 v2.6.1
|
||||
golang.org/x/sync v0.4.0
|
||||
)
|
||||
|
||||
|
||||
@ -3,8 +3,8 @@ module github.com/gogf/gf/contrib/rpc/grpcx/v2
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/gogf/gf/contrib/registry/file/v2 v2.5.7
|
||||
github.com/gogf/gf/v2 v2.5.7
|
||||
github.com/gogf/gf/contrib/registry/file/v2 v2.6.1
|
||||
github.com/gogf/gf/v2 v2.6.1
|
||||
go.opentelemetry.io/otel v1.14.0
|
||||
go.opentelemetry.io/otel/trace v1.14.0
|
||||
google.golang.org/grpc v1.57.2
|
||||
|
||||
@ -8,7 +8,6 @@ package grpcx
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
@ -18,18 +17,41 @@ import (
|
||||
|
||||
// GrpcServerConfig is the configuration for server.
|
||||
type GrpcServerConfig struct {
|
||||
Address string // (optional) Single address for server listening, use `:0` or `ip:0` to serve random port.
|
||||
Name string // (optional) Name for current service.
|
||||
Logger *glog.Logger // (optional) Logger for server.
|
||||
LogPath string // (optional) LogPath specifies the directory for storing logging files.
|
||||
LogStdout bool // (optional) LogStdout specifies whether printing logging content to stdout.
|
||||
ErrorStack bool // (optional) ErrorStack specifies whether logging stack information when error.
|
||||
ErrorLogEnabled bool // (optional) ErrorLogEnabled enables error logging content to files.
|
||||
ErrorLogPattern string // (optional) ErrorLogPattern specifies the error log file pattern like: error-{Ymd}.log
|
||||
AccessLogEnabled bool // (optional) AccessLogEnabled enables access logging content to file.
|
||||
AccessLogPattern string // (optional) AccessLogPattern specifies the error log file pattern like: access-{Ymd}.log
|
||||
Endpoints []string // (optional) Endpoints are custom endpoints for service register, it uses Address if empty.
|
||||
Options []grpc.ServerOption // (optional) GRPC Server options.
|
||||
// (optional) Name for current service.
|
||||
Name string
|
||||
|
||||
// (optional) Single address for server listening, use `:0` or `ip:0` to serve random port.
|
||||
Address string
|
||||
|
||||
// (optional) Logger for server.
|
||||
Logger *glog.Logger
|
||||
|
||||
// (optional) LogPath specifies the directory for storing logging files.
|
||||
LogPath string
|
||||
|
||||
// (optional) LogStdout specifies whether printing logging content to stdout.
|
||||
LogStdout bool
|
||||
|
||||
// (optional) ErrorStack specifies whether logging stack information when error.
|
||||
ErrorStack bool
|
||||
|
||||
// (optional) ErrorLogEnabled enables error logging content to files.
|
||||
ErrorLogEnabled bool
|
||||
|
||||
// (optional) ErrorLogPattern specifies the error log file pattern like: error-{Ymd}.log
|
||||
ErrorLogPattern string
|
||||
|
||||
// (optional) AccessLogEnabled enables access logging content to file.
|
||||
AccessLogEnabled bool
|
||||
|
||||
// (optional) AccessLogPattern specifies the error log file pattern like: access-{Ymd}.log
|
||||
AccessLogPattern string
|
||||
|
||||
// (optional) Endpoints are custom endpoints for service register, it uses Address if empty.
|
||||
Endpoints []string
|
||||
|
||||
// (optional) GRPC Server options.
|
||||
Options []grpc.ServerOption
|
||||
}
|
||||
|
||||
// NewConfig creates and returns a ServerConfig object with default configurations.
|
||||
@ -51,6 +73,7 @@ func (s modServer) NewConfig() *GrpcServerConfig {
|
||||
)
|
||||
// Reading configuration file and updating the configured keys.
|
||||
if g.Cfg().Available(ctx) {
|
||||
// Server attributes configuration.
|
||||
if err = g.Cfg().MustGet(ctx, configNodeNameGrpcServer).Struct(&config); err != nil {
|
||||
g.Log().Error(ctx, err)
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@ module github.com/gogf/gf/contrib/sdk/httpclient/v2
|
||||
|
||||
go 1.18
|
||||
|
||||
require github.com/gogf/gf/v2 v2.5.7
|
||||
require github.com/gogf/gf/v2 v2.6.1
|
||||
|
||||
require (
|
||||
github.com/BurntSushi/toml v1.2.0 // indirect
|
||||
|
||||
@ -3,7 +3,7 @@ module github.com/gogf/gf/contrib/trace/jaeger/v2
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/gogf/gf/v2 v2.5.7
|
||||
github.com/gogf/gf/v2 v2.6.1
|
||||
go.opentelemetry.io/otel v1.14.0
|
||||
go.opentelemetry.io/otel/exporters/jaeger v1.14.0
|
||||
go.opentelemetry.io/otel/sdk v1.14.0
|
||||
|
||||
@ -3,7 +3,7 @@ module github.com/gogf/gf/contrib/trace/otlpgrpc/v2
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
github.com/gogf/gf/v2 v2.5.7
|
||||
github.com/gogf/gf/v2 v2.6.1
|
||||
go.opentelemetry.io/otel v1.19.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0
|
||||
|
||||
@ -3,7 +3,7 @@ module github.com/gogf/gf/contrib/trace/otlphttp/v2
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
github.com/gogf/gf/v2 v2.5.7
|
||||
github.com/gogf/gf/v2 v2.6.1
|
||||
go.opentelemetry.io/otel v1.19.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0
|
||||
|
||||
@ -60,7 +60,7 @@ func (c *Core) GetFieldType(ctx context.Context, fieldName, table, schema string
|
||||
func (c *Core) ConvertDataForRecord(ctx context.Context, value interface{}, table string) (map[string]interface{}, error) {
|
||||
var (
|
||||
err error
|
||||
data = DataToMapDeep(value)
|
||||
data = MapOrStructToMapDeep(value, true)
|
||||
)
|
||||
for fieldName, fieldValue := range data {
|
||||
data[fieldName], err = c.db.ConvertValueForField(
|
||||
|
||||
@ -96,7 +96,9 @@ func DBFromCtx(ctx context.Context) DB {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ToSQL formats and returns the last one of sql statements in given closure function without truly executing it.
|
||||
// ToSQL formats and returns the last one of sql statements in given closure function
|
||||
// WITHOUT TRULY EXECUTING IT.
|
||||
// Be caution that, all the following sql statements should use the context object passing by function `f`.
|
||||
func ToSQL(ctx context.Context, f func(ctx context.Context) error) (sql string, err error) {
|
||||
var manager = &CatchSQLManager{
|
||||
SQLArray: garray.NewStrArray(),
|
||||
@ -108,7 +110,8 @@ func ToSQL(ctx context.Context, f func(ctx context.Context) error) (sql string,
|
||||
return
|
||||
}
|
||||
|
||||
// CatchSQL catches and returns all sql statements that are executed in given closure function.
|
||||
// CatchSQL catches and returns all sql statements that are EXECUTED in given closure function.
|
||||
// Be caution that, all the following sql statements should use the context object passing by function `f`.
|
||||
func CatchSQL(ctx context.Context, f func(ctx context.Context) error) (sqlArray []string, err error) {
|
||||
var manager = &CatchSQLManager{
|
||||
SQLArray: garray.NewStrArray(),
|
||||
@ -210,14 +213,25 @@ func GetInsertOperationByOption(option InsertOption) string {
|
||||
}
|
||||
|
||||
func anyValueToMapBeforeToRecord(value interface{}) map[string]interface{} {
|
||||
return gconv.Map(value, structTagPriority...)
|
||||
return gconv.Map(value, gconv.MapOption{
|
||||
Tags: structTagPriority,
|
||||
OmitEmpty: true, // To be compatible with old version from v2.6.0.
|
||||
})
|
||||
}
|
||||
|
||||
// DataToMapDeep converts `value` to map type recursively(if attribute struct is embedded).
|
||||
// DaToMapDeep is deprecated, use MapOrStructToMapDeep instead.
|
||||
func DaToMapDeep(value interface{}) map[string]interface{} {
|
||||
return MapOrStructToMapDeep(value, true)
|
||||
}
|
||||
|
||||
// MapOrStructToMapDeep converts `value` to map type recursively(if attribute struct is embedded).
|
||||
// The parameter `value` should be type of *map/map/*struct/struct.
|
||||
// It supports embedded struct definition for struct.
|
||||
func DataToMapDeep(value interface{}) map[string]interface{} {
|
||||
m := gconv.Map(value, structTagPriority...)
|
||||
func MapOrStructToMapDeep(value interface{}, omitempty bool) map[string]interface{} {
|
||||
m := gconv.Map(value, gconv.MapOption{
|
||||
Tags: structTagPriority,
|
||||
OmitEmpty: omitempty,
|
||||
})
|
||||
for k, v := range m {
|
||||
switch v.(type) {
|
||||
case time.Time, *time.Time, gtime.Time, *gtime.Time, gjson.Json, *gjson.Json:
|
||||
@ -413,7 +427,7 @@ func formatWhereHolder(ctx context.Context, db DB, in formatWhereHolderInput) (n
|
||||
newArgs = formatWhereInterfaces(db, gconv.Interfaces(in.Where), buffer, newArgs)
|
||||
|
||||
case reflect.Map:
|
||||
for key, value := range DataToMapDeep(in.Where) {
|
||||
for key, value := range MapOrStructToMapDeep(in.Where, true) {
|
||||
if in.OmitNil && empty.IsNil(value) {
|
||||
continue
|
||||
}
|
||||
@ -468,7 +482,7 @@ func formatWhereHolder(ctx context.Context, db DB, in formatWhereHolderInput) (n
|
||||
var (
|
||||
reflectType = reflectInfo.OriginValue.Type()
|
||||
structField reflect.StructField
|
||||
data = DataToMapDeep(in.Where)
|
||||
data = MapOrStructToMapDeep(in.Where, true)
|
||||
)
|
||||
// If `Prefix` is given, it checks and retrieves the table name.
|
||||
if in.Prefix != "" {
|
||||
|
||||
@ -268,7 +268,7 @@ func (m *Model) doInsertWithOption(ctx context.Context, insertOption InsertOptio
|
||||
|
||||
default:
|
||||
// It uses gconv.Map here to simply fo the type converting from interface{} to map[string]interface{},
|
||||
// as there's another DataToMapDeep in next logic to do the deep converting.
|
||||
// as there's another MapOrStructToMapDeep in next logic to do the deep converting.
|
||||
reflectInfo := reflection.OriginValueAndKind(newData)
|
||||
switch reflectInfo.OriginKind {
|
||||
// If it's slice type, it then converts it to List type.
|
||||
|
||||
@ -16,9 +16,9 @@ type Option struct {
|
||||
Code gcode.Code // Error code if necessary.
|
||||
}
|
||||
|
||||
// NewOption creates and returns a custom error with Option.
|
||||
// NewWithOption creates and returns a custom error with Option.
|
||||
// It is the senior usage for creating error, which is often used internally in framework.
|
||||
func NewOption(option Option) error {
|
||||
func NewWithOption(option Option) error {
|
||||
err := &Error{
|
||||
error: option.Error,
|
||||
text: option.Text,
|
||||
@ -29,3 +29,9 @@ func NewOption(option Option) error {
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// NewOption creates and returns a custom error with Option.
|
||||
// Deprecated: use NewWithOption instead.
|
||||
func NewOption(option Option) error {
|
||||
return NewWithOption(option)
|
||||
}
|
||||
|
||||
@ -442,7 +442,7 @@ func Test_HashCode(t *testing.T) {
|
||||
|
||||
func Test_NewOption(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
t.AssertNE(gerror.NewOption(gerror.Option{
|
||||
t.AssertNE(gerror.NewWithOption(gerror.Option{
|
||||
Error: errors.New("NewOptionError"),
|
||||
Stack: true,
|
||||
Text: "Text",
|
||||
|
||||
@ -3,21 +3,21 @@ module github.com/gogf/gf/example
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
github.com/gogf/gf/contrib/config/apollo/v2 v2.5.7
|
||||
github.com/gogf/gf/contrib/config/consul/v2 v2.5.7
|
||||
github.com/gogf/gf/contrib/config/kubecm/v2 v2.5.7
|
||||
github.com/gogf/gf/contrib/config/nacos/v2 v2.5.7
|
||||
github.com/gogf/gf/contrib/config/polaris/v2 v2.5.7
|
||||
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.5.7
|
||||
github.com/gogf/gf/contrib/nosql/redis/v2 v2.5.7
|
||||
github.com/gogf/gf/contrib/registry/etcd/v2 v2.5.7
|
||||
github.com/gogf/gf/contrib/registry/file/v2 v2.5.7
|
||||
github.com/gogf/gf/contrib/config/apollo/v2 v2.6.1
|
||||
github.com/gogf/gf/contrib/config/consul/v2 v2.6.1
|
||||
github.com/gogf/gf/contrib/config/kubecm/v2 v2.6.1
|
||||
github.com/gogf/gf/contrib/config/nacos/v2 v2.6.1
|
||||
github.com/gogf/gf/contrib/config/polaris/v2 v2.6.1
|
||||
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.6.1
|
||||
github.com/gogf/gf/contrib/nosql/redis/v2 v2.6.1
|
||||
github.com/gogf/gf/contrib/registry/etcd/v2 v2.6.1
|
||||
github.com/gogf/gf/contrib/registry/file/v2 v2.6.1
|
||||
github.com/gogf/gf/contrib/registry/nacos/v2 v2.5.6
|
||||
github.com/gogf/gf/contrib/registry/polaris/v2 v2.5.7
|
||||
github.com/gogf/gf/contrib/rpc/grpcx/v2 v2.5.7
|
||||
github.com/gogf/gf/contrib/trace/otlpgrpc/v2 v2.5.7
|
||||
github.com/gogf/gf/contrib/trace/otlphttp/v2 v2.5.7
|
||||
github.com/gogf/gf/v2 v2.5.7
|
||||
github.com/gogf/gf/contrib/registry/polaris/v2 v2.6.1
|
||||
github.com/gogf/gf/contrib/rpc/grpcx/v2 v2.6.1
|
||||
github.com/gogf/gf/contrib/trace/otlpgrpc/v2 v2.6.1
|
||||
github.com/gogf/gf/contrib/trace/otlphttp/v2 v2.6.1
|
||||
github.com/gogf/gf/v2 v2.6.1
|
||||
github.com/hashicorp/consul/api v1.24.0
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2
|
||||
github.com/nacos-group/nacos-sdk-go v1.1.4
|
||||
|
||||
44
example/httpserver/upload_file/main.go
Normal file
44
example/httpserver/upload_file/main.go
Normal file
@ -0,0 +1,44 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
)
|
||||
|
||||
type UploadReq struct {
|
||||
g.Meta `path:"/upload" method:"POST" tags:"Upload" mime:"multipart/form-data" summary:"上传文件"`
|
||||
File *ghttp.UploadFile `p:"file" type:"file" dc:"选择上传文件"`
|
||||
Msg string `dc:"消息"`
|
||||
}
|
||||
type UploadRes struct {
|
||||
FileName string `json:"fileName"`
|
||||
}
|
||||
|
||||
type cUpload struct{}
|
||||
|
||||
func (u cUpload) Upload(ctx context.Context, req *UploadReq) (*UploadRes, error) {
|
||||
if req.File != nil {
|
||||
return &UploadRes{
|
||||
FileName: req.File.Filename,
|
||||
}, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.Group("/", func(group *ghttp.RouterGroup) {
|
||||
group.Middleware(ghttp.MiddlewareHandlerResponse)
|
||||
group.Bind(cUpload{})
|
||||
})
|
||||
s.SetClientMaxBodySize(600 * 1024 * 1024) // 600M
|
||||
s.SetPort(8199)
|
||||
s.SetAccessLogEnabled(true)
|
||||
s.Run()
|
||||
}
|
||||
|
||||
// curl --location 'http://127.0.0.1:8199/upload' \
|
||||
// --form 'file=@"/D:/下载/goframe-v2.5.pdf"' \
|
||||
// --form 'msg="666"'
|
||||
@ -338,8 +338,8 @@ func (c *Client) callRequest(req *http.Request) (resp *Response, err error) {
|
||||
// raw HTTP request-response procedure.
|
||||
reqBodyContent, _ := io.ReadAll(req.Body)
|
||||
resp.requestBody = reqBodyContent
|
||||
req.Body = utils.NewReadCloser(reqBodyContent, false)
|
||||
for {
|
||||
req.Body = utils.NewReadCloser(reqBodyContent, false)
|
||||
if resp.Response, err = c.Do(req); err != nil {
|
||||
err = gerror.Wrapf(err, `request failed`)
|
||||
// The response might not be nil when err != nil.
|
||||
|
||||
@ -205,7 +205,7 @@ var (
|
||||
)
|
||||
|
||||
var (
|
||||
ErrNeedJsonBody = gerror.NewOption(gerror.Option{
|
||||
ErrNeedJsonBody = gerror.NewWithOption(gerror.Option{
|
||||
Text: "the request body content should be JSON format",
|
||||
Code: gcode.CodeInvalidRequest,
|
||||
})
|
||||
|
||||
@ -269,8 +269,6 @@ func (r *Request) parseForm() {
|
||||
return
|
||||
}
|
||||
if contentType := r.Header.Get("Content-Type"); contentType != "" {
|
||||
r.MakeBodyRepeatableRead(true)
|
||||
|
||||
var err error
|
||||
if gstr.Contains(contentType, "multipart/") {
|
||||
// multipart/form-data, multipart/mixed
|
||||
|
||||
@ -117,7 +117,7 @@ func forkReloadProcess(ctx context.Context, newExeFilePath ...string) error {
|
||||
var (
|
||||
path = os.Args[0]
|
||||
)
|
||||
if len(newExeFilePath) > 0 {
|
||||
if len(newExeFilePath) > 0 && newExeFilePath[0] != "" {
|
||||
path = newExeFilePath[0]
|
||||
}
|
||||
var (
|
||||
@ -156,12 +156,12 @@ func forkReloadProcess(ctx context.Context, newExeFilePath ...string) error {
|
||||
}
|
||||
|
||||
// forkRestartProcess creates a new server process.
|
||||
func forkRestartProcess(ctx context.Context, newExeFilePath string) error {
|
||||
func forkRestartProcess(ctx context.Context, newExeFilePath ...string) error {
|
||||
var (
|
||||
path = os.Args[0]
|
||||
)
|
||||
if newExeFilePath != "" {
|
||||
path = newExeFilePath
|
||||
if len(newExeFilePath) > 0 && newExeFilePath[0] != "" {
|
||||
path = newExeFilePath[0]
|
||||
}
|
||||
if err := os.Unsetenv(adminActionReloadEnvKey); err != nil {
|
||||
intlog.Errorf(ctx, `%+v`, err)
|
||||
|
||||
@ -43,6 +43,9 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
// Create a new request object.
|
||||
request := newRequest(s, r, w)
|
||||
|
||||
// Get sessionId before user handler
|
||||
sessionId := request.GetSessionId()
|
||||
|
||||
defer func() {
|
||||
request.LeaveTime = gtime.TimestampMilli()
|
||||
// error log handling.
|
||||
@ -176,10 +179,17 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
// Automatically set the session id to cookie
|
||||
// if it creates a new session id in this request
|
||||
// and SessionCookieOutput is enabled.
|
||||
if s.config.SessionCookieOutput &&
|
||||
request.Session.IsDirty() &&
|
||||
request.Session.MustId() != request.GetSessionId() {
|
||||
request.Cookie.SetSessionId(request.Session.MustId())
|
||||
if s.config.SessionCookieOutput && request.Session.IsDirty() {
|
||||
// Can change by r.Session.SetId("") before init session
|
||||
// Can change by r.Cookie.SetSessionId("")
|
||||
sidFromSession, sidFromRequest := request.Session.MustId(), request.GetSessionId()
|
||||
if sidFromSession != sidFromRequest {
|
||||
if sidFromSession != sessionId {
|
||||
request.Cookie.SetSessionId(sidFromSession)
|
||||
} else {
|
||||
request.Cookie.SetSessionId(sidFromRequest)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Output the cookie content to the client.
|
||||
request.Cookie.Flush()
|
||||
|
||||
@ -8,6 +8,7 @@ package ghttp_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@ -154,8 +155,11 @@ func Test_ClientMaxBodySize_File(t *testing.T) {
|
||||
t.Assert(gfile.PutBytes(path, data), nil)
|
||||
defer gfile.Remove(path)
|
||||
t.Assert(
|
||||
gstr.Trim(c.PostContent(ctx, "/", "name=john&file=@file:"+path)),
|
||||
"Read from request Body failed: http: request body too large",
|
||||
true,
|
||||
strings.Contains(
|
||||
gstr.Trim(c.PostContent(ctx, "/", "name=john&file=@file:"+path)),
|
||||
"http: request body too large",
|
||||
),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
@ -189,3 +189,92 @@ func Test_Session_Custom_Id(t *testing.T) {
|
||||
t.Assert(client.GetContent(ctx, "/value"), value)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Session_New_Id(t *testing.T) {
|
||||
var (
|
||||
sessionId = "1234567890"
|
||||
newSessionId = "0987654321"
|
||||
newSessionId2 = "abcdefghij"
|
||||
key = "key"
|
||||
value = "value"
|
||||
s = g.Server(guid.S())
|
||||
)
|
||||
s.BindHandler("/id", func(r *ghttp.Request) {
|
||||
if err := r.Session.SetId(sessionId); err != nil {
|
||||
r.Response.WriteExit(err.Error())
|
||||
}
|
||||
if err := r.Session.Set(key, value); err != nil {
|
||||
r.Response.WriteExit(err.Error())
|
||||
}
|
||||
r.Response.WriteExit(r.Session.Id())
|
||||
})
|
||||
|
||||
s.BindHandler("/newIdBySession", func(r *ghttp.Request) {
|
||||
// Use before session init
|
||||
if err := r.Session.SetId(newSessionId); err != nil {
|
||||
r.Response.WriteExit(err.Error())
|
||||
}
|
||||
if err := r.Session.Set(key, value); err != nil {
|
||||
r.Response.WriteExit(err.Error())
|
||||
}
|
||||
r.Response.WriteExit(r.Session.Id())
|
||||
})
|
||||
|
||||
s.BindHandler("/newIdByCookie", func(r *ghttp.Request) {
|
||||
if err := r.Session.Remove("someKey"); err != nil {
|
||||
r.Response.WriteExit(err.Error())
|
||||
}
|
||||
|
||||
r.Cookie.SetSessionId(newSessionId2)
|
||||
//r.Response.WriteExit(r.Session.Id()) // only change in cookie
|
||||
|
||||
r.Response.WriteExit(newSessionId2)
|
||||
})
|
||||
|
||||
s.BindHandler("/value", func(r *ghttp.Request) {
|
||||
r.Response.WriteExit(r.Session.Get(key))
|
||||
})
|
||||
s.SetDumpRouterMap(false)
|
||||
s.Start()
|
||||
defer s.Shutdown()
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
client := g.Client()
|
||||
client.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort()))
|
||||
r, err := client.Get(ctx, "/id")
|
||||
t.AssertNil(err)
|
||||
defer r.Close()
|
||||
t.Assert(r.ReadAllString(), sessionId)
|
||||
t.Assert(r.GetCookie(s.GetSessionIdName()), sessionId)
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
client := g.Client()
|
||||
client.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort()))
|
||||
client.SetHeader(s.GetSessionIdName(), sessionId)
|
||||
t.Assert(client.GetContent(ctx, "/value"), value)
|
||||
})
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
client := g.Client()
|
||||
client.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort()))
|
||||
client.SetHeader(s.GetSessionIdName(), sessionId)
|
||||
r, err := client.Get(ctx, "/newIdBySession")
|
||||
t.AssertNil(err)
|
||||
defer r.Close()
|
||||
t.Assert(r.ReadAllString(), newSessionId)
|
||||
t.Assert(r.GetCookie(s.GetSessionIdName()), newSessionId)
|
||||
})
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
client := g.Client()
|
||||
client.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort()))
|
||||
r, err := client.Get(ctx, "/newIdByCookie")
|
||||
client.SetHeader(s.GetSessionIdName(), sessionId)
|
||||
t.AssertNil(err)
|
||||
defer r.Close()
|
||||
t.Assert(r.ReadAllString(), newSessionId2)
|
||||
t.Assert(r.GetCookie(s.GetSessionIdName()), newSessionId2)
|
||||
})
|
||||
}
|
||||
|
||||
@ -11,6 +11,7 @@ import (
|
||||
"os"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gcfg"
|
||||
"github.com/gogf/gf/v2/os/gcmd"
|
||||
"github.com/gogf/gf/v2/os/gctx"
|
||||
"github.com/gogf/gf/v2/os/genv"
|
||||
@ -64,3 +65,21 @@ func ExampleConfig_GetWithCmd() {
|
||||
// cmd:
|
||||
// cmd:yes
|
||||
}
|
||||
|
||||
func Example_NewWithAdapter() {
|
||||
var (
|
||||
ctx = gctx.New()
|
||||
content = `{"a":"b", "c":1}`
|
||||
adapter, err = gcfg.NewAdapterContent(content)
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
config := gcfg.NewWithAdapter(adapter)
|
||||
fmt.Println(config.MustGet(ctx, "a"))
|
||||
fmt.Println(config.MustGet(ctx, "c"))
|
||||
|
||||
// Output:
|
||||
// b
|
||||
// 1
|
||||
}
|
||||
|
||||
@ -219,8 +219,8 @@ func (l *Logger) print(ctx context.Context, level int, stack string, values ...a
|
||||
}
|
||||
}
|
||||
|
||||
// doDefaultPrint outputs the logging content according configuration.
|
||||
func (l *Logger) doDefaultPrint(ctx context.Context, input *HandlerInput) *bytes.Buffer {
|
||||
// doFinalPrint outputs the logging content according configuration.
|
||||
func (l *Logger) doFinalPrint(ctx context.Context, input *HandlerInput) *bytes.Buffer {
|
||||
var buffer *bytes.Buffer
|
||||
// Allow output to stdout?
|
||||
if l.config.StdoutPrint {
|
||||
|
||||
@ -49,7 +49,7 @@ var defaultHandler Handler
|
||||
// doFinalPrint is a handler for logging content printing.
|
||||
// This handler outputs logging content to file/stdout/write if any of them configured.
|
||||
func doFinalPrint(ctx context.Context, in *HandlerInput) {
|
||||
buffer := in.Logger.doDefaultPrint(ctx, in)
|
||||
buffer := in.Logger.doFinalPrint(ctx, in)
|
||||
if in.Buffer.Len() == 0 {
|
||||
in.Buffer = buffer
|
||||
}
|
||||
|
||||
@ -15,7 +15,7 @@ import (
|
||||
|
||||
var (
|
||||
// ErrorDisabled is used for marking certain interface function not used.
|
||||
ErrorDisabled = gerror.NewOption(gerror.Option{
|
||||
ErrorDisabled = gerror.NewWithOption(gerror.Option{
|
||||
Text: "this feature is disabled in this storage",
|
||||
Code: gcode.CodeNotSupported,
|
||||
})
|
||||
|
||||
@ -8,6 +8,11 @@ package gconv
|
||||
|
||||
import "github.com/gogf/gf/v2/os/gtime"
|
||||
|
||||
// iVal is used for type assert api for String().
|
||||
type iVal interface {
|
||||
Val() interface{}
|
||||
}
|
||||
|
||||
// iString is used for type assert api for String().
|
||||
type iString interface {
|
||||
String() string
|
||||
|
||||
@ -22,40 +22,64 @@ const (
|
||||
recursiveTypeTrue recursiveType = "true"
|
||||
)
|
||||
|
||||
// MapOption specifies the option for map converting.
|
||||
type MapOption struct {
|
||||
// Deep marks doing Map function recursively, which means if the attribute of given converting value
|
||||
// is also a struct/*struct, it automatically calls Map function on this attribute converting it to
|
||||
// a map[string]interface{} type variable.
|
||||
Deep bool
|
||||
|
||||
// OmitEmpty ignores the attributes that has json `omitempty` tag.
|
||||
OmitEmpty bool
|
||||
|
||||
// Tags specifies the converted map key name by struct tag name.
|
||||
Tags []string
|
||||
}
|
||||
|
||||
// Map converts any variable `value` to map[string]interface{}. If the parameter `value` is not a
|
||||
// map/struct/*struct type, then the conversion will fail and returns nil.
|
||||
//
|
||||
// If `value` is a struct/*struct object, the second parameter `tags` specifies the most priority
|
||||
// tags that will be detected, otherwise it detects the tags in order of:
|
||||
// gconv, json, field name.
|
||||
func Map(value interface{}, tags ...string) map[string]interface{} {
|
||||
return doMapConvert(value, recursiveTypeAuto, false, tags...)
|
||||
func Map(value interface{}, option ...MapOption) map[string]interface{} {
|
||||
return doMapConvert(value, recursiveTypeAuto, false, option...)
|
||||
}
|
||||
|
||||
// MapDeep does Map function recursively, which means if the attribute of `value`
|
||||
// is also a struct/*struct, calls Map function on this attribute converting it to
|
||||
// a map[string]interface{} type variable.
|
||||
// Also see Map.
|
||||
// Deprecated: used Map instead.
|
||||
func MapDeep(value interface{}, tags ...string) map[string]interface{} {
|
||||
return doMapConvert(value, recursiveTypeTrue, false, tags...)
|
||||
return doMapConvert(value, recursiveTypeTrue, false, MapOption{
|
||||
Tags: tags,
|
||||
})
|
||||
}
|
||||
|
||||
// doMapConvert implements the map converting.
|
||||
// It automatically checks and converts json string to map if `value` is string/[]byte.
|
||||
//
|
||||
// TODO completely implement the recursive converting for all types, especially the map.
|
||||
func doMapConvert(value interface{}, recursive recursiveType, mustMapReturn bool, tags ...string) map[string]interface{} {
|
||||
func doMapConvert(value interface{}, recursive recursiveType, mustMapReturn bool, option ...MapOption) map[string]interface{} {
|
||||
if value == nil {
|
||||
return nil
|
||||
}
|
||||
newTags := StructTagPriority
|
||||
switch len(tags) {
|
||||
// It redirects to its underlying value if it has implemented interface iVal.
|
||||
if v, ok := value.(iVal); ok {
|
||||
value = v.Val()
|
||||
}
|
||||
|
||||
var (
|
||||
usedOption = getUsedMapOption(option...)
|
||||
newTags = StructTagPriority
|
||||
)
|
||||
switch len(usedOption.Tags) {
|
||||
case 0:
|
||||
// No need handling.
|
||||
case 1:
|
||||
newTags = append(strings.Split(tags[0], ","), StructTagPriority...)
|
||||
newTags = append(strings.Split(usedOption.Tags[0], ","), StructTagPriority...)
|
||||
default:
|
||||
newTags = append(tags, StructTagPriority...)
|
||||
newTags = append(usedOption.Tags, StructTagPriority...)
|
||||
}
|
||||
// Assert the common combination of types, and finally it uses reflection.
|
||||
dataMap := make(map[string]interface{})
|
||||
@ -79,6 +103,8 @@ func doMapConvert(value interface{}, recursive recursiveType, mustMapReturn bool
|
||||
return nil
|
||||
}
|
||||
case map[interface{}]interface{}:
|
||||
recursiveOption := usedOption
|
||||
recursiveOption.Tags = newTags
|
||||
for k, v := range r {
|
||||
dataMap[String(k)] = doMapConvertForMapOrStructValue(
|
||||
doMapConvertForMapOrStructValueInput{
|
||||
@ -86,7 +112,7 @@ func doMapConvert(value interface{}, recursive recursiveType, mustMapReturn bool
|
||||
Value: v,
|
||||
RecursiveType: recursive,
|
||||
RecursiveOption: recursive == recursiveTypeTrue,
|
||||
Tags: newTags,
|
||||
Option: recursiveOption,
|
||||
},
|
||||
)
|
||||
}
|
||||
@ -136,6 +162,8 @@ func doMapConvert(value interface{}, recursive recursiveType, mustMapReturn bool
|
||||
}
|
||||
case map[string]interface{}:
|
||||
if recursive == recursiveTypeTrue {
|
||||
recursiveOption := usedOption
|
||||
recursiveOption.Tags = newTags
|
||||
// A copy of current map.
|
||||
for k, v := range r {
|
||||
dataMap[k] = doMapConvertForMapOrStructValue(
|
||||
@ -144,7 +172,7 @@ func doMapConvert(value interface{}, recursive recursiveType, mustMapReturn bool
|
||||
Value: v,
|
||||
RecursiveType: recursive,
|
||||
RecursiveOption: recursive == recursiveTypeTrue,
|
||||
Tags: newTags,
|
||||
Option: recursiveOption,
|
||||
},
|
||||
)
|
||||
}
|
||||
@ -153,6 +181,8 @@ func doMapConvert(value interface{}, recursive recursiveType, mustMapReturn bool
|
||||
return r
|
||||
}
|
||||
case map[int]interface{}:
|
||||
recursiveOption := usedOption
|
||||
recursiveOption.Tags = newTags
|
||||
for k, v := range r {
|
||||
dataMap[String(k)] = doMapConvertForMapOrStructValue(
|
||||
doMapConvertForMapOrStructValueInput{
|
||||
@ -160,7 +190,7 @@ func doMapConvert(value interface{}, recursive recursiveType, mustMapReturn bool
|
||||
Value: v,
|
||||
RecursiveType: recursive,
|
||||
RecursiveOption: recursive == recursiveTypeTrue,
|
||||
Tags: newTags,
|
||||
Option: recursiveOption,
|
||||
},
|
||||
)
|
||||
}
|
||||
@ -202,13 +232,15 @@ func doMapConvert(value interface{}, recursive recursiveType, mustMapReturn bool
|
||||
}
|
||||
}
|
||||
case reflect.Map, reflect.Struct, reflect.Interface:
|
||||
recursiveOption := usedOption
|
||||
recursiveOption.Tags = newTags
|
||||
convertedValue := doMapConvertForMapOrStructValue(
|
||||
doMapConvertForMapOrStructValueInput{
|
||||
IsRoot: true,
|
||||
Value: value,
|
||||
RecursiveType: recursive,
|
||||
RecursiveOption: recursive == recursiveTypeTrue,
|
||||
Tags: newTags,
|
||||
Option: recursiveOption,
|
||||
MustMapReturn: mustMapReturn,
|
||||
},
|
||||
)
|
||||
@ -223,12 +255,20 @@ func doMapConvert(value interface{}, recursive recursiveType, mustMapReturn bool
|
||||
return dataMap
|
||||
}
|
||||
|
||||
func getUsedMapOption(option ...MapOption) MapOption {
|
||||
var usedOption MapOption
|
||||
if len(option) > 0 {
|
||||
usedOption = option[0]
|
||||
}
|
||||
return usedOption
|
||||
}
|
||||
|
||||
type doMapConvertForMapOrStructValueInput struct {
|
||||
IsRoot bool // It returns directly if it is not root and with no recursive converting.
|
||||
Value interface{} // Current operation value.
|
||||
RecursiveType recursiveType // The type from top function entry.
|
||||
RecursiveOption bool // Whether convert recursively for `current` operation.
|
||||
Tags []string // Map key mapping.
|
||||
Option MapOption // Map converting option.
|
||||
MustMapReturn bool // Must return map instead of Value when empty.
|
||||
}
|
||||
|
||||
@ -280,7 +320,7 @@ func doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) in
|
||||
Value: mapValue,
|
||||
RecursiveType: in.RecursiveType,
|
||||
RecursiveOption: in.RecursiveType == recursiveTypeTrue,
|
||||
Tags: in.Tags,
|
||||
Option: in.Option,
|
||||
},
|
||||
)
|
||||
}
|
||||
@ -299,7 +339,7 @@ func doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) in
|
||||
Value: mapV,
|
||||
RecursiveType: in.RecursiveType,
|
||||
RecursiveOption: in.RecursiveType == recursiveTypeTrue,
|
||||
Tags: in.Tags,
|
||||
Option: in.Option,
|
||||
},
|
||||
)
|
||||
} else {
|
||||
@ -327,7 +367,7 @@ func doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) in
|
||||
}
|
||||
mapKey = ""
|
||||
fieldTag := rtField.Tag
|
||||
for _, tag := range in.Tags {
|
||||
for _, tag := range in.Option.Tags {
|
||||
if mapKey = fieldTag.Get(tag); mapKey != "" {
|
||||
break
|
||||
}
|
||||
@ -344,7 +384,7 @@ func doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) in
|
||||
if len(array) > 1 {
|
||||
switch strings.TrimSpace(array[1]) {
|
||||
case "omitempty":
|
||||
if empty.IsEmpty(rvField.Interface()) {
|
||||
if in.Option.OmitEmpty && empty.IsEmpty(rvField.Interface()) {
|
||||
continue
|
||||
} else {
|
||||
mapKey = strings.TrimSpace(array[0])
|
||||
@ -389,7 +429,7 @@ func doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) in
|
||||
Value: rvInterface,
|
||||
RecursiveType: in.RecursiveType,
|
||||
RecursiveOption: true,
|
||||
Tags: in.Tags,
|
||||
Option: in.Option,
|
||||
})
|
||||
if m, ok := anonymousValue.(map[string]interface{}); ok {
|
||||
for k, v := range m {
|
||||
@ -406,7 +446,7 @@ func doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) in
|
||||
Value: rvInterface,
|
||||
RecursiveType: in.RecursiveType,
|
||||
RecursiveOption: true,
|
||||
Tags: in.Tags,
|
||||
Option: in.Option,
|
||||
})
|
||||
|
||||
default:
|
||||
@ -415,7 +455,7 @@ func doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) in
|
||||
Value: rvInterface,
|
||||
RecursiveType: in.RecursiveType,
|
||||
RecursiveOption: in.RecursiveType == recursiveTypeTrue,
|
||||
Tags: in.Tags,
|
||||
Option: in.Option,
|
||||
})
|
||||
}
|
||||
|
||||
@ -434,7 +474,7 @@ func doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) in
|
||||
Value: rvAttrField.Index(arrayIndex).Interface(),
|
||||
RecursiveType: in.RecursiveType,
|
||||
RecursiveOption: in.RecursiveType == recursiveTypeTrue,
|
||||
Tags: in.Tags,
|
||||
Option: in.Option,
|
||||
},
|
||||
)
|
||||
}
|
||||
@ -451,7 +491,7 @@ func doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) in
|
||||
Value: rvAttrField.MapIndex(k).Interface(),
|
||||
RecursiveType: in.RecursiveType,
|
||||
RecursiveOption: in.RecursiveType == recursiveTypeTrue,
|
||||
Tags: in.Tags,
|
||||
Option: in.Option,
|
||||
},
|
||||
)
|
||||
}
|
||||
@ -490,7 +530,7 @@ func doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) in
|
||||
Value: reflectValue.Index(i).Interface(),
|
||||
RecursiveType: in.RecursiveType,
|
||||
RecursiveOption: in.RecursiveType == recursiveTypeTrue,
|
||||
Tags: in.Tags,
|
||||
Option: in.Option,
|
||||
})
|
||||
}
|
||||
return array
|
||||
@ -500,11 +540,11 @@ func doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) in
|
||||
|
||||
// MapStrStr converts `value` to map[string]string.
|
||||
// Note that there might be data copy for this map type converting.
|
||||
func MapStrStr(value interface{}, tags ...string) map[string]string {
|
||||
func MapStrStr(value interface{}, option ...MapOption) map[string]string {
|
||||
if r, ok := value.(map[string]string); ok {
|
||||
return r
|
||||
}
|
||||
m := Map(value, tags...)
|
||||
m := Map(value, option...)
|
||||
if len(m) > 0 {
|
||||
vMap := make(map[string]string, len(m))
|
||||
for k, v := range m {
|
||||
@ -517,6 +557,7 @@ func MapStrStr(value interface{}, tags ...string) map[string]string {
|
||||
|
||||
// MapStrStrDeep converts `value` to map[string]string recursively.
|
||||
// Note that there might be data copy for this map type converting.
|
||||
// Deprecated: used MapStrStr instead.
|
||||
func MapStrStrDeep(value interface{}, tags ...string) map[string]string {
|
||||
if r, ok := value.(map[string]string); ok {
|
||||
return r
|
||||
|
||||
@ -9,23 +9,19 @@ package gconv
|
||||
import "github.com/gogf/gf/v2/internal/json"
|
||||
|
||||
// SliceMap is alias of Maps.
|
||||
func SliceMap(any interface{}) []map[string]interface{} {
|
||||
return Maps(any)
|
||||
func SliceMap(any interface{}, option ...MapOption) []map[string]interface{} {
|
||||
return Maps(any, option...)
|
||||
}
|
||||
|
||||
// SliceMapDeep is alias of MapsDeep.
|
||||
// Deprecated: used SliceMap instead.
|
||||
func SliceMapDeep(any interface{}) []map[string]interface{} {
|
||||
return MapsDeep(any)
|
||||
}
|
||||
|
||||
// SliceStruct is alias of Structs.
|
||||
func SliceStruct(params interface{}, pointer interface{}, mapping ...map[string]string) (err error) {
|
||||
return Structs(params, pointer, mapping...)
|
||||
}
|
||||
|
||||
// Maps converts `value` to []map[string]interface{}.
|
||||
// Note that it automatically checks and converts json string to []map if `value` is string/[]byte.
|
||||
func Maps(value interface{}, tags ...string) []map[string]interface{} {
|
||||
func Maps(value interface{}, option ...MapOption) []map[string]interface{} {
|
||||
if value == nil {
|
||||
return nil
|
||||
}
|
||||
@ -62,7 +58,7 @@ func Maps(value interface{}, tags ...string) []map[string]interface{} {
|
||||
}
|
||||
list := make([]map[string]interface{}, len(array))
|
||||
for k, v := range array {
|
||||
list[k] = Map(v, tags...)
|
||||
list[k] = Map(v, option...)
|
||||
}
|
||||
return list
|
||||
}
|
||||
@ -71,6 +67,7 @@ func Maps(value interface{}, tags ...string) []map[string]interface{} {
|
||||
// MapsDeep converts `value` to []map[string]interface{} recursively.
|
||||
//
|
||||
// TODO completely implement the recursive converting for all types.
|
||||
// Deprecated: used Maps instead.
|
||||
func MapsDeep(value interface{}, tags ...string) []map[string]interface{} {
|
||||
if value == nil {
|
||||
return nil
|
||||
|
||||
@ -20,6 +20,11 @@ func Structs(params interface{}, pointer interface{}, paramKeyToAttrMap ...map[s
|
||||
return Scan(params, pointer, paramKeyToAttrMap...)
|
||||
}
|
||||
|
||||
// SliceStruct is alias of Structs.
|
||||
func SliceStruct(params interface{}, pointer interface{}, mapping ...map[string]string) (err error) {
|
||||
return Structs(params, pointer, mapping...)
|
||||
}
|
||||
|
||||
// StructsTag acts as Structs but also with support for priority tag feature, which retrieves the
|
||||
// specified tags for `params` key-value items to struct attribute names mapping.
|
||||
// The parameter `priorityTag` supports multiple tags that can be joined with char ','.
|
||||
|
||||
@ -946,8 +946,8 @@ func Test_Map_StructWithJsonTag_All(t *testing.T) {
|
||||
ssa: "222",
|
||||
}
|
||||
user2 := &user1
|
||||
_ = gconv.Map(user1, "Ss")
|
||||
map1 := gconv.Map(user1, "json", "json2")
|
||||
_ = gconv.Map(user1, gconv.MapOption{Tags: []string{"Ss"}})
|
||||
map1 := gconv.Map(user1, gconv.MapOption{Tags: []string{"json", "json2"}})
|
||||
map2 := gconv.Map(user2)
|
||||
map3 := gconv.Map(user3)
|
||||
t.Assert(map1["Uid"], 100)
|
||||
|
||||
@ -617,6 +617,53 @@ func TestMapWithJsonOmitEmpty(t *testing.T) {
|
||||
Key: "",
|
||||
Value: 1,
|
||||
}
|
||||
t.Assert(gconv.Map(s), g.Map{"Value": 1})
|
||||
m1 := gconv.Map(s)
|
||||
t.Assert(m1, g.Map{
|
||||
"Key": "",
|
||||
"Value": 1,
|
||||
})
|
||||
|
||||
m2 := gconv.Map(s, gconv.MapOption{
|
||||
Deep: false,
|
||||
OmitEmpty: true,
|
||||
Tags: nil,
|
||||
})
|
||||
t.Assert(m2, g.Map{
|
||||
"Value": 1,
|
||||
})
|
||||
})
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
type ProductConfig struct {
|
||||
Pid int `v:"required" json:"pid,omitempty"`
|
||||
TimeSpan int `v:"required" json:"timeSpan,omitempty"`
|
||||
}
|
||||
type CreateGoodsDetail struct {
|
||||
ProductConfig
|
||||
AutoRenewFlag int `v:"required" json:"autoRenewFlag"`
|
||||
}
|
||||
s := &CreateGoodsDetail{
|
||||
ProductConfig: ProductConfig{
|
||||
Pid: 1,
|
||||
TimeSpan: 0,
|
||||
},
|
||||
AutoRenewFlag: 0,
|
||||
}
|
||||
m1 := gconv.Map(s)
|
||||
t.Assert(m1, g.Map{
|
||||
"pid": 1,
|
||||
"timeSpan": 0,
|
||||
"autoRenewFlag": 0,
|
||||
})
|
||||
|
||||
m2 := gconv.Map(s, gconv.MapOption{
|
||||
Deep: false,
|
||||
OmitEmpty: true,
|
||||
Tags: nil,
|
||||
})
|
||||
t.Assert(m2, g.Map{
|
||||
"pid": 1,
|
||||
"autoRenewFlag": 0,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@ -44,7 +44,7 @@ func newValidationError(code gcode.Code, rules []fieldRule, fieldRuleErrorMap ma
|
||||
for field, ruleErrorMap := range fieldRuleErrorMap {
|
||||
for rule, err := range ruleErrorMap {
|
||||
if !gerror.HasStack(err) {
|
||||
ruleErrorMap[rule] = gerror.NewOption(gerror.Option{
|
||||
ruleErrorMap[rule] = gerror.NewWithOption(gerror.Option{
|
||||
Stack: false,
|
||||
Text: gstr.Trim(err.Error()),
|
||||
Code: code,
|
||||
|
||||
@ -311,24 +311,28 @@ func Test_Datetime(t *testing.T) {
|
||||
|
||||
func Test_DateFormat(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
val1 := "2010"
|
||||
val2 := "201011"
|
||||
val3 := "2010.11"
|
||||
val4 := "201011-01"
|
||||
val5 := "2010~11~01"
|
||||
val6 := "2010-11~01"
|
||||
err1 := g.Validator().Data(val1).Rules("date-format:Y").Run(ctx)
|
||||
err2 := g.Validator().Data(val2).Rules("date-format:Ym").Run(ctx)
|
||||
err3 := g.Validator().Data(val3).Rules("date-format:Y.m").Run(ctx)
|
||||
err4 := g.Validator().Data(val4).Rules("date-format:Ym-d").Run(ctx)
|
||||
err5 := g.Validator().Data(val5).Rules("date-format:Y~m~d").Run(ctx)
|
||||
err6 := g.Validator().Data(val6).Rules("date-format:Y~m~d").Run(ctx)
|
||||
t.Assert(err1, nil)
|
||||
t.Assert(err2, nil)
|
||||
t.Assert(err3, nil)
|
||||
t.Assert(err4, nil)
|
||||
t.Assert(err5, nil)
|
||||
t.AssertNE(err6, nil)
|
||||
m := g.MapStrStr{
|
||||
"2010": "date-format:Y",
|
||||
"201011": "date-format:Ym",
|
||||
"2010.11": "date-format:Y.m",
|
||||
"201011-01": "date-format:Ym-d",
|
||||
"2010~11~01": "date-format:Y~m~d",
|
||||
"2010-11~01": "date-format:Y-m~d",
|
||||
"2023-09-10T19:46:31Z": "date-format:2006-01-02\\T15:04:05Z07:00", // RFC3339
|
||||
}
|
||||
for k, v := range m {
|
||||
err := g.Validator().Data(k).Rules(v).Run(ctx)
|
||||
t.AssertNil(err)
|
||||
}
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
errM := g.MapStrStr{
|
||||
"2010-11~01": "date-format:Y~m~d",
|
||||
}
|
||||
for k, v := range errM {
|
||||
err := g.Validator().Data(k).Rules(v).Run(ctx)
|
||||
t.AssertNE(err, nil)
|
||||
}
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
t1 := gtime.Now()
|
||||
|
||||
@ -2,5 +2,5 @@ package gf
|
||||
|
||||
const (
|
||||
// VERSION is the current GoFrame version.
|
||||
VERSION = "v2.5.7"
|
||||
VERSION = "v2.6.1"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user