mirror of
https://gitee.com/johng/gf
synced 2026-06-12 04:03:22 +08:00
Compare commits
156 Commits
v2.0.0-alp
...
v2.0.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
| 1a7450b9e9 | |||
| 684fa9b9c9 | |||
| 4e91039254 | |||
| 195e167502 | |||
| 01a50b06cb | |||
| 9b663b4c2b | |||
| 655426c322 | |||
| ae27afaeb4 | |||
| 30f462288e | |||
| 4862505c5e | |||
| 31d793fafb | |||
| be274478d0 | |||
| 5b8c91a877 | |||
| 95a4690e69 | |||
| e0a0fcbde2 | |||
| 02e1d01f29 | |||
| e0db3c87cf | |||
| 903299728f | |||
| c617ad6a04 | |||
| 814649e7a3 | |||
| d1b69142c4 | |||
| 2d1593f78e | |||
| d61f7af60c | |||
| 65140d1293 | |||
| 85299cd447 | |||
| 091df972f1 | |||
| 748040fb0b | |||
| df02ca764f | |||
| 6f64c26349 | |||
| 072355dc2c | |||
| 3ca2cad449 | |||
| 05bb81cd71 | |||
| fd9246358a | |||
| 42c4b32720 | |||
| 2757647211 | |||
| 45787dd8e4 | |||
| 38b797b42f | |||
| e8f6ebc154 | |||
| e715ce0625 | |||
| aceb586bef | |||
| 15f9b69b36 | |||
| b036767fc0 | |||
| b967cf6224 | |||
| 1a596fe84d | |||
| 64fa8d5282 | |||
| 99d2186c8c | |||
| 24f759e00e | |||
| 66731c9c66 | |||
| e5ec9cd676 | |||
| e7b63839c8 | |||
| 2511c378f2 | |||
| 12514a0311 | |||
| 5b83b2375e | |||
| 98d72fae25 | |||
| 4f2a22dd0e | |||
| 4acc0e9876 | |||
| 7be24776d5 | |||
| 485706a676 | |||
| ea7d963f20 | |||
| 613958a4b6 | |||
| 44023ea91d | |||
| ef7f7e35f8 | |||
| 613a50428b | |||
| 3091f61a26 | |||
| 5776b2596d | |||
| 430102c995 | |||
| 2a2bb4f1e1 | |||
| 205243e8b9 | |||
| d16ce643fd | |||
| e94eb8f668 | |||
| 357084e788 | |||
| 9a757acc88 | |||
| 3fb1c07eac | |||
| 6050b14087 | |||
| 58c1c1bb16 | |||
| b6f6ab17f9 | |||
| 7bcba437a0 | |||
| abf199bf61 | |||
| 9ea2db5c81 | |||
| 7a6fb4a807 | |||
| c3a75f5568 | |||
| c850c420fd | |||
| e045aaaf07 | |||
| 0cd40caf0c | |||
| f2bb9d65c3 | |||
| 4e05795642 | |||
| 1df52637e8 | |||
| b83362cc2e | |||
| 274052511c | |||
| 32bc1ec064 | |||
| 5fa62e02c6 | |||
| bf3c3367a6 | |||
| 9c05682605 | |||
| 8f090739d9 | |||
| 7971177c58 | |||
| 5707763758 | |||
| 35a786d765 | |||
| 12fe41e34d | |||
| 5ffd362b6e | |||
| a423fba2a8 | |||
| 41d0832fa5 | |||
| 5e7b0c9303 | |||
| 0c43e7986f | |||
| bc1d76a796 | |||
| 6b9f72d973 | |||
| d980cff663 | |||
| 7de69db707 | |||
| 5e34aee2d7 | |||
| 797719d8d5 | |||
| 6c3aa6ede5 | |||
| 18459ec1bc | |||
| e727788f42 | |||
| 3df7711e74 | |||
| c1f856fa8e | |||
| a3eff53c69 | |||
| 56c12ad7c3 | |||
| 77a0f59cd3 | |||
| 94768530cc | |||
| 79a233eb78 | |||
| 183d800f4c | |||
| 191ad20436 | |||
| c0c68d1e46 | |||
| ac6968edf1 | |||
| e22e1d0e4a | |||
| 42e27dd14c | |||
| d817047c98 | |||
| e15cd6ae89 | |||
| 17e6063c5c | |||
| a8b2a2ff33 | |||
| 4b3eb09492 | |||
| d1c09cb21d | |||
| 1188793f8f | |||
| 09b8df1818 | |||
| 6192d32501 | |||
| a6a8d787e4 | |||
| e5c6d3f777 | |||
| 1bfa792ea9 | |||
| 8ef4f68215 | |||
| 493f5dcff2 | |||
| 2cf84e020f | |||
| a19ba3d530 | |||
| e0674ee7fe | |||
| 2481435829 | |||
| e48b565e18 | |||
| f6c2206b88 | |||
| 4717e01708 | |||
| 17861fc45d | |||
| a92c31168a | |||
| f901f19714 | |||
| e0c4f7ccbf | |||
| 5a5809bd95 | |||
| b826ed6b03 | |||
| 2891c8e29d | |||
| 5820e6ebe1 | |||
| 799e8214f8 | |||
| e3b8f374e5 |
@ -14,7 +14,7 @@ func main() {
|
||||
p := gpool.New(3000*time.Millisecond, func() (interface{}, error) {
|
||||
return gtcp.NewConn("www.baidu.com:80")
|
||||
}, func(i interface{}) {
|
||||
glog.Println("expired")
|
||||
glog.Print("expired")
|
||||
i.(*gtcp.Conn).Close()
|
||||
})
|
||||
conn, err := p.Get()
|
||||
|
||||
@ -4,20 +4,20 @@ import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
|
||||
_ "github.com/denisenkom/go-mssqldb"
|
||||
//_ "github.com/denisenkom/go-mssqldb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type Table2 struct {
|
||||
Id string `orm:"id;pr" json:"id"` //ID
|
||||
Createtime gtime.Time `orm:"createtime" json:"createtime"` //创建时间
|
||||
Updatetime gtime.Time `orm:"updatetime" json:"updatetime"` //更新时间
|
||||
CreateTime gtime.Time `orm:"createtime" json:"createtime"` //创建时间
|
||||
UpdateTime gtime.Time `orm:"updatetime" json:"updatetime"` //更新时间
|
||||
}
|
||||
var table2 Table2
|
||||
err := g.DB().Table("table2").Where("id=?", 1).Struct(&table2)
|
||||
err := g.DB().Model("table2").Where("id", 1).Scan(&table2)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(table2.Createtime)
|
||||
fmt.Println(table2.CreateTime)
|
||||
}
|
||||
|
||||
@ -17,6 +17,6 @@ func Error2() error {
|
||||
}
|
||||
|
||||
func main() {
|
||||
glog.Println(Error1())
|
||||
glog.Println(Error2())
|
||||
glog.Print(Error1())
|
||||
glog.Print(Error2())
|
||||
}
|
||||
|
||||
@ -12,7 +12,7 @@ func MiddlewareCORS(r *ghttp.Request) {
|
||||
}
|
||||
|
||||
func Order(r *ghttp.Request) {
|
||||
glog.Println("order")
|
||||
glog.Print("order")
|
||||
r.Response.Write("GET")
|
||||
}
|
||||
|
||||
|
||||
@ -16,10 +16,10 @@ func main() {
|
||||
})
|
||||
s.BindHookHandlerByMap(p, map[string]ghttp.HandlerFunc{
|
||||
ghttp.HookBeforeServe: func(r *ghttp.Request) {
|
||||
glog.To(r.Response.Writer).Println("BeforeServe")
|
||||
glog.To(r.Response.Writer).Print(r.Context(), "BeforeServe")
|
||||
},
|
||||
ghttp.HookAfterServe: func(r *ghttp.Request) {
|
||||
glog.To(r.Response.Writer).Println("AfterServe")
|
||||
glog.To(r.Response.Writer).Print(r.Context(), "AfterServe")
|
||||
},
|
||||
})
|
||||
s.SetPort(8199)
|
||||
|
||||
@ -11,10 +11,10 @@ func main() {
|
||||
p := "/:name/info/{uid}"
|
||||
s := g.Server()
|
||||
s.BindHookHandlerByMap(p, map[string]ghttp.HandlerFunc{
|
||||
ghttp.HookBeforeServe: func(r *ghttp.Request) { glog.Println(ghttp.HookBeforeServe) },
|
||||
ghttp.HookAfterServe: func(r *ghttp.Request) { glog.Println(ghttp.HookAfterServe) },
|
||||
ghttp.HookBeforeOutput: func(r *ghttp.Request) { glog.Println(ghttp.HookBeforeOutput) },
|
||||
ghttp.HookAfterOutput: func(r *ghttp.Request) { glog.Println(ghttp.HookAfterOutput) },
|
||||
ghttp.HookBeforeServe: func(r *ghttp.Request) { glog.Print(ghttp.HookBeforeServe) },
|
||||
ghttp.HookAfterServe: func(r *ghttp.Request) { glog.Print(ghttp.HookAfterServe) },
|
||||
ghttp.HookBeforeOutput: func(r *ghttp.Request) { glog.Print(ghttp.HookBeforeOutput) },
|
||||
ghttp.HookAfterOutput: func(r *ghttp.Request) { glog.Print(ghttp.HookAfterOutput) },
|
||||
})
|
||||
s.BindHandler(p, func(r *ghttp.Request) {
|
||||
r.Response.Write("用户:", r.Get("name"), ", uid:", r.Get("uid"))
|
||||
|
||||
@ -25,7 +25,7 @@ func MiddlewareCORS(r *ghttp.Request) {
|
||||
|
||||
func MiddlewareLog(r *ghttp.Request) {
|
||||
r.Middleware.Next()
|
||||
g.Log().Println(r.Response.Status, r.URL.Path)
|
||||
g.Log().Print(r.Response.Status, r.URL.Path)
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
@ -10,7 +10,7 @@ func main() {
|
||||
s1 := ghttp.GetServer("s1")
|
||||
s1.SetPort(8882)
|
||||
s1.BindHandler("/", func(r *ghttp.Request) {
|
||||
glog.Println("s1")
|
||||
glog.Print(r.Context(), "s1")
|
||||
r.Response.Writeln("s1")
|
||||
})
|
||||
s1.Start()
|
||||
@ -18,7 +18,7 @@ func main() {
|
||||
s2 := ghttp.GetServer("s2")
|
||||
s2.SetPort(8882)
|
||||
s2.BindHandler("/", func(r *ghttp.Request) {
|
||||
glog.Println("s2")
|
||||
glog.Print(r.Context(), "s2")
|
||||
r.Response.Writeln("s2")
|
||||
})
|
||||
s2.Start()
|
||||
|
||||
@ -23,7 +23,7 @@ func MiddlewareCORS(r *ghttp.Request) {
|
||||
|
||||
func MiddlewareLog(r *ghttp.Request) {
|
||||
r.Middleware.Next()
|
||||
g.Log().Println(r.Response.Status, r.URL.Path)
|
||||
g.Log().Print(r.Response.Status, r.URL.Path)
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
@ -32,7 +32,7 @@ func main() {
|
||||
msg, err := funcs.RecvPkg(conn)
|
||||
if err != nil {
|
||||
if err.Error() == "EOF" {
|
||||
glog.Println("server closed")
|
||||
glog.Print("server closed")
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
@ -21,7 +21,7 @@ func main() {
|
||||
msg, err := funcs.RecvPkg(conn)
|
||||
if err != nil {
|
||||
if err.Error() == "EOF" {
|
||||
glog.Println("client closed")
|
||||
glog.Print("client closed")
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
@ -35,9 +35,9 @@ func main() {
|
||||
// 使用 SendRecvPkg 发送消息包并接受返回
|
||||
if result, err := conn.SendRecvPkg(info); err != nil {
|
||||
if err.Error() == "EOF" {
|
||||
glog.Println("server closed")
|
||||
glog.Print("server closed")
|
||||
}
|
||||
} else {
|
||||
glog.Println(string(result))
|
||||
glog.Print(string(result))
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,7 +16,7 @@ func main() {
|
||||
data, err := conn.RecvPkg()
|
||||
if err != nil {
|
||||
if err.Error() == "EOF" {
|
||||
glog.Println("client closed")
|
||||
glog.Print("client closed")
|
||||
}
|
||||
break
|
||||
}
|
||||
@ -24,7 +24,7 @@ func main() {
|
||||
if err := json.Unmarshal(data, info); err != nil {
|
||||
glog.Errorf("invalid package structure: %s", err.Error())
|
||||
} else {
|
||||
glog.Println(info)
|
||||
glog.Print(info)
|
||||
conn.SendPkg([]byte("ok"))
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,7 +10,7 @@ import (
|
||||
func main() {
|
||||
gcron.SetLogLevel(glog.LEVEL_ALL)
|
||||
gcron.Add("* * * * * ?", func() {
|
||||
glog.Println("test")
|
||||
glog.Print("test")
|
||||
})
|
||||
time.Sleep(3 * time.Second)
|
||||
}
|
||||
|
||||
@ -8,14 +8,14 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
gcron.Add("0 30 * * * *", func() { glog.Println("Every hour on the half hour") })
|
||||
gcron.Add("* * * * * *", func() { glog.Println("Every second, pattern") }, "second-cron")
|
||||
gcron.Add("*/5 * * * * *", func() { glog.Println("Every 5 seconds, pattern") })
|
||||
gcron.Add("0 30 * * * *", func() { glog.Print("Every hour on the half hour") })
|
||||
gcron.Add("* * * * * *", func() { glog.Print("Every second, pattern") }, "second-cron")
|
||||
gcron.Add("*/5 * * * * *", func() { glog.Print("Every 5 seconds, pattern") })
|
||||
|
||||
gcron.Add("@hourly", func() { glog.Println("Every hour") })
|
||||
gcron.Add("@every 1h30m", func() { glog.Println("Every hour thirty") })
|
||||
gcron.Add("@every 1s", func() { glog.Println("Every 1 second") })
|
||||
gcron.Add("@every 5s", func() { glog.Println("Every 5 seconds") })
|
||||
gcron.Add("@hourly", func() { glog.Print("Every hour") })
|
||||
gcron.Add("@every 1h30m", func() { glog.Print("Every hour thirty") })
|
||||
gcron.Add("@every 1s", func() { glog.Print("Every 1 second") })
|
||||
gcron.Add("@every 5s", func() { glog.Print("Every 5 seconds") })
|
||||
|
||||
time.Sleep(3 * time.Second)
|
||||
|
||||
|
||||
@ -8,7 +8,7 @@ import (
|
||||
)
|
||||
|
||||
func test() {
|
||||
glog.Println(111)
|
||||
glog.Print(111)
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
|
||||
"github.com/fsnotify/fsnotify"
|
||||
@ -25,7 +26,7 @@ func main() {
|
||||
for {
|
||||
select {
|
||||
case ev := <-watch.Events:
|
||||
glog.Println(ev)
|
||||
glog.Print(context.Background(), ev)
|
||||
|
||||
case err := <-watch.Errors:
|
||||
log.Println("error : ", err)
|
||||
|
||||
@ -9,7 +9,7 @@ func main() {
|
||||
//path := `D:\temp`
|
||||
path := "/Users/john/Temp"
|
||||
_, err := gfsnotify.Add(path, func(event *gfsnotify.Event) {
|
||||
glog.Println(event)
|
||||
glog.Print(event)
|
||||
})
|
||||
if err != nil {
|
||||
glog.Fatal(err)
|
||||
|
||||
@ -10,13 +10,13 @@ import (
|
||||
|
||||
func main() {
|
||||
c1, err := gfsnotify.Add("/home/john/temp/log", func(event *gfsnotify.Event) {
|
||||
glog.Println("callback1")
|
||||
glog.Print("callback1")
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
c2, err := gfsnotify.Add("/home/john/temp/log", func(event *gfsnotify.Event) {
|
||||
glog.Println("callback2")
|
||||
glog.Print("callback2")
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@ -24,12 +24,12 @@ func main() {
|
||||
// 5秒后移除c1的回调函数注册,仅剩c2
|
||||
gtimer.SetTimeout(5*time.Second, func() {
|
||||
gfsnotify.RemoveCallback(c1.Id)
|
||||
glog.Println("remove callback c1")
|
||||
glog.Print("remove callback c1")
|
||||
})
|
||||
// 10秒后移除c2的回调函数注册,所有的回调都移除,不再有任何打印信息输出
|
||||
gtimer.SetTimeout(10*time.Second, func() {
|
||||
gfsnotify.RemoveCallback(c2.Id)
|
||||
glog.Println("remove callback c2")
|
||||
glog.Print("remove callback c2")
|
||||
})
|
||||
|
||||
select {}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/v2/os/gfsnotify"
|
||||
@ -9,8 +10,11 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
var (
|
||||
ctx = context.Background()
|
||||
)
|
||||
callback, err := gfsnotify.Add("/home/john/temp", func(event *gfsnotify.Event) {
|
||||
glog.Println("callback")
|
||||
glog.Print(ctx, "callback")
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@ -19,9 +23,9 @@ func main() {
|
||||
// 在此期间创建文件、目录、修改文件、删除文件
|
||||
|
||||
// 20秒后移除回调函数注册,所有的回调都移除,不再有任何打印信息输出
|
||||
gtimer.SetTimeout(20*time.Second, func() {
|
||||
gtimer.SetTimeout(ctx, 20*time.Second, func(ctx context.Context) {
|
||||
gfsnotify.RemoveCallback(callback.Id)
|
||||
glog.Println("remove callback")
|
||||
glog.Print(ctx, "remove callback")
|
||||
})
|
||||
|
||||
select {}
|
||||
|
||||
@ -10,7 +10,7 @@ func main() {
|
||||
path := "/Users/john/temp/log"
|
||||
for i := 0; i < 9999999; i++ {
|
||||
_, err := gfsnotify.Add(path, func(event *gfsnotify.Event) {
|
||||
glog.Println(event)
|
||||
glog.Print(event)
|
||||
})
|
||||
if err != nil {
|
||||
glog.Fatal(err)
|
||||
|
||||
@ -8,7 +8,7 @@ import (
|
||||
func main() {
|
||||
path := "/tmp/glog-cat"
|
||||
g.Log().SetPath(path)
|
||||
g.Log().Stdout(false).Cat("cat1").Cat("cat2").Println("test")
|
||||
g.Log().Stdout(false).Cat("cat1").Cat("cat2").Print("test")
|
||||
list, err := gfile.ScanDir(path, "*", true)
|
||||
g.Dump(err)
|
||||
g.Dump(list)
|
||||
|
||||
@ -1,27 +1,32 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
)
|
||||
|
||||
// 设置日志等级
|
||||
func main() {
|
||||
path := "/tmp/glog"
|
||||
var (
|
||||
ctx = context.TODO()
|
||||
path = "/tmp/glog"
|
||||
)
|
||||
|
||||
g.Log().SetPath(path)
|
||||
g.Log().SetStdoutPrint(false)
|
||||
|
||||
// 使用默认文件名称格式
|
||||
g.Log().Println("标准文件名称格式,使用当前时间时期")
|
||||
g.Log().Print(ctx, "标准文件名称格式,使用当前时间时期")
|
||||
|
||||
// 通过SetFile设置文件名称格式
|
||||
g.Log().SetFile("stdout.log")
|
||||
g.Log().Println("设置日志输出文件名称格式为同一个文件")
|
||||
g.Log().Print(ctx, "设置日志输出文件名称格式为同一个文件")
|
||||
|
||||
// 链式操作设置文件名称格式
|
||||
g.Log().File("stderr.log").Println("支持链式操作")
|
||||
g.Log().File("error-{Ymd}.log").Println("文件名称支持带gtime日期格式")
|
||||
g.Log().File("access-{Ymd}.log").Println("文件名称支持带gtime日期格式")
|
||||
g.Log().File("stderr.log").Print(ctx, "支持链式操作")
|
||||
g.Log().File("error-{Ymd}.log").Print(ctx, "文件名称支持带gtime日期格式")
|
||||
g.Log().File("access-{Ymd}.log").Print(ctx, "文件名称支持带gtime日期格式")
|
||||
|
||||
list, err := gfile.ScanDir(path, "*")
|
||||
g.Dump(err)
|
||||
|
||||
@ -7,9 +7,9 @@ import (
|
||||
|
||||
func main() {
|
||||
g.Log().SetFlags(glog.F_TIME_TIME | glog.F_FILE_SHORT)
|
||||
g.Log().Println("time and short line number")
|
||||
g.Log().Print("time and short line number")
|
||||
g.Log().SetFlags(glog.F_TIME_MILLI | glog.F_FILE_LONG)
|
||||
g.Log().Println("time with millisecond and long line number")
|
||||
g.Log().Print("time with millisecond and long line number")
|
||||
g.Log().SetFlags(glog.F_TIME_STD | glog.F_FILE_LONG)
|
||||
g.Log().Println("standard time format and long line number")
|
||||
g.Log().Print("standard time format and long line number")
|
||||
}
|
||||
|
||||
@ -5,8 +5,8 @@ import (
|
||||
)
|
||||
|
||||
func PrintLog(content string) {
|
||||
g.Log().Skip(0).Line().Println("line number with skip:", content)
|
||||
g.Log().Line(true).Println("line number without skip:", content)
|
||||
g.Log().Skip(0).Line().Print("line number with skip:", content)
|
||||
g.Log().Line(true).Print("line number without skip:", content)
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
@ -9,7 +9,7 @@ import (
|
||||
func main() {
|
||||
path := "/tmp/glog"
|
||||
g.Log().SetPath(path)
|
||||
g.Log().Println("日志内容")
|
||||
g.Log().Print("日志内容")
|
||||
list, err := gfile.ScanDir(path, "*")
|
||||
g.Dump(err)
|
||||
g.Dump(list)
|
||||
|
||||
@ -12,7 +12,7 @@ func main() {
|
||||
path := "/Users/john/Temp/test"
|
||||
g.Log().SetPath(path)
|
||||
for {
|
||||
g.Log().Println(gtime.Now().String())
|
||||
g.Log().Print(gtime.Now().String())
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,6 +6,6 @@ import (
|
||||
|
||||
func main() {
|
||||
g.Log().SetPrefix("[API]")
|
||||
g.Log().Println("hello world")
|
||||
g.Log().Print("hello world")
|
||||
g.Log().Error("error occurred")
|
||||
}
|
||||
|
||||
@ -14,7 +14,7 @@ func main() {
|
||||
for i := 0; i < 3000; i++ {
|
||||
go func() {
|
||||
<-ch
|
||||
g.Log().Println("abcdefghijklmnopqrstuvwxyz1234567890")
|
||||
g.Log().Print("abcdefghijklmnopqrstuvwxyz1234567890")
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
|
||||
@ -26,5 +26,5 @@ package main
|
||||
// MaxChunkSizeLan : 1337,
|
||||
// }),
|
||||
// })
|
||||
// glog.Println("test log")
|
||||
// glog.Print("test log")
|
||||
//}
|
||||
|
||||
@ -27,5 +27,5 @@ package main
|
||||
// g.Log().Debug("Debugging...")
|
||||
// g.Log().Warning("It is warning info")
|
||||
// g.Log().Error("Error occurs, please have a check")
|
||||
// glog.Println("test log")
|
||||
// glog.Print("test log")
|
||||
//}
|
||||
|
||||
@ -18,7 +18,7 @@ func main() {
|
||||
wg.Add(1)
|
||||
go func(i int) {
|
||||
gmlock.Lock(key)
|
||||
glog.Println(i)
|
||||
glog.Print(i)
|
||||
time.Sleep(time.Second)
|
||||
gmlock.Unlock(key)
|
||||
wg.Done()
|
||||
|
||||
@ -16,11 +16,11 @@ func main() {
|
||||
wg.Add(1)
|
||||
go func(i int) {
|
||||
if gmlock.TryLock(key) {
|
||||
glog.Println(i)
|
||||
glog.Print(i)
|
||||
time.Sleep(time.Second)
|
||||
gmlock.Unlock(key)
|
||||
} else {
|
||||
glog.Println(false)
|
||||
glog.Print(false)
|
||||
}
|
||||
wg.Done()
|
||||
}(i)
|
||||
|
||||
@ -14,26 +14,26 @@ func main() {
|
||||
|
||||
// 第一次锁带时间
|
||||
gmlock.Lock(key)
|
||||
glog.Println("lock1")
|
||||
glog.Print("lock1")
|
||||
// 这个时候上一次的计时解锁已失效
|
||||
gmlock.Unlock(key)
|
||||
glog.Println("unlock1")
|
||||
glog.Print("unlock1")
|
||||
|
||||
fmt.Println()
|
||||
|
||||
// 第二次锁,不带时间,且在执行过程中钱一个Lock的定时解锁生效
|
||||
gmlock.Lock(key)
|
||||
glog.Println("lock2")
|
||||
glog.Print("lock2")
|
||||
go func() {
|
||||
// 正常情况下3秒后才能执行这句
|
||||
gmlock.Lock(key)
|
||||
glog.Println("lock by goroutine")
|
||||
glog.Print("lock by goroutine")
|
||||
}()
|
||||
time.Sleep(3 * time.Second)
|
||||
// 这时再解锁
|
||||
gmlock.Unlock(key)
|
||||
// 注意3秒之后才会执行这一句
|
||||
glog.Println("unlock2")
|
||||
glog.Print("unlock2")
|
||||
|
||||
select {}
|
||||
}
|
||||
|
||||
@ -13,7 +13,7 @@ func main() {
|
||||
go func(n int) {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
glog.Println("Lock:", n)
|
||||
glog.Print("Lock:", n)
|
||||
time.Sleep(time.Second)
|
||||
}(i)
|
||||
}
|
||||
@ -21,7 +21,7 @@ func main() {
|
||||
go func(n int) {
|
||||
mu.RLock()
|
||||
defer mu.RUnlock()
|
||||
glog.Println("RLock:", n)
|
||||
glog.Print("RLock:", n)
|
||||
time.Sleep(time.Second)
|
||||
}(i)
|
||||
}
|
||||
|
||||
@ -11,12 +11,12 @@ import (
|
||||
func main() {
|
||||
mu := gmutex.New()
|
||||
go mu.LockFunc(func() {
|
||||
glog.Println("lock func1")
|
||||
glog.Print("lock func1")
|
||||
time.Sleep(1 * time.Second)
|
||||
})
|
||||
time.Sleep(time.Millisecond)
|
||||
go mu.LockFunc(func() {
|
||||
glog.Println("lock func2")
|
||||
glog.Print("lock func2")
|
||||
})
|
||||
time.Sleep(2 * time.Second)
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
@ -38,7 +39,7 @@ func main() {
|
||||
fmt.Println(t.UTC().String())
|
||||
fmt.Println(t.In(cstLocal).String())
|
||||
} else {
|
||||
glog.Error(s, err)
|
||||
glog.Error(context.Background(), s, err)
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
@ -10,7 +10,7 @@ import (
|
||||
func main() {
|
||||
interval := time.Second
|
||||
gtimer.AddSingleton(interval, func() {
|
||||
glog.Println("doing")
|
||||
glog.Print("doing")
|
||||
time.Sleep(5 * time.Second)
|
||||
})
|
||||
|
||||
|
||||
@ -10,10 +10,10 @@ import (
|
||||
func main() {
|
||||
interval := time.Second
|
||||
gtimer.AddTimes(interval, 2, func() {
|
||||
glog.Println("doing1")
|
||||
glog.Print("doing1")
|
||||
})
|
||||
gtimer.AddTimes(interval, 2, func() {
|
||||
glog.Println("doing2")
|
||||
glog.Print("doing2")
|
||||
})
|
||||
|
||||
select {}
|
||||
|
||||
709
container/garray/garray_z_example_int_test.go
Normal file
709
container/garray/garray_z_example_int_test.go
Normal file
@ -0,0 +1,709 @@
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package garray_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/v2/container/garray"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/internal/json"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
func ExampleIntArray_Walk() {
|
||||
var array garray.IntArray
|
||||
tables := g.SliceInt{10, 20}
|
||||
prefix := 99
|
||||
array.Append(tables...)
|
||||
// Add prefix for given table names.
|
||||
array.Walk(func(value int) int {
|
||||
return prefix + value
|
||||
})
|
||||
fmt.Println(array.Slice())
|
||||
|
||||
// Output:
|
||||
// [109 119]
|
||||
}
|
||||
|
||||
func ExampleNewIntArray() {
|
||||
s := garray.NewIntArray()
|
||||
s.Append(10)
|
||||
s.Append(20)
|
||||
s.Append(15)
|
||||
s.Append(30)
|
||||
fmt.Println(s.Slice())
|
||||
|
||||
// Output:
|
||||
// [10 20 15 30]
|
||||
}
|
||||
|
||||
func ExampleNewIntArraySize() {
|
||||
s := garray.NewIntArraySize(3, 5)
|
||||
s.Set(0, 10)
|
||||
s.Set(1, 20)
|
||||
s.Set(2, 15)
|
||||
s.Set(3, 30)
|
||||
fmt.Println(s.Slice(), s.Len(), cap(s.Slice()))
|
||||
|
||||
// Output:
|
||||
// [10 20 15] 3 5
|
||||
}
|
||||
|
||||
func ExampleNewIntArrayFrom() {
|
||||
s := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30})
|
||||
fmt.Println(s.Slice(), s.Len(), cap(s.Slice()))
|
||||
|
||||
// Output:
|
||||
// [10 20 15 30] 4 4
|
||||
}
|
||||
|
||||
func ExampleNewIntArrayFromCopy() {
|
||||
s := garray.NewIntArrayFromCopy(g.SliceInt{10, 20, 15, 30})
|
||||
fmt.Println(s.Slice(), s.Len(), cap(s.Slice()))
|
||||
|
||||
// Output:
|
||||
// [10 20 15 30] 4 4
|
||||
}
|
||||
|
||||
func ExampleIntArray_At() {
|
||||
s := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30})
|
||||
sAt := s.At(2)
|
||||
fmt.Println(sAt)
|
||||
|
||||
// Output:
|
||||
// 15
|
||||
}
|
||||
|
||||
func ExampleIntArray_Get() {
|
||||
s := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30})
|
||||
sGet, sBool := s.Get(3)
|
||||
fmt.Println(sGet, sBool)
|
||||
|
||||
// Output:
|
||||
// 30 true
|
||||
}
|
||||
|
||||
func ExampleIntArray_Set() {
|
||||
s := garray.NewIntArraySize(3, 5)
|
||||
s.Set(0, 10)
|
||||
s.Set(1, 20)
|
||||
s.Set(2, 15)
|
||||
s.Set(3, 30)
|
||||
fmt.Println(s.Slice())
|
||||
|
||||
// Output:
|
||||
// [10 20 15]
|
||||
}
|
||||
|
||||
func ExampleIntArray_SetArray() {
|
||||
s := garray.NewIntArray()
|
||||
s.SetArray(g.SliceInt{10, 20, 15, 30})
|
||||
fmt.Println(s.Slice())
|
||||
|
||||
// Output:
|
||||
// [10 20 15 30]
|
||||
}
|
||||
|
||||
func ExampleIntArray_Replace() {
|
||||
s := garray.NewIntArray()
|
||||
s.SetArray(g.SliceInt{10, 20, 15, 30})
|
||||
fmt.Println(s.Slice())
|
||||
s.Replace(g.SliceInt{12, 13})
|
||||
fmt.Println(s.Slice())
|
||||
|
||||
// Output:
|
||||
// [10 20 15 30]
|
||||
// [12 13 15 30]
|
||||
}
|
||||
|
||||
func ExampleIntArray_Sum() {
|
||||
s := garray.NewIntArray()
|
||||
s.SetArray(g.SliceInt{10, 20, 15, 30})
|
||||
a := s.Sum()
|
||||
fmt.Println(a)
|
||||
|
||||
// Output:
|
||||
// 75
|
||||
}
|
||||
|
||||
func ExampleIntArray_Sort() {
|
||||
s := garray.NewIntArray()
|
||||
s.SetArray(g.SliceInt{10, 20, 15, 30})
|
||||
a := s.Sort()
|
||||
fmt.Println(a)
|
||||
|
||||
// Output:
|
||||
// [10,15,20,30]
|
||||
}
|
||||
|
||||
func ExampleIntArray_SortFunc() {
|
||||
s := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30})
|
||||
fmt.Println(s)
|
||||
s.SortFunc(func(v1, v2 int) bool {
|
||||
//fmt.Println(v1,v2)
|
||||
return v1 > v2
|
||||
})
|
||||
fmt.Println(s)
|
||||
s.SortFunc(func(v1, v2 int) bool {
|
||||
return v1 < v2
|
||||
})
|
||||
fmt.Println(s)
|
||||
|
||||
// Output:
|
||||
// [10,20,15,30]
|
||||
// [30,20,15,10]
|
||||
// [10,15,20,30]
|
||||
}
|
||||
|
||||
func ExampleIntArray_InsertBefore() {
|
||||
s := garray.NewIntArray()
|
||||
s.SetArray(g.SliceInt{10, 20, 15, 30})
|
||||
s.InsertBefore(1, 99)
|
||||
fmt.Println(s.Slice())
|
||||
|
||||
// Output:
|
||||
// [10 99 20 15 30]
|
||||
}
|
||||
|
||||
func ExampleIntArray_InsertAfter() {
|
||||
s := garray.NewIntArray()
|
||||
s.SetArray(g.SliceInt{10, 20, 15, 30})
|
||||
s.InsertAfter(1, 99)
|
||||
fmt.Println(s.Slice())
|
||||
|
||||
// Output:
|
||||
// [10 20 99 15 30]
|
||||
}
|
||||
|
||||
func ExampleIntArray_Remove() {
|
||||
s := garray.NewIntArray()
|
||||
s.SetArray(g.SliceInt{10, 20, 15, 30})
|
||||
fmt.Println(s)
|
||||
s.Remove(1)
|
||||
fmt.Println(s.Slice())
|
||||
|
||||
// Output:
|
||||
// [10,20,15,30]
|
||||
// [10 15 30]
|
||||
}
|
||||
|
||||
func ExampleIntArray_RemoveValue() {
|
||||
s := garray.NewIntArray()
|
||||
s.SetArray(g.SliceInt{10, 20, 15, 30})
|
||||
fmt.Println(s)
|
||||
s.RemoveValue(20)
|
||||
fmt.Println(s.Slice())
|
||||
|
||||
// Output:
|
||||
// [10,20,15,30]
|
||||
// [10 15 30]
|
||||
}
|
||||
|
||||
func ExampleIntArray_PushLeft() {
|
||||
s := garray.NewIntArray()
|
||||
s.SetArray(g.SliceInt{10, 20, 15, 30})
|
||||
fmt.Println(s)
|
||||
s.PushLeft(96, 97, 98, 99)
|
||||
fmt.Println(s.Slice())
|
||||
|
||||
// Output:
|
||||
// [10,20,15,30]
|
||||
// [96 97 98 99 10 20 15 30]
|
||||
}
|
||||
|
||||
func ExampleIntArray_PushRight() {
|
||||
s := garray.NewIntArray()
|
||||
s.SetArray(g.SliceInt{10, 20, 15, 30})
|
||||
fmt.Println(s)
|
||||
s.PushRight(96, 97, 98, 99)
|
||||
fmt.Println(s.Slice())
|
||||
|
||||
// Output:
|
||||
// [10,20,15,30]
|
||||
// [10 20 15 30 96 97 98 99]
|
||||
}
|
||||
|
||||
func ExampleIntArray_PopLeft() {
|
||||
s := garray.NewIntArray()
|
||||
s.SetArray(g.SliceInt{10, 20, 15, 30})
|
||||
fmt.Println(s)
|
||||
s.PopLeft()
|
||||
fmt.Println(s.Slice())
|
||||
|
||||
// Output:
|
||||
// [10,20,15,30]
|
||||
// [20 15 30]
|
||||
}
|
||||
|
||||
func ExampleIntArray_PopRight() {
|
||||
s := garray.NewIntArray()
|
||||
s.SetArray(g.SliceInt{10, 20, 15, 30})
|
||||
fmt.Println(s)
|
||||
s.PopRight()
|
||||
fmt.Println(s.Slice())
|
||||
|
||||
// Output:
|
||||
// [10,20,15,30]
|
||||
// [10 20 15]
|
||||
}
|
||||
|
||||
func ExampleIntArray_PopRand() {
|
||||
s := garray.NewIntArray()
|
||||
s.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60, 70})
|
||||
fmt.Println(s)
|
||||
r, _ := s.PopRand()
|
||||
fmt.Println(s)
|
||||
fmt.Println(r)
|
||||
|
||||
// May Output:
|
||||
// [10,20,15,30,40,50,60,70]
|
||||
// [10,20,15,30,40,60,70]
|
||||
// 50
|
||||
}
|
||||
|
||||
func ExampleIntArray_PopRands() {
|
||||
s := garray.NewIntArray()
|
||||
s.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
|
||||
fmt.Println(s)
|
||||
r := s.PopRands(2)
|
||||
fmt.Println(s)
|
||||
fmt.Println(r)
|
||||
|
||||
// May Output:
|
||||
// [10,20,15,30,40,50,60]
|
||||
// [10,20,15,30,40]
|
||||
// [50 60]
|
||||
}
|
||||
|
||||
func ExampleIntArray_PopLefts() {
|
||||
s := garray.NewIntArray()
|
||||
s.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
|
||||
fmt.Println(s)
|
||||
r := s.PopLefts(2)
|
||||
fmt.Println(s)
|
||||
fmt.Println(r)
|
||||
|
||||
// Output:
|
||||
// [10,20,15,30,40,50,60]
|
||||
// [15,30,40,50,60]
|
||||
// [10 20]
|
||||
}
|
||||
|
||||
func ExampleIntArray_PopRights() {
|
||||
s := garray.NewIntArray()
|
||||
s.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
|
||||
fmt.Println(s)
|
||||
r := s.PopRights(2)
|
||||
fmt.Println(s)
|
||||
fmt.Println(r)
|
||||
|
||||
// Output:
|
||||
// [10,20,15,30,40,50,60]
|
||||
// [10,20,15,30,40]
|
||||
// [50 60]
|
||||
}
|
||||
|
||||
func ExampleIntArray_Range() {
|
||||
s := garray.NewIntArray()
|
||||
s.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
|
||||
fmt.Println(s)
|
||||
r := s.Range(2, 5)
|
||||
fmt.Println(r)
|
||||
|
||||
// Output:
|
||||
// [10,20,15,30,40,50,60]
|
||||
// [15 30 40]
|
||||
}
|
||||
|
||||
func ExampleIntArray_SubSlice() {
|
||||
s := garray.NewIntArray()
|
||||
s.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
|
||||
fmt.Println(s)
|
||||
r := s.SubSlice(3, 4)
|
||||
fmt.Println(r)
|
||||
|
||||
// Output:
|
||||
// [10,20,15,30,40,50,60]
|
||||
// [30 40 50 60]
|
||||
}
|
||||
|
||||
func ExampleIntArray_Append() {
|
||||
s := garray.NewIntArray()
|
||||
s.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
|
||||
fmt.Println(s)
|
||||
s.Append(96, 97, 98)
|
||||
fmt.Println(s)
|
||||
|
||||
// Output:
|
||||
// [10,20,15,30,40,50,60]
|
||||
// [10,20,15,30,40,50,60,96,97,98]
|
||||
}
|
||||
|
||||
func ExampleIntArray_Len() {
|
||||
s := garray.NewIntArray()
|
||||
s.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
|
||||
fmt.Println(s)
|
||||
fmt.Println(s.Len())
|
||||
|
||||
// Output:
|
||||
// [10,20,15,30,40,50,60]
|
||||
// 7
|
||||
}
|
||||
|
||||
func ExampleIntArray_Slice() {
|
||||
s := garray.NewIntArray()
|
||||
s.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
|
||||
fmt.Println(s.Slice())
|
||||
|
||||
// Output:
|
||||
// [10 20 15 30 40 50 60]
|
||||
}
|
||||
|
||||
func ExampleIntArray_Interfaces() {
|
||||
s := garray.NewIntArray()
|
||||
s.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
|
||||
r := s.Interfaces()
|
||||
fmt.Println(r)
|
||||
|
||||
// Output:
|
||||
// [10 20 15 30 40 50 60]
|
||||
}
|
||||
|
||||
func ExampleIntArray_Clone() {
|
||||
s := garray.NewIntArray()
|
||||
s.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
|
||||
fmt.Println(s)
|
||||
r := s.Clone()
|
||||
fmt.Println(r)
|
||||
|
||||
// Output:
|
||||
// [10,20,15,30,40,50,60]
|
||||
// [10,20,15,30,40,50,60]
|
||||
}
|
||||
|
||||
func ExampleIntArray_Clear() {
|
||||
s := garray.NewIntArray()
|
||||
s.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
|
||||
fmt.Println(s)
|
||||
fmt.Println(s.Clear())
|
||||
fmt.Println(s)
|
||||
|
||||
// Output:
|
||||
// [10,20,15,30,40,50,60]
|
||||
// []
|
||||
// []
|
||||
}
|
||||
|
||||
func ExampleIntArray_Contains() {
|
||||
s := garray.NewIntArray()
|
||||
s.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
|
||||
fmt.Println(s.Contains(20))
|
||||
fmt.Println(s.Contains(21))
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleIntArray_Search() {
|
||||
s := garray.NewIntArray()
|
||||
s.SetArray(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
|
||||
fmt.Println(s.Search(20))
|
||||
fmt.Println(s.Search(21))
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// -1
|
||||
}
|
||||
|
||||
func ExampleIntArray_Unique() {
|
||||
s := garray.NewIntArray()
|
||||
s.SetArray(g.SliceInt{10, 20, 15, 15, 20, 50, 60})
|
||||
fmt.Println(s)
|
||||
fmt.Println(s.Unique())
|
||||
|
||||
// Output:
|
||||
// [10,20,15,15,20,50,60]
|
||||
// [10,20,15,50,60]
|
||||
}
|
||||
|
||||
func ExampleIntArray_LockFunc() {
|
||||
s := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
|
||||
s.LockFunc(func(array []int) {
|
||||
for i := 0; i < len(array)-1; i++ {
|
||||
fmt.Println(array[i])
|
||||
}
|
||||
})
|
||||
|
||||
// Output:
|
||||
// 10
|
||||
// 20
|
||||
// 15
|
||||
// 30
|
||||
// 40
|
||||
// 50
|
||||
}
|
||||
|
||||
func ExampleIntArray_RLockFunc() {
|
||||
s := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
|
||||
s.RLockFunc(func(array []int) {
|
||||
for i := 0; i < len(array); i++ {
|
||||
fmt.Println(array[i])
|
||||
}
|
||||
})
|
||||
|
||||
// Output:
|
||||
// 10
|
||||
// 20
|
||||
// 15
|
||||
// 30
|
||||
// 40
|
||||
// 50
|
||||
// 60
|
||||
}
|
||||
|
||||
func ExampleIntArray_Merge() {
|
||||
s1 := garray.NewIntArray()
|
||||
s2 := garray.NewIntArray()
|
||||
s1.SetArray(g.SliceInt{10, 20, 15})
|
||||
s2.SetArray(g.SliceInt{40, 50, 60})
|
||||
fmt.Println(s1)
|
||||
fmt.Println(s2)
|
||||
s1.Merge(s2)
|
||||
fmt.Println(s1)
|
||||
|
||||
// Output:
|
||||
// [10,20,15]
|
||||
// [40,50,60]
|
||||
// [10,20,15,40,50,60]
|
||||
}
|
||||
|
||||
func ExampleIntArray_Fill() {
|
||||
s := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
|
||||
fmt.Println(s)
|
||||
s.Fill(2, 3, 99)
|
||||
fmt.Println(s)
|
||||
|
||||
// Output:
|
||||
// [10,20,15,30,40,50,60]
|
||||
// [10,20,99,99,99,50,60]
|
||||
}
|
||||
|
||||
func ExampleIntArray_Chunk() {
|
||||
s := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
|
||||
fmt.Println(s)
|
||||
r := s.Chunk(3)
|
||||
fmt.Println(r)
|
||||
|
||||
// Output:
|
||||
// [10,20,15,30,40,50,60]
|
||||
// [[10 20 15] [30 40 50] [60]]
|
||||
}
|
||||
|
||||
func ExampleIntArray_Pad() {
|
||||
s := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
|
||||
s.Pad(8, 99)
|
||||
fmt.Println(s)
|
||||
s.Pad(-10, 89)
|
||||
fmt.Println(s)
|
||||
|
||||
// Output:
|
||||
// [10,20,15,30,40,50,60,99]
|
||||
// [89,89,10,20,15,30,40,50,60,99]
|
||||
}
|
||||
|
||||
func ExampleIntArray_Rand() {
|
||||
s := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
|
||||
fmt.Println(s)
|
||||
fmt.Println(s.Rand())
|
||||
|
||||
// May Output:
|
||||
// [10,20,15,30,40,50,60]
|
||||
// 10 true
|
||||
}
|
||||
|
||||
func ExampleIntArray_Rands() {
|
||||
s := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
|
||||
fmt.Println(s)
|
||||
fmt.Println(s.Rands(3))
|
||||
|
||||
// May Output:
|
||||
// [10,20,15,30,40,50,60]
|
||||
// [20 50 20]
|
||||
}
|
||||
|
||||
func ExampleIntArray_Shuffle() {
|
||||
s := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
|
||||
fmt.Println(s)
|
||||
fmt.Println(s.Shuffle())
|
||||
|
||||
// May Output:
|
||||
// [10,20,15,30,40,50,60]
|
||||
// [10,40,15,50,20,60,30]
|
||||
}
|
||||
|
||||
func ExampleIntArray_Reverse() {
|
||||
s := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
|
||||
fmt.Println(s)
|
||||
fmt.Println(s.Reverse())
|
||||
|
||||
// Output:
|
||||
// [10,20,15,30,40,50,60]
|
||||
// [60,50,40,30,15,20,10]
|
||||
}
|
||||
|
||||
func ExampleIntArray_Join() {
|
||||
s := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
|
||||
fmt.Println(s)
|
||||
fmt.Println(s.Join(","))
|
||||
|
||||
// Output:
|
||||
// [10,20,15,30,40,50,60]
|
||||
// 10,20,15,30,40,50,60
|
||||
}
|
||||
|
||||
func ExampleIntArray_CountValues() {
|
||||
s := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 15, 40, 40, 40})
|
||||
fmt.Println(s.CountValues())
|
||||
|
||||
// Output:
|
||||
// map[10:1 15:2 20:1 40:3]
|
||||
}
|
||||
|
||||
func ExampleIntArray_Iterator() {
|
||||
s := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
|
||||
s.Iterator(func(k int, v int) bool {
|
||||
fmt.Println(k, v)
|
||||
return true
|
||||
})
|
||||
|
||||
// Output:
|
||||
// 0 10
|
||||
// 1 20
|
||||
// 2 15
|
||||
// 3 30
|
||||
// 4 40
|
||||
// 5 50
|
||||
// 6 60
|
||||
}
|
||||
|
||||
func ExampleIntArray_IteratorAsc() {
|
||||
s := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
|
||||
s.IteratorAsc(func(k int, v int) bool {
|
||||
fmt.Println(k, v)
|
||||
return true
|
||||
})
|
||||
|
||||
// Output:
|
||||
// 0 10
|
||||
// 1 20
|
||||
// 2 15
|
||||
// 3 30
|
||||
// 4 40
|
||||
// 5 50
|
||||
// 6 60
|
||||
}
|
||||
|
||||
func ExampleIntArray_IteratorDesc() {
|
||||
s := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
|
||||
s.IteratorDesc(func(k int, v int) bool {
|
||||
fmt.Println(k, v)
|
||||
return true
|
||||
})
|
||||
|
||||
// Output:
|
||||
// 6 60
|
||||
// 5 50
|
||||
// 4 40
|
||||
// 3 30
|
||||
// 2 15
|
||||
// 1 20
|
||||
// 0 10
|
||||
}
|
||||
|
||||
func ExampleIntArray_String() {
|
||||
s := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
|
||||
fmt.Println(s)
|
||||
fmt.Println(s.String())
|
||||
|
||||
// Output:
|
||||
// [10,20,15,30,40,50,60]
|
||||
// [10,20,15,30,40,50,60]
|
||||
}
|
||||
|
||||
func ExampleIntArray_MarshalJSON() {
|
||||
type Student struct {
|
||||
Id int
|
||||
Name string
|
||||
Scores garray.IntArray
|
||||
}
|
||||
var array garray.IntArray
|
||||
array.SetArray(g.SliceInt{98, 97, 96})
|
||||
s := Student{
|
||||
Id: 1,
|
||||
Name: "john",
|
||||
Scores: array,
|
||||
}
|
||||
b, _ := json.Marshal(s)
|
||||
fmt.Println(string(b))
|
||||
|
||||
// Output:
|
||||
// {"Id":1,"Name":"john","Scores":[98,97,96]}
|
||||
}
|
||||
|
||||
func ExampleIntArray_UnmarshalJSON() {
|
||||
b := []byte(`{"Id":1,"Name":"john","Scores":[98,96,97]}`)
|
||||
type Student struct {
|
||||
Id int
|
||||
Name string
|
||||
Scores *garray.IntArray
|
||||
}
|
||||
s := Student{}
|
||||
json.Unmarshal(b, &s)
|
||||
fmt.Println(s)
|
||||
|
||||
// Output:
|
||||
// {1 john [98,96,97]}
|
||||
}
|
||||
|
||||
func ExampleIntArray_UnmarshalValue() {
|
||||
type Student struct {
|
||||
Name string
|
||||
Scores *garray.IntArray
|
||||
}
|
||||
|
||||
var s *Student
|
||||
gconv.Struct(g.Map{
|
||||
"name": "john",
|
||||
"scores": g.SliceInt{96, 98, 97},
|
||||
}, &s)
|
||||
fmt.Println(s)
|
||||
|
||||
// Output:
|
||||
// &{john [96,98,97]}
|
||||
}
|
||||
|
||||
func ExampleIntArray_FilterEmpty() {
|
||||
s := garray.NewIntArrayFrom(g.SliceInt{10, 40, 50, 0, 0, 0, 60})
|
||||
fmt.Println(s)
|
||||
fmt.Println(s.FilterEmpty())
|
||||
|
||||
// Output:
|
||||
// [10,40,50,0,0,0,60]
|
||||
// [10,40,50,60]
|
||||
}
|
||||
|
||||
func ExampleIntArray_IsEmpty() {
|
||||
s := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30, 40, 50, 60})
|
||||
fmt.Println(s.IsEmpty())
|
||||
s1 := garray.NewIntArray()
|
||||
fmt.Println(s1.IsEmpty())
|
||||
|
||||
// Output:
|
||||
// false
|
||||
// true
|
||||
}
|
||||
573
container/garray/garray_z_example_sorted_str_test.go
Normal file
573
container/garray/garray_z_example_sorted_str_test.go
Normal file
@ -0,0 +1,573 @@
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package garray_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/v2/container/garray"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/internal/json"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
func ExampleSortedStrArray_Walk() {
|
||||
var array garray.SortedStrArray
|
||||
tables := g.SliceStr{"user", "user_detail"}
|
||||
prefix := "gf_"
|
||||
array.Append(tables...)
|
||||
// Add prefix for given table names.
|
||||
array.Walk(func(value string) string {
|
||||
return prefix + value
|
||||
})
|
||||
fmt.Println(array.Slice())
|
||||
|
||||
// Output:
|
||||
// [gf_user gf_user_detail]
|
||||
}
|
||||
|
||||
func ExampleNewSortedStrArray() {
|
||||
s := garray.NewSortedStrArray()
|
||||
s.Append("b")
|
||||
s.Append("d")
|
||||
s.Append("c")
|
||||
s.Append("a")
|
||||
fmt.Println(s.Slice())
|
||||
|
||||
// Output:
|
||||
// [a b c d]
|
||||
}
|
||||
|
||||
func ExampleNewSortedStrArraySize() {
|
||||
s := garray.NewSortedStrArraySize(3)
|
||||
s.SetArray([]string{"b", "d", "a", "c"})
|
||||
fmt.Println(s.Slice(), s.Len(), cap(s.Slice()))
|
||||
|
||||
// Output:
|
||||
// [a b c d] 4 4
|
||||
}
|
||||
|
||||
func ExampleNewStrArrayFromCopy() {
|
||||
s := garray.NewSortedStrArrayFromCopy(g.SliceStr{"b", "d", "c", "a"})
|
||||
fmt.Println(s.Slice())
|
||||
|
||||
// Output:
|
||||
// [a b c d]
|
||||
}
|
||||
|
||||
func ExampleSortedStrArray_At() {
|
||||
s := garray.NewSortedStrArrayFrom(g.SliceStr{"b", "d", "c", "a"})
|
||||
sAt := s.At(2)
|
||||
fmt.Println(s)
|
||||
fmt.Println(sAt)
|
||||
|
||||
// Output:
|
||||
// ["a","b","c","d"]
|
||||
// c
|
||||
|
||||
}
|
||||
|
||||
func ExampleSortedStrArray_Get() {
|
||||
s := garray.NewSortedStrArrayFrom(g.SliceStr{"b", "d", "c", "a", "e"})
|
||||
sGet, sBool := s.Get(3)
|
||||
fmt.Println(s)
|
||||
fmt.Println(sGet, sBool)
|
||||
|
||||
// Output:
|
||||
// ["a","b","c","d","e"]
|
||||
// d true
|
||||
}
|
||||
|
||||
func ExampleSortedStrArray_SetArray() {
|
||||
s := garray.NewSortedStrArray()
|
||||
s.SetArray([]string{"b", "d", "a", "c"})
|
||||
fmt.Println(s.Slice())
|
||||
|
||||
// Output:
|
||||
// [a b c d]
|
||||
}
|
||||
|
||||
func ExampleSortedStrArray_SetUnique() {
|
||||
s := garray.NewSortedStrArray()
|
||||
s.SetArray([]string{"b", "d", "a", "c", "c", "a"})
|
||||
fmt.Println(s.SetUnique(true))
|
||||
|
||||
// Output:
|
||||
// ["a","b","c","d"]
|
||||
}
|
||||
|
||||
func ExampleSortedStrArray_Sum() {
|
||||
s := garray.NewSortedStrArray()
|
||||
s.SetArray([]string{"5", "3", "2"})
|
||||
fmt.Println(s)
|
||||
a := s.Sum()
|
||||
fmt.Println(a)
|
||||
|
||||
// Output:
|
||||
// ["2","3","5"]
|
||||
// 10
|
||||
}
|
||||
|
||||
func ExampleSortedStrArray_Sort() {
|
||||
s := garray.NewSortedStrArray()
|
||||
s.SetArray(g.SliceStr{"b", "d", "a", "c"})
|
||||
fmt.Println(s)
|
||||
a := s.Sort()
|
||||
fmt.Println(a)
|
||||
|
||||
// Output:
|
||||
// ["a","b","c","d"]
|
||||
// ["a","b","c","d"]
|
||||
}
|
||||
|
||||
func ExampleSortedStrArray_Remove() {
|
||||
s := garray.NewSortedStrArray()
|
||||
s.SetArray(g.SliceStr{"b", "d", "c", "a"})
|
||||
fmt.Println(s.Slice())
|
||||
s.Remove(1)
|
||||
fmt.Println(s.Slice())
|
||||
|
||||
// Output:
|
||||
// [a b c d]
|
||||
// [a c d]
|
||||
}
|
||||
|
||||
func ExampleSortedStrArray_RemoveValue() {
|
||||
s := garray.NewSortedStrArray()
|
||||
s.SetArray(g.SliceStr{"b", "d", "c", "a"})
|
||||
fmt.Println(s.Slice())
|
||||
s.RemoveValue("b")
|
||||
fmt.Println(s.Slice())
|
||||
|
||||
// Output:
|
||||
// [a b c d]
|
||||
// [a c d]
|
||||
}
|
||||
|
||||
func ExampleSortedStrArray_PopLeft() {
|
||||
s := garray.NewSortedStrArray()
|
||||
s.SetArray(g.SliceStr{"b", "d", "c", "a"})
|
||||
r, _ := s.PopLeft()
|
||||
fmt.Println(r)
|
||||
fmt.Println(s.Slice())
|
||||
|
||||
// Output:
|
||||
// a
|
||||
// [b c d]
|
||||
}
|
||||
|
||||
func ExampleSortedStrArray_PopRight() {
|
||||
s := garray.NewSortedStrArray()
|
||||
s.SetArray(g.SliceStr{"b", "d", "c", "a"})
|
||||
fmt.Println(s.Slice())
|
||||
r, _ := s.PopRight()
|
||||
fmt.Println(r)
|
||||
fmt.Println(s.Slice())
|
||||
|
||||
// Output:
|
||||
// [a b c d]
|
||||
// d
|
||||
// [a b c]
|
||||
}
|
||||
|
||||
func ExampleSortedStrArray_PopRights() {
|
||||
s := garray.NewSortedStrArray()
|
||||
s.SetArray(g.SliceStr{"c", "b", "a", "d", "f", "e", "h", "g"})
|
||||
r := s.PopRights(2)
|
||||
fmt.Println(r)
|
||||
fmt.Println(s)
|
||||
|
||||
// Output:
|
||||
// [g h]
|
||||
// ["a","b","c","d","e","f"]
|
||||
}
|
||||
|
||||
func ExampleSortedStrArray_Rand() {
|
||||
s := garray.NewSortedStrArray()
|
||||
s.SetArray(g.SliceStr{"c", "b", "a", "d", "f", "e", "h", "g"})
|
||||
r, _ := s.PopRand()
|
||||
fmt.Println(r)
|
||||
fmt.Println(s)
|
||||
|
||||
// May Output:
|
||||
// b
|
||||
// ["a","c","d","e","f","g","h"]
|
||||
}
|
||||
|
||||
func ExampleSortedStrArray_PopRands() {
|
||||
s := garray.NewSortedStrArray()
|
||||
s.SetArray(g.SliceStr{"c", "b", "a", "d", "f", "e", "h", "g"})
|
||||
r := s.PopRands(2)
|
||||
fmt.Println(r)
|
||||
fmt.Println(s)
|
||||
|
||||
// May Output:
|
||||
// [d a]
|
||||
// ["b","c","e","f","g","h"]
|
||||
}
|
||||
|
||||
func ExampleSortedStrArray_PopLefts() {
|
||||
s := garray.NewSortedStrArray()
|
||||
s.SetArray(g.SliceStr{"c", "b", "a", "d", "f", "e", "h", "g"})
|
||||
r := s.PopLefts(2)
|
||||
fmt.Println(r)
|
||||
fmt.Println(s)
|
||||
|
||||
// Output:
|
||||
// [a b]
|
||||
// ["c","d","e","f","g","h"]
|
||||
}
|
||||
|
||||
func ExampleSortedStrArray_Range() {
|
||||
s := garray.NewSortedStrArray()
|
||||
s.SetArray(g.SliceStr{"c", "b", "a", "d", "f", "e", "h", "g"})
|
||||
r := s.Range(2, 5)
|
||||
fmt.Println(r)
|
||||
|
||||
// Output:
|
||||
// [c d e]
|
||||
}
|
||||
|
||||
func ExampleSortedStrArray_SubSlice() {
|
||||
s := garray.NewSortedStrArray()
|
||||
s.SetArray(g.SliceStr{"c", "b", "a", "d", "f", "e", "h", "g"})
|
||||
r := s.SubSlice(3, 4)
|
||||
fmt.Println(s.Slice())
|
||||
fmt.Println(r)
|
||||
|
||||
// Output:
|
||||
// [a b c d e f g h]
|
||||
// [d e f g]
|
||||
}
|
||||
|
||||
func ExampleSortedStrArray_Add() {
|
||||
s := garray.NewSortedStrArray()
|
||||
s.Add("b", "d", "c", "a")
|
||||
fmt.Println(s)
|
||||
|
||||
// Output:
|
||||
// ["a","b","c","d"]
|
||||
}
|
||||
|
||||
func ExampleSortedStrArray_Append() {
|
||||
s := garray.NewSortedStrArray()
|
||||
s.SetArray(g.SliceStr{"b", "d", "c", "a"})
|
||||
fmt.Println(s)
|
||||
s.Append("f", "e", "g")
|
||||
fmt.Println(s)
|
||||
|
||||
// Output:
|
||||
// ["a","b","c","d"]
|
||||
// ["a","b","c","d","e","f","g"]
|
||||
}
|
||||
|
||||
func ExampleSortedStrArray_Len() {
|
||||
s := garray.NewSortedStrArray()
|
||||
s.SetArray(g.SliceStr{"c", "b", "a", "d", "f", "e", "h", "g"})
|
||||
fmt.Println(s)
|
||||
fmt.Println(s.Len())
|
||||
|
||||
// Output:
|
||||
// ["a","b","c","d","e","f","g","h"]
|
||||
// 8
|
||||
}
|
||||
|
||||
func ExampleSortedStrArray_Slice() {
|
||||
s := garray.NewSortedStrArray()
|
||||
s.SetArray(g.SliceStr{"c", "b", "a", "d", "f", "e", "h", "g"})
|
||||
fmt.Println(s.Slice())
|
||||
|
||||
// Output:
|
||||
// [a b c d e f g h]
|
||||
}
|
||||
|
||||
func ExampleSortedStrArray_Interfaces() {
|
||||
s := garray.NewSortedStrArray()
|
||||
s.SetArray(g.SliceStr{"c", "b", "a", "d", "f", "e", "h", "g"})
|
||||
r := s.Interfaces()
|
||||
fmt.Println(r)
|
||||
|
||||
// Output:
|
||||
// [a b c d e f g h]
|
||||
}
|
||||
|
||||
func ExampleSortedStrArray_Clone() {
|
||||
s := garray.NewSortedStrArray()
|
||||
s.SetArray(g.SliceStr{"c", "b", "a", "d", "f", "e", "h", "g"})
|
||||
r := s.Clone()
|
||||
fmt.Println(r)
|
||||
fmt.Println(s)
|
||||
|
||||
// Output:
|
||||
// ["a","b","c","d","e","f","g","h"]
|
||||
// ["a","b","c","d","e","f","g","h"]
|
||||
}
|
||||
|
||||
func ExampleSortedStrArray_Clear() {
|
||||
s := garray.NewSortedStrArray()
|
||||
s.SetArray(g.SliceStr{"c", "b", "a", "d", "f", "e", "h", "g"})
|
||||
fmt.Println(s)
|
||||
fmt.Println(s.Clear())
|
||||
fmt.Println(s)
|
||||
|
||||
// Output:
|
||||
// ["a","b","c","d","e","f","g","h"]
|
||||
// []
|
||||
// []
|
||||
}
|
||||
|
||||
func ExampleSortedStrArray_Contains() {
|
||||
s := garray.NewSortedStrArray()
|
||||
s.SetArray(g.SliceStr{"c", "b", "a", "d", "f", "e", "h", "g"})
|
||||
fmt.Println(s.Contains("e"))
|
||||
fmt.Println(s.Contains("E"))
|
||||
fmt.Println(s.Contains("z"))
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleSortedStrArray_ContainsI() {
|
||||
s := garray.NewSortedStrArray()
|
||||
s.SetArray(g.SliceStr{"c", "b", "a", "d", "f", "e", "h", "g"})
|
||||
fmt.Println(s)
|
||||
fmt.Println(s.ContainsI("E"))
|
||||
fmt.Println(s.ContainsI("z"))
|
||||
|
||||
// Output:
|
||||
// ["a","b","c","d","e","f","g","h"]
|
||||
// true
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleSortedStrArray_Search() {
|
||||
s := garray.NewSortedStrArray()
|
||||
s.SetArray(g.SliceStr{"c", "b", "a", "d", "f", "e", "h", "g"})
|
||||
fmt.Println(s)
|
||||
fmt.Println(s.Search("e"))
|
||||
fmt.Println(s.Search("E"))
|
||||
fmt.Println(s.Search("z"))
|
||||
|
||||
// Output:
|
||||
// ["a","b","c","d","e","f","g","h"]
|
||||
// 4
|
||||
// -1
|
||||
// -1
|
||||
}
|
||||
|
||||
func ExampleSortedStrArray_Unique() {
|
||||
s := garray.NewSortedStrArray()
|
||||
s.SetArray(g.SliceStr{"a", "b", "c", "c", "c", "d", "d"})
|
||||
fmt.Println(s)
|
||||
fmt.Println(s.Unique())
|
||||
|
||||
// Output:
|
||||
// ["a","b","c","c","c","d","d"]
|
||||
// ["a","b","c","d"]
|
||||
}
|
||||
|
||||
func ExampleSortedStrArray_LockFunc() {
|
||||
s := garray.NewSortedStrArrayFrom(g.SliceStr{"b", "c", "a"})
|
||||
s.LockFunc(func(array []string) {
|
||||
array[len(array)-1] = "GF fans"
|
||||
})
|
||||
fmt.Println(s)
|
||||
|
||||
// Output:
|
||||
// ["a","b","GF fans"]
|
||||
}
|
||||
|
||||
func ExampleSortedStrArray_RLockFunc() {
|
||||
s := garray.NewSortedStrArrayFrom(g.SliceStr{"b", "c", "a"})
|
||||
s.RLockFunc(func(array []string) {
|
||||
array[len(array)-1] = "GF fans"
|
||||
fmt.Println(array[len(array)-1])
|
||||
})
|
||||
fmt.Println(s)
|
||||
|
||||
// Output:
|
||||
// GF fans
|
||||
// ["a","b","GF fans"]
|
||||
}
|
||||
|
||||
func ExampleSortedStrArray_Merge() {
|
||||
s1 := garray.NewSortedStrArray()
|
||||
s2 := garray.NewSortedStrArray()
|
||||
s1.SetArray(g.SliceStr{"b", "c", "a"})
|
||||
s2.SetArray(g.SliceStr{"e", "d", "f"})
|
||||
fmt.Println(s1)
|
||||
fmt.Println(s2)
|
||||
s1.Merge(s2)
|
||||
fmt.Println(s1)
|
||||
|
||||
// Output:
|
||||
// ["a","b","c"]
|
||||
// ["d","e","f"]
|
||||
// ["a","b","c","d","e","f"]
|
||||
}
|
||||
|
||||
func ExampleSortedStrArray_Chunk() {
|
||||
s := garray.NewSortedStrArrayFrom(g.SliceStr{"c", "b", "a", "d", "f", "e", "h", "g"})
|
||||
r := s.Chunk(3)
|
||||
fmt.Println(r)
|
||||
|
||||
// Output:
|
||||
// [[a b c] [d e f] [g h]]
|
||||
}
|
||||
|
||||
func ExampleSortedStrArray_Rands() {
|
||||
s := garray.NewSortedStrArrayFrom(g.SliceStr{"c", "b", "a", "d", "f", "e", "h", "g"})
|
||||
fmt.Println(s)
|
||||
fmt.Println(s.Rands(3))
|
||||
|
||||
// May Output:
|
||||
// ["a","b","c","d","e","f","g","h"]
|
||||
// [h g c]
|
||||
}
|
||||
|
||||
func ExampleSortedStrArray_Join() {
|
||||
s := garray.NewSortedStrArrayFrom(g.SliceStr{"c", "b", "a", "d", "f", "e", "h", "g"})
|
||||
fmt.Println(s.Join(","))
|
||||
|
||||
// Output:
|
||||
// a,b,c,d,e,f,g,h
|
||||
}
|
||||
|
||||
func ExampleSortedStrArray_CountValues() {
|
||||
s := garray.NewSortedStrArrayFrom(g.SliceStr{"a", "b", "c", "c", "c", "d", "d"})
|
||||
fmt.Println(s.CountValues())
|
||||
|
||||
// Output:
|
||||
// map[a:1 b:1 c:3 d:2]
|
||||
}
|
||||
|
||||
func ExampleSortedStrArray_Iterator() {
|
||||
s := garray.NewSortedStrArrayFrom(g.SliceStr{"b", "c", "a"})
|
||||
s.Iterator(func(k int, v string) bool {
|
||||
fmt.Println(k, v)
|
||||
return true
|
||||
})
|
||||
|
||||
// Output:
|
||||
// 0 a
|
||||
// 1 b
|
||||
// 2 c
|
||||
}
|
||||
|
||||
func ExampleSortedStrArray_IteratorAsc() {
|
||||
s := garray.NewSortedStrArrayFrom(g.SliceStr{"b", "c", "a"})
|
||||
s.IteratorAsc(func(k int, v string) bool {
|
||||
fmt.Println(k, v)
|
||||
return true
|
||||
})
|
||||
|
||||
// Output:
|
||||
// 0 a
|
||||
// 1 b
|
||||
// 2 c
|
||||
}
|
||||
|
||||
func ExampleSortedStrArray_IteratorDesc() {
|
||||
s := garray.NewSortedStrArrayFrom(g.SliceStr{"b", "c", "a"})
|
||||
s.IteratorDesc(func(k int, v string) bool {
|
||||
fmt.Println(k, v)
|
||||
return true
|
||||
})
|
||||
|
||||
// Output:
|
||||
// 2 c
|
||||
// 1 b
|
||||
// 0 a
|
||||
}
|
||||
|
||||
func ExampleSortedStrArray_String() {
|
||||
s := garray.NewSortedStrArrayFrom(g.SliceStr{"b", "c", "a"})
|
||||
fmt.Println(s.String())
|
||||
|
||||
// Output:
|
||||
// ["a","b","c"]
|
||||
}
|
||||
|
||||
func ExampleSortedStrArray_MarshalJSON() {
|
||||
type Student struct {
|
||||
ID int
|
||||
Name string
|
||||
Levels garray.SortedStrArray
|
||||
}
|
||||
r := garray.NewSortedStrArrayFrom(g.SliceStr{"b", "c", "a"})
|
||||
s := Student{
|
||||
ID: 1,
|
||||
Name: "john",
|
||||
Levels: *r,
|
||||
}
|
||||
b, _ := json.Marshal(s)
|
||||
fmt.Println(string(b))
|
||||
|
||||
// Output:
|
||||
// {"ID":1,"Name":"john","Levels":["a","b","c"]}
|
||||
}
|
||||
|
||||
func ExampleSortedStrArray_UnmarshalJSON() {
|
||||
b := []byte(`{"Id":1,"Name":"john","Lessons":["Math","English","Sport"]}`)
|
||||
type Student struct {
|
||||
Id int
|
||||
Name string
|
||||
Lessons *garray.StrArray
|
||||
}
|
||||
s := Student{}
|
||||
json.Unmarshal(b, &s)
|
||||
fmt.Println(s)
|
||||
|
||||
// Output:
|
||||
// {1 john ["Math","English","Sport"]}
|
||||
}
|
||||
|
||||
func ExampleSortedStrArray_UnmarshalValue() {
|
||||
type Student struct {
|
||||
Name string
|
||||
Lessons *garray.StrArray
|
||||
}
|
||||
var s *Student
|
||||
gconv.Struct(g.Map{
|
||||
"name": "john",
|
||||
"lessons": []byte(`["Math","English","Sport"]`),
|
||||
}, &s)
|
||||
fmt.Println(s)
|
||||
|
||||
var s1 *Student
|
||||
gconv.Struct(g.Map{
|
||||
"name": "john",
|
||||
"lessons": g.SliceStr{"Math", "English", "Sport"},
|
||||
}, &s1)
|
||||
fmt.Println(s1)
|
||||
|
||||
// Output:
|
||||
// &{john ["Math","English","Sport"]}
|
||||
// &{john ["Math","English","Sport"]}
|
||||
}
|
||||
|
||||
func ExampleSortedStrArray_FilterEmpty() {
|
||||
s := garray.NewSortedStrArrayFrom(g.SliceStr{"b", "a", "", "c", "", "", "d"})
|
||||
fmt.Println(s)
|
||||
fmt.Println(s.FilterEmpty())
|
||||
|
||||
// Output:
|
||||
// ["","","","a","b","c","d"]
|
||||
// ["a","b","c","d"]
|
||||
}
|
||||
|
||||
func ExampleSortedStrArray_IsEmpty() {
|
||||
s := garray.NewSortedStrArrayFrom(g.SliceStr{"b", "a", "", "c", "", "", "d"})
|
||||
fmt.Println(s.IsEmpty())
|
||||
s1 := garray.NewSortedStrArray()
|
||||
fmt.Println(s1.IsEmpty())
|
||||
|
||||
// Output:
|
||||
// false
|
||||
// true
|
||||
}
|
||||
@ -10,6 +10,9 @@ import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/v2/container/garray"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/internal/json"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
func ExampleStrArray_Walk() {
|
||||
@ -26,3 +29,621 @@ func ExampleStrArray_Walk() {
|
||||
// Output:
|
||||
// [gf_user gf_user_detail]
|
||||
}
|
||||
|
||||
func ExampleStrArray_NewStrArray() {
|
||||
s := garray.NewStrArray()
|
||||
s.Append("We")
|
||||
s.Append("are")
|
||||
s.Append("GF")
|
||||
s.Append("fans")
|
||||
fmt.Println(s.Slice())
|
||||
|
||||
// Output:
|
||||
// [We are GF fans]
|
||||
}
|
||||
|
||||
func ExampleStrArray_NewStrArraySize() {
|
||||
s := garray.NewStrArraySize(3, 5)
|
||||
s.Set(0, "We")
|
||||
s.Set(1, "are")
|
||||
s.Set(2, "GF")
|
||||
s.Set(3, "fans")
|
||||
fmt.Println(s.Slice(), s.Len(), cap(s.Slice()))
|
||||
|
||||
// Output:
|
||||
// [We are GF] 3 5
|
||||
}
|
||||
|
||||
func ExampleStrArray_NewStrArrayFrom() {
|
||||
s := garray.NewStrArrayFrom(g.SliceStr{"We", "are", "GF", "fans", "!"})
|
||||
fmt.Println(s.Slice(), s.Len(), cap(s.Slice()))
|
||||
|
||||
// Output:
|
||||
// [We are GF fans !] 5 5
|
||||
}
|
||||
|
||||
func ExampleStrArray_NewStrArrayFromCopy() {
|
||||
s := garray.NewStrArrayFromCopy(g.SliceStr{"We", "are", "GF", "fans", "!"})
|
||||
fmt.Println(s.Slice(), s.Len(), cap(s.Slice()))
|
||||
|
||||
// Output:
|
||||
// [We are GF fans !] 5 5
|
||||
}
|
||||
|
||||
func ExampleStrArray_At() {
|
||||
s := garray.NewStrArrayFrom(g.SliceStr{"We", "are", "GF", "fans", "!"})
|
||||
sAt := s.At(2)
|
||||
fmt.Println(sAt)
|
||||
|
||||
// Output:
|
||||
// GF
|
||||
}
|
||||
|
||||
func ExampleStrArray_Get() {
|
||||
s := garray.NewStrArrayFrom(g.SliceStr{"We", "are", "GF", "fans", "!"})
|
||||
sGet, sBool := s.Get(3)
|
||||
fmt.Println(sGet, sBool)
|
||||
|
||||
// Output:
|
||||
// fans true
|
||||
}
|
||||
|
||||
func ExampleStrArray_Set() {
|
||||
s := garray.NewStrArraySize(3, 5)
|
||||
s.Set(0, "We")
|
||||
s.Set(1, "are")
|
||||
s.Set(2, "GF")
|
||||
s.Set(3, "fans")
|
||||
fmt.Println(s.Slice())
|
||||
|
||||
// Output:
|
||||
// [We are GF]
|
||||
}
|
||||
|
||||
func ExampleStrArray_SetArray() {
|
||||
s := garray.NewStrArray()
|
||||
s.SetArray(g.SliceStr{"We", "are", "GF", "fans", "!"})
|
||||
fmt.Println(s.Slice())
|
||||
|
||||
// Output:
|
||||
// [We are GF fans !]
|
||||
}
|
||||
|
||||
func ExampleStrArray_Replace() {
|
||||
s := garray.NewStrArray()
|
||||
s.SetArray(g.SliceStr{"We", "are", "GF", "fans", "!"})
|
||||
fmt.Println(s.Slice())
|
||||
s.Replace(g.SliceStr{"Happy", "coding"})
|
||||
fmt.Println(s.Slice())
|
||||
|
||||
// Output:
|
||||
// [We are GF fans !]
|
||||
// [Happy coding GF fans !]
|
||||
}
|
||||
|
||||
func ExampleStrArray_Sum() {
|
||||
s := garray.NewStrArray()
|
||||
s.SetArray(g.SliceStr{"3", "5", "10"})
|
||||
a := s.Sum()
|
||||
fmt.Println(a)
|
||||
|
||||
// Output:
|
||||
// 18
|
||||
}
|
||||
|
||||
func ExampleStrArray_Sort() {
|
||||
s := garray.NewStrArray()
|
||||
s.SetArray(g.SliceStr{"b", "d", "a", "c"})
|
||||
a := s.Sort()
|
||||
fmt.Println(a)
|
||||
|
||||
// Output:
|
||||
// ["a","b","c","d"]
|
||||
}
|
||||
|
||||
func ExampleStrArray_SortFunc() {
|
||||
s := garray.NewStrArrayFrom(g.SliceStr{"b", "c", "a"})
|
||||
fmt.Println(s)
|
||||
s.SortFunc(func(v1, v2 string) bool {
|
||||
return gstr.Compare(v1, v2) > 0
|
||||
})
|
||||
fmt.Println(s)
|
||||
s.SortFunc(func(v1, v2 string) bool {
|
||||
return gstr.Compare(v1, v2) < 0
|
||||
})
|
||||
fmt.Println(s)
|
||||
|
||||
// Output:
|
||||
// ["b","c","a"]
|
||||
// ["c","b","a"]
|
||||
// ["a","b","c"]
|
||||
}
|
||||
|
||||
func ExampleStrArray_InsertBefore() {
|
||||
s := garray.NewStrArray()
|
||||
s.SetArray(g.SliceStr{"a", "b", "c", "d"})
|
||||
s.InsertBefore(1, "here")
|
||||
fmt.Println(s.Slice())
|
||||
|
||||
// Output:
|
||||
// [a here b c d]
|
||||
}
|
||||
|
||||
func ExampleStrArray_InsertAfter() {
|
||||
s := garray.NewStrArray()
|
||||
s.SetArray(g.SliceStr{"a", "b", "c", "d"})
|
||||
s.InsertAfter(1, "here")
|
||||
fmt.Println(s.Slice())
|
||||
|
||||
// Output:
|
||||
// [a b here c d]
|
||||
}
|
||||
|
||||
func ExampleStrArray_Remove() {
|
||||
s := garray.NewStrArray()
|
||||
s.SetArray(g.SliceStr{"a", "b", "c", "d"})
|
||||
s.Remove(1)
|
||||
fmt.Println(s.Slice())
|
||||
|
||||
// Output:
|
||||
// [a c d]
|
||||
}
|
||||
|
||||
func ExampleStrArray_RemoveValue() {
|
||||
s := garray.NewStrArray()
|
||||
s.SetArray(g.SliceStr{"a", "b", "c", "d"})
|
||||
s.RemoveValue("b")
|
||||
fmt.Println(s.Slice())
|
||||
|
||||
// Output:
|
||||
// [a c d]
|
||||
}
|
||||
|
||||
func ExampleStrArray_PushLeft() {
|
||||
s := garray.NewStrArray()
|
||||
s.SetArray(g.SliceStr{"a", "b", "c", "d"})
|
||||
s.PushLeft("We", "are", "GF", "fans")
|
||||
fmt.Println(s.Slice())
|
||||
|
||||
// Output:
|
||||
// [We are GF fans a b c d]
|
||||
}
|
||||
|
||||
func ExampleStrArray_PushRight() {
|
||||
s := garray.NewStrArray()
|
||||
s.SetArray(g.SliceStr{"a", "b", "c", "d"})
|
||||
s.PushRight("We", "are", "GF", "fans")
|
||||
fmt.Println(s.Slice())
|
||||
|
||||
// Output:
|
||||
// [a b c d We are GF fans]
|
||||
}
|
||||
|
||||
func ExampleStrArray_PopLeft() {
|
||||
s := garray.NewStrArray()
|
||||
s.SetArray(g.SliceStr{"a", "b", "c", "d"})
|
||||
s.PopLeft()
|
||||
fmt.Println(s.Slice())
|
||||
|
||||
// Output:
|
||||
// [b c d]
|
||||
}
|
||||
|
||||
func ExampleStrArray_PopRight() {
|
||||
s := garray.NewStrArray()
|
||||
s.SetArray(g.SliceStr{"a", "b", "c", "d"})
|
||||
s.PopRight()
|
||||
fmt.Println(s.Slice())
|
||||
|
||||
// Output:
|
||||
// [a b c]
|
||||
}
|
||||
|
||||
func ExampleStrArray_PopRand() {
|
||||
s := garray.NewStrArray()
|
||||
s.SetArray(g.SliceStr{"a", "b", "c", "d", "e", "f", "g", "h"})
|
||||
r, _ := s.PopRand()
|
||||
fmt.Println(r)
|
||||
|
||||
// May Output:
|
||||
// e
|
||||
}
|
||||
|
||||
func ExampleStrArray_PopRands() {
|
||||
s := garray.NewStrArray()
|
||||
s.SetArray(g.SliceStr{"a", "b", "c", "d", "e", "f", "g", "h"})
|
||||
r := s.PopRands(2)
|
||||
fmt.Println(r)
|
||||
|
||||
// May Output:
|
||||
// [e c]
|
||||
}
|
||||
|
||||
func ExampleStrArray_PopLefts() {
|
||||
s := garray.NewStrArray()
|
||||
s.SetArray(g.SliceStr{"a", "b", "c", "d", "e", "f", "g", "h"})
|
||||
r := s.PopLefts(2)
|
||||
fmt.Println(r)
|
||||
fmt.Println(s)
|
||||
|
||||
// Output:
|
||||
// [a b]
|
||||
// ["c","d","e","f","g","h"]
|
||||
}
|
||||
|
||||
func ExampleStrArray_PopRights() {
|
||||
s := garray.NewStrArray()
|
||||
s.SetArray(g.SliceStr{"a", "b", "c", "d", "e", "f", "g", "h"})
|
||||
r := s.PopRights(2)
|
||||
fmt.Println(r)
|
||||
fmt.Println(s)
|
||||
|
||||
// Output:
|
||||
// [g h]
|
||||
// ["a","b","c","d","e","f"]
|
||||
}
|
||||
|
||||
func ExampleStrArray_Range() {
|
||||
s := garray.NewStrArray()
|
||||
s.SetArray(g.SliceStr{"a", "b", "c", "d", "e", "f", "g", "h"})
|
||||
r := s.Range(2, 5)
|
||||
fmt.Println(r)
|
||||
|
||||
// Output:
|
||||
// [c d e]
|
||||
}
|
||||
|
||||
func ExampleStrArray_SubSlice() {
|
||||
s := garray.NewStrArray()
|
||||
s.SetArray(g.SliceStr{"a", "b", "c", "d", "e", "f", "g", "h"})
|
||||
r := s.SubSlice(3, 4)
|
||||
fmt.Println(r)
|
||||
|
||||
// Output:
|
||||
// [d e f g]
|
||||
}
|
||||
|
||||
func ExampleStrArray_Append() {
|
||||
s := garray.NewStrArray()
|
||||
s.SetArray(g.SliceStr{"We", "are", "GF", "fans"})
|
||||
s.Append("a", "b", "c")
|
||||
fmt.Println(s)
|
||||
|
||||
// Output:
|
||||
// ["We","are","GF","fans","a","b","c"]
|
||||
}
|
||||
|
||||
func ExampleStrArray_Len() {
|
||||
s := garray.NewStrArray()
|
||||
s.SetArray(g.SliceStr{"a", "b", "c", "d", "e", "f", "g", "h"})
|
||||
fmt.Println(s.Len())
|
||||
|
||||
// Output:
|
||||
// 8
|
||||
}
|
||||
|
||||
func ExampleStrArray_Slice() {
|
||||
s := garray.NewStrArray()
|
||||
s.SetArray(g.SliceStr{"a", "b", "c", "d", "e", "f", "g", "h"})
|
||||
fmt.Println(s.Slice())
|
||||
|
||||
// Output:
|
||||
// [a b c d e f g h]
|
||||
}
|
||||
|
||||
func ExampleStrArray_Interfaces() {
|
||||
s := garray.NewStrArray()
|
||||
s.SetArray(g.SliceStr{"a", "b", "c", "d", "e", "f", "g", "h"})
|
||||
r := s.Interfaces()
|
||||
fmt.Println(r)
|
||||
|
||||
// Output:
|
||||
// [a b c d e f g h]
|
||||
}
|
||||
|
||||
func ExampleStrArray_Clone() {
|
||||
s := garray.NewStrArray()
|
||||
s.SetArray(g.SliceStr{"a", "b", "c", "d", "e", "f", "g", "h"})
|
||||
r := s.Clone()
|
||||
fmt.Println(r)
|
||||
fmt.Println(s)
|
||||
|
||||
// Output:
|
||||
// ["a","b","c","d","e","f","g","h"]
|
||||
// ["a","b","c","d","e","f","g","h"]
|
||||
}
|
||||
|
||||
func ExampleStrArray_Clear() {
|
||||
s := garray.NewStrArray()
|
||||
s.SetArray(g.SliceStr{"a", "b", "c", "d", "e", "f", "g", "h"})
|
||||
fmt.Println(s)
|
||||
fmt.Println(s.Clear())
|
||||
fmt.Println(s)
|
||||
|
||||
// Output:
|
||||
// ["a","b","c","d","e","f","g","h"]
|
||||
// []
|
||||
// []
|
||||
}
|
||||
|
||||
func ExampleStrArray_Contains() {
|
||||
s := garray.NewStrArray()
|
||||
s.SetArray(g.SliceStr{"a", "b", "c", "d", "e", "f", "g", "h"})
|
||||
fmt.Println(s.Contains("e"))
|
||||
fmt.Println(s.Contains("z"))
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleStrArray_ContainsI() {
|
||||
s := garray.NewStrArray()
|
||||
s.SetArray(g.SliceStr{"a", "b", "c", "d", "e", "f", "g", "h"})
|
||||
fmt.Println(s.ContainsI("E"))
|
||||
fmt.Println(s.ContainsI("z"))
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleStrArray_Search() {
|
||||
s := garray.NewStrArray()
|
||||
s.SetArray(g.SliceStr{"a", "b", "c", "d", "e", "f", "g", "h"})
|
||||
fmt.Println(s.Search("e"))
|
||||
fmt.Println(s.Search("z"))
|
||||
|
||||
// Output:
|
||||
// 4
|
||||
// -1
|
||||
}
|
||||
|
||||
func ExampleStrArray_Unique() {
|
||||
s := garray.NewStrArray()
|
||||
s.SetArray(g.SliceStr{"a", "b", "c", "c", "c", "d", "d"})
|
||||
fmt.Println(s.Unique())
|
||||
|
||||
// Output:
|
||||
// ["a","b","c","d"]
|
||||
}
|
||||
|
||||
func ExampleStrArray_LockFunc() {
|
||||
s := garray.NewStrArrayFrom(g.SliceStr{"a", "b", "c"})
|
||||
s.LockFunc(func(array []string) {
|
||||
array[len(array)-1] = "GF fans"
|
||||
})
|
||||
fmt.Println(s)
|
||||
|
||||
// Output:
|
||||
// ["a","b","GF fans"]
|
||||
}
|
||||
|
||||
func ExampleStrArray_RLockFunc() {
|
||||
s := garray.NewStrArrayFrom(g.SliceStr{"a", "b", "c", "d", "e"})
|
||||
s.RLockFunc(func(array []string) {
|
||||
for i := 0; i < len(array); i++ {
|
||||
fmt.Println(array[i])
|
||||
}
|
||||
})
|
||||
|
||||
// Output:
|
||||
// a
|
||||
// b
|
||||
// c
|
||||
// d
|
||||
// e
|
||||
}
|
||||
|
||||
func ExampleStrArray_Merge() {
|
||||
s1 := garray.NewStrArray()
|
||||
s2 := garray.NewStrArray()
|
||||
s1.SetArray(g.SliceStr{"a", "b", "c"})
|
||||
s2.SetArray(g.SliceStr{"d", "e", "f"})
|
||||
s1.Merge(s2)
|
||||
fmt.Println(s1)
|
||||
|
||||
// Output:
|
||||
// ["a","b","c","d","e","f"]
|
||||
}
|
||||
|
||||
func ExampleStrArray_Fill() {
|
||||
s := garray.NewStrArrayFrom(g.SliceStr{"a", "b", "c", "d", "e", "f", "g", "h"})
|
||||
s.Fill(2, 3, "here")
|
||||
fmt.Println(s)
|
||||
|
||||
// Output:
|
||||
// ["a","b","here","here","here","f","g","h"]
|
||||
}
|
||||
|
||||
func ExampleStrArray_Chunk() {
|
||||
s := garray.NewStrArrayFrom(g.SliceStr{"a", "b", "c", "d", "e", "f", "g", "h"})
|
||||
r := s.Chunk(3)
|
||||
fmt.Println(r)
|
||||
|
||||
// Output:
|
||||
// [[a b c] [d e f] [g h]]
|
||||
}
|
||||
|
||||
func ExampleStrArray_Pad() {
|
||||
s := garray.NewStrArrayFrom(g.SliceStr{"a", "b", "c"})
|
||||
s.Pad(7, "here")
|
||||
fmt.Println(s)
|
||||
s.Pad(-10, "there")
|
||||
fmt.Println(s)
|
||||
|
||||
// Output:
|
||||
// ["a","b","c","here","here","here","here"]
|
||||
// ["there","there","there","a","b","c","here","here","here","here"]
|
||||
}
|
||||
|
||||
func ExampleStrArray_Rand() {
|
||||
s := garray.NewStrArrayFrom(g.SliceStr{"a", "b", "c", "d", "e", "f", "g", "h"})
|
||||
fmt.Println(s.Rand())
|
||||
|
||||
// May Output:
|
||||
// c true
|
||||
}
|
||||
|
||||
func ExampleStrArray_Rands() {
|
||||
s := garray.NewStrArrayFrom(g.SliceStr{"a", "b", "c", "d", "e", "f", "g", "h"})
|
||||
fmt.Println(s.Rands(3))
|
||||
|
||||
// May Output:
|
||||
// [e h e]
|
||||
}
|
||||
|
||||
func ExampleStrArray_Shuffle() {
|
||||
s := garray.NewStrArrayFrom(g.SliceStr{"a", "b", "c", "d", "e", "f", "g", "h"})
|
||||
fmt.Println(s.Shuffle())
|
||||
|
||||
// May Output:
|
||||
// ["a","c","e","d","b","g","f","h"]
|
||||
}
|
||||
|
||||
func ExampleStrArray_Reverse() {
|
||||
s := garray.NewStrArrayFrom(g.SliceStr{"a", "b", "c", "d", "e", "f", "g", "h"})
|
||||
fmt.Println(s.Reverse())
|
||||
|
||||
// Output:
|
||||
// ["h","g","f","e","d","c","b","a"]
|
||||
}
|
||||
|
||||
func ExampleStrArray_Join() {
|
||||
s := garray.NewStrArrayFrom(g.SliceStr{"a", "b", "c"})
|
||||
fmt.Println(s.Join(","))
|
||||
|
||||
// Output:
|
||||
// a,b,c
|
||||
}
|
||||
|
||||
func ExampleStrArray_CountValues() {
|
||||
s := garray.NewStrArrayFrom(g.SliceStr{"a", "b", "c", "c", "c", "d", "d"})
|
||||
fmt.Println(s.CountValues())
|
||||
|
||||
// Output:
|
||||
// map[a:1 b:1 c:3 d:2]
|
||||
}
|
||||
|
||||
func ExampleStrArray_Iterator() {
|
||||
s := garray.NewStrArrayFrom(g.SliceStr{"a", "b", "c"})
|
||||
s.Iterator(func(k int, v string) bool {
|
||||
fmt.Println(k, v)
|
||||
return true
|
||||
})
|
||||
|
||||
// Output:
|
||||
// 0 a
|
||||
// 1 b
|
||||
// 2 c
|
||||
}
|
||||
|
||||
func ExampleStrArray_IteratorAsc() {
|
||||
s := garray.NewStrArrayFrom(g.SliceStr{"a", "b", "c"})
|
||||
s.IteratorAsc(func(k int, v string) bool {
|
||||
fmt.Println(k, v)
|
||||
return true
|
||||
})
|
||||
|
||||
// Output:
|
||||
// 0 a
|
||||
// 1 b
|
||||
// 2 c
|
||||
}
|
||||
|
||||
func ExampleStrArray_IteratorDesc() {
|
||||
s := garray.NewStrArrayFrom(g.SliceStr{"a", "b", "c"})
|
||||
s.IteratorDesc(func(k int, v string) bool {
|
||||
fmt.Println(k, v)
|
||||
return true
|
||||
})
|
||||
|
||||
// Output:
|
||||
// 2 c
|
||||
// 1 b
|
||||
// 0 a
|
||||
}
|
||||
|
||||
func ExampleStrArray_String() {
|
||||
s := garray.NewStrArrayFrom(g.SliceStr{"a", "b", "c"})
|
||||
fmt.Println(s.String())
|
||||
|
||||
// Output:
|
||||
// ["a","b","c"]
|
||||
}
|
||||
|
||||
func ExampleStrArray_MarshalJSON() {
|
||||
type Student struct {
|
||||
Id int
|
||||
Name string
|
||||
Lessons []string
|
||||
}
|
||||
s := Student{
|
||||
Id: 1,
|
||||
Name: "john",
|
||||
Lessons: []string{"Math", "English", "Music"},
|
||||
}
|
||||
b, _ := json.Marshal(s)
|
||||
fmt.Println(string(b))
|
||||
|
||||
// Output:
|
||||
// {"Id":1,"Name":"john","Lessons":["Math","English","Music"]}
|
||||
}
|
||||
|
||||
func ExampleStrArray_UnmarshalJSON() {
|
||||
b := []byte(`{"Id":1,"Name":"john","Lessons":["Math","English","Sport"]}`)
|
||||
type Student struct {
|
||||
Id int
|
||||
Name string
|
||||
Lessons *garray.StrArray
|
||||
}
|
||||
s := Student{}
|
||||
json.Unmarshal(b, &s)
|
||||
fmt.Println(s)
|
||||
|
||||
// Output:
|
||||
// {1 john ["Math","English","Sport"]}
|
||||
}
|
||||
|
||||
func ExampleStrArray_UnmarshalValue() {
|
||||
type Student struct {
|
||||
Name string
|
||||
Lessons *garray.StrArray
|
||||
}
|
||||
var s *Student
|
||||
gconv.Struct(g.Map{
|
||||
"name": "john",
|
||||
"lessons": []byte(`["Math","English","Sport"]`),
|
||||
}, &s)
|
||||
fmt.Println(s)
|
||||
|
||||
var s1 *Student
|
||||
gconv.Struct(g.Map{
|
||||
"name": "john",
|
||||
"lessons": g.SliceStr{"Math", "English", "Sport"},
|
||||
}, &s1)
|
||||
fmt.Println(s1)
|
||||
|
||||
// Output:
|
||||
// &{john ["Math","English","Sport"]}
|
||||
// &{john ["Math","English","Sport"]}
|
||||
}
|
||||
|
||||
func ExampleStrArray_FilterEmpty() {
|
||||
s := garray.NewStrArrayFrom(g.SliceStr{"a", "b", "", "c", "", "", "d"})
|
||||
fmt.Println(s.FilterEmpty())
|
||||
|
||||
// Output:
|
||||
// ["a","b","c","d"]
|
||||
}
|
||||
|
||||
func ExampleStrArray_IsEmpty() {
|
||||
s := garray.NewStrArrayFrom(g.SliceStr{"a", "b", "", "c", "", "", "d"})
|
||||
fmt.Println(s.IsEmpty())
|
||||
s1 := garray.NewStrArray()
|
||||
fmt.Println(s1.IsEmpty())
|
||||
|
||||
// Output:
|
||||
// false
|
||||
// true
|
||||
}
|
||||
|
||||
@ -416,7 +416,7 @@ func (l *List) RemoveAll() {
|
||||
l.mu.Unlock()
|
||||
}
|
||||
|
||||
// See RemoveAll().
|
||||
// Clear is alias of RemoveAll.
|
||||
func (l *List) Clear() {
|
||||
l.RemoveAll()
|
||||
}
|
||||
|
||||
@ -1,160 +0,0 @@
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package glist_test
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/v2/container/garray"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
"github.com/gogf/gf/v2/container/glist"
|
||||
)
|
||||
|
||||
func ExampleNew() {
|
||||
n := 10
|
||||
l := glist.New()
|
||||
for i := 0; i < n; i++ {
|
||||
l.PushBack(i)
|
||||
}
|
||||
fmt.Println(l.Len())
|
||||
fmt.Println(l.FrontAll())
|
||||
fmt.Println(l.BackAll())
|
||||
for i := 0; i < n; i++ {
|
||||
fmt.Print(l.PopFront())
|
||||
}
|
||||
l.Clear()
|
||||
fmt.Println()
|
||||
fmt.Println(l.Len())
|
||||
|
||||
// Output:
|
||||
// 10
|
||||
// [0 1 2 3 4 5 6 7 8 9]
|
||||
// [9 8 7 6 5 4 3 2 1 0]
|
||||
// 0123456789
|
||||
// 0
|
||||
}
|
||||
|
||||
func ExampleList_RLockFunc() {
|
||||
// concurrent-safe list.
|
||||
l := glist.NewFrom(garray.NewArrayRange(1, 10, 1).Slice(), true)
|
||||
// iterate reading from head.
|
||||
l.RLockFunc(func(list *list.List) {
|
||||
length := list.Len()
|
||||
if length > 0 {
|
||||
for i, e := 0, list.Front(); i < length; i, e = i+1, e.Next() {
|
||||
fmt.Print(e.Value)
|
||||
}
|
||||
}
|
||||
})
|
||||
fmt.Println()
|
||||
// iterate reading from tail.
|
||||
l.RLockFunc(func(list *list.List) {
|
||||
length := list.Len()
|
||||
if length > 0 {
|
||||
for i, e := 0, list.Back(); i < length; i, e = i+1, e.Prev() {
|
||||
fmt.Print(e.Value)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
fmt.Println()
|
||||
// Output:
|
||||
// 12345678910
|
||||
// 10987654321
|
||||
}
|
||||
|
||||
func ExampleList_IteratorAsc() {
|
||||
// concurrent-safe list.
|
||||
l := glist.NewFrom(garray.NewArrayRange(1, 10, 1).Slice(), true)
|
||||
// iterate reading from head using IteratorAsc.
|
||||
l.IteratorAsc(func(e *glist.Element) bool {
|
||||
fmt.Print(e.Value)
|
||||
return true
|
||||
})
|
||||
|
||||
// Output:
|
||||
// 12345678910
|
||||
}
|
||||
|
||||
func ExampleList_IteratorDesc() {
|
||||
// concurrent-safe list.
|
||||
l := glist.NewFrom(garray.NewArrayRange(1, 10, 1).Slice(), true)
|
||||
// iterate reading from tail using IteratorDesc.
|
||||
l.IteratorDesc(func(e *glist.Element) bool {
|
||||
fmt.Print(e.Value)
|
||||
return true
|
||||
})
|
||||
// Output:
|
||||
// 10987654321
|
||||
}
|
||||
|
||||
func ExampleList_LockFunc() {
|
||||
// concurrent-safe list.
|
||||
l := glist.NewFrom(garray.NewArrayRange(1, 10, 1).Slice(), true)
|
||||
// iterate writing from head.
|
||||
l.LockFunc(func(list *list.List) {
|
||||
length := list.Len()
|
||||
if length > 0 {
|
||||
for i, e := 0, list.Front(); i < length; i, e = i+1, e.Next() {
|
||||
if e.Value == 6 {
|
||||
e.Value = "M"
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
fmt.Println(l)
|
||||
|
||||
// Output:
|
||||
// [1,2,3,4,5,M,7,8,9,10]
|
||||
}
|
||||
|
||||
func ExampleList_PopBack() {
|
||||
l := glist.NewFrom(g.Slice{1, 2, 3, 4, 5, 6, 7, 8, 9})
|
||||
|
||||
fmt.Println(l.PopBack())
|
||||
|
||||
// Output:
|
||||
// 9
|
||||
}
|
||||
func ExampleList_PopBacks() {
|
||||
l := glist.NewFrom(g.Slice{1, 2, 3, 4, 5, 6, 7, 8, 9})
|
||||
|
||||
fmt.Println(l.PopBacks(2))
|
||||
|
||||
// Output:
|
||||
// [9 8]
|
||||
}
|
||||
|
||||
func ExampleList_PopFront() {
|
||||
l := glist.NewFrom(g.Slice{1, 2, 3, 4, 5, 6, 7, 8, 9})
|
||||
|
||||
fmt.Println(l.PopFront())
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
}
|
||||
|
||||
func ExampleList_PopFronts() {
|
||||
l := glist.NewFrom(g.Slice{1, 2, 3, 4, 5, 6, 7, 8, 9})
|
||||
|
||||
fmt.Println(l.PopFronts(2))
|
||||
|
||||
// Output:
|
||||
// [1 2]
|
||||
}
|
||||
|
||||
func ExampleList_Join() {
|
||||
var l glist.List
|
||||
l.PushBacks(g.Slice{"a", "b", "c", "d"})
|
||||
|
||||
fmt.Println(l.Join(","))
|
||||
|
||||
// Output:
|
||||
// a,b,c,d
|
||||
}
|
||||
689
container/glist/glist_z_example_test.go
Normal file
689
container/glist/glist_z_example_test.go
Normal file
@ -0,0 +1,689 @@
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package glist_test
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/v2/container/garray"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
"github.com/gogf/gf/v2/container/glist"
|
||||
)
|
||||
|
||||
func ExampleNew() {
|
||||
n := 10
|
||||
l := glist.New()
|
||||
for i := 0; i < n; i++ {
|
||||
l.PushBack(i)
|
||||
}
|
||||
|
||||
fmt.Println(l.Len())
|
||||
fmt.Println(l)
|
||||
fmt.Println(l.FrontAll())
|
||||
fmt.Println(l.BackAll())
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
fmt.Print(l.PopFront())
|
||||
}
|
||||
|
||||
fmt.Println()
|
||||
fmt.Println(l.Len())
|
||||
|
||||
// Output:
|
||||
// 10
|
||||
// [0,1,2,3,4,5,6,7,8,9]
|
||||
// [0 1 2 3 4 5 6 7 8 9]
|
||||
// [9 8 7 6 5 4 3 2 1 0]
|
||||
// 0123456789
|
||||
// 0
|
||||
}
|
||||
|
||||
func ExampleNewFrom() {
|
||||
n := 10
|
||||
l := glist.NewFrom(garray.NewArrayRange(1, 10, 1).Slice())
|
||||
|
||||
fmt.Println(l.Len())
|
||||
fmt.Println(l)
|
||||
fmt.Println(l.FrontAll())
|
||||
fmt.Println(l.BackAll())
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
fmt.Print(l.PopFront())
|
||||
}
|
||||
|
||||
fmt.Println()
|
||||
fmt.Println(l.Len())
|
||||
|
||||
// Output:
|
||||
// 10
|
||||
// [1,2,3,4,5,6,7,8,9,10]
|
||||
// [1 2 3 4 5 6 7 8 9 10]
|
||||
// [10 9 8 7 6 5 4 3 2 1]
|
||||
// 12345678910
|
||||
// 0
|
||||
}
|
||||
|
||||
func ExampleList_PushFront() {
|
||||
l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())
|
||||
|
||||
fmt.Println(l.Len())
|
||||
fmt.Println(l)
|
||||
|
||||
l.PushFront(0)
|
||||
|
||||
fmt.Println(l.Len())
|
||||
fmt.Println(l)
|
||||
|
||||
// Output:
|
||||
// 5
|
||||
// [1,2,3,4,5]
|
||||
// 6
|
||||
// [0,1,2,3,4,5]
|
||||
}
|
||||
|
||||
func ExampleList_PushBack() {
|
||||
l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())
|
||||
|
||||
fmt.Println(l.Len())
|
||||
fmt.Println(l)
|
||||
|
||||
l.PushBack(6)
|
||||
|
||||
fmt.Println(l.Len())
|
||||
fmt.Println(l)
|
||||
|
||||
// Output:
|
||||
// 5
|
||||
// [1,2,3,4,5]
|
||||
// 6
|
||||
// [1,2,3,4,5,6]
|
||||
}
|
||||
|
||||
func ExampleList_PushFronts() {
|
||||
l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())
|
||||
|
||||
fmt.Println(l.Len())
|
||||
fmt.Println(l)
|
||||
|
||||
l.PushFronts(g.Slice{0, -1, -2, -3, -4})
|
||||
|
||||
fmt.Println(l.Len())
|
||||
fmt.Println(l)
|
||||
|
||||
// Output:
|
||||
// 5
|
||||
// [1,2,3,4,5]
|
||||
// 10
|
||||
// [-4,-3,-2,-1,0,1,2,3,4,5]
|
||||
}
|
||||
|
||||
func ExampleList_PushBacks() {
|
||||
l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())
|
||||
|
||||
fmt.Println(l.Len())
|
||||
fmt.Println(l)
|
||||
|
||||
l.PushBacks(g.Slice{6, 7, 8, 9, 10})
|
||||
|
||||
fmt.Println(l.Len())
|
||||
fmt.Println(l)
|
||||
|
||||
// Output:
|
||||
// 5
|
||||
// [1,2,3,4,5]
|
||||
// 10
|
||||
// [1,2,3,4,5,6,7,8,9,10]
|
||||
}
|
||||
|
||||
func ExampleList_PopBack() {
|
||||
l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())
|
||||
|
||||
fmt.Println(l.Len())
|
||||
fmt.Println(l)
|
||||
fmt.Println(l.PopBack())
|
||||
fmt.Println(l.Len())
|
||||
fmt.Println(l)
|
||||
|
||||
// Output:
|
||||
// 5
|
||||
// [1,2,3,4,5]
|
||||
// 5
|
||||
// 4
|
||||
// [1,2,3,4]
|
||||
}
|
||||
|
||||
func ExampleList_PopFront() {
|
||||
l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())
|
||||
|
||||
fmt.Println(l.Len())
|
||||
fmt.Println(l)
|
||||
fmt.Println(l.PopFront())
|
||||
fmt.Println(l.Len())
|
||||
fmt.Println(l)
|
||||
|
||||
// Output:
|
||||
// 5
|
||||
// [1,2,3,4,5]
|
||||
// 1
|
||||
// 4
|
||||
// [2,3,4,5]
|
||||
}
|
||||
|
||||
func ExampleList_PopBacks() {
|
||||
l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())
|
||||
|
||||
fmt.Println(l.Len())
|
||||
fmt.Println(l)
|
||||
fmt.Println(l.PopBacks(2))
|
||||
fmt.Println(l.Len())
|
||||
fmt.Println(l)
|
||||
|
||||
// Output:
|
||||
// 5
|
||||
// [1,2,3,4,5]
|
||||
// [5 4]
|
||||
// 3
|
||||
// [1,2,3]
|
||||
}
|
||||
|
||||
func ExampleList_PopFronts() {
|
||||
l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())
|
||||
|
||||
fmt.Println(l.Len())
|
||||
fmt.Println(l)
|
||||
fmt.Println(l.PopFronts(2))
|
||||
fmt.Println(l.Len())
|
||||
fmt.Println(l)
|
||||
|
||||
// Output:
|
||||
// 5
|
||||
// [1,2,3,4,5]
|
||||
// [1 2]
|
||||
// 3
|
||||
// [3,4,5]
|
||||
}
|
||||
|
||||
func ExampleList_PopBackAll() {
|
||||
l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())
|
||||
|
||||
fmt.Println(l.Len())
|
||||
fmt.Println(l)
|
||||
fmt.Println(l.PopBackAll())
|
||||
fmt.Println(l.Len())
|
||||
|
||||
// Output:
|
||||
// 5
|
||||
// [1,2,3,4,5]
|
||||
// [5 4 3 2 1]
|
||||
// 0
|
||||
}
|
||||
|
||||
func ExampleList_PopFrontAll() {
|
||||
l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())
|
||||
|
||||
fmt.Println(l.Len())
|
||||
fmt.Println(l)
|
||||
fmt.Println(l.PopFrontAll())
|
||||
fmt.Println(l.Len())
|
||||
|
||||
// Output:
|
||||
// 5
|
||||
// [1,2,3,4,5]
|
||||
// [1 2 3 4 5]
|
||||
// 0
|
||||
}
|
||||
|
||||
func ExampleList_FrontAll() {
|
||||
l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())
|
||||
|
||||
fmt.Println(l)
|
||||
fmt.Println(l.FrontAll())
|
||||
|
||||
// Output:
|
||||
// [1,2,3,4,5]
|
||||
// [1 2 3 4 5]
|
||||
}
|
||||
|
||||
func ExampleList_BackAll() {
|
||||
l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())
|
||||
|
||||
fmt.Println(l)
|
||||
fmt.Println(l.BackAll())
|
||||
|
||||
// Output:
|
||||
// [1,2,3,4,5]
|
||||
// [5 4 3 2 1]
|
||||
}
|
||||
|
||||
func ExampleList_FrontValue() {
|
||||
l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())
|
||||
|
||||
fmt.Println(l)
|
||||
fmt.Println(l.FrontValue())
|
||||
|
||||
// Output:
|
||||
// [1,2,3,4,5]
|
||||
// 1
|
||||
}
|
||||
|
||||
func ExampleList_BackValue() {
|
||||
l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())
|
||||
|
||||
fmt.Println(l)
|
||||
fmt.Println(l.BackValue())
|
||||
|
||||
// Output:
|
||||
// [1,2,3,4,5]
|
||||
// 5
|
||||
}
|
||||
|
||||
func ExampleList_Front() {
|
||||
l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())
|
||||
|
||||
fmt.Println(l.Front().Value)
|
||||
fmt.Println(l)
|
||||
|
||||
e := l.Front()
|
||||
l.InsertBefore(e, 0)
|
||||
l.InsertAfter(e, "a")
|
||||
|
||||
fmt.Println(l)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// [1,2,3,4,5]
|
||||
// [0,1,a,2,3,4,5]
|
||||
}
|
||||
|
||||
func ExampleList_Back() {
|
||||
l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())
|
||||
|
||||
fmt.Println(l.Back().Value)
|
||||
fmt.Println(l)
|
||||
|
||||
e := l.Back()
|
||||
l.InsertBefore(e, "a")
|
||||
l.InsertAfter(e, 6)
|
||||
|
||||
fmt.Println(l)
|
||||
|
||||
// Output:
|
||||
// 5
|
||||
// [1,2,3,4,5]
|
||||
// [1,2,3,4,a,5,6]
|
||||
}
|
||||
|
||||
func ExampleList_Len() {
|
||||
l := glist.NewFrom(g.Slice{1, 2, 3, 4, 5})
|
||||
|
||||
fmt.Println(l.Len())
|
||||
|
||||
// Output:
|
||||
// 5
|
||||
}
|
||||
|
||||
func ExampleList_Size() {
|
||||
l := glist.NewFrom(g.Slice{1, 2, 3, 4, 5})
|
||||
|
||||
fmt.Println(l.Size())
|
||||
|
||||
// Output:
|
||||
// 5
|
||||
}
|
||||
|
||||
func ExampleList_MoveBefore() {
|
||||
l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())
|
||||
|
||||
fmt.Println(l.Size())
|
||||
fmt.Println(l)
|
||||
|
||||
// element of `l`
|
||||
e := l.PushBack(6)
|
||||
fmt.Println(l.Size())
|
||||
fmt.Println(l)
|
||||
|
||||
l.MoveBefore(e, l.Front())
|
||||
|
||||
fmt.Println(l.Size())
|
||||
fmt.Println(l)
|
||||
|
||||
// not element of `l`
|
||||
e = &glist.Element{Value: 7}
|
||||
l.MoveBefore(e, l.Front())
|
||||
|
||||
fmt.Println(l.Size())
|
||||
fmt.Println(l)
|
||||
|
||||
// Output:
|
||||
// 5
|
||||
// [1,2,3,4,5]
|
||||
// 6
|
||||
// [1,2,3,4,5,6]
|
||||
// 6
|
||||
// [6,1,2,3,4,5]
|
||||
// 6
|
||||
// [6,1,2,3,4,5]
|
||||
}
|
||||
|
||||
func ExampleList_MoveAfter() {
|
||||
l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())
|
||||
|
||||
fmt.Println(l.Size())
|
||||
fmt.Println(l)
|
||||
|
||||
// element of `l`
|
||||
e := l.PushFront(0)
|
||||
fmt.Println(l.Size())
|
||||
fmt.Println(l)
|
||||
|
||||
l.MoveAfter(e, l.Back())
|
||||
|
||||
fmt.Println(l.Size())
|
||||
fmt.Println(l)
|
||||
|
||||
// not element of `l`
|
||||
e = &glist.Element{Value: -1}
|
||||
l.MoveAfter(e, l.Back())
|
||||
|
||||
fmt.Println(l.Size())
|
||||
fmt.Println(l)
|
||||
|
||||
// Output:
|
||||
// 5
|
||||
// [1,2,3,4,5]
|
||||
// 6
|
||||
// [0,1,2,3,4,5]
|
||||
// 6
|
||||
// [1,2,3,4,5,0]
|
||||
// 6
|
||||
// [1,2,3,4,5,0]
|
||||
}
|
||||
|
||||
func ExampleList_MoveToFront() {
|
||||
l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())
|
||||
|
||||
fmt.Println(l.Size())
|
||||
fmt.Println(l)
|
||||
|
||||
// element of `l`
|
||||
l.MoveToFront(l.Back())
|
||||
|
||||
fmt.Println(l.Size())
|
||||
fmt.Println(l)
|
||||
|
||||
// not element of `l`
|
||||
e := &glist.Element{Value: 6}
|
||||
l.MoveToFront(e)
|
||||
|
||||
fmt.Println(l.Size())
|
||||
fmt.Println(l)
|
||||
|
||||
// Output:
|
||||
// 5
|
||||
// [1,2,3,4,5]
|
||||
// 5
|
||||
// [5,1,2,3,4]
|
||||
// 5
|
||||
// [5,1,2,3,4]
|
||||
}
|
||||
|
||||
func ExampleList_MoveToBack() {
|
||||
l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())
|
||||
|
||||
fmt.Println(l.Size())
|
||||
fmt.Println(l)
|
||||
|
||||
// element of `l`
|
||||
l.MoveToBack(l.Front())
|
||||
|
||||
fmt.Println(l.Size())
|
||||
fmt.Println(l)
|
||||
|
||||
// not element of `l`
|
||||
e := &glist.Element{Value: 0}
|
||||
l.MoveToBack(e)
|
||||
|
||||
fmt.Println(l.Size())
|
||||
fmt.Println(l)
|
||||
|
||||
// Output:
|
||||
// 5
|
||||
// [1,2,3,4,5]
|
||||
// 5
|
||||
// [2,3,4,5,1]
|
||||
// 5
|
||||
// [2,3,4,5,1]
|
||||
}
|
||||
|
||||
func ExampleList_PushBackList() {
|
||||
l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())
|
||||
|
||||
fmt.Println(l.Size())
|
||||
fmt.Println(l)
|
||||
|
||||
other := glist.NewFrom(g.Slice{6, 7, 8, 9, 10})
|
||||
|
||||
fmt.Println(other.Size())
|
||||
fmt.Println(other)
|
||||
|
||||
l.PushBackList(other)
|
||||
|
||||
fmt.Println(l.Size())
|
||||
fmt.Println(l)
|
||||
|
||||
// Output:
|
||||
// 5
|
||||
// [1,2,3,4,5]
|
||||
// 5
|
||||
// [6,7,8,9,10]
|
||||
// 10
|
||||
// [1,2,3,4,5,6,7,8,9,10]
|
||||
}
|
||||
|
||||
func ExampleList_PushFrontList() {
|
||||
l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())
|
||||
|
||||
fmt.Println(l.Size())
|
||||
fmt.Println(l)
|
||||
|
||||
other := glist.NewFrom(g.Slice{-4, -3, -2, -1, 0})
|
||||
|
||||
fmt.Println(other.Size())
|
||||
fmt.Println(other)
|
||||
|
||||
l.PushFrontList(other)
|
||||
|
||||
fmt.Println(l.Size())
|
||||
fmt.Println(l)
|
||||
|
||||
// Output:
|
||||
// 5
|
||||
// [1,2,3,4,5]
|
||||
// 5
|
||||
// [-4,-3,-2,-1,0]
|
||||
// 10
|
||||
// [-4,-3,-2,-1,0,1,2,3,4,5]
|
||||
}
|
||||
|
||||
func ExampleList_InsertAfter() {
|
||||
l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())
|
||||
|
||||
fmt.Println(l.Len())
|
||||
fmt.Println(l)
|
||||
|
||||
l.InsertAfter(l.Front(), "a")
|
||||
l.InsertAfter(l.Back(), "b")
|
||||
|
||||
fmt.Println(l.Len())
|
||||
fmt.Println(l)
|
||||
|
||||
// Output:
|
||||
// 5
|
||||
// [1,2,3,4,5]
|
||||
// 7
|
||||
// [1,a,2,3,4,5,b]
|
||||
}
|
||||
|
||||
func ExampleList_InsertBefore() {
|
||||
l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())
|
||||
|
||||
fmt.Println(l.Len())
|
||||
fmt.Println(l)
|
||||
|
||||
l.InsertBefore(l.Front(), "a")
|
||||
l.InsertBefore(l.Back(), "b")
|
||||
|
||||
fmt.Println(l.Len())
|
||||
fmt.Println(l)
|
||||
|
||||
// Output:
|
||||
// 5
|
||||
// [1,2,3,4,5]
|
||||
// 7
|
||||
// [a,1,2,3,4,b,5]
|
||||
}
|
||||
|
||||
func ExampleList_Remove() {
|
||||
l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())
|
||||
|
||||
fmt.Println(l.Len())
|
||||
fmt.Println(l)
|
||||
|
||||
fmt.Println(l.Remove(l.Front()))
|
||||
fmt.Println(l.Remove(l.Back()))
|
||||
|
||||
fmt.Println(l.Len())
|
||||
fmt.Println(l)
|
||||
|
||||
// Output:
|
||||
// 5
|
||||
// [1,2,3,4,5]
|
||||
// 1
|
||||
// 5
|
||||
// 3
|
||||
// [2,3,4]
|
||||
}
|
||||
|
||||
func ExampleList_Removes() {
|
||||
l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())
|
||||
|
||||
fmt.Println(l.Len())
|
||||
fmt.Println(l)
|
||||
|
||||
l.Removes([]*glist.Element{l.Front(), l.Back()})
|
||||
|
||||
fmt.Println(l.Len())
|
||||
fmt.Println(l)
|
||||
|
||||
// Output:
|
||||
// 5
|
||||
// [1,2,3,4,5]
|
||||
// 3
|
||||
// [2,3,4]
|
||||
}
|
||||
|
||||
func ExampleList_RemoveAll() {
|
||||
l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice())
|
||||
|
||||
fmt.Println(l.Len())
|
||||
fmt.Println(l)
|
||||
|
||||
l.RemoveAll()
|
||||
|
||||
fmt.Println(l.Len())
|
||||
|
||||
// Output:
|
||||
// 5
|
||||
// [1,2,3,4,5]
|
||||
// 0
|
||||
}
|
||||
|
||||
func ExampleList_RLockFunc() {
|
||||
// concurrent-safe list.
|
||||
l := glist.NewFrom(garray.NewArrayRange(1, 10, 1).Slice(), true)
|
||||
// iterate reading from head.
|
||||
l.RLockFunc(func(list *list.List) {
|
||||
length := list.Len()
|
||||
if length > 0 {
|
||||
for i, e := 0, list.Front(); i < length; i, e = i+1, e.Next() {
|
||||
fmt.Print(e.Value)
|
||||
}
|
||||
}
|
||||
})
|
||||
fmt.Println()
|
||||
// iterate reading from tail.
|
||||
l.RLockFunc(func(list *list.List) {
|
||||
length := list.Len()
|
||||
if length > 0 {
|
||||
for i, e := 0, list.Back(); i < length; i, e = i+1, e.Prev() {
|
||||
fmt.Print(e.Value)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
fmt.Println()
|
||||
// Output:
|
||||
// 12345678910
|
||||
// 10987654321
|
||||
}
|
||||
|
||||
func ExampleList_IteratorAsc() {
|
||||
// concurrent-safe list.
|
||||
l := glist.NewFrom(garray.NewArrayRange(1, 10, 1).Slice(), true)
|
||||
// iterate reading from head using IteratorAsc.
|
||||
l.IteratorAsc(func(e *glist.Element) bool {
|
||||
fmt.Print(e.Value)
|
||||
return true
|
||||
})
|
||||
|
||||
// Output:
|
||||
// 12345678910
|
||||
}
|
||||
|
||||
func ExampleList_IteratorDesc() {
|
||||
// concurrent-safe list.
|
||||
l := glist.NewFrom(garray.NewArrayRange(1, 10, 1).Slice(), true)
|
||||
// iterate reading from tail using IteratorDesc.
|
||||
l.IteratorDesc(func(e *glist.Element) bool {
|
||||
fmt.Print(e.Value)
|
||||
return true
|
||||
})
|
||||
// Output:
|
||||
// 10987654321
|
||||
}
|
||||
|
||||
func ExampleList_LockFunc() {
|
||||
// concurrent-safe list.
|
||||
l := glist.NewFrom(garray.NewArrayRange(1, 10, 1).Slice(), true)
|
||||
// iterate writing from head.
|
||||
l.LockFunc(func(list *list.List) {
|
||||
length := list.Len()
|
||||
if length > 0 {
|
||||
for i, e := 0, list.Front(); i < length; i, e = i+1, e.Next() {
|
||||
if e.Value == 6 {
|
||||
e.Value = "M"
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
fmt.Println(l)
|
||||
|
||||
// Output:
|
||||
// [1,2,3,4,5,M,7,8,9,10]
|
||||
}
|
||||
|
||||
func ExampleList_Join() {
|
||||
var l glist.List
|
||||
l.PushBacks(g.Slice{"a", "b", "c", "d"})
|
||||
|
||||
fmt.Println(l.Join(","))
|
||||
|
||||
// Output:
|
||||
// a,b,c,d
|
||||
}
|
||||
@ -8,6 +8,7 @@
|
||||
package gpool
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/errors/gcode"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"time"
|
||||
@ -60,7 +61,7 @@ func New(ttl time.Duration, newFunc NewFunc, expireFunc ...ExpireFunc) *Pool {
|
||||
if len(expireFunc) > 0 {
|
||||
r.ExpireFunc = expireFunc[0]
|
||||
}
|
||||
gtimer.AddSingleton(time.Second, r.checkExpireItems)
|
||||
gtimer.AddSingleton(context.Background(), time.Second, r.checkExpireItems)
|
||||
return r
|
||||
}
|
||||
|
||||
@ -134,7 +135,7 @@ func (p *Pool) Close() {
|
||||
}
|
||||
|
||||
// checkExpire removes expired items from pool in every second.
|
||||
func (p *Pool) checkExpireItems() {
|
||||
func (p *Pool) checkExpireItems(ctx context.Context) {
|
||||
if p.closed.Val() {
|
||||
// If p has ExpireFunc,
|
||||
// then it must close all items using this function.
|
||||
@ -157,7 +158,7 @@ func (p *Pool) checkExpireItems() {
|
||||
var latestExpire int64 = -1
|
||||
// Retrieve the current timestamp in milliseconds, it expires the items
|
||||
// by comparing with this timestamp. It is not accurate comparison for
|
||||
// every items expired, but high performance.
|
||||
// every item expired, but high performance.
|
||||
var timestampMilli = gtime.TimestampMilli()
|
||||
for {
|
||||
if latestExpire > timestampMilli {
|
||||
|
||||
@ -59,7 +59,7 @@ func New(limit ...int) *Queue {
|
||||
}
|
||||
|
||||
// asyncLoopFromListToChannel starts an asynchronous goroutine,
|
||||
// which handles the data synchronization from list <q.list> to channel <q.C>.
|
||||
// which handles the data synchronization from list `q.list` to channel `q.C`.
|
||||
func (q *Queue) asyncLoopFromListToChannel() {
|
||||
defer func() {
|
||||
if q.closed.Val() {
|
||||
@ -87,13 +87,13 @@ func (q *Queue) asyncLoopFromListToChannel() {
|
||||
<-q.events
|
||||
}
|
||||
}
|
||||
// It should be here to close q.C if `q` is unlimited size.
|
||||
// It should be here to close `q.C` if `q` is unlimited size.
|
||||
// It's the sender's responsibility to close channel when it should be closed.
|
||||
close(q.C)
|
||||
}
|
||||
|
||||
// Push pushes the data `v` into the queue.
|
||||
// Note that it would panics if Push is called after the queue is closed.
|
||||
// Note that it would panic if Push is called after the queue is closed.
|
||||
func (q *Queue) Push(v interface{}) {
|
||||
if q.limit > 0 {
|
||||
q.C <- v
|
||||
@ -121,14 +121,15 @@ func (q *Queue) Close() {
|
||||
}
|
||||
if q.limit > 0 {
|
||||
close(q.C)
|
||||
}
|
||||
for i := 0; i < defaultBatchSize; i++ {
|
||||
q.Pop()
|
||||
} else {
|
||||
for i := 0; i < defaultBatchSize; i++ {
|
||||
q.Pop()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Len returns the length of the queue.
|
||||
// Note that the result might not be accurate as there's a
|
||||
// Note that the result might not be accurate as there's an
|
||||
// asynchronous channel reading the list constantly.
|
||||
func (q *Queue) Len() (length int) {
|
||||
if q.list != nil {
|
||||
|
||||
135
container/gqueue/gqueue_z_example_test.go
Normal file
135
container/gqueue/gqueue_z_example_test.go
Normal file
@ -0,0 +1,135 @@
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package gqueue_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/v2/container/gqueue"
|
||||
"github.com/gogf/gf/v2/os/gtimer"
|
||||
"time"
|
||||
)
|
||||
|
||||
func ExampleNew() {
|
||||
n := 10
|
||||
q := gqueue.New()
|
||||
|
||||
// Producer
|
||||
for i := 0; i < n; i++ {
|
||||
q.Push(i)
|
||||
}
|
||||
|
||||
fmt.Println(q.Len())
|
||||
|
||||
// Close the queue in three seconds.
|
||||
gtimer.SetTimeout(context.Background(), time.Second*3, func(ctx context.Context) {
|
||||
q.Close()
|
||||
})
|
||||
|
||||
// The consumer constantly reads the queue data.
|
||||
// If there is no data in the queue, it will block.
|
||||
// The queue is read using the queue.C property exposed
|
||||
// by the queue object and the selectIO multiplexing syntax
|
||||
// example:
|
||||
// for {
|
||||
// select {
|
||||
// case v := <-queue.C:
|
||||
// if v != nil {
|
||||
// fmt.Println(v)
|
||||
// } else {
|
||||
// return
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
for {
|
||||
if v := q.Pop(); v != nil {
|
||||
fmt.Print(v)
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 10
|
||||
// 0123456789
|
||||
}
|
||||
|
||||
func ExampleQueue_Push() {
|
||||
q := gqueue.New()
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
q.Push(i)
|
||||
}
|
||||
|
||||
fmt.Println(q.Pop())
|
||||
fmt.Println(q.Pop())
|
||||
fmt.Println(q.Pop())
|
||||
|
||||
// Output:
|
||||
// 0
|
||||
// 1
|
||||
// 2
|
||||
}
|
||||
|
||||
func ExampleQueue_Pop() {
|
||||
q := gqueue.New()
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
q.Push(i)
|
||||
}
|
||||
|
||||
fmt.Println(q.Pop())
|
||||
q.Close()
|
||||
fmt.Println(q.Pop())
|
||||
|
||||
// Output:
|
||||
// 0
|
||||
// <nil>
|
||||
}
|
||||
|
||||
func ExampleQueue_Close() {
|
||||
q := gqueue.New()
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
q.Push(i)
|
||||
}
|
||||
|
||||
time.Sleep(time.Millisecond)
|
||||
q.Close()
|
||||
|
||||
fmt.Println(q.Len())
|
||||
fmt.Println(q.Pop())
|
||||
|
||||
// Output:
|
||||
// 0
|
||||
// <nil>
|
||||
}
|
||||
|
||||
func ExampleQueue_Len() {
|
||||
q := gqueue.New()
|
||||
|
||||
q.Push(1)
|
||||
q.Push(2)
|
||||
|
||||
fmt.Println(q.Len())
|
||||
|
||||
// May Output:
|
||||
// 2
|
||||
}
|
||||
|
||||
func ExampleQueue_Size() {
|
||||
q := gqueue.New()
|
||||
|
||||
q.Push(1)
|
||||
q.Push(2)
|
||||
|
||||
// Size is alias of Len.
|
||||
fmt.Println(q.Size())
|
||||
|
||||
// May Output:
|
||||
// 2
|
||||
}
|
||||
@ -7,17 +7,401 @@
|
||||
package gset_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/v2/container/gset"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// New create and returns a new set, which contains un-repeated items.
|
||||
// The parameter `safe` is used to specify whether using set in concurrent-safety,
|
||||
// which is false in default.
|
||||
func ExampleNewIntSet() {
|
||||
intSet := gset.NewIntSet()
|
||||
intSet.Add([]int{1, 2, 3}...)
|
||||
fmt.Println(intSet.Slice())
|
||||
|
||||
// May Output:
|
||||
// [2 1 3]
|
||||
}
|
||||
|
||||
// NewIntSetFrom returns a new set from `items`.
|
||||
func ExampleNewFrom() {
|
||||
intSet := gset.NewIntSetFrom([]int{1, 2, 3})
|
||||
fmt.Println(intSet.Slice())
|
||||
|
||||
// May Output:
|
||||
// [2 1 3]
|
||||
}
|
||||
|
||||
// Add adds one or multiple items to the set.
|
||||
func ExampleIntSet_Add() {
|
||||
intSet := gset.NewIntSetFrom([]int{1, 2, 3})
|
||||
intSet.Add(1)
|
||||
fmt.Println(intSet.Slice())
|
||||
fmt.Println(intSet.AddIfNotExist(1))
|
||||
|
||||
// Mya Output:
|
||||
// [1 2 3]
|
||||
// false
|
||||
}
|
||||
|
||||
// AddIfNotExist checks whether item exists in the set,
|
||||
// it adds the item to set and returns true if it does not exists in the set,
|
||||
// or else it does nothing and returns false.
|
||||
func ExampleIntSet_AddIfNotExist() {
|
||||
intSet := gset.NewIntSetFrom([]int{1, 2, 3})
|
||||
intSet.Add(1)
|
||||
fmt.Println(intSet.Slice())
|
||||
fmt.Println(intSet.AddIfNotExist(1))
|
||||
|
||||
// Mya Output:
|
||||
// [1 2 3]
|
||||
// false
|
||||
}
|
||||
|
||||
// AddIfNotExistFunc checks whether item exists in the set,
|
||||
// it adds the item to set and returns true if it does not exists in the set and function `f` returns true,
|
||||
// or else it does nothing and returns false.
|
||||
// Note that, the function `f` is executed without writing lock.
|
||||
func ExampleIntSet_AddIfNotExistFunc() {
|
||||
intSet := gset.NewIntSetFrom([]int{1, 2, 3})
|
||||
intSet.Add(1)
|
||||
fmt.Println(intSet.Slice())
|
||||
fmt.Println(intSet.AddIfNotExistFunc(5, func() bool {
|
||||
return true
|
||||
}))
|
||||
|
||||
// May Output:
|
||||
// [1 2 3]
|
||||
// true
|
||||
}
|
||||
|
||||
// AddIfNotExistFunc checks whether item exists in the set,
|
||||
// it adds the item to set and returns true if it does not exists in the set and function `f` returns true,
|
||||
// or else it does nothing and returns false.
|
||||
// Note that, the function `f` is executed without writing lock.
|
||||
func ExampleIntSet_AddIfNotExistFuncLock() {
|
||||
intSet := gset.NewIntSetFrom([]int{1, 2, 3})
|
||||
intSet.Add(1)
|
||||
fmt.Println(intSet.Slice())
|
||||
fmt.Println(intSet.AddIfNotExistFuncLock(4, func() bool {
|
||||
return true
|
||||
}))
|
||||
|
||||
// May Output:
|
||||
// [1 2 3]
|
||||
// true
|
||||
}
|
||||
|
||||
// Clear deletes all items of the set.
|
||||
func ExampleIntSet_Clear() {
|
||||
intSet := gset.NewIntSetFrom([]int{1, 2, 3})
|
||||
fmt.Println(intSet.Size())
|
||||
intSet.Clear()
|
||||
fmt.Println(intSet.Size())
|
||||
|
||||
// Output:
|
||||
// 3
|
||||
// 0
|
||||
}
|
||||
|
||||
// Complement returns a new set which is the complement from `set` to `full`.
|
||||
// Which means, all the items in `newSet` are in `full` and not in `set`.
|
||||
// It returns the difference between `full` and `set` if the given set `full` is not the full set of `set`.
|
||||
func ExampleIntSet_Complement() {
|
||||
intSet := gset.NewIntSetFrom([]int{1, 2, 3, 4, 5})
|
||||
s := gset.NewIntSetFrom([]int{1, 2, 3})
|
||||
fmt.Println(s.Complement(intSet).Slice())
|
||||
|
||||
// May Output:
|
||||
// [4 5]
|
||||
}
|
||||
|
||||
// Contains checks whether the set contains `item`.
|
||||
func ExampleIntSet_Contains() {
|
||||
var set gset.IntSet
|
||||
set.Add(1)
|
||||
fmt.Println(set.Contains(1))
|
||||
fmt.Println(set.Contains(2))
|
||||
var set1 gset.IntSet
|
||||
set1.Add(1, 4, 5, 6, 7)
|
||||
fmt.Println(set1.Contains(1))
|
||||
|
||||
var set2 gset.IntSet
|
||||
set2.Add(1, 4, 5, 6, 7)
|
||||
fmt.Println(set2.Contains(8))
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
|
||||
// Diff returns a new set which is the difference set from `set` to `other`.
|
||||
// Which means, all the items in `newSet` are in `set` but not in `other`.
|
||||
func ExampleIntSet_Diff() {
|
||||
s1 := gset.NewIntSetFrom([]int{1, 2, 3})
|
||||
s2 := gset.NewIntSetFrom([]int{1, 2, 3, 4})
|
||||
fmt.Println(s2.Diff(s1).Slice())
|
||||
|
||||
// Output:
|
||||
// [4]
|
||||
}
|
||||
|
||||
// Equal checks whether the two sets equal.
|
||||
func ExampleIntSet_Equal() {
|
||||
s1 := gset.NewIntSetFrom([]int{1, 2, 3})
|
||||
s2 := gset.NewIntSetFrom([]int{1, 2, 3, 4})
|
||||
fmt.Println(s2.Equal(s1))
|
||||
|
||||
s3 := gset.NewIntSetFrom([]int{1, 2, 3})
|
||||
s4 := gset.NewIntSetFrom([]int{1, 2, 3})
|
||||
fmt.Println(s3.Equal(s4))
|
||||
|
||||
// Output:
|
||||
// false
|
||||
// true
|
||||
}
|
||||
|
||||
// Intersect returns a new set which is the intersection from `set` to `other`.
|
||||
// Which means, all the items in `newSet` are in `set` and also in `other`.
|
||||
func ExampleIntSet_Intersect() {
|
||||
s1 := gset.NewIntSet()
|
||||
s1.Add([]int{1, 2, 3}...)
|
||||
var s2 gset.IntSet
|
||||
s2.Add([]int{1, 2, 3, 4}...)
|
||||
fmt.Println(s2.Intersect(s1).Slice())
|
||||
|
||||
// May Output:
|
||||
// [1 2 3]
|
||||
}
|
||||
|
||||
// IsSubsetOf checks whether the current set is a sub-set of `other`
|
||||
func ExampleIntSet_IsSubsetOf() {
|
||||
s1 := gset.NewIntSet()
|
||||
s1.Add([]int{1, 2, 3, 4}...)
|
||||
var s2 gset.IntSet
|
||||
s2.Add([]int{1, 2, 4}...)
|
||||
fmt.Println(s2.IsSubsetOf(s1))
|
||||
|
||||
// Output:
|
||||
// true
|
||||
}
|
||||
|
||||
// Iterator iterates the set readonly with given callback function `f`,
|
||||
// if `f` returns true then continue iterating; or false to stop.
|
||||
func ExampleIntSet_Iterator() {
|
||||
s1 := gset.NewIntSet()
|
||||
s1.Add([]int{1, 2, 3, 4}...)
|
||||
s1.Iterator(func(v int) bool {
|
||||
fmt.Println("Iterator", v)
|
||||
return true
|
||||
})
|
||||
// May Output:
|
||||
// Iterator 2
|
||||
// Iterator 3
|
||||
// Iterator 1
|
||||
// Iterator 4
|
||||
}
|
||||
|
||||
// Join joins items with a string `glue`.
|
||||
func ExampleIntSet_Join() {
|
||||
s1 := gset.NewIntSet()
|
||||
s1.Add([]int{1, 2, 3, 4}...)
|
||||
fmt.Println(s1.Join(","))
|
||||
|
||||
// May Output:
|
||||
// 3,4,1,2
|
||||
}
|
||||
|
||||
// LockFunc locks writing with callback function `f`.
|
||||
func ExampleIntSet_LockFunc() {
|
||||
s1 := gset.NewIntSet()
|
||||
s1.Add([]int{1, 2}...)
|
||||
s1.LockFunc(func(m map[int]struct{}) {
|
||||
m[3] = struct{}{}
|
||||
})
|
||||
fmt.Println(s1.Slice())
|
||||
|
||||
// May Output
|
||||
// [2 3 1]
|
||||
}
|
||||
|
||||
// MarshalJSON implements the interface MarshalJSON for json.Marshal.
|
||||
func ExampleIntSet_MarshalJSON() {
|
||||
type Student struct {
|
||||
Id int
|
||||
Name string
|
||||
Scores *gset.IntSet
|
||||
}
|
||||
s := Student{
|
||||
Id: 1,
|
||||
Name: "john",
|
||||
Scores: gset.NewIntSetFrom([]int{100, 99, 98}),
|
||||
}
|
||||
b, _ := json.Marshal(s)
|
||||
fmt.Println(string(b))
|
||||
|
||||
// May Output:
|
||||
// {"Id":1,"Name":"john","Scores":[100,99,98]}
|
||||
}
|
||||
|
||||
// Merge adds items from `others` sets into `set`.
|
||||
func ExampleIntSet_Merge() {
|
||||
s1 := gset.NewIntSet()
|
||||
s1.Add([]int{1, 2, 3, 4}...)
|
||||
|
||||
s2 := gset.NewIntSet()
|
||||
fmt.Println(s1.Merge(s2).Slice())
|
||||
|
||||
// May Output:
|
||||
// [1 2 3 4]
|
||||
}
|
||||
|
||||
// Pops randomly pops an item from set.
|
||||
func ExampleIntSet_Pop() {
|
||||
s1 := gset.NewIntSet()
|
||||
s1.Add([]int{1, 2, 3, 4}...)
|
||||
|
||||
fmt.Println(s1.Pop())
|
||||
|
||||
// May Output:
|
||||
// 1
|
||||
}
|
||||
|
||||
// Pops randomly pops `size` items from set.
|
||||
// It returns all items if size == -1.
|
||||
func ExampleIntSet_Pops() {
|
||||
s1 := gset.NewIntSet()
|
||||
s1.Add([]int{1, 2, 3, 4}...)
|
||||
for _, v := range s1.Pops(2) {
|
||||
fmt.Println(v)
|
||||
}
|
||||
|
||||
// May Output:
|
||||
// 1
|
||||
// 2
|
||||
}
|
||||
|
||||
// RLockFunc locks reading with callback function `f`.
|
||||
func ExampleIntSet_RLockFunc() {
|
||||
s1 := gset.NewIntSet()
|
||||
s1.Add([]int{1, 2, 3, 4}...)
|
||||
s1.RLockFunc(func(m map[int]struct{}) {
|
||||
fmt.Println(m)
|
||||
})
|
||||
|
||||
// Output:
|
||||
// map[1:{} 2:{} 3:{} 4:{}]
|
||||
}
|
||||
|
||||
// Remove deletes `item` from set.
|
||||
func ExampleIntSet_Remove() {
|
||||
s1 := gset.NewIntSet()
|
||||
s1.Add([]int{1, 2, 3, 4}...)
|
||||
s1.Remove(1)
|
||||
fmt.Println(s1.Slice())
|
||||
|
||||
// May Output:
|
||||
// [3 4 2]
|
||||
}
|
||||
|
||||
// Size returns the size of the set.
|
||||
func ExampleIntSet_Size() {
|
||||
s1 := gset.NewIntSet()
|
||||
s1.Add([]int{1, 2, 3, 4}...)
|
||||
fmt.Println(s1.Size())
|
||||
|
||||
// Output:
|
||||
// 4
|
||||
}
|
||||
|
||||
// Slice returns the a of items of the set as slice.
|
||||
func ExampleIntSet_Slice() {
|
||||
s1 := gset.NewIntSet()
|
||||
s1.Add([]int{1, 2, 3, 4}...)
|
||||
fmt.Println(s1.Slice())
|
||||
|
||||
// May Output:
|
||||
// [1, 2, 3, 4]
|
||||
}
|
||||
|
||||
// String returns items as a string, which implements like json.Marshal does.
|
||||
func ExampleIntSet_String() {
|
||||
s1 := gset.NewIntSet()
|
||||
s1.Add([]int{1, 2, 3, 4}...)
|
||||
fmt.Println(s1.String())
|
||||
|
||||
// May Output:
|
||||
// [1,2,3,4]
|
||||
}
|
||||
|
||||
// Sum sums items. Note: The items should be converted to int type,
|
||||
// or you'd get a result that you unexpected.
|
||||
func ExampleIntSet_Sum() {
|
||||
s1 := gset.NewIntSet()
|
||||
s1.Add([]int{1, 2, 3, 4}...)
|
||||
fmt.Println(s1.Sum())
|
||||
|
||||
// Output:
|
||||
// 10
|
||||
}
|
||||
|
||||
// Union returns a new set which is the union of `set` and `other`.
|
||||
// Which means, all the items in `newSet` are in `set` or in `other`.
|
||||
func ExampleIntSet_Union() {
|
||||
s1 := gset.NewIntSet()
|
||||
s1.Add([]int{1, 2, 3, 4}...)
|
||||
s2 := gset.NewIntSet()
|
||||
s2.Add([]int{1, 2, 4}...)
|
||||
fmt.Println(s1.Union(s2).Slice())
|
||||
|
||||
// May Output:
|
||||
// [3 4 1 2]
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
|
||||
func ExampleIntSet_UnmarshalJSON() {
|
||||
b := []byte(`{"Id":1,"Name":"john","Scores":[100,99,98]}`)
|
||||
type Student struct {
|
||||
Id int
|
||||
Name string
|
||||
Scores *gset.IntSet
|
||||
}
|
||||
s := Student{}
|
||||
json.Unmarshal(b, &s)
|
||||
fmt.Println(s)
|
||||
|
||||
// May Output:
|
||||
// {1 john [100,99,98]}
|
||||
}
|
||||
|
||||
// UnmarshalValue is an interface implement which sets any type of value for set.
|
||||
func ExampleIntSet_UnmarshalValue() {
|
||||
b := []byte(`{"Id":1,"Name":"john","Scores":100,99,98}`)
|
||||
type Student struct {
|
||||
Id int
|
||||
Name string
|
||||
Scores *gset.IntSet
|
||||
}
|
||||
s := Student{}
|
||||
json.Unmarshal(b, &s)
|
||||
fmt.Println(s)
|
||||
|
||||
// May Output:
|
||||
// {1 john [100,99,98]}
|
||||
}
|
||||
|
||||
// Walk applies a user supplied function `f` to every item of set.
|
||||
func ExampleIntSet_Walk() {
|
||||
var (
|
||||
set gset.IntSet
|
||||
names = g.SliceInt{1, 0}
|
||||
delta = 10
|
||||
)
|
||||
set.Add(names...)
|
||||
// Add prefix for given table names.
|
||||
set.Walk(func(item int) int {
|
||||
return delta + item
|
||||
})
|
||||
fmt.Println(set.Slice())
|
||||
|
||||
// May Output:
|
||||
// [12 60]
|
||||
}
|
||||
|
||||
@ -7,24 +7,400 @@
|
||||
package gset_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/v2/container/gset"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// NewStrSet create and returns a new set, which contains un-repeated items.
|
||||
// The parameter `safe` is used to specify whether using set in concurrent-safety,
|
||||
// which is false in default.
|
||||
func ExampleNewStrSet() {
|
||||
strSet := gset.NewStrSet(true)
|
||||
strSet.Add([]string{"str1", "str2", "str3"}...)
|
||||
fmt.Println(strSet.Slice())
|
||||
|
||||
// May Output:
|
||||
// [str3 str1 str2]
|
||||
}
|
||||
|
||||
// NewStrSetFrom returns a new set from `items`.
|
||||
func ExampleNewStrSetFrom() {
|
||||
strSet := gset.NewStrSetFrom([]string{"str1", "str2", "str3"}, true)
|
||||
fmt.Println(strSet.Slice())
|
||||
|
||||
// May Output:
|
||||
// [str1 str2 str3]
|
||||
}
|
||||
|
||||
// Add adds one or multiple items to the set.
|
||||
func ExampleStrSet_Add() {
|
||||
strSet := gset.NewStrSetFrom([]string{"str1", "str2", "str3"}, true)
|
||||
strSet.Add("str")
|
||||
fmt.Println(strSet.Slice())
|
||||
fmt.Println(strSet.AddIfNotExist("str"))
|
||||
|
||||
// Mya Output:
|
||||
// [str str1 str2 str3]
|
||||
// false
|
||||
}
|
||||
|
||||
// AddIfNotExist checks whether item exists in the set,
|
||||
// it adds the item to set and returns true if it does not exists in the set,
|
||||
// or else it does nothing and returns false.
|
||||
func ExampleStrSet_AddIfNotExist() {
|
||||
strSet := gset.NewStrSetFrom([]string{"str1", "str2", "str3"}, true)
|
||||
strSet.Add("str")
|
||||
fmt.Println(strSet.Slice())
|
||||
fmt.Println(strSet.AddIfNotExist("str"))
|
||||
|
||||
// Mya Output:
|
||||
// [str str1 str2 str3]
|
||||
// false
|
||||
}
|
||||
|
||||
// AddIfNotExistFunc checks whether item exists in the set,
|
||||
// it adds the item to set and returns true if it does not exists in the set and function `f` returns true,
|
||||
// or else it does nothing and returns false.
|
||||
// Note that, the function `f` is executed without writing lock.
|
||||
func ExampleStrSet_AddIfNotExistFunc() {
|
||||
strSet := gset.NewStrSetFrom([]string{"str1", "str2", "str3"}, true)
|
||||
strSet.Add("str")
|
||||
fmt.Println(strSet.Slice())
|
||||
fmt.Println(strSet.AddIfNotExistFunc("str5", func() bool {
|
||||
return true
|
||||
}))
|
||||
|
||||
// May Output:
|
||||
// [str1 str2 str3 str]
|
||||
// true
|
||||
}
|
||||
|
||||
// AddIfNotExistFunc checks whether item exists in the set,
|
||||
// it adds the item to set and returns true if it does not exists in the set and function `f` returns true,
|
||||
// or else it does nothing and returns false.
|
||||
// Note that, the function `f` is executed without writing lock.
|
||||
func ExampleStrSet_AddIfNotExistFuncLock() {
|
||||
strSet := gset.NewStrSetFrom([]string{"str1", "str2", "str3"}, true)
|
||||
strSet.Add("str")
|
||||
fmt.Println(strSet.Slice())
|
||||
fmt.Println(strSet.AddIfNotExistFuncLock("str4", func() bool {
|
||||
return true
|
||||
}))
|
||||
|
||||
// May Output:
|
||||
// [str1 str2 str3 str]
|
||||
// true
|
||||
}
|
||||
|
||||
// Clear deletes all items of the set.
|
||||
func ExampleStrSet_Clear() {
|
||||
strSet := gset.NewStrSetFrom([]string{"str1", "str2", "str3"}, true)
|
||||
fmt.Println(strSet.Size())
|
||||
strSet.Clear()
|
||||
fmt.Println(strSet.Size())
|
||||
|
||||
// Output:
|
||||
// 3
|
||||
// 0
|
||||
}
|
||||
|
||||
// Complement returns a new set which is the complement from `set` to `full`.
|
||||
// Which means, all the items in `newSet` are in `full` and not in `set`.
|
||||
// It returns the difference between `full` and `set` if the given set `full` is not the full set of `set`.
|
||||
func ExampleStrSet_Complement() {
|
||||
strSet := gset.NewStrSetFrom([]string{"str1", "str2", "str3", "str4", "str5"}, true)
|
||||
s := gset.NewStrSetFrom([]string{"str1", "str2", "str3"}, true)
|
||||
fmt.Println(s.Complement(strSet).Slice())
|
||||
|
||||
// May Output:
|
||||
// [str4 str5]
|
||||
}
|
||||
|
||||
// Contains checks whether the set contains `item`.
|
||||
func ExampleStrSet_Contains() {
|
||||
var set gset.StrSet
|
||||
set.Add("a")
|
||||
fmt.Println(set.Contains("a"))
|
||||
fmt.Println(set.Contains("A"))
|
||||
fmt.Println(set.ContainsI("A"))
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
|
||||
// ContainsI checks whether a value exists in the set with case-insensitively.
|
||||
// Note that it internally iterates the whole set to do the comparison with case-insensitively.
|
||||
func ExampleStrSet_ContainsI() {
|
||||
var set gset.StrSet
|
||||
set.Add("a")
|
||||
fmt.Println(set.ContainsI("a"))
|
||||
fmt.Println(set.ContainsI("A"))
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
}
|
||||
|
||||
// Diff returns a new set which is the difference set from `set` to `other`.
|
||||
// Which means, all the items in `newSet` are in `set` but not in `other`.
|
||||
func ExampleStrSet_Diff() {
|
||||
s1 := gset.NewStrSetFrom([]string{"a", "b", "c"}, true)
|
||||
s2 := gset.NewStrSetFrom([]string{"a", "b", "c", "d"}, true)
|
||||
fmt.Println(s2.Diff(s1).Slice())
|
||||
|
||||
// Output:
|
||||
// [d]
|
||||
}
|
||||
|
||||
// Equal checks whether the two sets equal.
|
||||
func ExampleStrSet_Equal() {
|
||||
s1 := gset.NewStrSetFrom([]string{"a", "b", "c"}, true)
|
||||
s2 := gset.NewStrSetFrom([]string{"a", "b", "c", "d"}, true)
|
||||
fmt.Println(s2.Equal(s1))
|
||||
|
||||
s3 := gset.NewStrSetFrom([]string{"a", "b", "c"}, true)
|
||||
s4 := gset.NewStrSetFrom([]string{"a", "b", "c"}, true)
|
||||
fmt.Println(s3.Equal(s4))
|
||||
|
||||
// Output:
|
||||
// false
|
||||
// true
|
||||
}
|
||||
|
||||
// Intersect returns a new set which is the intersection from `set` to `other`.
|
||||
// Which means, all the items in `newSet` are in `set` and also in `other`.
|
||||
func ExampleStrSet_Intersect() {
|
||||
s1 := gset.NewStrSet(true)
|
||||
s1.Add([]string{"a", "b", "c"}...)
|
||||
var s2 gset.StrSet
|
||||
s2.Add([]string{"a", "b", "c", "d"}...)
|
||||
fmt.Println(s2.Intersect(s1).Slice())
|
||||
|
||||
// May Output:
|
||||
// [c a b]
|
||||
}
|
||||
|
||||
// IsSubsetOf checks whether the current set is a sub-set of `other`
|
||||
func ExampleStrSet_IsSubsetOf() {
|
||||
s1 := gset.NewStrSet(true)
|
||||
s1.Add([]string{"a", "b", "c", "d"}...)
|
||||
var s2 gset.StrSet
|
||||
s2.Add([]string{"a", "b", "d"}...)
|
||||
fmt.Println(s2.IsSubsetOf(s1))
|
||||
|
||||
// Output:
|
||||
// true
|
||||
}
|
||||
|
||||
// Iterator iterates the set readonly with given callback function `f`,
|
||||
// if `f` returns true then continue iterating; or false to stop.
|
||||
func ExampleStrSet_Iterator() {
|
||||
s1 := gset.NewStrSet(true)
|
||||
s1.Add([]string{"a", "b", "c", "d"}...)
|
||||
s1.Iterator(func(v string) bool {
|
||||
fmt.Println("Iterator", v)
|
||||
return true
|
||||
})
|
||||
|
||||
// May Output:
|
||||
// Iterator a
|
||||
// Iterator b
|
||||
// Iterator c
|
||||
// Iterator d
|
||||
}
|
||||
|
||||
// Join joins items with a string `glue`.
|
||||
func ExampleStrSet_Join() {
|
||||
s1 := gset.NewStrSet(true)
|
||||
s1.Add([]string{"a", "b", "c", "d"}...)
|
||||
fmt.Println(s1.Join(","))
|
||||
|
||||
// May Output:
|
||||
// b,c,d,a
|
||||
}
|
||||
|
||||
// LockFunc locks writing with callback function `f`.
|
||||
func ExampleStrSet_LockFunc() {
|
||||
s1 := gset.NewStrSet(true)
|
||||
s1.Add([]string{"1", "2"}...)
|
||||
s1.LockFunc(func(m map[string]struct{}) {
|
||||
m["3"] = struct{}{}
|
||||
})
|
||||
fmt.Println(s1.Slice())
|
||||
|
||||
// May Output
|
||||
// [2 3 1]
|
||||
|
||||
}
|
||||
|
||||
// MarshalJSON implements the interface MarshalJSON for json.Marshal.
|
||||
func ExampleStrSet_MarshalJSON() {
|
||||
type Student struct {
|
||||
Id int
|
||||
Name string
|
||||
Scores *gset.StrSet
|
||||
}
|
||||
s := Student{
|
||||
Id: 1,
|
||||
Name: "john",
|
||||
Scores: gset.NewStrSetFrom([]string{"100", "99", "98"}, true),
|
||||
}
|
||||
b, _ := json.Marshal(s)
|
||||
fmt.Println(string(b))
|
||||
|
||||
// May Output:
|
||||
// {"Id":1,"Name":"john","Scores":["100","99","98"]}
|
||||
}
|
||||
|
||||
// Merge adds items from `others` sets into `set`.
|
||||
func ExampleStrSet_Merge() {
|
||||
s1 := gset.NewStrSet(true)
|
||||
s1.Add([]string{"a", "b", "c", "d"}...)
|
||||
|
||||
s2 := gset.NewStrSet(true)
|
||||
fmt.Println(s1.Merge(s2).Slice())
|
||||
|
||||
// May Output:
|
||||
// [d a b c]
|
||||
}
|
||||
|
||||
// Pops randomly pops an item from set.
|
||||
func ExampleStrSet_Pop() {
|
||||
s1 := gset.NewStrSet(true)
|
||||
s1.Add([]string{"a", "b", "c", "d"}...)
|
||||
|
||||
fmt.Println(s1.Pop())
|
||||
|
||||
// May Output:
|
||||
// a
|
||||
}
|
||||
|
||||
// Pops randomly pops `size` items from set.
|
||||
// It returns all items if size == -1.
|
||||
func ExampleStrSet_Pops() {
|
||||
s1 := gset.NewStrSet(true)
|
||||
s1.Add([]string{"a", "b", "c", "d"}...)
|
||||
for _, v := range s1.Pops(2) {
|
||||
fmt.Println(v)
|
||||
}
|
||||
|
||||
// May Output:
|
||||
// a
|
||||
// b
|
||||
}
|
||||
|
||||
// RLockFunc locks reading with callback function `f`.
|
||||
func ExampleStrSet_RLockFunc() {
|
||||
s1 := gset.NewStrSet(true)
|
||||
s1.Add([]string{"a", "b", "c", "d"}...)
|
||||
s1.RLockFunc(func(m map[string]struct{}) {
|
||||
fmt.Println(m)
|
||||
})
|
||||
|
||||
// Output:
|
||||
// map[a:{} b:{} c:{} d:{}]
|
||||
}
|
||||
|
||||
// Remove deletes `item` from set.
|
||||
func ExampleStrSet_Remove() {
|
||||
s1 := gset.NewStrSet(true)
|
||||
s1.Add([]string{"a", "b", "c", "d"}...)
|
||||
s1.Remove("a")
|
||||
fmt.Println(s1.Slice())
|
||||
|
||||
// May Output:
|
||||
// [b c d]
|
||||
}
|
||||
|
||||
// Size returns the size of the set.
|
||||
func ExampleStrSet_Size() {
|
||||
s1 := gset.NewStrSet(true)
|
||||
s1.Add([]string{"a", "b", "c", "d"}...)
|
||||
fmt.Println(s1.Size())
|
||||
|
||||
// Output:
|
||||
// 4
|
||||
}
|
||||
|
||||
// Slice returns the a of items of the set as slice.
|
||||
func ExampleStrSet_Slice() {
|
||||
s1 := gset.NewStrSet(true)
|
||||
s1.Add([]string{"a", "b", "c", "d"}...)
|
||||
fmt.Println(s1.Slice())
|
||||
|
||||
// May Output:
|
||||
// [a,b,c,d]
|
||||
}
|
||||
|
||||
// String returns items as a string, which implements like json.Marshal does.
|
||||
func ExampleStrSet_String() {
|
||||
s1 := gset.NewStrSet(true)
|
||||
s1.Add([]string{"a", "b", "c", "d"}...)
|
||||
fmt.Println(s1.String())
|
||||
|
||||
// May Output:
|
||||
// "a","b","c","d"
|
||||
}
|
||||
|
||||
// Sum sums items. Note: The items should be converted to int type,
|
||||
// or you'd get a result that you unexpected.
|
||||
func ExampleStrSet_Sum() {
|
||||
s1 := gset.NewStrSet(true)
|
||||
s1.Add([]string{"1", "2", "3", "4"}...)
|
||||
fmt.Println(s1.Sum())
|
||||
|
||||
// Output:
|
||||
// 10
|
||||
}
|
||||
|
||||
// Union returns a new set which is the union of `set` and `other`.
|
||||
// Which means, all the items in `newSet` are in `set` or in `other`.
|
||||
func ExampleStrSet_Union() {
|
||||
s1 := gset.NewStrSet(true)
|
||||
s1.Add([]string{"a", "b", "c", "d"}...)
|
||||
s2 := gset.NewStrSet(true)
|
||||
s2.Add([]string{"a", "b", "d"}...)
|
||||
fmt.Println(s1.Union(s2).Slice())
|
||||
|
||||
// May Output:
|
||||
// [a b c d]
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
|
||||
func ExampleStrSet_UnmarshalJSON() {
|
||||
b := []byte(`{"Id":1,"Name":"john","Scores":["100","99","98"]}`)
|
||||
type Student struct {
|
||||
Id int
|
||||
Name string
|
||||
Scores *gset.StrSet
|
||||
}
|
||||
s := Student{}
|
||||
json.Unmarshal(b, &s)
|
||||
fmt.Println(s)
|
||||
|
||||
// May Output:
|
||||
// {1 john "99","98","100"}
|
||||
}
|
||||
|
||||
// UnmarshalValue is an interface implement which sets any type of value for set.
|
||||
func ExampleStrSet_UnmarshalValue() {
|
||||
b := []byte(`{"Id":1,"Name":"john","Scores":["100","99","98"]}`)
|
||||
type Student struct {
|
||||
Id int
|
||||
Name string
|
||||
Scores *gset.StrSet
|
||||
}
|
||||
s := Student{}
|
||||
json.Unmarshal(b, &s)
|
||||
fmt.Println(s)
|
||||
|
||||
// May Output:
|
||||
// {1 john "99","98","100"}
|
||||
}
|
||||
|
||||
// Walk applies a user supplied function `f` to every item of set.
|
||||
func ExampleStrSet_Walk() {
|
||||
var (
|
||||
set gset.StrSet
|
||||
|
||||
@ -202,12 +202,6 @@ type Link interface {
|
||||
IsTransaction() bool
|
||||
}
|
||||
|
||||
// Logger is the logging interface for DB.
|
||||
type Logger interface {
|
||||
Error(ctx context.Context, s string)
|
||||
Debug(ctx context.Context, s string)
|
||||
}
|
||||
|
||||
// Sql is the sql recording struct.
|
||||
type Sql struct {
|
||||
Sql string // SQL string(may contain reserved char '?').
|
||||
@ -281,6 +275,7 @@ const (
|
||||
sqlTypeQueryContext = `DB.QueryContext`
|
||||
sqlTypeExecContext = `DB.ExecContext`
|
||||
sqlTypePrepareContext = `DB.PrepareContext`
|
||||
modelForDaoSuffix = `ForDao`
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@ -196,20 +196,26 @@ func (c *Core) GetStructs(ctx context.Context, pointer interface{}, sql string,
|
||||
// the conversion. If parameter `pointer` is type of slice, it calls GetStructs internally
|
||||
// for conversion.
|
||||
func (c *Core) GetScan(ctx context.Context, pointer interface{}, sql string, args ...interface{}) error {
|
||||
t := reflect.TypeOf(pointer)
|
||||
k := t.Kind()
|
||||
if k != reflect.Ptr {
|
||||
return gerror.NewCodef(gcode.CodeInvalidParameter, "params should be type of pointer, but got: %v", k)
|
||||
reflectInfo := utils.OriginTypeAndKind(pointer)
|
||||
if reflectInfo.InputKind != reflect.Ptr {
|
||||
return gerror.NewCodef(
|
||||
gcode.CodeInvalidParameter,
|
||||
"params should be type of pointer, but got: %v",
|
||||
reflectInfo.InputKind,
|
||||
)
|
||||
}
|
||||
k = t.Elem().Kind()
|
||||
switch k {
|
||||
switch reflectInfo.OriginKind {
|
||||
case reflect.Array, reflect.Slice:
|
||||
return c.db.GetCore().GetStructs(ctx, pointer, sql, args...)
|
||||
|
||||
case reflect.Struct:
|
||||
return c.db.GetCore().GetStruct(ctx, pointer, sql, args...)
|
||||
}
|
||||
return gerror.NewCodef(gcode.CodeInvalidParameter, "element type should be type of struct/slice, unsupported: %v", k)
|
||||
return gerror.NewCodef(
|
||||
gcode.CodeInvalidParameter,
|
||||
`in valid parameter type "%v", of which element type should be type of struct/slice`,
|
||||
reflectInfo.InputType,
|
||||
)
|
||||
}
|
||||
|
||||
// GetValue queries and returns the field value from database.
|
||||
@ -626,9 +632,9 @@ func (c *Core) writeSqlToLogger(ctx context.Context, sql *Sql) {
|
||||
)
|
||||
switch sql.Type {
|
||||
case sqlTypeQueryContext:
|
||||
sqlTypeKey = `selected`
|
||||
sqlTypeKey = `rows`
|
||||
default:
|
||||
sqlTypeKey = `affected`
|
||||
sqlTypeKey = `rows`
|
||||
}
|
||||
if sql.IsTransaction {
|
||||
if v := ctx.Value(transactionIdForLoggerCtx); v != nil {
|
||||
@ -636,7 +642,7 @@ func (c *Core) writeSqlToLogger(ctx context.Context, sql *Sql) {
|
||||
}
|
||||
}
|
||||
s := fmt.Sprintf(
|
||||
"[%3d ms] [%s] [%s:%d] %s%s",
|
||||
"[%3d ms] [%s] [%s:%-3d] %s%s",
|
||||
sql.End-sql.Start, sql.Group, sqlTypeKey, sql.RowsAffected, transactionIdStr, sql.Format,
|
||||
)
|
||||
if sql.Error != nil {
|
||||
|
||||
@ -151,7 +151,7 @@ func (c *Core) convertFieldValueToLocalValue(fieldValue interface{}, fieldType s
|
||||
// mappingAndFilterData automatically mappings the map key to table field and removes
|
||||
// all key-value pairs that are not the field of given table.
|
||||
func (c *Core) mappingAndFilterData(schema, table string, data map[string]interface{}, filter bool) (map[string]interface{}, error) {
|
||||
if fieldsMap, err := c.db.TableFields(c.GetCtx(), table, schema); err == nil {
|
||||
if fieldsMap, err := c.db.TableFields(c.GetCtx(), c.guessPrimaryTableName(table), schema); err == nil {
|
||||
fieldsKeyMap := make(map[string]interface{}, len(fieldsMap))
|
||||
for k, _ := range fieldsMap {
|
||||
fieldsKeyMap[k] = nil
|
||||
|
||||
@ -11,6 +11,7 @@ import (
|
||||
"database/sql"
|
||||
"github.com/gogf/gf/v2/errors/gcode"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/internal/utils"
|
||||
"reflect"
|
||||
|
||||
"github.com/gogf/gf/v2/container/gtype"
|
||||
@ -399,20 +400,26 @@ func (tx *TX) GetStructs(objPointerSlice interface{}, sql string, args ...interf
|
||||
// the conversion. If parameter `pointer` is type of slice, it calls GetStructs internally
|
||||
// for conversion.
|
||||
func (tx *TX) GetScan(pointer interface{}, sql string, args ...interface{}) error {
|
||||
t := reflect.TypeOf(pointer)
|
||||
k := t.Kind()
|
||||
if k != reflect.Ptr {
|
||||
return gerror.NewCodef(gcode.CodeInvalidParameter, "params should be type of pointer, but got: %v", k)
|
||||
reflectInfo := utils.OriginTypeAndKind(pointer)
|
||||
if reflectInfo.InputKind != reflect.Ptr {
|
||||
return gerror.NewCodef(
|
||||
gcode.CodeInvalidParameter,
|
||||
"params should be type of pointer, but got: %v",
|
||||
reflectInfo.InputKind,
|
||||
)
|
||||
}
|
||||
k = t.Elem().Kind()
|
||||
switch k {
|
||||
switch reflectInfo.OriginKind {
|
||||
case reflect.Array, reflect.Slice:
|
||||
return tx.GetStructs(pointer, sql, args...)
|
||||
|
||||
case reflect.Struct:
|
||||
return tx.GetStruct(pointer, sql, args...)
|
||||
}
|
||||
return gerror.NewCodef(gcode.CodeInvalidParameter, "element type should be type of struct/slice, unsupported: %v", k)
|
||||
return gerror.NewCodef(
|
||||
gcode.CodeInvalidParameter,
|
||||
`in valid parameter type "%v", of which element type should be type of struct/slice`,
|
||||
reflectInfo.InputType,
|
||||
)
|
||||
}
|
||||
|
||||
// GetValue queries and returns the field value from database.
|
||||
|
||||
@ -7,6 +7,13 @@
|
||||
|
||||
package gdb
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/errors/gcode"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/text/gregex"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
)
|
||||
|
||||
// MasterLink acts like function Master but with additional `schema` parameter specifying
|
||||
// the schema for the connection. It is defined for internal usage.
|
||||
// Also see Master.
|
||||
@ -29,8 +36,10 @@ func (c *Core) SlaveLink(schema ...string) (Link, error) {
|
||||
return &dbLink{db}, nil
|
||||
}
|
||||
|
||||
// QuoteWord checks given string `s` a word, if true quotes it with security chars of the database
|
||||
// and returns the quoted string; or else return `s` without any change.
|
||||
// QuoteWord checks given string `s` a word,
|
||||
// if true it quotes `s` with security chars of the database
|
||||
// and returns the quoted string; or else it returns `s` without any change.
|
||||
//
|
||||
// The meaning of a `word` can be considered as a column name.
|
||||
func (c *Core) QuoteWord(s string) string {
|
||||
charLeft, charRight := c.db.GetChars()
|
||||
@ -39,6 +48,7 @@ func (c *Core) QuoteWord(s string) string {
|
||||
|
||||
// QuoteString quotes string with quote chars. Strings like:
|
||||
// "user", "user u", "user,user_detail", "user u, user_detail ut", "u.id asc".
|
||||
//
|
||||
// The meaning of a `string` can be considered as part of a statement string including columns.
|
||||
func (c *Core) QuoteString(s string) string {
|
||||
charLeft, charRight := c.db.GetChars()
|
||||
@ -84,3 +94,56 @@ func (c *Core) Tables(schema ...string) (tables []string, err error) {
|
||||
func (c *Core) TableFields(table string, schema ...string) (fields map[string]*TableField, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// HasField determine whether the field exists in the table.
|
||||
func (c *Core) HasField(table, field string, schema ...string) (bool, error) {
|
||||
table = c.guessPrimaryTableName(table)
|
||||
tableFields, err := c.db.TableFields(c.GetCtx(), table, schema...)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if len(tableFields) == 0 {
|
||||
return false, gerror.NewCodef(
|
||||
gcode.CodeNotFound,
|
||||
`empty table fields for table "%s"`, table,
|
||||
)
|
||||
}
|
||||
fieldsArray := make([]string, len(tableFields))
|
||||
for k, v := range tableFields {
|
||||
fieldsArray[v.Index] = k
|
||||
}
|
||||
charLeft, charRight := c.db.GetChars()
|
||||
field = gstr.Trim(field, charLeft+charRight)
|
||||
for _, f := range fieldsArray {
|
||||
if f == field {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// guessPrimaryTableName parses and returns the primary table name.
|
||||
func (c *Core) guessPrimaryTableName(tableStr string) string {
|
||||
if tableStr == "" {
|
||||
return ""
|
||||
}
|
||||
var (
|
||||
guessedTableName = ""
|
||||
array1 = gstr.SplitAndTrim(tableStr, ",")
|
||||
array2 = gstr.SplitAndTrim(array1[0], " ")
|
||||
array3 = gstr.SplitAndTrim(array2[0], ".")
|
||||
)
|
||||
if len(array3) >= 2 {
|
||||
guessedTableName = array3[1]
|
||||
} else {
|
||||
guessedTableName = array3[0]
|
||||
}
|
||||
charL, charR := c.db.GetChars()
|
||||
if charL != "" || charR != "" {
|
||||
guessedTableName = gstr.Trim(guessedTableName, charL+charR)
|
||||
}
|
||||
if !gregex.IsMatchString(regularFieldNameRegPattern, guessedTableName) {
|
||||
return ""
|
||||
}
|
||||
return guessedTableName
|
||||
}
|
||||
|
||||
@ -58,8 +58,6 @@ type iTableName interface {
|
||||
|
||||
const (
|
||||
OrmTagForStruct = "orm"
|
||||
OrmTagForUnique = "unique"
|
||||
OrmTagForPrimary = "primary"
|
||||
OrmTagForTable = "table"
|
||||
OrmTagForWith = "with"
|
||||
OrmTagForWithWhere = "where"
|
||||
@ -74,32 +72,6 @@ var (
|
||||
structTagPriority = append([]string{OrmTagForStruct}, gconv.StructTagPriority...)
|
||||
)
|
||||
|
||||
// guessPrimaryTableName parses and returns the primary table name.
|
||||
func (m *Model) guessPrimaryTableName(tableStr string) string {
|
||||
if tableStr == "" {
|
||||
return ""
|
||||
}
|
||||
var (
|
||||
guessedTableName = ""
|
||||
array1 = gstr.SplitAndTrim(tableStr, ",")
|
||||
array2 = gstr.SplitAndTrim(array1[0], " ")
|
||||
array3 = gstr.SplitAndTrim(array2[0], ".")
|
||||
)
|
||||
if len(array3) >= 2 {
|
||||
guessedTableName = array3[1]
|
||||
} else {
|
||||
guessedTableName = array3[0]
|
||||
}
|
||||
charL, charR := m.db.GetChars()
|
||||
if charL != "" || charR != "" {
|
||||
guessedTableName = gstr.Trim(guessedTableName, charL+charR)
|
||||
}
|
||||
if !gregex.IsMatchString(regularFieldNameRegPattern, guessedTableName) {
|
||||
return ""
|
||||
}
|
||||
return guessedTableName
|
||||
}
|
||||
|
||||
// getTableNameFromOrmTag retrieves and returns the table name from struct object.
|
||||
func getTableNameFromOrmTag(object interface{}) string {
|
||||
var tableName string
|
||||
@ -348,44 +320,6 @@ func getFieldsFromStructOrMap(structOrMap interface{}) (fields []string) {
|
||||
return
|
||||
}
|
||||
|
||||
// GetWhereConditionOfStruct returns the where condition sql and arguments by given struct pointer.
|
||||
// This function automatically retrieves primary or unique field and its attribute value as condition.
|
||||
func GetWhereConditionOfStruct(pointer interface{}) (where string, args []interface{}, err error) {
|
||||
tagField, err := structs.TagFields(pointer, []string{OrmTagForStruct})
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
array := ([]string)(nil)
|
||||
for _, field := range tagField {
|
||||
array = strings.Split(field.TagValue, ",")
|
||||
if len(array) > 1 && gstr.InArray([]string{OrmTagForUnique, OrmTagForPrimary}, array[1]) {
|
||||
return array[0], []interface{}{field.Value.Interface()}, nil
|
||||
}
|
||||
if len(where) > 0 {
|
||||
where += " AND "
|
||||
}
|
||||
where += field.TagValue + "=?"
|
||||
args = append(args, field.Value.Interface())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GetPrimaryKey retrieves and returns primary key field name from given struct.
|
||||
func GetPrimaryKey(pointer interface{}) (string, error) {
|
||||
tagField, err := structs.TagFields(pointer, []string{OrmTagForStruct})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
array := ([]string)(nil)
|
||||
for _, field := range tagField {
|
||||
array = strings.Split(field.TagValue, ",")
|
||||
if len(array) > 1 && array[1] == OrmTagForPrimary {
|
||||
return array[0], nil
|
||||
}
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// GetPrimaryKeyCondition returns a new where condition by primary field name.
|
||||
// The optional parameter `where` is like follows:
|
||||
// 123 => primary=123
|
||||
@ -446,20 +380,16 @@ type formatWhereInput struct {
|
||||
OmitEmpty bool
|
||||
Schema string
|
||||
Table string
|
||||
Prefix string // Field prefix, eg: "user.", "order.".
|
||||
}
|
||||
|
||||
// formatWhere formats where statement and its arguments for `Where` and `Having` statements.
|
||||
func formatWhere(db DB, in formatWhereInput) (newWhere string, newArgs []interface{}) {
|
||||
var (
|
||||
buffer = bytes.NewBuffer(nil)
|
||||
reflectValue = reflect.ValueOf(in.Where)
|
||||
reflectKind = reflectValue.Kind()
|
||||
buffer = bytes.NewBuffer(nil)
|
||||
reflectInfo = utils.OriginValueAndKind(in.Where)
|
||||
)
|
||||
for reflectKind == reflect.Ptr {
|
||||
reflectValue = reflectValue.Elem()
|
||||
reflectKind = reflectValue.Kind()
|
||||
}
|
||||
switch reflectKind {
|
||||
switch reflectInfo.OriginKind {
|
||||
case reflect.Array, reflect.Slice:
|
||||
newArgs = formatWhereInterfaces(db, gconv.Interfaces(in.Where), buffer, newArgs)
|
||||
|
||||
@ -473,10 +403,22 @@ func formatWhere(db DB, in formatWhereInput) (newWhere string, newArgs []interfa
|
||||
continue
|
||||
}
|
||||
}
|
||||
newArgs = formatWhereKeyValue(db, buffer, newArgs, key, value)
|
||||
newArgs = formatWhereKeyValue(formatWhereKeyValueInput{
|
||||
Db: db,
|
||||
Buffer: buffer,
|
||||
Args: newArgs,
|
||||
Key: key,
|
||||
Value: value,
|
||||
Prefix: in.Prefix,
|
||||
})
|
||||
}
|
||||
|
||||
case reflect.Struct:
|
||||
// If the `where` parameter is defined like `xxxForDao`, it then adds `OmitNil` option for this condition,
|
||||
// which will filter all nil parameters in `where`.
|
||||
if gstr.HasSuffix(reflect.TypeOf(in.Where).String(), modelForDaoSuffix) {
|
||||
in.OmitNil = true
|
||||
}
|
||||
// If `where` struct implements iIterator interface,
|
||||
// it then uses its Iterate function to iterate its key-value pairs.
|
||||
// For example, ListMap and TreeMap are ordered map,
|
||||
@ -492,14 +434,22 @@ func formatWhere(db DB, in formatWhereInput) (newWhere string, newArgs []interfa
|
||||
return true
|
||||
}
|
||||
}
|
||||
newArgs = formatWhereKeyValue(db, buffer, newArgs, ketStr, value)
|
||||
newArgs = formatWhereKeyValue(formatWhereKeyValueInput{
|
||||
Db: db,
|
||||
Buffer: buffer,
|
||||
Args: newArgs,
|
||||
Key: ketStr,
|
||||
Value: value,
|
||||
OmitEmpty: in.OmitEmpty,
|
||||
Prefix: in.Prefix,
|
||||
})
|
||||
return true
|
||||
})
|
||||
break
|
||||
}
|
||||
// Automatically mapping and filtering the struct attribute.
|
||||
var (
|
||||
reflectType = reflectValue.Type()
|
||||
reflectType = reflectInfo.OriginValue.Type()
|
||||
structField reflect.StructField
|
||||
)
|
||||
data := DataToMapDeep(in.Where)
|
||||
@ -517,16 +467,53 @@ func formatWhere(db DB, in formatWhereInput) (newWhere string, newArgs []interfa
|
||||
if in.OmitEmpty && empty.IsEmpty(foundValue) {
|
||||
continue
|
||||
}
|
||||
newArgs = formatWhereKeyValue(db, buffer, newArgs, foundKey, foundValue)
|
||||
newArgs = formatWhereKeyValue(formatWhereKeyValueInput{
|
||||
Db: db,
|
||||
Buffer: buffer,
|
||||
Args: newArgs,
|
||||
Key: foundKey,
|
||||
Value: foundValue,
|
||||
OmitEmpty: in.OmitEmpty,
|
||||
Prefix: in.Prefix,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
// Usually a string.
|
||||
var (
|
||||
i = 0
|
||||
whereStr = gconv.String(in.Where)
|
||||
)
|
||||
// Is `whereStr` a field name which composed as a key-value condition?
|
||||
// Eg:
|
||||
// Where("id", 1)
|
||||
// Where("id", g.Slice{1,2,3})
|
||||
if gregex.IsMatchString(regularFieldNameWithoutDotRegPattern, whereStr) && len(in.Args) == 1 {
|
||||
newArgs = formatWhereKeyValue(formatWhereKeyValueInput{
|
||||
Db: db,
|
||||
Buffer: buffer,
|
||||
Args: newArgs,
|
||||
Key: whereStr,
|
||||
Value: in.Args[0],
|
||||
OmitEmpty: in.OmitEmpty,
|
||||
Prefix: in.Prefix,
|
||||
})
|
||||
in.Args = in.Args[:0]
|
||||
break
|
||||
}
|
||||
// If the first part is column name, it automatically adds prefix to the column.
|
||||
if in.Prefix != "" {
|
||||
array := gstr.Split(whereStr, " ")
|
||||
if ok, _ := db.GetCore().HasField(in.Table, array[0]); ok {
|
||||
whereStr = in.Prefix + "." + whereStr
|
||||
}
|
||||
}
|
||||
// Regular string and parameter place holder handling.
|
||||
// Eg:
|
||||
// Where("id in(?) and name=?", g.Slice{1,2,3}, "john")
|
||||
var (
|
||||
i = 0
|
||||
)
|
||||
for {
|
||||
if i >= len(in.Args) {
|
||||
break
|
||||
@ -557,7 +544,9 @@ func formatWhere(db DB, in formatWhereInput) (newWhere string, newArgs []interfa
|
||||
if buffer.Len() == 0 {
|
||||
return "", in.Args
|
||||
}
|
||||
newArgs = append(newArgs, in.Args...)
|
||||
if len(in.Args) > 0 {
|
||||
newArgs = append(newArgs, in.Args...)
|
||||
}
|
||||
newWhere = buffer.String()
|
||||
if len(newArgs) > 0 {
|
||||
if gstr.Pos(newWhere, "?") == -1 {
|
||||
@ -617,77 +606,104 @@ func formatWhereInterfaces(db DB, where []interface{}, buffer *bytes.Buffer, new
|
||||
return newArgs
|
||||
}
|
||||
|
||||
type formatWhereKeyValueInput struct {
|
||||
Db DB
|
||||
Buffer *bytes.Buffer
|
||||
Args []interface{}
|
||||
Key string
|
||||
Value interface{}
|
||||
OmitEmpty bool
|
||||
Prefix string // Field prefix, eg: "user.", "order.".
|
||||
}
|
||||
|
||||
// formatWhereKeyValue handles each key-value pair of the parameter map.
|
||||
func formatWhereKeyValue(db DB, buffer *bytes.Buffer, newArgs []interface{}, key string, value interface{}) []interface{} {
|
||||
quotedKey := db.GetCore().QuoteWord(key)
|
||||
if buffer.Len() > 0 {
|
||||
buffer.WriteString(" AND ")
|
||||
func formatWhereKeyValue(in formatWhereKeyValueInput) (newArgs []interface{}) {
|
||||
var (
|
||||
quotedKey = in.Db.GetCore().QuoteWord(in.Key)
|
||||
holderCount = gstr.Count(quotedKey, "?")
|
||||
)
|
||||
// Eg:
|
||||
// Where("id", []int{}).All() -> SELECT xxx FROM xxx WHERE 0=1
|
||||
// Where("name", "").All() -> SELECT xxx FROM xxx WHERE `name`=''
|
||||
// OmitEmpty().Where("id", []int{}).All() -> SELECT xxx FROM xxx
|
||||
// OmitEmpty().("name", "").All() -> SELECT xxx FROM xxx
|
||||
if in.OmitEmpty && holderCount == 0 && gutil.IsEmpty(in.Value) {
|
||||
return in.Args
|
||||
}
|
||||
if in.Prefix != "" && !gstr.Contains(quotedKey, ".") {
|
||||
quotedKey = in.Prefix + "." + quotedKey
|
||||
}
|
||||
if in.Buffer.Len() > 0 {
|
||||
in.Buffer.WriteString(" AND ")
|
||||
}
|
||||
// If the value is type of slice, and there's only one '?' holder in
|
||||
// the key string, it automatically adds '?' holder chars according to its arguments count
|
||||
// and converts it to "IN" statement.
|
||||
var (
|
||||
rv = reflect.ValueOf(value)
|
||||
kind = rv.Kind()
|
||||
reflectValue = reflect.ValueOf(in.Value)
|
||||
reflectKind = reflectValue.Kind()
|
||||
)
|
||||
switch kind {
|
||||
switch reflectKind {
|
||||
// Slice argument.
|
||||
case reflect.Slice, reflect.Array:
|
||||
count := gstr.Count(quotedKey, "?")
|
||||
if count == 0 {
|
||||
buffer.WriteString(quotedKey + " IN(?)")
|
||||
newArgs = append(newArgs, value)
|
||||
} else if count != rv.Len() {
|
||||
buffer.WriteString(quotedKey)
|
||||
newArgs = append(newArgs, value)
|
||||
if holderCount == 0 {
|
||||
in.Buffer.WriteString(quotedKey + " IN(?)")
|
||||
in.Args = append(in.Args, in.Value)
|
||||
} else {
|
||||
buffer.WriteString(quotedKey)
|
||||
newArgs = append(newArgs, gconv.Interfaces(value)...)
|
||||
if holderCount != reflectValue.Len() {
|
||||
in.Buffer.WriteString(quotedKey)
|
||||
in.Args = append(in.Args, in.Value)
|
||||
} else {
|
||||
in.Buffer.WriteString(quotedKey)
|
||||
in.Args = append(in.Args, gconv.Interfaces(in.Value)...)
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
if value == nil || empty.IsNil(rv) {
|
||||
if gregex.IsMatchString(regularFieldNameRegPattern, key) {
|
||||
if in.Value == nil || empty.IsNil(reflectValue) {
|
||||
if gregex.IsMatchString(regularFieldNameRegPattern, in.Key) {
|
||||
// The key is a single field name.
|
||||
buffer.WriteString(quotedKey + " IS NULL")
|
||||
in.Buffer.WriteString(quotedKey + " IS NULL")
|
||||
} else {
|
||||
// The key may have operation chars.
|
||||
buffer.WriteString(quotedKey)
|
||||
in.Buffer.WriteString(quotedKey)
|
||||
}
|
||||
} else {
|
||||
// It also supports "LIKE" statement, which we considers it an operator.
|
||||
// It also supports "LIKE" statement, which we consider it an operator.
|
||||
quotedKey = gstr.Trim(quotedKey)
|
||||
if gstr.Pos(quotedKey, "?") == -1 {
|
||||
like := " like"
|
||||
like := " LIKE"
|
||||
if len(quotedKey) > len(like) && gstr.Equal(quotedKey[len(quotedKey)-len(like):], like) {
|
||||
// Eg: Where(g.Map{"name like": "john%"})
|
||||
buffer.WriteString(quotedKey + " ?")
|
||||
in.Buffer.WriteString(quotedKey + " ?")
|
||||
} else if gregex.IsMatchString(lastOperatorRegPattern, quotedKey) {
|
||||
// Eg: Where(g.Map{"age > ": 16})
|
||||
buffer.WriteString(quotedKey + " ?")
|
||||
} else if gregex.IsMatchString(regularFieldNameRegPattern, key) {
|
||||
in.Buffer.WriteString(quotedKey + " ?")
|
||||
} else if gregex.IsMatchString(regularFieldNameRegPattern, in.Key) {
|
||||
// The key is a regular field name.
|
||||
buffer.WriteString(quotedKey + "=?")
|
||||
in.Buffer.WriteString(quotedKey + "=?")
|
||||
} else {
|
||||
// The key is not a regular field name.
|
||||
// Eg: Where(g.Map{"age > 16": nil})
|
||||
// Issue: https://github.com/gogf/gf/issues/765
|
||||
if empty.IsEmpty(value) {
|
||||
buffer.WriteString(quotedKey)
|
||||
if empty.IsEmpty(in.Value) {
|
||||
in.Buffer.WriteString(quotedKey)
|
||||
break
|
||||
} else {
|
||||
buffer.WriteString(quotedKey + "=?")
|
||||
in.Buffer.WriteString(quotedKey + "=?")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
buffer.WriteString(quotedKey)
|
||||
in.Buffer.WriteString(quotedKey)
|
||||
}
|
||||
if s, ok := value.(Raw); ok {
|
||||
buffer.WriteString(gconv.String(s))
|
||||
if s, ok := in.Value.(Raw); ok {
|
||||
in.Buffer.WriteString(gconv.String(s))
|
||||
} else {
|
||||
newArgs = append(newArgs, value)
|
||||
in.Args = append(in.Args, in.Value)
|
||||
}
|
||||
}
|
||||
}
|
||||
return newArgs
|
||||
return in.Args
|
||||
}
|
||||
|
||||
// handleArguments is an important function, which handles the sql and all its arguments
|
||||
@ -699,15 +715,8 @@ func handleArguments(sql string, args []interface{}) (newSql string, newArgs []i
|
||||
// Handles the slice arguments.
|
||||
if len(args) > 0 {
|
||||
for index, arg := range args {
|
||||
var (
|
||||
reflectValue = reflect.ValueOf(arg)
|
||||
reflectKind = reflectValue.Kind()
|
||||
)
|
||||
for reflectKind == reflect.Ptr {
|
||||
reflectValue = reflectValue.Elem()
|
||||
reflectKind = reflectValue.Kind()
|
||||
}
|
||||
switch reflectKind {
|
||||
reflectInfo := utils.OriginValueAndKind(arg)
|
||||
switch reflectInfo.OriginKind {
|
||||
case reflect.Slice, reflect.Array:
|
||||
// It does not split the type of []byte.
|
||||
// Eg: table.Where("name = ?", []byte("john"))
|
||||
@ -716,7 +725,7 @@ func handleArguments(sql string, args []interface{}) (newSql string, newArgs []i
|
||||
continue
|
||||
}
|
||||
|
||||
if reflectValue.Len() == 0 {
|
||||
if reflectInfo.OriginValue.Len() == 0 {
|
||||
// Empty slice argument, it converts the sql to a false sql.
|
||||
// Eg:
|
||||
// Query("select * from xxx where id in(?)", g.Slice{}) -> select * from xxx where 0=1
|
||||
@ -730,15 +739,15 @@ func handleArguments(sql string, args []interface{}) (newSql string, newArgs []i
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for i := 0; i < reflectValue.Len(); i++ {
|
||||
newArgs = append(newArgs, reflectValue.Index(i).Interface())
|
||||
for i := 0; i < reflectInfo.OriginValue.Len(); i++ {
|
||||
newArgs = append(newArgs, reflectInfo.OriginValue.Index(i).Interface())
|
||||
}
|
||||
}
|
||||
|
||||
// If the '?' holder count equals the length of the slice,
|
||||
// it does not implement the arguments splitting logic.
|
||||
// Eg: db.Query("SELECT ?+?", g.Slice{1, 2})
|
||||
if len(args) == 1 && gstr.Count(newSql, "?") == reflectValue.Len() {
|
||||
if len(args) == 1 && gstr.Count(newSql, "?") == reflectInfo.OriginValue.Len() {
|
||||
break
|
||||
}
|
||||
// counter is used to finding the inserting position for the '?' holder.
|
||||
@ -753,8 +762,8 @@ func handleArguments(sql string, args []interface{}) (newSql string, newArgs []i
|
||||
counter++
|
||||
if counter == index+insertHolderCount+1 {
|
||||
replaced = true
|
||||
insertHolderCount += reflectValue.Len() - 1
|
||||
return "?" + strings.Repeat(",?", reflectValue.Len()-1)
|
||||
insertHolderCount += reflectInfo.OriginValue.Len() - 1
|
||||
return "?" + strings.Repeat(",?", reflectInfo.OriginValue.Len()-1)
|
||||
}
|
||||
return s
|
||||
})
|
||||
@ -820,18 +829,18 @@ func FormatSqlWithArgs(sql string, args []interface{}) string {
|
||||
if args[index] == nil {
|
||||
return "null"
|
||||
}
|
||||
var (
|
||||
rv = reflect.ValueOf(args[index])
|
||||
kind = rv.Kind()
|
||||
)
|
||||
if kind == reflect.Ptr {
|
||||
if rv.IsNil() || !rv.IsValid() {
|
||||
return "null"
|
||||
}
|
||||
rv = rv.Elem()
|
||||
kind = rv.Kind()
|
||||
// Parameters of type Raw do not require special treatment
|
||||
if v, ok := args[index].(Raw); ok {
|
||||
return gconv.String(v)
|
||||
}
|
||||
switch kind {
|
||||
var (
|
||||
reflectInfo = utils.OriginValueAndKind(args[index])
|
||||
)
|
||||
if reflectInfo.OriginKind == reflect.Ptr &&
|
||||
(reflectInfo.OriginValue.IsNil() || !reflectInfo.OriginValue.IsValid()) {
|
||||
return "null"
|
||||
}
|
||||
switch reflectInfo.OriginKind {
|
||||
case reflect.String, reflect.Map, reflect.Slice, reflect.Array:
|
||||
return `'` + gstr.QuoteMeta(gconv.String(args[index]), `'`) + `'`
|
||||
|
||||
|
||||
@ -9,10 +9,8 @@ package gdb
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/v2/text/gregex"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
)
|
||||
@ -45,8 +43,7 @@ type Model struct {
|
||||
distinct string // Force the query to only return distinct results.
|
||||
lockInfo string // Lock for update or in shared lock.
|
||||
cacheEnabled bool // Enable sql result cache feature.
|
||||
cacheDuration time.Duration // Cache TTL duration (< 1 for removing cache, >= 0 for saving cache).
|
||||
cacheName string // Cache name for custom operation.
|
||||
cacheOption CacheOption // Cache option for query statement.
|
||||
unscoped bool // Disables soft deleting features when select/delete operations.
|
||||
safe bool // If true, it clones and returns a new model object whenever operation done; or else it changes the attribute of current model.
|
||||
onDuplicate interface{} // onDuplicate is used for ON "DUPLICATE KEY UPDATE" statement.
|
||||
@ -65,6 +62,7 @@ type ModelWhereHolder struct {
|
||||
Operator int // Operator for this holder.
|
||||
Where interface{} // Where parameter, which can commonly be type of string/map/struct.
|
||||
Args []interface{} // Arguments for where parameter.
|
||||
Prefix string // Field prefix, eg: "user.", "order.".
|
||||
}
|
||||
|
||||
const (
|
||||
|
||||
@ -11,26 +11,32 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type CacheOption struct {
|
||||
// Duration is the TTL for the cache.
|
||||
// If the parameter `Duration` < 0, which means it clear the cache with given `Name`.
|
||||
// If the parameter `Duration` = 0, which means it never expires.
|
||||
// If the parameter `Duration` > 0, which means it expires after `Duration`.
|
||||
Duration time.Duration
|
||||
|
||||
// Name is an optional unique name for the cache.
|
||||
// The Name is used to bind a name to the cache, which means you can later control the cache
|
||||
// like changing the `duration` or clearing the cache with specified Name.
|
||||
Name string
|
||||
|
||||
// Force caches the query result whatever the result is nil or not.
|
||||
// It is used to avoid Cache Penetration.
|
||||
Force bool
|
||||
}
|
||||
|
||||
// Cache sets the cache feature for the model. It caches the result of the sql, which means
|
||||
// if there's another same sql request, it just reads and returns the result from cache, it
|
||||
// but not committed and executed into the database.
|
||||
//
|
||||
// If the parameter `duration` < 0, which means it clear the cache with given `name`.
|
||||
// If the parameter `duration` = 0, which means it never expires.
|
||||
// If the parameter `duration` > 0, which means it expires after `duration`.
|
||||
//
|
||||
// The optional parameter `name` is used to bind a name to the cache, which means you can
|
||||
// later control the cache like changing the `duration` or clearing the cache with specified
|
||||
// `name`.
|
||||
//
|
||||
// Note that, the cache feature is disabled if the model is performing select statement
|
||||
// on a transaction.
|
||||
func (m *Model) Cache(duration time.Duration, name ...string) *Model {
|
||||
func (m *Model) Cache(option CacheOption) *Model {
|
||||
model := m.getModel()
|
||||
model.cacheDuration = duration
|
||||
if len(name) > 0 {
|
||||
model.cacheName = name[0]
|
||||
}
|
||||
model.cacheOption = option
|
||||
model.cacheEnabled = true
|
||||
return model
|
||||
}
|
||||
@ -38,9 +44,9 @@ func (m *Model) Cache(duration time.Duration, name ...string) *Model {
|
||||
// checkAndRemoveCache checks and removes the cache in insert/update/delete statement if
|
||||
// cache feature is enabled.
|
||||
func (m *Model) checkAndRemoveCache() {
|
||||
if m.cacheEnabled && m.cacheDuration < 0 && len(m.cacheName) > 0 {
|
||||
if m.cacheEnabled && m.cacheOption.Duration < 0 && len(m.cacheOption.Name) > 0 {
|
||||
var ctx = m.GetCtx()
|
||||
_, err := m.db.GetCache().Remove(ctx, m.cacheName)
|
||||
_, err := m.db.GetCache().Remove(ctx, m.cacheOption.Name)
|
||||
if err != nil {
|
||||
intlog.Error(ctx, err)
|
||||
}
|
||||
|
||||
@ -10,7 +10,6 @@ import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Where sets the condition statement for the model. The parameter `where` can be type of
|
||||
@ -37,6 +36,21 @@ func (m *Model) Where(where interface{}, args ...interface{}) *Model {
|
||||
return model
|
||||
}
|
||||
|
||||
// WherePrefix performs as Where, but it adds prefix to each field in where statement.
|
||||
func (m *Model) WherePrefix(prefix string, where interface{}, args ...interface{}) *Model {
|
||||
model := m.getModel()
|
||||
if model.whereHolder == nil {
|
||||
model.whereHolder = make([]ModelWhereHolder, 0)
|
||||
}
|
||||
model.whereHolder = append(model.whereHolder, ModelWhereHolder{
|
||||
Operator: whereHolderOperatorWhere,
|
||||
Where: where,
|
||||
Args: args,
|
||||
Prefix: prefix,
|
||||
})
|
||||
return model
|
||||
}
|
||||
|
||||
// Having sets the having statement for the model.
|
||||
// The parameters of this function usage are as the same as function Where.
|
||||
// See Where.
|
||||
@ -159,6 +173,21 @@ func (m *Model) WhereOr(where interface{}, args ...interface{}) *Model {
|
||||
return model
|
||||
}
|
||||
|
||||
// WhereOrPrefix performs as WhereOr, but it adds prefix to each field in where statement.
|
||||
func (m *Model) WhereOrPrefix(prefix string, where interface{}, args ...interface{}) *Model {
|
||||
model := m.getModel()
|
||||
if model.whereHolder == nil {
|
||||
model.whereHolder = make([]ModelWhereHolder, 0)
|
||||
}
|
||||
model.whereHolder = append(model.whereHolder, ModelWhereHolder{
|
||||
Operator: whereHolderOperatorOr,
|
||||
Where: where,
|
||||
Args: args,
|
||||
Prefix: prefix,
|
||||
})
|
||||
return model
|
||||
}
|
||||
|
||||
// WhereOrf builds `OR` condition string using fmt.Sprintf and arguments.
|
||||
func (m *Model) WhereOrf(format string, args ...interface{}) *Model {
|
||||
var (
|
||||
@ -236,55 +265,6 @@ func (m *Model) WhereOrNotNull(columns ...string) *Model {
|
||||
return model
|
||||
}
|
||||
|
||||
// Group sets the "GROUP BY" statement for the model.
|
||||
func (m *Model) Group(groupBy ...string) *Model {
|
||||
if len(groupBy) == 0 {
|
||||
return m
|
||||
}
|
||||
model := m.getModel()
|
||||
if model.groupBy != "" {
|
||||
model.groupBy += ","
|
||||
}
|
||||
model.groupBy = model.db.GetCore().QuoteString(strings.Join(groupBy, ","))
|
||||
return model
|
||||
}
|
||||
|
||||
// Order sets the "ORDER BY" statement for the model.
|
||||
func (m *Model) Order(orderBy ...string) *Model {
|
||||
if len(orderBy) == 0 {
|
||||
return m
|
||||
}
|
||||
model := m.getModel()
|
||||
if model.orderBy != "" {
|
||||
model.orderBy += ","
|
||||
}
|
||||
model.orderBy = model.db.GetCore().QuoteString(strings.Join(orderBy, " "))
|
||||
return model
|
||||
}
|
||||
|
||||
// OrderAsc sets the "ORDER BY xxx ASC" statement for the model.
|
||||
func (m *Model) OrderAsc(column string) *Model {
|
||||
if len(column) == 0 {
|
||||
return m
|
||||
}
|
||||
return m.Order(column + " ASC")
|
||||
}
|
||||
|
||||
// OrderDesc sets the "ORDER BY xxx DESC" statement for the model.
|
||||
func (m *Model) OrderDesc(column string) *Model {
|
||||
if len(column) == 0 {
|
||||
return m
|
||||
}
|
||||
return m.Order(column + " DESC")
|
||||
}
|
||||
|
||||
// OrderRandom sets the "ORDER BY RANDOM()" statement for the model.
|
||||
func (m *Model) OrderRandom() *Model {
|
||||
model := m.getModel()
|
||||
model.orderBy = "RAND()"
|
||||
return model
|
||||
}
|
||||
|
||||
// Limit sets the "LIMIT" statement for the model.
|
||||
// The parameter `limit` can be either one or two number, if passed two number is passed,
|
||||
// it then sets "LIMIT limit[0],limit[1]" statement for the model, or else it sets "LIMIT limit[0]"
|
||||
@ -334,8 +314,17 @@ func (m *Model) Page(page, limit int) *Model {
|
||||
//
|
||||
// The parameter `limit1` specifies whether limits querying only one record if m.limit is not set.
|
||||
func (m *Model) formatCondition(limit1 bool, isCountStatement bool) (conditionWhere string, conditionExtra string, conditionArgs []interface{}) {
|
||||
var (
|
||||
autoPrefix = ""
|
||||
)
|
||||
if gstr.Contains(m.tables, " JOIN ") {
|
||||
autoPrefix = m.db.GetCore().QuoteWord(m.tablesInit)
|
||||
}
|
||||
if len(m.whereHolder) > 0 {
|
||||
for _, v := range m.whereHolder {
|
||||
if v.Prefix == "" {
|
||||
v.Prefix = autoPrefix
|
||||
}
|
||||
switch v.Operator {
|
||||
case whereHolderOperatorWhere:
|
||||
if conditionWhere == "" {
|
||||
@ -346,6 +335,7 @@ func (m *Model) formatCondition(limit1 bool, isCountStatement bool) (conditionWh
|
||||
OmitEmpty: m.option&optionOmitEmptyWhere > 0,
|
||||
Schema: m.schema,
|
||||
Table: m.tables,
|
||||
Prefix: v.Prefix,
|
||||
})
|
||||
if len(newWhere) > 0 {
|
||||
conditionWhere = newWhere
|
||||
@ -363,6 +353,7 @@ func (m *Model) formatCondition(limit1 bool, isCountStatement bool) (conditionWh
|
||||
OmitEmpty: m.option&optionOmitEmptyWhere > 0,
|
||||
Schema: m.schema,
|
||||
Table: m.tables,
|
||||
Prefix: v.Prefix,
|
||||
})
|
||||
if len(newWhere) > 0 {
|
||||
if len(conditionWhere) == 0 {
|
||||
@ -383,6 +374,7 @@ func (m *Model) formatCondition(limit1 bool, isCountStatement bool) (conditionWh
|
||||
OmitEmpty: m.option&optionOmitEmptyWhere > 0,
|
||||
Schema: m.schema,
|
||||
Table: m.tables,
|
||||
Prefix: v.Prefix,
|
||||
})
|
||||
if len(newWhere) > 0 {
|
||||
if len(conditionWhere) == 0 {
|
||||
@ -430,6 +422,7 @@ func (m *Model) formatCondition(limit1 bool, isCountStatement bool) (conditionWh
|
||||
OmitEmpty: m.option&optionOmitEmptyWhere > 0,
|
||||
Schema: m.schema,
|
||||
Table: m.tables,
|
||||
Prefix: autoPrefix,
|
||||
})
|
||||
if len(havingStr) > 0 {
|
||||
conditionExtra += " HAVING " + havingStr
|
||||
|
||||
@ -9,14 +9,18 @@ package gdb
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/v2/container/gset"
|
||||
"github.com/gogf/gf/v2/errors/gcode"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
// Fields appends `fieldNamesOrMapStruct` to the operation fields of the model, multiple fields joined using char ','.
|
||||
// The parameter `fieldNamesOrMapStruct` can be type of string/map/*map/struct/*struct.
|
||||
//
|
||||
// Eg:
|
||||
// Fields("id", "name", "age")
|
||||
// Fields([]string{"id", "name", "age"})
|
||||
// Fields(map[string]interface{}{"id":1, "name":"john", "age":18})
|
||||
// Fields(User{ Id: 1, Name: "john", Age: 18})
|
||||
func (m *Model) Fields(fieldNamesOrMapStruct ...interface{}) *Model {
|
||||
length := len(fieldNamesOrMapStruct)
|
||||
if length == 0 {
|
||||
@ -52,10 +56,21 @@ func (m *Model) Fields(fieldNamesOrMapStruct ...interface{}) *Model {
|
||||
return m
|
||||
}
|
||||
|
||||
// FieldsPrefix performs as function Fields but add extra prefix for each field.
|
||||
func (m *Model) FieldsPrefix(prefix string, fieldNamesOrMapStruct ...interface{}) *Model {
|
||||
model := m.Fields(fieldNamesOrMapStruct...)
|
||||
array := gstr.SplitAndTrim(model.fields, ",")
|
||||
gstr.PrefixArray(array, prefix+".")
|
||||
model.fields = gstr.Join(array, ",")
|
||||
return model
|
||||
}
|
||||
|
||||
// FieldsEx appends `fieldNamesOrMapStruct` to the excluded operation fields of the model,
|
||||
// multiple fields joined using char ','.
|
||||
// Note that this function supports only single table operations.
|
||||
// The parameter `fieldNamesOrMapStruct` can be type of string/map/*map/struct/*struct.
|
||||
//
|
||||
// Also see Fields.
|
||||
func (m *Model) FieldsEx(fieldNamesOrMapStruct ...interface{}) *Model {
|
||||
length := len(fieldNamesOrMapStruct)
|
||||
if length == 0 {
|
||||
@ -80,6 +95,15 @@ func (m *Model) FieldsEx(fieldNamesOrMapStruct ...interface{}) *Model {
|
||||
return m
|
||||
}
|
||||
|
||||
// FieldsExPrefix performs as function FieldsEx but add extra prefix for each field.
|
||||
func (m *Model) FieldsExPrefix(prefix string, fieldNamesOrMapStruct ...interface{}) *Model {
|
||||
model := m.FieldsEx(fieldNamesOrMapStruct...)
|
||||
array := gstr.SplitAndTrim(model.fieldsEx, ",")
|
||||
gstr.PrefixArray(array, prefix+".")
|
||||
model.fieldsEx = gstr.Join(array, ",")
|
||||
return model
|
||||
}
|
||||
|
||||
// FieldCount formats and appends commonly used field `COUNT(column)` to the select fields of model.
|
||||
func (m *Model) FieldCount(column string, as ...string) *Model {
|
||||
asStr := ""
|
||||
@ -218,21 +242,5 @@ func (m *Model) GetFieldsExStr(fields string, prefix ...string) string {
|
||||
|
||||
// HasField determine whether the field exists in the table.
|
||||
func (m *Model) HasField(field string) (bool, error) {
|
||||
tableFields, err := m.TableFields(m.tablesInit)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if len(tableFields) == 0 {
|
||||
return false, gerror.NewCodef(gcode.CodeNotFound, `empty table fields for table "%s"`, m.tables)
|
||||
}
|
||||
fieldsArray := make([]string, len(tableFields))
|
||||
for k, v := range tableFields {
|
||||
fieldsArray[v.Index] = k
|
||||
}
|
||||
for _, f := range fieldsArray {
|
||||
if f == field {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
return m.db.GetCore().HasField(m.tablesInit, field)
|
||||
}
|
||||
|
||||
@ -10,6 +10,7 @@ import (
|
||||
"database/sql"
|
||||
"github.com/gogf/gf/v2/container/gset"
|
||||
"github.com/gogf/gf/v2/errors/gcode"
|
||||
"github.com/gogf/gf/v2/internal/utils"
|
||||
"reflect"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
@ -50,37 +51,32 @@ func (m *Model) Data(data ...interface{}) *Model {
|
||||
model.data = m
|
||||
}
|
||||
} else {
|
||||
switch params := data[0].(type) {
|
||||
switch value := data[0].(type) {
|
||||
case Result:
|
||||
model.data = params.List()
|
||||
model.data = value.List()
|
||||
|
||||
case Record:
|
||||
model.data = params.Map()
|
||||
model.data = value.Map()
|
||||
|
||||
case List:
|
||||
list := make(List, len(params))
|
||||
for k, v := range params {
|
||||
list := make(List, len(value))
|
||||
for k, v := range value {
|
||||
list[k] = gutil.MapCopy(v)
|
||||
}
|
||||
model.data = list
|
||||
|
||||
case Map:
|
||||
model.data = gutil.MapCopy(params)
|
||||
model.data = gutil.MapCopy(value)
|
||||
|
||||
default:
|
||||
var (
|
||||
rv = reflect.ValueOf(params)
|
||||
kind = rv.Kind()
|
||||
reflectInfo = utils.OriginValueAndKind(value)
|
||||
)
|
||||
if kind == reflect.Ptr {
|
||||
rv = rv.Elem()
|
||||
kind = rv.Kind()
|
||||
}
|
||||
switch kind {
|
||||
switch reflectInfo.OriginKind {
|
||||
case reflect.Slice, reflect.Array:
|
||||
list := make(List, rv.Len())
|
||||
for i := 0; i < rv.Len(); i++ {
|
||||
list[i] = ConvertDataForTableRecord(rv.Index(i).Interface())
|
||||
list := make(List, reflectInfo.OriginValue.Len())
|
||||
for i := 0; i < reflectInfo.OriginValue.Len(); i++ {
|
||||
list[i] = ConvertDataForTableRecord(reflectInfo.OriginValue.Index(i).Interface())
|
||||
}
|
||||
model.data = list
|
||||
|
||||
@ -88,6 +84,12 @@ func (m *Model) Data(data ...interface{}) *Model {
|
||||
model.data = ConvertDataForTableRecord(data[0])
|
||||
|
||||
case reflect.Struct:
|
||||
// If the `data` parameter is defined like `xxxForDao`,
|
||||
// it then adds `OmitNilData` option for this condition,
|
||||
// which will filter all nil parameters in `data`.
|
||||
if gstr.HasSuffix(reflect.TypeOf(value).String(), modelForDaoSuffix) {
|
||||
model = model.OmitNilData()
|
||||
}
|
||||
if v, ok := data[0].(iInterfaces); ok {
|
||||
var (
|
||||
array = v.Interfaces()
|
||||
@ -246,19 +248,14 @@ func (m *Model) doInsertWithOption(insertOption int) (result sql.Result, err err
|
||||
|
||||
default:
|
||||
var (
|
||||
rv = reflect.ValueOf(newData)
|
||||
kind = rv.Kind()
|
||||
reflectInfo = utils.OriginValueAndKind(newData)
|
||||
)
|
||||
if kind == reflect.Ptr {
|
||||
rv = rv.Elem()
|
||||
kind = rv.Kind()
|
||||
}
|
||||
switch kind {
|
||||
switch reflectInfo.OriginKind {
|
||||
// If it's slice type, it then converts it to List type.
|
||||
case reflect.Slice, reflect.Array:
|
||||
list = make(List, rv.Len())
|
||||
for i := 0; i < rv.Len(); i++ {
|
||||
list[i] = ConvertDataForTableRecord(rv.Index(i).Interface())
|
||||
list = make(List, reflectInfo.OriginValue.Len())
|
||||
for i := 0; i < reflectInfo.OriginValue.Len(); i++ {
|
||||
list[i] = ConvertDataForTableRecord(reflectInfo.OriginValue.Index(i).Interface())
|
||||
}
|
||||
|
||||
case reflect.Map:
|
||||
@ -278,7 +275,11 @@ func (m *Model) doInsertWithOption(insertOption int) (result sql.Result, err err
|
||||
}
|
||||
|
||||
default:
|
||||
return result, gerror.NewCodef(gcode.CodeInvalidParameter, "unsupported list type:%v", kind)
|
||||
return result, gerror.NewCodef(
|
||||
gcode.CodeInvalidParameter,
|
||||
"unsupported data list type: %v",
|
||||
reflectInfo.InputValue.Type(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -331,17 +332,12 @@ func (m *Model) formatDoInsertOption(insertOption int, columnNames []string) (op
|
||||
|
||||
default:
|
||||
var (
|
||||
reflectValue = reflect.ValueOf(m.onDuplicate)
|
||||
reflectKind = reflectValue.Kind()
|
||||
reflectInfo = utils.OriginValueAndKind(m.onDuplicate)
|
||||
)
|
||||
for reflectKind == reflect.Ptr {
|
||||
reflectValue = reflectValue.Elem()
|
||||
reflectKind = reflectValue.Kind()
|
||||
}
|
||||
switch reflectKind {
|
||||
switch reflectInfo.OriginKind {
|
||||
case reflect.String:
|
||||
option.OnDuplicateMap = make(map[string]interface{})
|
||||
for _, v := range gstr.SplitAndTrim(reflectValue.String(), ",") {
|
||||
for _, v := range gstr.SplitAndTrim(reflectInfo.OriginValue.String(), ",") {
|
||||
if onDuplicateExKeySet.Contains(v) {
|
||||
continue
|
||||
}
|
||||
@ -393,16 +389,11 @@ func (m *Model) formatOnDuplicateExKeys(onDuplicateEx interface{}) ([]string, er
|
||||
}
|
||||
|
||||
var (
|
||||
reflectValue = reflect.ValueOf(onDuplicateEx)
|
||||
reflectKind = reflectValue.Kind()
|
||||
reflectInfo = utils.OriginValueAndKind(onDuplicateEx)
|
||||
)
|
||||
for reflectKind == reflect.Ptr {
|
||||
reflectValue = reflectValue.Elem()
|
||||
reflectKind = reflectValue.Kind()
|
||||
}
|
||||
switch reflectKind {
|
||||
switch reflectInfo.OriginKind {
|
||||
case reflect.String:
|
||||
return gstr.SplitAndTrim(reflectValue.String(), ","), nil
|
||||
return gstr.SplitAndTrim(reflectInfo.OriginValue.String(), ","), nil
|
||||
|
||||
case reflect.Map:
|
||||
return gutil.Keys(onDuplicateEx), nil
|
||||
|
||||
@ -25,40 +25,93 @@ func isSubQuery(s string) bool {
|
||||
|
||||
// LeftJoin does "LEFT JOIN ... ON ..." statement on the model.
|
||||
// The parameter `table` can be joined table and its joined condition,
|
||||
// and also with its alias name, like:
|
||||
// Table("user").LeftJoin("user_detail", "user_detail.uid=user.uid")
|
||||
// Table("user", "u").LeftJoin("user_detail", "ud", "ud.uid=u.uid")
|
||||
// Table("user", "u").LeftJoin("SELECT xxx FROM xxx AS a", "a.uid=u.uid")
|
||||
// and also with its alias name.
|
||||
//
|
||||
// Eg:
|
||||
// Model("user").LeftJoin("user_detail", "user_detail.uid=user.uid")
|
||||
// Model("user", "u").LeftJoin("user_detail", "ud", "ud.uid=u.uid")
|
||||
// Model("user", "u").LeftJoin("SELECT xxx FROM xxx AS a", "a.uid=u.uid")
|
||||
func (m *Model) LeftJoin(table ...string) *Model {
|
||||
return m.doJoin("LEFT", table...)
|
||||
}
|
||||
|
||||
// RightJoin does "RIGHT JOIN ... ON ..." statement on the model.
|
||||
// The parameter `table` can be joined table and its joined condition,
|
||||
// and also with its alias name, like:
|
||||
// Table("user").RightJoin("user_detail", "user_detail.uid=user.uid")
|
||||
// Table("user", "u").RightJoin("user_detail", "ud", "ud.uid=u.uid")
|
||||
// Table("user", "u").RightJoin("SELECT xxx FROM xxx AS a", "a.uid=u.uid")
|
||||
// and also with its alias name.
|
||||
//
|
||||
// Eg:
|
||||
// Model("user").RightJoin("user_detail", "user_detail.uid=user.uid")
|
||||
// Model("user", "u").RightJoin("user_detail", "ud", "ud.uid=u.uid")
|
||||
// Model("user", "u").RightJoin("SELECT xxx FROM xxx AS a", "a.uid=u.uid")
|
||||
func (m *Model) RightJoin(table ...string) *Model {
|
||||
return m.doJoin("RIGHT", table...)
|
||||
}
|
||||
|
||||
// InnerJoin does "INNER JOIN ... ON ..." statement on the model.
|
||||
// The parameter `table` can be joined table and its joined condition,
|
||||
// and also with its alias name, like:
|
||||
// Table("user").InnerJoin("user_detail", "user_detail.uid=user.uid")
|
||||
// Table("user", "u").InnerJoin("user_detail", "ud", "ud.uid=u.uid")
|
||||
// Table("user", "u").InnerJoin("SELECT xxx FROM xxx AS a", "a.uid=u.uid")
|
||||
// and also with its alias name。
|
||||
//
|
||||
// Eg:
|
||||
// Model("user").InnerJoin("user_detail", "user_detail.uid=user.uid")
|
||||
// Model("user", "u").InnerJoin("user_detail", "ud", "ud.uid=u.uid")
|
||||
// Model("user", "u").InnerJoin("SELECT xxx FROM xxx AS a", "a.uid=u.uid")
|
||||
func (m *Model) InnerJoin(table ...string) *Model {
|
||||
return m.doJoin("INNER", table...)
|
||||
}
|
||||
|
||||
// LeftJoinOnField performs as LeftJoin, but it joins both tables with the same field name.
|
||||
//
|
||||
// Eg:
|
||||
// Model("order").LeftJoinOnField("user", "user_id")
|
||||
// Model("order").LeftJoinOnField("product", "product_id")
|
||||
func (m *Model) LeftJoinOnField(table, field string) *Model {
|
||||
return m.doJoin("LEFT", table, fmt.Sprintf(
|
||||
`%s.%s=%s.%s`,
|
||||
m.tables,
|
||||
m.db.GetCore().QuoteWord(field),
|
||||
m.db.GetCore().QuoteWord(table),
|
||||
m.db.GetCore().QuoteWord(field),
|
||||
))
|
||||
}
|
||||
|
||||
// RightJoinOnField performs as RightJoin, but it joins both tables with the same field name.
|
||||
//
|
||||
// Eg:
|
||||
// Model("order").InnerJoinOnField("user", "user_id")
|
||||
// Model("order").InnerJoinOnField("product", "product_id")
|
||||
func (m *Model) RightJoinOnField(table, field string) *Model {
|
||||
return m.doJoin("RIGHT", table, fmt.Sprintf(
|
||||
`%s.%s=%s.%s`,
|
||||
m.tables,
|
||||
m.db.GetCore().QuoteWord(field),
|
||||
m.db.GetCore().QuoteWord(table),
|
||||
m.db.GetCore().QuoteWord(field),
|
||||
))
|
||||
}
|
||||
|
||||
// InnerJoinOnField performs as InnerJoin, but it joins both tables with the same field name.
|
||||
//
|
||||
// Eg:
|
||||
// Model("order").InnerJoinOnField("user", "user_id")
|
||||
// Model("order").InnerJoinOnField("product", "product_id")
|
||||
func (m *Model) InnerJoinOnField(table, field string) *Model {
|
||||
return m.doJoin("INNER", table, fmt.Sprintf(
|
||||
`%s.%s=%s.%s`,
|
||||
m.tables,
|
||||
m.db.GetCore().QuoteWord(field),
|
||||
m.db.GetCore().QuoteWord(table),
|
||||
m.db.GetCore().QuoteWord(field),
|
||||
))
|
||||
}
|
||||
|
||||
// doJoin does "LEFT/RIGHT/INNER JOIN ... ON ..." statement on the model.
|
||||
// The parameter `table` can be joined table and its joined condition,
|
||||
// and also with its alias name, like:
|
||||
// Model("user").InnerJoin("user_detail", "user_detail.uid=user.uid")
|
||||
// Model("user", "u").InnerJoin("user_detail", "ud", "ud.uid=u.uid")
|
||||
// Model("user", "u").InnerJoin("SELECT xxx FROM xxx AS a", "a.uid=u.uid")
|
||||
// and also with its alias name.
|
||||
//
|
||||
// Eg:
|
||||
// Model("user").InnerJoin("user_detail", "user_detail.uid=user.uid")
|
||||
// Model("user", "u").InnerJoin("user_detail", "ud", "ud.uid=u.uid")
|
||||
// Model("user", "u").InnerJoin("SELECT xxx FROM xxx AS a", "a.uid=u.uid")
|
||||
// Related issues:
|
||||
// https://github.com/gogf/gf/issues/1024
|
||||
func (m *Model) doJoin(operator string, table ...string) *Model {
|
||||
|
||||
@ -25,6 +25,12 @@ func (m *Model) OmitEmpty() *Model {
|
||||
|
||||
// OmitEmptyWhere sets optionOmitEmptyWhere option for the model, which automatically filers
|
||||
// the Where/Having parameters for `empty` values.
|
||||
//
|
||||
// Eg:
|
||||
// Where("id", []int{}).All() -> SELECT xxx FROM xxx WHERE 0=1
|
||||
// Where("name", "").All() -> SELECT xxx FROM xxx WHERE `name`=''
|
||||
// OmitEmpty().Where("id", []int{}).All() -> SELECT xxx FROM xxx
|
||||
// OmitEmpty().("name", "").All() -> SELECT xxx FROM xxx
|
||||
func (m *Model) OmitEmptyWhere() *Model {
|
||||
model := m.getModel()
|
||||
model.option = model.option | optionOmitEmptyWhere
|
||||
|
||||
63
database/gdb/gdb_model_order_group.go
Normal file
63
database/gdb/gdb_model_order_group.go
Normal file
@ -0,0 +1,63 @@
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package gdb
|
||||
|
||||
import "strings"
|
||||
|
||||
// Order sets the "ORDER BY" statement for the model.
|
||||
//
|
||||
// Eg:
|
||||
// Order("id desc")
|
||||
// Order("id", "desc")
|
||||
// Order("id desc,name asc")
|
||||
func (m *Model) Order(orderBy ...string) *Model {
|
||||
if len(orderBy) == 0 {
|
||||
return m
|
||||
}
|
||||
model := m.getModel()
|
||||
if model.orderBy != "" {
|
||||
model.orderBy += ","
|
||||
}
|
||||
model.orderBy = model.db.GetCore().QuoteString(strings.Join(orderBy, " "))
|
||||
return model
|
||||
}
|
||||
|
||||
// OrderAsc sets the "ORDER BY xxx ASC" statement for the model.
|
||||
func (m *Model) OrderAsc(column string) *Model {
|
||||
if len(column) == 0 {
|
||||
return m
|
||||
}
|
||||
return m.Order(column + " ASC")
|
||||
}
|
||||
|
||||
// OrderDesc sets the "ORDER BY xxx DESC" statement for the model.
|
||||
func (m *Model) OrderDesc(column string) *Model {
|
||||
if len(column) == 0 {
|
||||
return m
|
||||
}
|
||||
return m.Order(column + " DESC")
|
||||
}
|
||||
|
||||
// OrderRandom sets the "ORDER BY RANDOM()" statement for the model.
|
||||
func (m *Model) OrderRandom() *Model {
|
||||
model := m.getModel()
|
||||
model.orderBy = "RAND()"
|
||||
return model
|
||||
}
|
||||
|
||||
// Group sets the "GROUP BY" statement for the model.
|
||||
func (m *Model) Group(groupBy ...string) *Model {
|
||||
if len(groupBy) == 0 {
|
||||
return m
|
||||
}
|
||||
model := m.getModel()
|
||||
if model.groupBy != "" {
|
||||
model.groupBy += ","
|
||||
}
|
||||
model.groupBy = model.db.GetCore().QuoteString(strings.Join(groupBy, ","))
|
||||
return model
|
||||
}
|
||||
@ -10,6 +10,7 @@ import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/v2/errors/gcode"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/internal/utils"
|
||||
"reflect"
|
||||
|
||||
"github.com/gogf/gf/v2/container/gset"
|
||||
@ -293,24 +294,15 @@ func (m *Model) doStructs(pointer interface{}, where ...interface{}) error {
|
||||
// err := db.Model("user").Scan(&users)
|
||||
func (m *Model) Scan(pointer interface{}, where ...interface{}) error {
|
||||
var (
|
||||
reflectValue reflect.Value
|
||||
reflectKind reflect.Kind
|
||||
reflectInfo = utils.OriginTypeAndKind(pointer)
|
||||
)
|
||||
if v, ok := pointer.(reflect.Value); ok {
|
||||
reflectValue = v
|
||||
} else {
|
||||
reflectValue = reflect.ValueOf(pointer)
|
||||
if reflectInfo.InputKind != reflect.Ptr {
|
||||
return gerror.NewCode(
|
||||
gcode.CodeInvalidParameter,
|
||||
`the parameter "pointer" for function Scan should type of pointer`,
|
||||
)
|
||||
}
|
||||
|
||||
reflectKind = reflectValue.Kind()
|
||||
if reflectKind != reflect.Ptr {
|
||||
return gerror.NewCode(gcode.CodeInvalidParameter, `the parameter "pointer" for function Scan should type of pointer`)
|
||||
}
|
||||
for reflectKind == reflect.Ptr {
|
||||
reflectValue = reflectValue.Elem()
|
||||
reflectKind = reflectValue.Kind()
|
||||
}
|
||||
switch reflectKind {
|
||||
switch reflectInfo.OriginKind {
|
||||
case reflect.Slice, reflect.Array:
|
||||
return m.doStructs(pointer, where...)
|
||||
|
||||
@ -327,32 +319,25 @@ func (m *Model) Scan(pointer interface{}, where ...interface{}) error {
|
||||
|
||||
// ScanList converts `r` to struct slice which contains other complex struct attributes.
|
||||
// Note that the parameter `listPointer` should be type of *[]struct/*[]*struct.
|
||||
// Usage example:
|
||||
//
|
||||
// type Entity struct {
|
||||
// User *EntityUser
|
||||
// UserDetail *EntityUserDetail
|
||||
// UserScores []*EntityUserScores
|
||||
// }
|
||||
// var users []*Entity
|
||||
// or
|
||||
// var users []Entity
|
||||
//
|
||||
// ScanList(&users, "User")
|
||||
// ScanList(&users, "UserDetail", "User", "uid:Uid")
|
||||
// ScanList(&users, "UserScores", "User", "uid:Uid")
|
||||
// The parameters "User"/"UserDetail"/"UserScores" in the example codes specify the target attribute struct
|
||||
// that current result will be bound to.
|
||||
// The "uid" in the example codes is the table field name of the result, and the "Uid" is the relational
|
||||
// struct attribute name. It automatically calculates the HasOne/HasMany relationship with given `relation`
|
||||
// parameter.
|
||||
// See the example or unit testing cases for clear understanding for this function.
|
||||
func (m *Model) ScanList(listPointer interface{}, attributeName string, relation ...string) (err error) {
|
||||
// See Result.ScanList.
|
||||
func (m *Model) ScanList(structSlicePointer interface{}, bindToAttrName string, relationAttrNameAndFields ...string) (err error) {
|
||||
result, err := m.All()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return doScanList(m, result, listPointer, attributeName, relation...)
|
||||
var (
|
||||
relationAttrName string
|
||||
relationFields string
|
||||
)
|
||||
switch len(relationAttrNameAndFields) {
|
||||
case 2:
|
||||
relationAttrName = relationAttrNameAndFields[0]
|
||||
relationFields = relationAttrNameAndFields[1]
|
||||
case 1:
|
||||
relationFields = relationAttrNameAndFields[0]
|
||||
}
|
||||
return doScanList(m, result, structSlicePointer, bindToAttrName, relationAttrName, relationFields)
|
||||
}
|
||||
|
||||
// Count does "SELECT COUNT(x) FROM ..." statement for the model.
|
||||
@ -452,7 +437,7 @@ func (m *Model) doGetAllBySql(sql string, args ...interface{}) (result Result, e
|
||||
)
|
||||
// Retrieve from cache.
|
||||
if m.cacheEnabled && m.tx == nil {
|
||||
cacheKey = m.cacheName
|
||||
cacheKey = m.cacheOption.Name
|
||||
if len(cacheKey) == 0 {
|
||||
cacheKey = sql + ", @PARAMS:" + gconv.String(args)
|
||||
}
|
||||
@ -476,16 +461,16 @@ func (m *Model) doGetAllBySql(sql string, args ...interface{}) (result Result, e
|
||||
)
|
||||
// Cache the result.
|
||||
if cacheKey != "" && err == nil {
|
||||
if m.cacheDuration < 0 {
|
||||
if m.cacheOption.Duration < 0 {
|
||||
if _, err := cacheObj.Remove(ctx, cacheKey); err != nil {
|
||||
intlog.Error(m.GetCtx(), err)
|
||||
}
|
||||
} else {
|
||||
// In case of Cache Penetration.
|
||||
if result == nil {
|
||||
if result.IsEmpty() && m.cacheOption.Force {
|
||||
result = Result{}
|
||||
}
|
||||
if err := cacheObj.Set(ctx, cacheKey, result, m.cacheDuration); err != nil {
|
||||
if err := cacheObj.Set(ctx, cacheKey, result, m.cacheOption.Duration); err != nil {
|
||||
intlog.Error(m.GetCtx(), err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,6 +10,7 @@ import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/v2/errors/gcode"
|
||||
"github.com/gogf/gf/v2/internal/utils"
|
||||
"reflect"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
@ -49,14 +50,9 @@ func (m *Model) Update(dataAndWhere ...interface{}) (result sql.Result, err erro
|
||||
// Automatically update the record updating time.
|
||||
if !m.unscoped && fieldNameUpdate != "" {
|
||||
var (
|
||||
refValue = reflect.ValueOf(m.data)
|
||||
refKind = refValue.Kind()
|
||||
reflectInfo = utils.OriginTypeAndKind(m.data)
|
||||
)
|
||||
if refKind == reflect.Ptr {
|
||||
refValue = refValue.Elem()
|
||||
refKind = refValue.Kind()
|
||||
}
|
||||
switch refKind {
|
||||
switch reflectInfo.OriginKind {
|
||||
case reflect.Map, reflect.Struct:
|
||||
dataMap := ConvertDataForTableRecord(m.data)
|
||||
if fieldNameUpdate != "" {
|
||||
|
||||
@ -26,7 +26,11 @@ func (m *Model) TableFields(tableStr string, schema ...string) (fields map[strin
|
||||
if len(schema) > 0 && schema[0] != "" {
|
||||
useSchema = schema[0]
|
||||
}
|
||||
return m.db.TableFields(m.GetCtx(), m.guessPrimaryTableName(tableStr), useSchema)
|
||||
return m.db.TableFields(
|
||||
m.GetCtx(),
|
||||
m.db.GetCore().guessPrimaryTableName(tableStr),
|
||||
useSchema,
|
||||
)
|
||||
}
|
||||
|
||||
// getModel creates and returns a cloned model of current model if `safe` is true, or else it returns
|
||||
@ -104,7 +108,7 @@ func (m *Model) filterDataForInsertOrUpdate(data interface{}) (interface{}, erro
|
||||
func (m *Model) doMappingAndFilterForInsertOrUpdateDataMap(data Map, allowOmitEmpty bool) (Map, error) {
|
||||
var err error
|
||||
data, err = m.db.GetCore().mappingAndFilterData(
|
||||
m.schema, m.guessPrimaryTableName(m.tablesInit), data, m.filter,
|
||||
m.schema, m.tablesInit, data, m.filter,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@ -30,10 +30,10 @@ func (tx *TX) Schema(schema string) *Schema {
|
||||
}
|
||||
}
|
||||
|
||||
// Table creates and returns a new ORM model.
|
||||
// Model creates and returns a new ORM model.
|
||||
// The parameter `tables` can be more than one table names, like :
|
||||
// "user", "user u", "user, user_detail", "user u, user_detail ud"
|
||||
func (s *Schema) Table(table string) *Model {
|
||||
func (s *Schema) Model(table string) *Model {
|
||||
var m *Model
|
||||
if s.tx != nil {
|
||||
m = s.tx.Model(table)
|
||||
@ -51,9 +51,3 @@ func (s *Schema) Table(table string) *Model {
|
||||
m.schema = s.schema
|
||||
return m
|
||||
}
|
||||
|
||||
// Model is alias of Core.Table.
|
||||
// See Core.Table.
|
||||
func (s *Schema) Model(table string) *Model {
|
||||
return s.Table(table)
|
||||
}
|
||||
|
||||
@ -10,6 +10,7 @@ import (
|
||||
"database/sql"
|
||||
"github.com/gogf/gf/v2/errors/gcode"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/internal/structs"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"github.com/gogf/gf/v2/util/gutil"
|
||||
@ -17,21 +18,61 @@ import (
|
||||
)
|
||||
|
||||
// ScanList converts `r` to struct slice which contains other complex struct attributes.
|
||||
// Note that the parameter `listPointer` should be type of *[]struct/*[]*struct.
|
||||
// Usage example:
|
||||
// Note that the parameter `structSlicePointer` should be type of *[]struct/*[]*struct.
|
||||
//
|
||||
// Usage example 1: Normal attribute struct relation:
|
||||
// type EntityUser struct {
|
||||
// Uid int
|
||||
// Name string
|
||||
// }
|
||||
// type EntityUserDetail struct {
|
||||
// Uid int
|
||||
// Address string
|
||||
// }
|
||||
// type EntityUserScores struct {
|
||||
// Id int
|
||||
// Uid int
|
||||
// Score int
|
||||
// Course string
|
||||
// }
|
||||
// type Entity struct {
|
||||
// User *EntityUser
|
||||
// User *EntityUser
|
||||
// UserDetail *EntityUserDetail
|
||||
// UserScores []*EntityUserScores
|
||||
// UserScores []*EntityUserScores
|
||||
// }
|
||||
// var users []*Entity
|
||||
// or
|
||||
// var users []Entity
|
||||
//
|
||||
// ScanList(&users, "User")
|
||||
// ScanList(&users, "User", "uid")
|
||||
// ScanList(&users, "UserDetail", "User", "uid:Uid")
|
||||
// ScanList(&users, "UserScores", "User", "uid:Uid")
|
||||
// ScanList(&users, "UserScores", "User", "uid")
|
||||
//
|
||||
//
|
||||
// Usage example 2: Embedded attribute struct relation:
|
||||
// type EntityUser struct {
|
||||
// Uid int
|
||||
// Name string
|
||||
// }
|
||||
// type EntityUserDetail struct {
|
||||
// Uid int
|
||||
// Address string
|
||||
// }
|
||||
// type EntityUserScores struct {
|
||||
// Id int
|
||||
// Uid int
|
||||
// Score int
|
||||
// }
|
||||
// type Entity struct {
|
||||
// EntityUser
|
||||
// UserDetail EntityUserDetail
|
||||
// UserScores []EntityUserScores
|
||||
// }
|
||||
//
|
||||
// var users []*Entity
|
||||
// ScanList(&users)
|
||||
// ScanList(&users, "UserDetail", "uid")
|
||||
// ScanList(&users, "UserScores", "uid")
|
||||
//
|
||||
//
|
||||
// The parameters "User/UserDetail/UserScores" in the example codes specify the target attribute struct
|
||||
// that current result will be bound to.
|
||||
@ -42,15 +83,26 @@ import (
|
||||
// given `relation` parameter.
|
||||
//
|
||||
// See the example or unit testing cases for clear understanding for this function.
|
||||
func (r Result) ScanList(listPointer interface{}, bindToAttrName string, relationKV ...string) (err error) {
|
||||
return doScanList(nil, r, listPointer, bindToAttrName, relationKV...)
|
||||
func (r Result) ScanList(structSlicePointer interface{}, bindToAttrName string, relationAttrNameAndFields ...string) (err error) {
|
||||
var (
|
||||
relationAttrName string
|
||||
relationFields string
|
||||
)
|
||||
switch len(relationAttrNameAndFields) {
|
||||
case 2:
|
||||
relationAttrName = relationAttrNameAndFields[0]
|
||||
relationFields = relationAttrNameAndFields[1]
|
||||
case 1:
|
||||
relationFields = relationAttrNameAndFields[0]
|
||||
}
|
||||
return doScanList(nil, r, structSlicePointer, bindToAttrName, relationAttrName, relationFields)
|
||||
}
|
||||
|
||||
// doScanList converts `result` to struct slice which contains other complex struct attributes recursively.
|
||||
// The parameter `model` is used for recursively scanning purpose, which means, it can scans the attribute struct/structs recursively but
|
||||
// it needs the Model for database accessing.
|
||||
// Note that the parameter `listPointer` should be type of *[]struct/*[]*struct.
|
||||
func doScanList(model *Model, result Result, listPointer interface{}, bindToAttrName string, relationKV ...string) (err error) {
|
||||
// The parameter `model` is used for recursively scanning purpose, which means, it can scan the attribute struct/structs recursively,
|
||||
// but it needs the Model for database accessing.
|
||||
// Note that the parameter `structSlicePointer` should be type of *[]struct/*[]*struct.
|
||||
func doScanList(model *Model, result Result, structSlicePointer interface{}, bindToAttrName, relationAttrName, relationFields string) (err error) {
|
||||
if result.IsEmpty() {
|
||||
return nil
|
||||
}
|
||||
@ -59,8 +111,12 @@ func doScanList(model *Model, result Result, listPointer interface{}, bindToAttr
|
||||
return gerror.NewCode(gcode.CodeInvalidParameter, `bindToAttrName should not be empty`)
|
||||
}
|
||||
|
||||
if relationAttrName == "." {
|
||||
relationAttrName = ""
|
||||
}
|
||||
|
||||
var (
|
||||
reflectValue = reflect.ValueOf(listPointer)
|
||||
reflectValue = reflect.ValueOf(structSlicePointer)
|
||||
reflectKind = reflectValue.Kind()
|
||||
)
|
||||
if reflectKind == reflect.Interface {
|
||||
@ -68,12 +124,20 @@ func doScanList(model *Model, result Result, listPointer interface{}, bindToAttr
|
||||
reflectKind = reflectValue.Kind()
|
||||
}
|
||||
if reflectKind != reflect.Ptr {
|
||||
return gerror.NewCodef(gcode.CodeInvalidParameter, "listPointer should be type of *[]struct/*[]*struct, but got: %v", reflectKind)
|
||||
return gerror.NewCodef(
|
||||
gcode.CodeInvalidParameter,
|
||||
"structSlicePointer should be type of *[]struct/*[]*struct, but got: %v",
|
||||
reflectKind,
|
||||
)
|
||||
}
|
||||
reflectValue = reflectValue.Elem()
|
||||
reflectKind = reflectValue.Kind()
|
||||
if reflectKind != reflect.Slice && reflectKind != reflect.Array {
|
||||
return gerror.NewCodef(gcode.CodeInvalidParameter, "listPointer should be type of *[]struct/*[]*struct, but got: %v", reflectKind)
|
||||
return gerror.NewCodef(
|
||||
gcode.CodeInvalidParameter,
|
||||
"structSlicePointer should be type of *[]struct/*[]*struct, but got: %v",
|
||||
reflectKind,
|
||||
)
|
||||
}
|
||||
length := len(result)
|
||||
if length == 0 {
|
||||
@ -91,7 +155,7 @@ func doScanList(model *Model, result Result, listPointer interface{}, bindToAttr
|
||||
var (
|
||||
arrayValue reflect.Value // Like: []*Entity
|
||||
arrayItemType reflect.Type // Like: *Entity
|
||||
reflectType = reflect.TypeOf(listPointer)
|
||||
reflectType = reflect.TypeOf(structSlicePointer)
|
||||
)
|
||||
if reflectValue.Len() > 0 {
|
||||
arrayValue = reflectValue
|
||||
@ -104,56 +168,55 @@ func doScanList(model *Model, result Result, listPointer interface{}, bindToAttr
|
||||
|
||||
// Relation variables.
|
||||
var (
|
||||
relationKVStr string
|
||||
relationDataMap map[string]Value
|
||||
relationFromAttrName string // Eg: relationKV: User, uid:Uid -> User
|
||||
relationResultFieldName string // Eg: relationKV: uid:Uid -> uid
|
||||
relationBindToSubAttrName string // Eg: relationKV: uid:Uid -> Uid
|
||||
relationDataMap map[string]Value
|
||||
relationFromFieldName string // Eg: relationKV: id:uid -> id
|
||||
relationBindToFieldName string // Eg: relationKV: id:uid -> uid
|
||||
)
|
||||
if len(relationKV) > 0 {
|
||||
if len(relationKV) == 1 {
|
||||
relationKVStr = relationKV[0]
|
||||
} else {
|
||||
relationFromAttrName = relationKV[0]
|
||||
relationKVStr = relationKV[1]
|
||||
}
|
||||
if len(relationFields) > 0 {
|
||||
// The relation key string of table filed name and attribute name
|
||||
// can be joined with char '=' or ':'.
|
||||
array := gstr.SplitAndTrim(relationKVStr, "=")
|
||||
array := gstr.SplitAndTrim(relationFields, "=")
|
||||
if len(array) == 1 {
|
||||
// Compatible with old splitting char ':'.
|
||||
array = gstr.SplitAndTrim(relationKVStr, ":")
|
||||
array = gstr.SplitAndTrim(relationFields, ":")
|
||||
}
|
||||
if len(array) == 1 {
|
||||
// The relation names are the same.
|
||||
array = []string{relationKVStr, relationKVStr}
|
||||
array = []string{relationFields, relationFields}
|
||||
}
|
||||
if len(array) == 2 {
|
||||
// Defined table field to relation attribute name.
|
||||
// Like:
|
||||
// uid:Uid
|
||||
// uid:UserId
|
||||
relationResultFieldName = array[0]
|
||||
relationBindToSubAttrName = array[1]
|
||||
if key, _ := gutil.MapPossibleItemByKey(result[0].Map(), relationResultFieldName); key == "" {
|
||||
relationFromFieldName = array[0]
|
||||
relationBindToFieldName = array[1]
|
||||
if key, _ := gutil.MapPossibleItemByKey(result[0].Map(), relationFromFieldName); key == "" {
|
||||
return gerror.NewCodef(
|
||||
gcode.CodeInvalidParameter,
|
||||
`cannot find possible related table field name "%s" from given relation key "%s"`,
|
||||
relationResultFieldName,
|
||||
relationKVStr,
|
||||
`cannot find possible related table field name "%s" from given relation fields "%s"`,
|
||||
relationFromFieldName,
|
||||
relationFields,
|
||||
)
|
||||
} else {
|
||||
relationResultFieldName = key
|
||||
relationFromFieldName = key
|
||||
}
|
||||
} else {
|
||||
return gerror.NewCode(gcode.CodeInvalidParameter, `parameter relationKV should be format of "ResultFieldName:BindToAttrName"`)
|
||||
return gerror.NewCode(
|
||||
gcode.CodeInvalidParameter,
|
||||
`parameter relationKV should be format of "ResultFieldName:BindToAttrName"`,
|
||||
)
|
||||
}
|
||||
if relationResultFieldName != "" {
|
||||
if relationFromFieldName != "" {
|
||||
// Note that the value might be type of slice.
|
||||
relationDataMap = result.MapKeyValue(relationResultFieldName)
|
||||
relationDataMap = result.MapKeyValue(relationFromFieldName)
|
||||
}
|
||||
if len(relationDataMap) == 0 {
|
||||
return gerror.NewCodef(gcode.CodeInvalidParameter, `cannot find the relation data map, maybe invalid relation given "%v"`, relationKV)
|
||||
return gerror.NewCodef(
|
||||
gcode.CodeInvalidParameter,
|
||||
`cannot find the relation data map, maybe invalid relation fields given "%v"`,
|
||||
relationFields,
|
||||
)
|
||||
}
|
||||
}
|
||||
// Bind to target attribute.
|
||||
@ -186,9 +249,9 @@ func doScanList(model *Model, result Result, listPointer interface{}, bindToAttr
|
||||
|
||||
// Bind to relation conditions.
|
||||
var (
|
||||
relationFromAttrValue reflect.Value
|
||||
relationFromAttrField reflect.Value
|
||||
relationBindToSubAttrNameChecked bool
|
||||
relationFromAttrValue reflect.Value
|
||||
relationFromAttrField reflect.Value
|
||||
relationBindToFieldNameChecked bool
|
||||
)
|
||||
for i := 0; i < arrayValue.Len(); i++ {
|
||||
arrayElemValue := arrayValue.Index(i)
|
||||
@ -209,9 +272,9 @@ func doScanList(model *Model, result Result, listPointer interface{}, bindToAttr
|
||||
// Like: []Entity
|
||||
}
|
||||
bindToAttrValue = arrayElemValue.FieldByName(bindToAttrName)
|
||||
if relationFromAttrName != "" {
|
||||
if relationAttrName != "" {
|
||||
// Attribute value of current slice element.
|
||||
relationFromAttrValue = arrayElemValue.FieldByName(relationFromAttrName)
|
||||
relationFromAttrValue = arrayElemValue.FieldByName(relationAttrName)
|
||||
if relationFromAttrValue.Kind() == reflect.Ptr {
|
||||
relationFromAttrValue = relationFromAttrValue.Elem()
|
||||
}
|
||||
@ -220,36 +283,35 @@ func doScanList(model *Model, result Result, listPointer interface{}, bindToAttr
|
||||
relationFromAttrValue = arrayElemValue
|
||||
}
|
||||
if len(relationDataMap) > 0 && !relationFromAttrValue.IsValid() {
|
||||
return gerror.NewCodef(gcode.CodeInvalidParameter, `invalid relation specified: "%v"`, relationKV)
|
||||
return gerror.NewCodef(gcode.CodeInvalidParameter, `invalid relation fields specified: "%v"`, relationFields)
|
||||
}
|
||||
// Check and find possible bind to attribute name.
|
||||
if relationKVStr != "" && !relationBindToSubAttrNameChecked {
|
||||
relationFromAttrField = relationFromAttrValue.FieldByName(relationBindToSubAttrName)
|
||||
if relationFields != "" && !relationBindToFieldNameChecked {
|
||||
relationFromAttrField = relationFromAttrValue.FieldByName(relationBindToFieldName)
|
||||
if !relationFromAttrField.IsValid() {
|
||||
var (
|
||||
relationFromAttrType = relationFromAttrValue.Type()
|
||||
filedMap = make(map[string]interface{})
|
||||
filedMap, _ = structs.FieldMap(structs.FieldMapInput{
|
||||
Pointer: relationFromAttrValue,
|
||||
RecursiveOption: structs.RecursiveOptionEmbeddedNoTag,
|
||||
})
|
||||
)
|
||||
for i := 0; i < relationFromAttrType.NumField(); i++ {
|
||||
filedMap[relationFromAttrType.Field(i).Name] = struct{}{}
|
||||
}
|
||||
if key, _ := gutil.MapPossibleItemByKey(filedMap, relationBindToSubAttrName); key == "" {
|
||||
if key, _ := gutil.MapPossibleItemByKey(gconv.Map(filedMap), relationBindToFieldName); key == "" {
|
||||
return gerror.NewCodef(
|
||||
gcode.CodeInvalidParameter,
|
||||
`cannot find possible related attribute name "%s" from given relation key "%s"`,
|
||||
relationBindToSubAttrName,
|
||||
relationKVStr,
|
||||
`cannot find possible related attribute name "%s" from given relation fields "%s"`,
|
||||
relationBindToFieldName,
|
||||
relationFields,
|
||||
)
|
||||
} else {
|
||||
relationBindToSubAttrName = key
|
||||
relationBindToFieldName = key
|
||||
}
|
||||
}
|
||||
relationBindToSubAttrNameChecked = true
|
||||
relationBindToFieldNameChecked = true
|
||||
}
|
||||
switch bindToAttrKind {
|
||||
case reflect.Array, reflect.Slice:
|
||||
if len(relationDataMap) > 0 {
|
||||
relationFromAttrField = relationFromAttrValue.FieldByName(relationBindToSubAttrName)
|
||||
relationFromAttrField = relationFromAttrValue.FieldByName(relationBindToFieldName)
|
||||
if relationFromAttrField.IsValid() {
|
||||
results := make(Result, 0)
|
||||
for _, v := range relationDataMap[gconv.String(relationFromAttrField.Interface())].Slice() {
|
||||
@ -265,8 +327,8 @@ func doScanList(model *Model, result Result, listPointer interface{}, bindToAttr
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// May be the attribute does not exist yet.
|
||||
return gerror.NewCodef(gcode.CodeInvalidParameter, `invalid relation specified: "%v"`, relationKV)
|
||||
// Maybe the attribute does not exist yet.
|
||||
return gerror.NewCodef(gcode.CodeInvalidParameter, `invalid relation fields specified: "%v"`, relationFields)
|
||||
}
|
||||
} else {
|
||||
return gerror.NewCodef(
|
||||
@ -284,7 +346,7 @@ func doScanList(model *Model, result Result, listPointer interface{}, bindToAttr
|
||||
element = bindToAttrValue.Elem()
|
||||
}
|
||||
if len(relationDataMap) > 0 {
|
||||
relationFromAttrField = relationFromAttrValue.FieldByName(relationBindToSubAttrName)
|
||||
relationFromAttrField = relationFromAttrValue.FieldByName(relationBindToFieldName)
|
||||
if relationFromAttrField.IsValid() {
|
||||
v := relationDataMap[gconv.String(relationFromAttrField.Interface())]
|
||||
if v == nil {
|
||||
@ -301,8 +363,8 @@ func doScanList(model *Model, result Result, listPointer interface{}, bindToAttr
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// May be the attribute does not exist yet.
|
||||
return gerror.NewCodef(gcode.CodeInvalidParameter, `invalid relation specified: "%v"`, relationKV)
|
||||
// Maybe the attribute does not exist yet.
|
||||
return gerror.NewCodef(gcode.CodeInvalidParameter, `invalid relation fields specified: "%v"`, relationFields)
|
||||
}
|
||||
} else {
|
||||
if i >= len(result) {
|
||||
@ -328,7 +390,7 @@ func doScanList(model *Model, result Result, listPointer interface{}, bindToAttr
|
||||
|
||||
case reflect.Struct:
|
||||
if len(relationDataMap) > 0 {
|
||||
relationFromAttrField = relationFromAttrValue.FieldByName(relationBindToSubAttrName)
|
||||
relationFromAttrField = relationFromAttrValue.FieldByName(relationBindToFieldName)
|
||||
if relationFromAttrField.IsValid() {
|
||||
relationDataItem := relationDataMap[gconv.String(relationFromAttrField.Interface())]
|
||||
if relationDataItem == nil {
|
||||
@ -345,8 +407,8 @@ func doScanList(model *Model, result Result, listPointer interface{}, bindToAttr
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// May be the attribute does not exist yet.
|
||||
return gerror.NewCodef(gcode.CodeInvalidParameter, `invalid relation specified: "%v"`, relationKV)
|
||||
// Maybe the attribute does not exist yet.
|
||||
return gerror.NewCodef(gcode.CodeInvalidParameter, `invalid relation fields specified: "%v"`, relationFields)
|
||||
}
|
||||
} else {
|
||||
if i >= len(result) {
|
||||
@ -373,6 +435,6 @@ func doScanList(model *Model, result Result, listPointer interface{}, bindToAttr
|
||||
return gerror.NewCodef(gcode.CodeInvalidParameter, `unsupported attribute type: %s`, bindToAttrKind.String())
|
||||
}
|
||||
}
|
||||
reflect.ValueOf(listPointer).Elem().Set(arrayValue)
|
||||
reflect.ValueOf(structSlicePointer).Elem().Set(arrayValue)
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -1553,7 +1553,7 @@ CREATE TABLE %s (
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Table_Relation_EmbeddedStruct(t *testing.T) {
|
||||
func Test_Table_Relation_EmbeddedStruct1(t *testing.T) {
|
||||
var (
|
||||
tableUser = "user_" + gtime.TimestampMicroStr()
|
||||
tableUserDetail = "user_detail_" + gtime.TimestampMicroStr()
|
||||
@ -1670,3 +1670,310 @@ CREATE TABLE %s (
|
||||
t.Assert(scores[24].Address, "address_5")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Table_Relation_EmbeddedStruct2(t *testing.T) {
|
||||
var (
|
||||
tableUser = "user_" + gtime.TimestampMicroStr()
|
||||
tableUserDetail = "user_detail_" + gtime.TimestampMicroStr()
|
||||
tableUserScores = "user_scores_" + gtime.TimestampMicroStr()
|
||||
)
|
||||
if _, err := db.Exec(ctx, fmt.Sprintf(`
|
||||
CREATE TABLE %s (
|
||||
uid int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
name varchar(45) NOT NULL,
|
||||
PRIMARY KEY (uid)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
`, tableUser)); err != nil {
|
||||
gtest.Error(err)
|
||||
}
|
||||
defer dropTable(tableUser)
|
||||
|
||||
if _, err := db.Exec(ctx, fmt.Sprintf(`
|
||||
CREATE TABLE %s (
|
||||
uid int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
address varchar(45) NOT NULL,
|
||||
PRIMARY KEY (uid)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
`, tableUserDetail)); err != nil {
|
||||
gtest.Error(err)
|
||||
}
|
||||
defer dropTable(tableUserDetail)
|
||||
|
||||
if _, err := db.Exec(ctx, fmt.Sprintf(`
|
||||
CREATE TABLE %s (
|
||||
id int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
uid int(10) unsigned NOT NULL,
|
||||
score int(10) unsigned NOT NULL,
|
||||
PRIMARY KEY (id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
`, tableUserScores)); err != nil {
|
||||
gtest.Error(err)
|
||||
}
|
||||
defer dropTable(tableUserScores)
|
||||
|
||||
type EntityUser struct {
|
||||
Uid int `json:"uid"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
type EntityUserDetail struct {
|
||||
Uid int `json:"uid"`
|
||||
Address string `json:"address"`
|
||||
}
|
||||
type EntityUserScores struct {
|
||||
Id int `json:"id"`
|
||||
Uid int `json:"uid"`
|
||||
Score int `json:"score"`
|
||||
}
|
||||
type Entity struct {
|
||||
*EntityUser
|
||||
UserDetail *EntityUserDetail
|
||||
UserScores []*EntityUserScores
|
||||
}
|
||||
|
||||
// Initialize the data.
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var err error
|
||||
for i := 1; i <= 5; i++ {
|
||||
// User.
|
||||
_, err = db.Insert(ctx, tableUser, g.Map{
|
||||
"uid": i,
|
||||
"name": fmt.Sprintf(`name_%d`, i),
|
||||
})
|
||||
t.AssertNil(err)
|
||||
// Detail.
|
||||
_, err = db.Insert(ctx, tableUserDetail, g.Map{
|
||||
"uid": i,
|
||||
"address": fmt.Sprintf(`address_%d`, i),
|
||||
})
|
||||
t.AssertNil(err)
|
||||
// Scores.
|
||||
for j := 1; j <= 5; j++ {
|
||||
_, err = db.Insert(ctx, tableUserScores, g.Map{
|
||||
"uid": i,
|
||||
"score": j,
|
||||
})
|
||||
t.AssertNil(err)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// MapKeyValue.
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
all, err := db.Model(tableUser).Where("uid", g.Slice{3, 4}).Order("uid asc").All()
|
||||
t.AssertNil(err)
|
||||
t.Assert(all.Len(), 2)
|
||||
t.Assert(len(all.MapKeyValue("uid")), 2)
|
||||
t.Assert(all.MapKeyValue("uid")["3"].Map()["uid"], 3)
|
||||
t.Assert(all.MapKeyValue("uid")["4"].Map()["uid"], 4)
|
||||
all, err = db.Model(tableUserScores).Where("uid", g.Slice{3, 4}).Order("id asc").All()
|
||||
t.AssertNil(err)
|
||||
t.Assert(all.Len(), 10)
|
||||
t.Assert(len(all.MapKeyValue("uid")), 2)
|
||||
t.Assert(len(all.MapKeyValue("uid")["3"].Slice()), 5)
|
||||
t.Assert(len(all.MapKeyValue("uid")["4"].Slice()), 5)
|
||||
t.Assert(gconv.Map(all.MapKeyValue("uid")["3"].Slice()[0])["uid"], 3)
|
||||
t.Assert(gconv.Map(all.MapKeyValue("uid")["3"].Slice()[0])["score"], 1)
|
||||
t.Assert(gconv.Map(all.MapKeyValue("uid")["3"].Slice()[4])["uid"], 3)
|
||||
t.Assert(gconv.Map(all.MapKeyValue("uid")["3"].Slice()[4])["score"], 5)
|
||||
})
|
||||
|
||||
// Result ScanList with struct elements and pointer attributes.
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var users []Entity
|
||||
// User
|
||||
err := db.Model(tableUser).Where("uid", g.Slice{3, 4}).Order("uid asc").Scan(&users)
|
||||
t.AssertNil(err)
|
||||
t.Assert(len(users), 2)
|
||||
t.Assert(users[0].EntityUser, &EntityUser{3, "name_3"})
|
||||
t.Assert(users[1].EntityUser, &EntityUser{4, "name_4"})
|
||||
// Detail
|
||||
all, err := db.Model(tableUserDetail).Where("uid", gdb.ListItemValues(users, "Uid")).Order("uid asc").All()
|
||||
t.AssertNil(err)
|
||||
err = all.ScanList(&users, "UserDetail", "uid")
|
||||
t.AssertNil(err)
|
||||
t.Assert(users[0].UserDetail, &EntityUserDetail{3, "address_3"})
|
||||
t.Assert(users[1].UserDetail, &EntityUserDetail{4, "address_4"})
|
||||
// Scores
|
||||
all, err = db.Model(tableUserScores).Where("uid", gdb.ListItemValues(users, "Uid")).Order("id asc").All()
|
||||
t.AssertNil(err)
|
||||
err = all.ScanList(&users, "UserScores", "uid")
|
||||
t.AssertNil(err)
|
||||
t.Assert(len(users[0].UserScores), 5)
|
||||
t.Assert(len(users[1].UserScores), 5)
|
||||
t.Assert(users[0].UserScores[0].Uid, 3)
|
||||
t.Assert(users[0].UserScores[0].Score, 1)
|
||||
t.Assert(users[0].UserScores[4].Score, 5)
|
||||
t.Assert(users[1].UserScores[0].Uid, 4)
|
||||
t.Assert(users[1].UserScores[0].Score, 1)
|
||||
t.Assert(users[1].UserScores[4].Score, 5)
|
||||
})
|
||||
|
||||
// Result ScanList with pointer elements and pointer attributes.
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var users []*Entity
|
||||
// User
|
||||
err := db.Model(tableUser).Where("uid", g.Slice{3, 4}).Order("uid asc").Scan(&users)
|
||||
t.AssertNil(err)
|
||||
t.Assert(len(users), 2)
|
||||
t.Assert(users[0].EntityUser, &EntityUser{3, "name_3"})
|
||||
t.Assert(users[1].EntityUser, &EntityUser{4, "name_4"})
|
||||
// Detail
|
||||
all, err := db.Model(tableUserDetail).Where("uid", gdb.ListItemValues(users, "Uid")).Order("uid asc").All()
|
||||
t.AssertNil(err)
|
||||
err = all.ScanList(&users, "UserDetail", "uid")
|
||||
t.AssertNil(err)
|
||||
t.Assert(users[0].UserDetail, &EntityUserDetail{3, "address_3"})
|
||||
t.Assert(users[1].UserDetail, &EntityUserDetail{4, "address_4"})
|
||||
// Scores
|
||||
all, err = db.Model(tableUserScores).Where("uid", gdb.ListItemValues(users, "Uid")).Order("id asc").All()
|
||||
t.AssertNil(err)
|
||||
err = all.ScanList(&users, "UserScores", "uid")
|
||||
t.AssertNil(err)
|
||||
t.Assert(len(users[0].UserScores), 5)
|
||||
t.Assert(len(users[1].UserScores), 5)
|
||||
t.Assert(users[0].UserScores[0].Uid, 3)
|
||||
t.Assert(users[0].UserScores[0].Score, 1)
|
||||
t.Assert(users[0].UserScores[4].Score, 5)
|
||||
t.Assert(users[1].UserScores[0].Uid, 4)
|
||||
t.Assert(users[1].UserScores[0].Score, 1)
|
||||
t.Assert(users[1].UserScores[4].Score, 5)
|
||||
})
|
||||
|
||||
// Result ScanList with struct elements and struct attributes.
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
type EntityUser struct {
|
||||
Uid int `json:"uid"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
type EntityUserDetail struct {
|
||||
Uid int `json:"uid"`
|
||||
Address string `json:"address"`
|
||||
}
|
||||
type EntityUserScores struct {
|
||||
Id int `json:"id"`
|
||||
Uid int `json:"uid"`
|
||||
Score int `json:"score"`
|
||||
}
|
||||
type Entity struct {
|
||||
EntityUser
|
||||
UserDetail EntityUserDetail
|
||||
UserScores []EntityUserScores
|
||||
}
|
||||
var users []Entity
|
||||
// User
|
||||
err := db.Model(tableUser).Where("uid", g.Slice{3, 4}).Order("uid asc").Scan(&users)
|
||||
t.AssertNil(err)
|
||||
t.Assert(len(users), 2)
|
||||
t.Assert(users[0].EntityUser, &EntityUser{3, "name_3"})
|
||||
t.Assert(users[1].EntityUser, &EntityUser{4, "name_4"})
|
||||
// Detail
|
||||
all, err := db.Model(tableUserDetail).Where("uid", gdb.ListItemValues(users, "Uid")).Order("uid asc").All()
|
||||
t.AssertNil(err)
|
||||
err = all.ScanList(&users, "UserDetail", "uid")
|
||||
t.AssertNil(err)
|
||||
t.Assert(users[0].UserDetail, &EntityUserDetail{3, "address_3"})
|
||||
t.Assert(users[1].UserDetail, &EntityUserDetail{4, "address_4"})
|
||||
// Scores
|
||||
all, err = db.Model(tableUserScores).Where("uid", gdb.ListItemValues(users, "Uid")).Order("id asc").All()
|
||||
t.AssertNil(err)
|
||||
err = all.ScanList(&users, "UserScores", "uid")
|
||||
t.AssertNil(err)
|
||||
t.Assert(len(users[0].UserScores), 5)
|
||||
t.Assert(len(users[1].UserScores), 5)
|
||||
t.Assert(users[0].UserScores[0].Uid, 3)
|
||||
t.Assert(users[0].UserScores[0].Score, 1)
|
||||
t.Assert(users[0].UserScores[4].Score, 5)
|
||||
t.Assert(users[1].UserScores[0].Uid, 4)
|
||||
t.Assert(users[1].UserScores[0].Score, 1)
|
||||
t.Assert(users[1].UserScores[4].Score, 5)
|
||||
})
|
||||
|
||||
// Result ScanList with pointer elements and struct attributes.
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
type EntityUser struct {
|
||||
Uid int `json:"uid"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
type EntityUserDetail struct {
|
||||
Uid int `json:"uid"`
|
||||
Address string `json:"address"`
|
||||
}
|
||||
type EntityUserScores struct {
|
||||
Id int `json:"id"`
|
||||
Uid int `json:"uid"`
|
||||
Score int `json:"score"`
|
||||
}
|
||||
type Entity struct {
|
||||
EntityUser
|
||||
UserDetail EntityUserDetail
|
||||
UserScores []EntityUserScores
|
||||
}
|
||||
var users []*Entity
|
||||
|
||||
// User
|
||||
err := db.Model(tableUser).Where("uid", g.Slice{3, 4}).Order("uid asc").Scan(&users)
|
||||
t.AssertNil(err)
|
||||
t.Assert(len(users), 2)
|
||||
t.Assert(users[0].EntityUser, &EntityUser{3, "name_3"})
|
||||
t.Assert(users[1].EntityUser, &EntityUser{4, "name_4"})
|
||||
// Detail
|
||||
all, err := db.Model(tableUserDetail).Where("uid", gdb.ListItemValues(users, "Uid")).Order("uid asc").All()
|
||||
t.AssertNil(err)
|
||||
err = all.ScanList(&users, "UserDetail", "uid")
|
||||
t.AssertNil(err)
|
||||
t.Assert(users[0].UserDetail, &EntityUserDetail{3, "address_3"})
|
||||
t.Assert(users[1].UserDetail, &EntityUserDetail{4, "address_4"})
|
||||
// Scores
|
||||
all, err = db.Model(tableUserScores).Where("uid", gdb.ListItemValues(users, "Uid")).Order("id asc").All()
|
||||
t.AssertNil(err)
|
||||
err = all.ScanList(&users, "UserScores", "uid")
|
||||
t.AssertNil(err)
|
||||
t.Assert(len(users[0].UserScores), 5)
|
||||
t.Assert(len(users[1].UserScores), 5)
|
||||
t.Assert(users[0].UserScores[0].Uid, 3)
|
||||
t.Assert(users[0].UserScores[0].Score, 1)
|
||||
t.Assert(users[0].UserScores[4].Score, 5)
|
||||
t.Assert(users[1].UserScores[0].Uid, 4)
|
||||
t.Assert(users[1].UserScores[0].Score, 1)
|
||||
t.Assert(users[1].UserScores[4].Score, 5)
|
||||
})
|
||||
|
||||
// Model ScanList with pointer elements and pointer attributes.
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var users []*Entity
|
||||
// User
|
||||
err := db.Model(tableUser).
|
||||
Where("uid", g.Slice{3, 4}).
|
||||
Order("uid asc").
|
||||
Scan(&users)
|
||||
t.AssertNil(err)
|
||||
// Detail
|
||||
err = db.Model(tableUserDetail).
|
||||
Where("uid", gdb.ListItemValues(users, "Uid")).
|
||||
Order("uid asc").
|
||||
ScanList(&users, "UserDetail", "uid:Uid")
|
||||
t.AssertNil(err)
|
||||
// Scores
|
||||
err = db.Model(tableUserScores).
|
||||
Where("uid", gdb.ListItemValues(users, "Uid")).
|
||||
Order("id asc").
|
||||
ScanList(&users, "UserScores", "uid:Uid")
|
||||
t.AssertNil(err)
|
||||
|
||||
t.Assert(len(users), 2)
|
||||
t.Assert(users[0].EntityUser, &EntityUser{3, "name_3"})
|
||||
t.Assert(users[1].EntityUser, &EntityUser{4, "name_4"})
|
||||
|
||||
t.Assert(users[0].UserDetail, &EntityUserDetail{3, "address_3"})
|
||||
t.Assert(users[1].UserDetail, &EntityUserDetail{4, "address_4"})
|
||||
|
||||
t.Assert(len(users[0].UserScores), 5)
|
||||
t.Assert(len(users[1].UserScores), 5)
|
||||
t.Assert(users[0].UserScores[0].Uid, 3)
|
||||
t.Assert(users[0].UserScores[0].Score, 1)
|
||||
t.Assert(users[0].UserScores[4].Score, 5)
|
||||
t.Assert(users[1].UserScores[0].Uid, 4)
|
||||
t.Assert(users[1].UserScores[0].Score, 1)
|
||||
t.Assert(users[1].UserScores[4].Score, 5)
|
||||
})
|
||||
}
|
||||
|
||||
@ -251,6 +251,7 @@ CREATE TABLE %s (
|
||||
model := db.Model(fmt.Sprintf(`%s as t`, table1))
|
||||
t.Assert(model.getConditionForSoftDeleting(), "`delete_at` IS NULL")
|
||||
})
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
model := db.Model(fmt.Sprintf(`%s, %s`, table1, table2))
|
||||
t.Assert(model.getConditionForSoftDeleting(), fmt.Sprintf(
|
||||
|
||||
@ -662,6 +662,19 @@ func Test_DB_GetScan(t *testing.T) {
|
||||
t.AssertNil(err)
|
||||
t.Assert(user.NickName, "name_3")
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
type User struct {
|
||||
Id int
|
||||
Passport string
|
||||
Password string
|
||||
NickName string
|
||||
CreateTime gtime.Time
|
||||
}
|
||||
var user *User
|
||||
err := db.GetScan(ctx, &user, fmt.Sprintf("SELECT * FROM %s WHERE id=?", table), 3)
|
||||
t.AssertNil(err)
|
||||
t.Assert(user.NickName, "name_3")
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
type User struct {
|
||||
Id int
|
||||
|
||||
@ -2308,31 +2308,31 @@ func Test_Model_Schema2(t *testing.T) {
|
||||
}()
|
||||
// Schema.
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
v, err := db.Schema(TestSchema1).Table(table).Value("nickname", "id=2")
|
||||
v, err := db.Schema(TestSchema1).Model(table).Value("nickname", "id=2")
|
||||
t.AssertNil(err)
|
||||
t.Assert(v.String(), "name_2")
|
||||
|
||||
r, err := db.Schema(TestSchema1).Table(table).Update(g.Map{"nickname": "name_200"}, "id=2")
|
||||
r, err := db.Schema(TestSchema1).Model(table).Update(g.Map{"nickname": "name_200"}, "id=2")
|
||||
t.AssertNil(err)
|
||||
n, _ := r.RowsAffected()
|
||||
t.Assert(n, 1)
|
||||
|
||||
v, err = db.Schema(TestSchema1).Table(table).Value("nickname", "id=2")
|
||||
v, err = db.Schema(TestSchema1).Model(table).Value("nickname", "id=2")
|
||||
t.AssertNil(err)
|
||||
t.Assert(v.String(), "name_200")
|
||||
|
||||
v, err = db.Schema(TestSchema2).Table(table).Value("nickname", "id=2")
|
||||
v, err = db.Schema(TestSchema2).Model(table).Value("nickname", "id=2")
|
||||
t.AssertNil(err)
|
||||
t.Assert(v.String(), "name_2")
|
||||
|
||||
v, err = db.Schema(TestSchema1).Table(table).Value("nickname", "id=2")
|
||||
v, err = db.Schema(TestSchema1).Model(table).Value("nickname", "id=2")
|
||||
t.AssertNil(err)
|
||||
t.Assert(v.String(), "name_200")
|
||||
})
|
||||
// Schema.
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
i := 1000
|
||||
_, err := db.Schema(TestSchema1).Table(table).Insert(g.Map{
|
||||
_, err := db.Schema(TestSchema1).Model(table).Insert(g.Map{
|
||||
"id": i,
|
||||
"passport": fmt.Sprintf(`user_%d`, i),
|
||||
"password": fmt.Sprintf(`pass_%d`, i),
|
||||
@ -2342,11 +2342,11 @@ func Test_Model_Schema2(t *testing.T) {
|
||||
})
|
||||
t.AssertNil(err)
|
||||
|
||||
v, err := db.Schema(TestSchema1).Table(table).Value("nickname", "id=?", i)
|
||||
v, err := db.Schema(TestSchema1).Model(table).Value("nickname", "id=?", i)
|
||||
t.AssertNil(err)
|
||||
t.Assert(v.String(), "name_1000")
|
||||
|
||||
v, err = db.Schema(TestSchema2).Table(table).Value("nickname", "id=?", i)
|
||||
v, err = db.Schema(TestSchema2).Model(table).Value("nickname", "id=?", i)
|
||||
t.AssertNil(err)
|
||||
t.Assert(v.String(), "")
|
||||
})
|
||||
@ -2479,7 +2479,11 @@ func Test_Model_Cache(t *testing.T) {
|
||||
defer dropTable(table)
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
one, err := db.Model(table).Cache(time.Second, "test1").WherePri(1).One()
|
||||
one, err := db.Model(table).Cache(gdb.CacheOption{
|
||||
Duration: time.Second,
|
||||
Name: "test1",
|
||||
Force: false,
|
||||
}).WherePri(1).One()
|
||||
t.AssertNil(err)
|
||||
t.Assert(one["passport"], "user_1")
|
||||
|
||||
@ -2489,63 +2493,107 @@ func Test_Model_Cache(t *testing.T) {
|
||||
t.AssertNil(err)
|
||||
t.Assert(n, 1)
|
||||
|
||||
one, err = db.Model(table).Cache(time.Second, "test1").WherePri(1).One()
|
||||
one, err = db.Model(table).Cache(gdb.CacheOption{
|
||||
Duration: time.Second,
|
||||
Name: "test1",
|
||||
Force: false,
|
||||
}).WherePri(1).One()
|
||||
t.AssertNil(err)
|
||||
t.Assert(one["passport"], "user_1")
|
||||
|
||||
time.Sleep(time.Second * 2)
|
||||
|
||||
one, err = db.Model(table).Cache(time.Second, "test1").WherePri(1).One()
|
||||
one, err = db.Model(table).Cache(gdb.CacheOption{
|
||||
Duration: time.Second,
|
||||
Name: "test1",
|
||||
Force: false,
|
||||
}).WherePri(1).One()
|
||||
t.AssertNil(err)
|
||||
t.Assert(one["passport"], "user_100")
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
one, err := db.Model(table).Cache(time.Second, "test2").WherePri(2).One()
|
||||
one, err := db.Model(table).Cache(gdb.CacheOption{
|
||||
Duration: time.Second,
|
||||
Name: "test2",
|
||||
Force: false,
|
||||
}).WherePri(2).One()
|
||||
t.AssertNil(err)
|
||||
t.Assert(one["passport"], "user_2")
|
||||
|
||||
r, err := db.Model(table).Data("passport", "user_200").Cache(-1, "test2").WherePri(2).Update()
|
||||
r, err := db.Model(table).Data("passport", "user_200").Cache(gdb.CacheOption{
|
||||
Duration: -1,
|
||||
Name: "test2",
|
||||
Force: false,
|
||||
}).WherePri(2).Update()
|
||||
t.AssertNil(err)
|
||||
n, err := r.RowsAffected()
|
||||
t.AssertNil(err)
|
||||
t.Assert(n, 1)
|
||||
|
||||
one, err = db.Model(table).Cache(time.Second, "test2").WherePri(2).One()
|
||||
one, err = db.Model(table).Cache(gdb.CacheOption{
|
||||
Duration: time.Second,
|
||||
Name: "test2",
|
||||
Force: false,
|
||||
}).WherePri(2).One()
|
||||
t.AssertNil(err)
|
||||
t.Assert(one["passport"], "user_200")
|
||||
})
|
||||
// transaction.
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
// make cache for id 3
|
||||
one, err := db.Model(table).Cache(time.Second, "test3").WherePri(3).One()
|
||||
one, err := db.Model(table).Cache(gdb.CacheOption{
|
||||
Duration: time.Second,
|
||||
Name: "test3",
|
||||
Force: false,
|
||||
}).WherePri(3).One()
|
||||
t.AssertNil(err)
|
||||
t.Assert(one["passport"], "user_3")
|
||||
|
||||
r, err := db.Model(table).Data("passport", "user_300").Cache(time.Second, "test3").WherePri(3).Update()
|
||||
r, err := db.Model(table).Data("passport", "user_300").Cache(gdb.CacheOption{
|
||||
Duration: time.Second,
|
||||
Name: "test3",
|
||||
Force: false,
|
||||
}).WherePri(3).Update()
|
||||
t.AssertNil(err)
|
||||
n, err := r.RowsAffected()
|
||||
t.AssertNil(err)
|
||||
t.Assert(n, 1)
|
||||
|
||||
err = db.Transaction(context.TODO(), func(ctx context.Context, tx *gdb.TX) error {
|
||||
one, err := tx.Model(table).Cache(time.Second, "test3").WherePri(3).One()
|
||||
one, err := tx.Model(table).Cache(gdb.CacheOption{
|
||||
Duration: time.Second,
|
||||
Name: "test3",
|
||||
Force: false,
|
||||
}).WherePri(3).One()
|
||||
t.AssertNil(err)
|
||||
t.Assert(one["passport"], "user_300")
|
||||
return nil
|
||||
})
|
||||
t.AssertNil(err)
|
||||
|
||||
one, err = db.Model(table).Cache(time.Second, "test3").WherePri(3).One()
|
||||
one, err = db.Model(table).Cache(gdb.CacheOption{
|
||||
Duration: time.Second,
|
||||
Name: "test3",
|
||||
Force: false,
|
||||
}).WherePri(3).One()
|
||||
t.AssertNil(err)
|
||||
t.Assert(one["passport"], "user_3")
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
// make cache for id 4
|
||||
one, err := db.Model(table).Cache(time.Second, "test4").WherePri(4).One()
|
||||
one, err := db.Model(table).Cache(gdb.CacheOption{
|
||||
Duration: time.Second,
|
||||
Name: "test4",
|
||||
Force: false,
|
||||
}).WherePri(4).One()
|
||||
t.AssertNil(err)
|
||||
t.Assert(one["passport"], "user_4")
|
||||
|
||||
r, err := db.Model(table).Data("passport", "user_400").Cache(time.Second, "test3").WherePri(4).Update()
|
||||
r, err := db.Model(table).Data("passport", "user_400").Cache(gdb.CacheOption{
|
||||
Duration: time.Second,
|
||||
Name: "test3",
|
||||
Force: false,
|
||||
}).WherePri(4).Update()
|
||||
t.AssertNil(err)
|
||||
n, err := r.RowsAffected()
|
||||
t.AssertNil(err)
|
||||
@ -2553,12 +2601,20 @@ func Test_Model_Cache(t *testing.T) {
|
||||
|
||||
err = db.Transaction(context.TODO(), func(ctx context.Context, tx *gdb.TX) error {
|
||||
// Cache feature disabled.
|
||||
one, err := tx.Model(table).Cache(time.Second, "test4").WherePri(4).One()
|
||||
one, err := tx.Model(table).Cache(gdb.CacheOption{
|
||||
Duration: time.Second,
|
||||
Name: "test4",
|
||||
Force: false,
|
||||
}).WherePri(4).One()
|
||||
t.AssertNil(err)
|
||||
t.Assert(one["passport"], "user_400")
|
||||
// Update the cache.
|
||||
r, err := tx.Model(table).Data("passport", "user_4000").
|
||||
Cache(-1, "test4").WherePri(4).Update()
|
||||
Cache(gdb.CacheOption{
|
||||
Duration: -1,
|
||||
Name: "test4",
|
||||
Force: false,
|
||||
}).WherePri(4).Update()
|
||||
t.AssertNil(err)
|
||||
n, err := r.RowsAffected()
|
||||
t.AssertNil(err)
|
||||
@ -2567,7 +2623,11 @@ func Test_Model_Cache(t *testing.T) {
|
||||
})
|
||||
t.AssertNil(err)
|
||||
// Read from db.
|
||||
one, err = db.Model(table).Cache(time.Second, "test4").WherePri(4).One()
|
||||
one, err = db.Model(table).Cache(gdb.CacheOption{
|
||||
Duration: time.Second,
|
||||
Name: "test4",
|
||||
Force: false,
|
||||
}).WherePri(4).One()
|
||||
t.AssertNil(err)
|
||||
t.Assert(one["passport"], "user_4000")
|
||||
})
|
||||
@ -3676,6 +3736,87 @@ func Test_Model_FieldAvg(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Model_OmitEmptyWhere(t *testing.T) {
|
||||
table := createInitTable()
|
||||
defer dropTable(table)
|
||||
|
||||
// Basic type where.
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
count, err := db.Model(table).Where("id", 0).Count()
|
||||
t.AssertNil(err)
|
||||
t.Assert(count, 0)
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
count, err := db.Model(table).OmitEmptyWhere().Where("id", 0).Count()
|
||||
t.AssertNil(err)
|
||||
t.Assert(count, TableSize)
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
count, err := db.Model(table).OmitEmptyWhere().Where("id", 0).Where("nickname", "").Count()
|
||||
t.AssertNil(err)
|
||||
t.Assert(count, TableSize)
|
||||
})
|
||||
// Slice where.
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
count, err := db.Model(table).Where("id", g.Slice{1, 2, 3}).Count()
|
||||
t.AssertNil(err)
|
||||
t.Assert(count, 3)
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
count, err := db.Model(table).Where("id", g.Slice{}).Count()
|
||||
t.AssertNil(err)
|
||||
t.Assert(count, 0)
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
count, err := db.Model(table).OmitEmptyWhere().Where("id", g.Slice{}).Count()
|
||||
t.AssertNil(err)
|
||||
t.Assert(count, TableSize)
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
count, err := db.Model(table).Where("id", g.Slice{}).OmitEmptyWhere().Count()
|
||||
t.AssertNil(err)
|
||||
t.Assert(count, TableSize)
|
||||
})
|
||||
// Struct Where.
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
type Input struct {
|
||||
Id []int
|
||||
Name []string
|
||||
}
|
||||
count, err := db.Model(table).Where(Input{}).Count()
|
||||
t.AssertNil(err)
|
||||
t.Assert(count, 0)
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
type Input struct {
|
||||
Id []int
|
||||
Name []string
|
||||
}
|
||||
count, err := db.Model(table).Where(Input{}).OmitEmptyWhere().Count()
|
||||
t.AssertNil(err)
|
||||
t.Assert(count, TableSize)
|
||||
})
|
||||
// Map Where.
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
count, err := db.Model(table).Where(g.Map{
|
||||
"id": []int{},
|
||||
"nickname": []string{},
|
||||
}).Count()
|
||||
t.AssertNil(err)
|
||||
t.Assert(count, 0)
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
type Input struct {
|
||||
Id []int
|
||||
}
|
||||
count, err := db.Model(table).Where(g.Map{
|
||||
"id": []int{},
|
||||
}).OmitEmptyWhere().Count()
|
||||
t.AssertNil(err)
|
||||
t.Assert(count, TableSize)
|
||||
})
|
||||
}
|
||||
|
||||
// https://github.com/gogf/gf/issues/1387
|
||||
func Test_Model_GTime_DefaultValue(t *testing.T) {
|
||||
table := createTable()
|
||||
99
database/gdb/gdb_z_mysql_model_for_dao_test.go
Normal file
99
database/gdb/gdb_z_mysql_model_for_dao_test.go
Normal file
@ -0,0 +1,99 @@
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package gdb_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/test/gtest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_Model_Insert_Data_ForDao(t *testing.T) {
|
||||
table := createTable()
|
||||
defer dropTable(table)
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
type UserForDao struct {
|
||||
Id interface{}
|
||||
Passport interface{}
|
||||
Password interface{}
|
||||
Nickname interface{}
|
||||
CreateTime interface{}
|
||||
}
|
||||
data := UserForDao{
|
||||
Id: 1,
|
||||
Passport: "user_1",
|
||||
Password: "pass_1",
|
||||
}
|
||||
result, err := db.Model(table).Data(data).Insert()
|
||||
t.AssertNil(err)
|
||||
n, _ := result.LastInsertId()
|
||||
t.Assert(n, 1)
|
||||
|
||||
one, err := db.Model(table).WherePri(1).One()
|
||||
t.AssertNil(err)
|
||||
t.Assert(one[`id`], `1`)
|
||||
t.Assert(one[`passport`], `user_1`)
|
||||
t.Assert(one[`password`], `pass_1`)
|
||||
t.Assert(one[`nickname`], ``)
|
||||
t.Assert(one[`create_time`], ``)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Model_Update_Data_ForDao(t *testing.T) {
|
||||
table := createInitTable()
|
||||
defer dropTable(table)
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
type UserForDao struct {
|
||||
Id interface{}
|
||||
Passport interface{}
|
||||
Password interface{}
|
||||
Nickname interface{}
|
||||
CreateTime interface{}
|
||||
}
|
||||
data := UserForDao{
|
||||
Id: 1,
|
||||
Passport: "user_100",
|
||||
Password: "pass_100",
|
||||
}
|
||||
_, err := db.Model(table).Data(data).WherePri(1).Update()
|
||||
t.AssertNil(err)
|
||||
|
||||
one, err := db.Model(table).WherePri(1).One()
|
||||
t.AssertNil(err)
|
||||
t.Assert(one[`id`], `1`)
|
||||
t.Assert(one[`passport`], `user_100`)
|
||||
t.Assert(one[`password`], `pass_100`)
|
||||
t.Assert(one[`nickname`], `name_1`)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Model_Where_ForDao(t *testing.T) {
|
||||
table := createInitTable()
|
||||
defer dropTable(table)
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
type UserForDao struct {
|
||||
Id interface{}
|
||||
Passport interface{}
|
||||
Password interface{}
|
||||
Nickname interface{}
|
||||
CreateTime interface{}
|
||||
}
|
||||
where := UserForDao{
|
||||
Id: 1,
|
||||
Passport: "user_1",
|
||||
Password: "pass_1",
|
||||
}
|
||||
one, err := db.Model(table).Where(where).One()
|
||||
t.AssertNil(err)
|
||||
t.Assert(one[`id`], `1`)
|
||||
t.Assert(one[`passport`], `user_1`)
|
||||
t.Assert(one[`password`], `pass_1`)
|
||||
t.Assert(one[`nickname`], `name_1`)
|
||||
})
|
||||
}
|
||||
83
database/gdb/gdb_z_mysql_model_join_test.go
Normal file
83
database/gdb/gdb_z_mysql_model_join_test.go
Normal file
@ -0,0 +1,83 @@
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package gdb_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"github.com/gogf/gf/v2/test/gtest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_Model_LeftJoinOnField(t *testing.T) {
|
||||
var (
|
||||
table1 = gtime.TimestampNanoStr() + "_table1"
|
||||
table2 = gtime.TimestampNanoStr() + "_table2"
|
||||
)
|
||||
createInitTable(table1)
|
||||
defer dropTable(table1)
|
||||
createInitTable(table2)
|
||||
defer dropTable(table2)
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
r, err := db.Model(table1).
|
||||
FieldsPrefix(table1, "*").
|
||||
LeftJoinOnField(table2, "id").
|
||||
WhereIn("id", g.Slice{1, 2}).
|
||||
Order("id asc").All()
|
||||
t.AssertNil(err)
|
||||
t.Assert(len(r), 2)
|
||||
t.Assert(r[0]["id"], "1")
|
||||
t.Assert(r[1]["id"], "2")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Model_RightJoinOnField(t *testing.T) {
|
||||
var (
|
||||
table1 = gtime.TimestampNanoStr() + "_table1"
|
||||
table2 = gtime.TimestampNanoStr() + "_table2"
|
||||
)
|
||||
createInitTable(table1)
|
||||
defer dropTable(table1)
|
||||
createInitTable(table2)
|
||||
defer dropTable(table2)
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
r, err := db.Model(table1).
|
||||
FieldsPrefix(table1, "*").
|
||||
RightJoinOnField(table2, "id").
|
||||
WhereIn("id", g.Slice{1, 2}).
|
||||
Order("id asc").All()
|
||||
t.AssertNil(err)
|
||||
t.Assert(len(r), 2)
|
||||
t.Assert(r[0]["id"], "1")
|
||||
t.Assert(r[1]["id"], "2")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Model_InnerJoinOnField(t *testing.T) {
|
||||
var (
|
||||
table1 = gtime.TimestampNanoStr() + "_table1"
|
||||
table2 = gtime.TimestampNanoStr() + "_table2"
|
||||
)
|
||||
createInitTable(table1)
|
||||
defer dropTable(table1)
|
||||
createInitTable(table2)
|
||||
defer dropTable(table2)
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
r, err := db.Model(table1).
|
||||
FieldsPrefix(table1, "*").
|
||||
InnerJoinOnField(table2, "id").
|
||||
WhereIn("id", g.Slice{1, 2}).
|
||||
Order("id asc").All()
|
||||
t.AssertNil(err)
|
||||
t.Assert(len(r), 2)
|
||||
t.Assert(r[0]["id"], "1")
|
||||
t.Assert(r[1]["id"], "2")
|
||||
})
|
||||
}
|
||||
70
database/gdb/gdb_z_mysql_model_where_test.go
Normal file
70
database/gdb/gdb_z_mysql_model_where_test.go
Normal file
@ -0,0 +1,70 @@
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package gdb_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"github.com/gogf/gf/v2/test/gtest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_Model_WherePrefix(t *testing.T) {
|
||||
var (
|
||||
table1 = gtime.TimestampNanoStr() + "_table1"
|
||||
table2 = gtime.TimestampNanoStr() + "_table2"
|
||||
)
|
||||
createInitTable(table1)
|
||||
defer dropTable(table1)
|
||||
createInitTable(table2)
|
||||
defer dropTable(table2)
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
r, err := db.Model(table1).
|
||||
FieldsPrefix(table1, "*").
|
||||
LeftJoinOnField(table2, "id").
|
||||
WherePrefix(table2, g.Map{
|
||||
"id": g.Slice{1, 2},
|
||||
}).
|
||||
Order("id asc").All()
|
||||
t.AssertNil(err)
|
||||
t.Assert(len(r), 2)
|
||||
t.Assert(r[0]["id"], "1")
|
||||
t.Assert(r[1]["id"], "2")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Model_WhereOrPrefix(t *testing.T) {
|
||||
var (
|
||||
table1 = gtime.TimestampNanoStr() + "_table1"
|
||||
table2 = gtime.TimestampNanoStr() + "_table2"
|
||||
)
|
||||
createInitTable(table1)
|
||||
defer dropTable(table1)
|
||||
createInitTable(table2)
|
||||
defer dropTable(table2)
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
r, err := db.Model(table1).
|
||||
FieldsPrefix(table1, "*").
|
||||
LeftJoinOnField(table2, "id").
|
||||
WhereOrPrefix(table1, g.Map{
|
||||
"id": g.Slice{1, 2},
|
||||
}).
|
||||
WhereOrPrefix(table2, g.Map{
|
||||
"id": g.Slice{8, 9},
|
||||
}).
|
||||
Order("id asc").All()
|
||||
t.AssertNil(err)
|
||||
t.Assert(len(r), 4)
|
||||
t.Assert(r[0]["id"], "1")
|
||||
t.Assert(r[1]["id"], "2")
|
||||
t.Assert(r[2]["id"], "8")
|
||||
t.Assert(r[3]["id"], "9")
|
||||
|
||||
})
|
||||
}
|
||||
@ -10,6 +10,7 @@ import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/container/gvar"
|
||||
"github.com/gogf/gf/v2/internal/json"
|
||||
"github.com/gogf/gf/v2/internal/utils"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"reflect"
|
||||
)
|
||||
@ -23,18 +24,11 @@ type RedisConn struct {
|
||||
// Do sends a command to the server and returns the received reply.
|
||||
// It uses json.Marshal for struct/slice/map type values before committing them to redis.
|
||||
func (c *RedisConn) Do(ctx context.Context, command string, args ...interface{}) (reply *gvar.Var, err error) {
|
||||
var (
|
||||
reflectValue reflect.Value
|
||||
reflectKind reflect.Kind
|
||||
)
|
||||
for k, v := range args {
|
||||
reflectValue = reflect.ValueOf(v)
|
||||
reflectKind = reflectValue.Kind()
|
||||
if reflectKind == reflect.Ptr {
|
||||
reflectValue = reflectValue.Elem()
|
||||
reflectKind = reflectValue.Kind()
|
||||
}
|
||||
switch reflectKind {
|
||||
var (
|
||||
reflectInfo = utils.OriginTypeAndKind(v)
|
||||
)
|
||||
switch reflectInfo.OriginKind {
|
||||
case
|
||||
reflect.Struct,
|
||||
reflect.Map,
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
// Package charset implements character-set conversion functionality.
|
||||
// Package gcharset implements character-set conversion functionality.
|
||||
//
|
||||
// Supported Character Set:
|
||||
//
|
||||
@ -21,8 +21,10 @@ package gcharset
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/errors/gcode"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/internal/intlog"
|
||||
"io/ioutil"
|
||||
|
||||
"golang.org/x/text/encoding"
|
||||
@ -104,8 +106,9 @@ func getEncoding(charset string) encoding.Encoding {
|
||||
if c, ok := charsetAlias[charset]; ok {
|
||||
charset = c
|
||||
}
|
||||
if e, err := ianaindex.MIB.Encoding(charset); err == nil && e != nil {
|
||||
return e
|
||||
enc, err := ianaindex.MIB.Encoding(charset)
|
||||
if err != nil {
|
||||
intlog.Error(context.TODO(), err)
|
||||
}
|
||||
return nil
|
||||
return enc
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
// Package ghash provides some classic hash functions(uint32/uint64) in go.
|
||||
package ghash
|
||||
|
||||
// BKDR Hash Function
|
||||
// BKDRHash implements the classic BKDR hash algorithm for 32 bits.
|
||||
func BKDRHash(str []byte) uint32 {
|
||||
var seed uint32 = 131 // 31 131 1313 13131 131313 etc..
|
||||
var hash uint32 = 0
|
||||
@ -17,7 +17,7 @@ func BKDRHash(str []byte) uint32 {
|
||||
return hash
|
||||
}
|
||||
|
||||
// BKDR Hash Function 64
|
||||
// BKDRHash64 implements the classic BKDR hash algorithm for 64 bits.
|
||||
func BKDRHash64(str []byte) uint64 {
|
||||
var seed uint64 = 131 // 31 131 1313 13131 131313 etc..
|
||||
var hash uint64 = 0
|
||||
@ -27,7 +27,7 @@ func BKDRHash64(str []byte) uint64 {
|
||||
return hash
|
||||
}
|
||||
|
||||
// SDBM Hash
|
||||
// SDBMHash implements the classic SDBM hash algorithm for 32 bits.
|
||||
func SDBMHash(str []byte) uint32 {
|
||||
var hash uint32 = 0
|
||||
for i := 0; i < len(str); i++ {
|
||||
@ -37,7 +37,7 @@ func SDBMHash(str []byte) uint32 {
|
||||
return hash
|
||||
}
|
||||
|
||||
// SDBM Hash 64
|
||||
// SDBMHash64 implements the classic SDBM hash algorithm for 64 bits.
|
||||
func SDBMHash64(str []byte) uint64 {
|
||||
var hash uint64 = 0
|
||||
for i := 0; i < len(str); i++ {
|
||||
@ -47,7 +47,7 @@ func SDBMHash64(str []byte) uint64 {
|
||||
return hash
|
||||
}
|
||||
|
||||
// RS Hash Function
|
||||
// RSHash implements the classic RS hash algorithm for 32 bits.
|
||||
func RSHash(str []byte) uint32 {
|
||||
var b uint32 = 378551
|
||||
var a uint32 = 63689
|
||||
@ -59,7 +59,7 @@ func RSHash(str []byte) uint32 {
|
||||
return hash
|
||||
}
|
||||
|
||||
// RS Hash Function 64
|
||||
// RSHash64 implements the classic RS hash algorithm for 64 bits.
|
||||
func RSHash64(str []byte) uint64 {
|
||||
var b uint64 = 378551
|
||||
var a uint64 = 63689
|
||||
@ -71,7 +71,7 @@ func RSHash64(str []byte) uint64 {
|
||||
return hash
|
||||
}
|
||||
|
||||
// JS Hash Function
|
||||
// JSHash implements the classic JS hash algorithm for 32 bits.
|
||||
func JSHash(str []byte) uint32 {
|
||||
var hash uint32 = 1315423911
|
||||
for i := 0; i < len(str); i++ {
|
||||
@ -80,7 +80,7 @@ func JSHash(str []byte) uint32 {
|
||||
return hash
|
||||
}
|
||||
|
||||
// JS Hash Function 64
|
||||
// JSHash64 implements the classic JS hash algorithm for 64 bits.
|
||||
func JSHash64(str []byte) uint64 {
|
||||
var hash uint64 = 1315423911
|
||||
for i := 0; i < len(str); i++ {
|
||||
@ -89,7 +89,7 @@ func JSHash64(str []byte) uint64 {
|
||||
return hash
|
||||
}
|
||||
|
||||
// P. J. Weinberger Hash Function
|
||||
// PJWHash implements the classic PJW hash algorithm for 32 bits.
|
||||
func PJWHash(str []byte) uint32 {
|
||||
var BitsInUnignedInt uint32 = 4 * 8
|
||||
var ThreeQuarters uint32 = (BitsInUnignedInt * 3) / 4
|
||||
@ -106,7 +106,7 @@ func PJWHash(str []byte) uint32 {
|
||||
return hash
|
||||
}
|
||||
|
||||
// P. J. Weinberger Hash Function 64
|
||||
// PJWHash64 implements the classic PJW hash algorithm for 64 bits.
|
||||
func PJWHash64(str []byte) uint64 {
|
||||
var BitsInUnignedInt uint64 = 4 * 8
|
||||
var ThreeQuarters uint64 = (BitsInUnignedInt * 3) / 4
|
||||
@ -123,7 +123,7 @@ func PJWHash64(str []byte) uint64 {
|
||||
return hash
|
||||
}
|
||||
|
||||
// ELF Hash Function
|
||||
// ELFHash implements the classic ELF hash algorithm for 32 bits.
|
||||
func ELFHash(str []byte) uint32 {
|
||||
var hash uint32 = 0
|
||||
var x uint32 = 0
|
||||
@ -137,7 +137,7 @@ func ELFHash(str []byte) uint32 {
|
||||
return hash
|
||||
}
|
||||
|
||||
// ELF Hash Function 64
|
||||
// ELFHash64 implements the classic ELF hash algorithm for 64 bits.
|
||||
func ELFHash64(str []byte) uint64 {
|
||||
var hash uint64 = 0
|
||||
var x uint64 = 0
|
||||
@ -151,7 +151,7 @@ func ELFHash64(str []byte) uint64 {
|
||||
return hash
|
||||
}
|
||||
|
||||
// DJB Hash Function
|
||||
// DJBHash implements the classic DJB hash algorithm for 32 bits.
|
||||
func DJBHash(str []byte) uint32 {
|
||||
var hash uint32 = 5381
|
||||
for i := 0; i < len(str); i++ {
|
||||
@ -160,7 +160,7 @@ func DJBHash(str []byte) uint32 {
|
||||
return hash
|
||||
}
|
||||
|
||||
// DJB Hash Function 64.
|
||||
// DJBHash64 implements the classic DJB hash algorithm for 64 bits.
|
||||
func DJBHash64(str []byte) uint64 {
|
||||
var hash uint64 = 5381
|
||||
for i := 0; i < len(str); i++ {
|
||||
@ -169,7 +169,7 @@ func DJBHash64(str []byte) uint64 {
|
||||
return hash
|
||||
}
|
||||
|
||||
// AP Hash Function
|
||||
// APHash implements the classic AP hash algorithm for 32 bits.
|
||||
func APHash(str []byte) uint32 {
|
||||
var hash uint32 = 0
|
||||
for i := 0; i < len(str); i++ {
|
||||
@ -182,7 +182,7 @@ func APHash(str []byte) uint32 {
|
||||
return hash
|
||||
}
|
||||
|
||||
// AP Hash Function 64
|
||||
// APHash64 implements the classic AP hash algorithm for 64 bits.
|
||||
func APHash64(str []byte) uint64 {
|
||||
var hash uint64 = 0
|
||||
for i := 0; i < len(str); i++ {
|
||||
|
||||
@ -1,3 +1,9 @@
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package ghash_test
|
||||
|
||||
import (
|
||||
|
||||
@ -65,7 +65,7 @@ func Decode(data []byte) (res map[string]interface{}, err error) {
|
||||
|
||||
if strings.Contains(lineStr, "=") && haveSection {
|
||||
values := strings.Split(lineStr, "=")
|
||||
fieldMap[strings.TrimSpace(values[0])] = strings.TrimSpace(strings.Join(values[1:], ""))
|
||||
fieldMap[strings.TrimSpace(values[0])] = strings.TrimSpace(strings.Join(values[1:], "="))
|
||||
res[section] = fieldMap
|
||||
}
|
||||
}
|
||||
|
||||
@ -22,6 +22,7 @@ aa=bb
|
||||
ip = 127.0.0.1
|
||||
port=9001
|
||||
enable=true
|
||||
command=/bin/echo "gf=GoFrame"
|
||||
|
||||
[DBINFO]
|
||||
type=mysql
|
||||
@ -40,6 +41,7 @@ func TestDecode(t *testing.T) {
|
||||
}
|
||||
t.Assert(res["addr"].(map[string]interface{})["ip"], "127.0.0.1")
|
||||
t.Assert(res["addr"].(map[string]interface{})["port"], "9001")
|
||||
t.Assert(res["addr"].(map[string]interface{})["command"], `/bin/echo "gf=GoFrame"`)
|
||||
t.Assert(res["DBINFO"].(map[string]interface{})["user"], "root")
|
||||
t.Assert(res["DBINFO"].(map[string]interface{})["type"], "mysql")
|
||||
t.Assert(res["键"].(map[string]interface{})["呵呵"], "值")
|
||||
|
||||
@ -259,13 +259,10 @@ func (j *Json) convertValue(value interface{}) interface{} {
|
||||
case []interface{}:
|
||||
return value
|
||||
default:
|
||||
rv := reflect.ValueOf(value)
|
||||
kind := rv.Kind()
|
||||
if kind == reflect.Ptr {
|
||||
rv = rv.Elem()
|
||||
kind = rv.Kind()
|
||||
}
|
||||
switch kind {
|
||||
var (
|
||||
reflectInfo = utils.OriginValueAndKind(value)
|
||||
)
|
||||
switch reflectInfo.OriginKind {
|
||||
case reflect.Array:
|
||||
return gconv.Interfaces(value)
|
||||
case reflect.Slice:
|
||||
|
||||
@ -10,6 +10,7 @@ import (
|
||||
"bytes"
|
||||
"github.com/gogf/gf/v2/errors/gcode"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/internal/utils"
|
||||
"reflect"
|
||||
|
||||
"github.com/gogf/gf/v2/internal/json"
|
||||
@ -68,14 +69,9 @@ func NewWithOptions(data interface{}, options Options) *Json {
|
||||
}
|
||||
default:
|
||||
var (
|
||||
rv = reflect.ValueOf(data)
|
||||
kind = rv.Kind()
|
||||
reflectInfo = utils.OriginValueAndKind(data)
|
||||
)
|
||||
if kind == reflect.Ptr {
|
||||
rv = rv.Elem()
|
||||
kind = rv.Kind()
|
||||
}
|
||||
switch kind {
|
||||
switch reflectInfo.OriginKind {
|
||||
case reflect.Slice, reflect.Array:
|
||||
i := interface{}(nil)
|
||||
i = gconv.Interfaces(data)
|
||||
|
||||
@ -48,10 +48,10 @@ func Example_conversionNormalFormats() {
|
||||
// ======================
|
||||
// YAML:
|
||||
// users:
|
||||
// array:
|
||||
// - John
|
||||
// - Ming
|
||||
// count: 1
|
||||
// array:
|
||||
// - John
|
||||
// - Ming
|
||||
// count: 1
|
||||
//
|
||||
// ======================
|
||||
// TOML:
|
||||
|
||||
@ -246,3 +246,46 @@ enable=true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Load_YamlWithV3(t *testing.T) {
|
||||
content := `
|
||||
# CLI tool, only in development environment.
|
||||
# https://goframe.org/pages/viewpage.action?pageId=3673173
|
||||
gfcli:
|
||||
gen:
|
||||
dao:
|
||||
- path : "../../pkg/oss/oss/internal"
|
||||
group : "oss"
|
||||
stdTime : true
|
||||
descriptionTag : true
|
||||
noJsonTag : true
|
||||
noModelComment : true
|
||||
overwriteDao : true
|
||||
modelFileForDao : "model_dao.go"
|
||||
tablesEx : |
|
||||
bpmn_info,
|
||||
dlocker,
|
||||
dlocker_detail,
|
||||
message_table,
|
||||
monitor_data,
|
||||
resource_param_info,
|
||||
version_info,
|
||||
version_topology_info,
|
||||
work_flow,
|
||||
work_flow_step_info,
|
||||
work_flow_undo_step_info
|
||||
|
||||
- path : "../../pkg/oss/workflow/internal"
|
||||
group : "workflow"
|
||||
stdTime : true
|
||||
descriptionTag : true
|
||||
noJsonTag : true
|
||||
noModelComment : true
|
||||
overwriteDao : true
|
||||
modelFileForDao : "model_dao.go"
|
||||
`
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
_, err := gjson.LoadContent(content)
|
||||
t.AssertNil(err)
|
||||
})
|
||||
}
|
||||
|
||||
@ -8,32 +8,50 @@
|
||||
package gyaml
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/internal/json"
|
||||
"gopkg.in/yaml.v2"
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
func Encode(v interface{}) ([]byte, error) {
|
||||
return yaml.Marshal(v)
|
||||
func Encode(value interface{}) (out []byte, err error) {
|
||||
if out, err = yaml.Marshal(value); err != nil {
|
||||
err = gerror.Wrap(err, `encode value to yaml failed`)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func Decode(v []byte) (interface{}, error) {
|
||||
var result map[string]interface{}
|
||||
if err := yaml.Unmarshal(v, &result); err != nil {
|
||||
func Decode(value []byte) (interface{}, error) {
|
||||
var (
|
||||
result map[string]interface{}
|
||||
err error
|
||||
)
|
||||
if err = yaml.Unmarshal(value, &result); err != nil {
|
||||
err = gerror.Wrap(err, `decode yaml failed`)
|
||||
return nil, err
|
||||
}
|
||||
return gconv.MapDeep(result), nil
|
||||
}
|
||||
|
||||
func DecodeTo(v []byte, result interface{}) error {
|
||||
return yaml.Unmarshal(v, result)
|
||||
func DecodeTo(value []byte, result interface{}) (err error) {
|
||||
err = yaml.Unmarshal(value, result)
|
||||
if err != nil {
|
||||
err = gerror.Wrap(err, `encode yaml to value failed`)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func ToJson(v []byte) ([]byte, error) {
|
||||
if r, err := Decode(v); err != nil {
|
||||
func ToJson(value []byte) (out []byte, err error) {
|
||||
var (
|
||||
result interface{}
|
||||
)
|
||||
if result, err = Decode(value); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return json.Marshal(r)
|
||||
if out, err = json.Marshal(result); err != nil {
|
||||
err = gerror.Wrap(err, `convert yaml to json failed`)
|
||||
}
|
||||
return out, err
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,10 +38,10 @@ func Dump(values ...interface{}) {
|
||||
gutil.Dump(values...)
|
||||
}
|
||||
|
||||
// DumpBrief acts like Dump, but with no type information.
|
||||
// DumpWithType acts like Dump, but with type information.
|
||||
// Also see Dump.
|
||||
func DumpBrief(values ...interface{}) {
|
||||
gutil.DumpBrief(values...)
|
||||
func DumpWithType(values ...interface{}) {
|
||||
gutil.DumpWithType(values...)
|
||||
}
|
||||
|
||||
// Throw throws an exception, which can be caught by TryCatch function.
|
||||
|
||||
@ -60,7 +60,7 @@ func Server(name ...interface{}) *ghttp.Server {
|
||||
}
|
||||
} else {
|
||||
// The configuration is not necessary, so it just prints internal logs.
|
||||
intlog.Printf(ctx, `missing configuration for HTTP server "%s"`, instanceName)
|
||||
intlog.Printf(ctx, `missing configuration from configuration component for HTTP server "%s"`, instanceName)
|
||||
}
|
||||
|
||||
// Server logger configuration checks.
|
||||
|
||||
2
go.mod
2
go.mod
@ -16,5 +16,5 @@ require (
|
||||
go.opentelemetry.io/otel/trace v1.0.0
|
||||
golang.org/x/net v0.0.0-20210520170846-37e1c6afe023
|
||||
golang.org/x/text v0.3.6
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
|
||||
)
|
||||
|
||||
23
go.sum
23
go.sum
@ -15,14 +15,6 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI=
|
||||
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
|
||||
github.com/getkin/kin-openapi v0.76.0 h1:j77zg3Ec+k+r+GA3d8hBoXpAc6KX9TbBPrwQGBIy2sY=
|
||||
github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg=
|
||||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
|
||||
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY=
|
||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-redis/redis/v8 v8.11.3 h1:GCjoYp8c+yQTJfc0n69iwSiHjvuAdruxl7elnZCxgt8=
|
||||
github.com/go-redis/redis/v8 v8.11.3/go.mod h1:xNJ9xDG09FsIPwh3bWdk+0oDWHbtF9rPN0F/oD9XeKc=
|
||||
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
|
||||
@ -44,20 +36,11 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/grokify/html-strip-tags-go v0.0.1 h1:0fThFwLbW7P/kOiTBs03FsJSV9RM2M/Q/MOnCQxKMo0=
|
||||
github.com/grokify/html-strip-tags-go v0.0.1/go.mod h1:2Su6romC5/1VXOQMaWL2yb618ARB8iVo6/DR99A6d78=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e h1:hB2xlXdHp/pmPZq0y3QnmWAArdw9PqbmotexnWx/FU8=
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
|
||||
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
@ -80,7 +63,6 @@ github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+t
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
@ -141,9 +123,8 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
@ -154,3 +135,5 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
||||
@ -116,9 +116,6 @@ type FieldsInput struct {
|
||||
// RecursiveOption specifies the way retrieving the fields recursively if the attribute
|
||||
// is an embedded struct. It is RecursiveOptionNone in default.
|
||||
RecursiveOption int
|
||||
|
||||
// fieldFilterMap is used internally for repeated fields filtering.
|
||||
fieldFilterMap map[string]struct{}
|
||||
}
|
||||
|
||||
type FieldMapInput struct {
|
||||
@ -136,19 +133,28 @@ type FieldMapInput struct {
|
||||
|
||||
// Fields retrieves and returns the fields of `pointer` as slice.
|
||||
func Fields(in FieldsInput) ([]*Field, error) {
|
||||
if in.fieldFilterMap == nil {
|
||||
in.fieldFilterMap = make(map[string]struct{})
|
||||
}
|
||||
var (
|
||||
retrievedFields = make([]*Field, 0)
|
||||
ok bool
|
||||
fieldFilterMap = make(map[string]struct{})
|
||||
retrievedFields = make([]*Field, 0)
|
||||
currentLevelFieldMap = make(map[string]*Field)
|
||||
)
|
||||
rangeFields, err := getFieldValues(in.Pointer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for index := 0; index < len(rangeFields); index++ {
|
||||
field := rangeFields[index]
|
||||
if _, ok := in.fieldFilterMap[field.Name()]; ok {
|
||||
if !field.IsExported() {
|
||||
continue
|
||||
}
|
||||
currentLevelFieldMap[field.Name()] = field
|
||||
}
|
||||
|
||||
for index := 0; index < len(rangeFields); index++ {
|
||||
field := rangeFields[index]
|
||||
if _, ok = fieldFilterMap[field.Name()]; ok {
|
||||
continue
|
||||
}
|
||||
// It only retrieves exported attributes.
|
||||
@ -167,18 +173,32 @@ func Fields(in FieldsInput) ([]*Field, error) {
|
||||
structFields, err := Fields(FieldsInput{
|
||||
Pointer: field.Value,
|
||||
RecursiveOption: in.RecursiveOption,
|
||||
fieldFilterMap: in.fieldFilterMap,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
retrievedFields = append(retrievedFields, structFields...)
|
||||
// The current level fields can overwrite the sub-struct fields with the same name.
|
||||
for i := 0; i < len(structFields); i++ {
|
||||
var (
|
||||
structField = structFields[i]
|
||||
fieldName = structField.Name()
|
||||
)
|
||||
if _, ok = fieldFilterMap[fieldName]; ok {
|
||||
continue
|
||||
}
|
||||
fieldFilterMap[fieldName] = struct{}{}
|
||||
if v := currentLevelFieldMap[fieldName]; v == nil {
|
||||
retrievedFields = append(retrievedFields, structField)
|
||||
} else {
|
||||
retrievedFields = append(retrievedFields, v)
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
in.fieldFilterMap[field.Name()] = struct{}{}
|
||||
fieldFilterMap[field.Name()] = struct{}{}
|
||||
retrievedFields = append(retrievedFields, field)
|
||||
}
|
||||
return retrievedFields, nil
|
||||
|
||||
@ -125,7 +125,7 @@ func Test_Fields(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Fields_WithEmbedded(t *testing.T) {
|
||||
func Test_Fields_WithEmbedded1(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
type B struct {
|
||||
Name string
|
||||
@ -149,6 +149,44 @@ func Test_Fields_WithEmbedded(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Fields_WithEmbedded2(t *testing.T) {
|
||||
type MetaNode struct {
|
||||
Id uint `orm:"id,primary" description:""`
|
||||
Capacity string `orm:"capacity" description:"Capacity string"`
|
||||
Allocatable string `orm:"allocatable" description:"Allocatable string"`
|
||||
Status string `orm:"status" description:"Status string"`
|
||||
}
|
||||
type MetaNodeZone struct {
|
||||
Nodes uint
|
||||
Clusters uint
|
||||
Disk uint
|
||||
Cpu uint
|
||||
Memory uint
|
||||
Zone string
|
||||
}
|
||||
|
||||
type MetaNodeItem struct {
|
||||
MetaNode
|
||||
Capacity []MetaNodeZone `dc:"Capacity []MetaNodeZone"`
|
||||
Allocatable []MetaNodeZone `dc:"Allocatable []MetaNodeZone"`
|
||||
}
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
r, err := structs.Fields(structs.FieldsInput{
|
||||
Pointer: new(MetaNodeItem),
|
||||
RecursiveOption: structs.RecursiveOptionEmbeddedNoTag,
|
||||
})
|
||||
t.AssertNil(err)
|
||||
t.Assert(len(r), 4)
|
||||
t.Assert(r[0].Name(), `Id`)
|
||||
t.Assert(r[1].Name(), `Capacity`)
|
||||
t.Assert(r[1].TagStr(), `dc:"Capacity []MetaNodeZone"`)
|
||||
t.Assert(r[2].Name(), `Allocatable`)
|
||||
t.Assert(r[2].TagStr(), `dc:"Allocatable []MetaNodeZone"`)
|
||||
t.Assert(r[3].Name(), `Status`)
|
||||
})
|
||||
}
|
||||
|
||||
// Filter repeated fields when there is embedded struct.
|
||||
func Test_Fields_WithEmbedded_Filter(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
|
||||
@ -13,7 +13,7 @@ import (
|
||||
|
||||
// IsNil checks whether `value` is nil.
|
||||
func IsNil(value interface{}) bool {
|
||||
return value == nil
|
||||
return empty.IsNil(value)
|
||||
}
|
||||
|
||||
// IsEmpty checks whether `value` is empty.
|
||||
|
||||
37
internal/utils/utils_list.go
Normal file
37
internal/utils/utils_list.go
Normal file
@ -0,0 +1,37 @@
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package utils
|
||||
|
||||
import "fmt"
|
||||
|
||||
// ListToMapByKey converts `list` to a map[string]interface{} of which key is specified by `key`.
|
||||
// Note that the item value may be type of slice.
|
||||
func ListToMapByKey(list []map[string]interface{}, key string) map[string]interface{} {
|
||||
var (
|
||||
s = ""
|
||||
m = make(map[string]interface{})
|
||||
tempMap = make(map[string][]interface{})
|
||||
hasMultiValues bool
|
||||
)
|
||||
for _, item := range list {
|
||||
if k, ok := item[key]; ok {
|
||||
s = fmt.Sprintf(`%v`, k)
|
||||
tempMap[s] = append(tempMap[s], item)
|
||||
if len(tempMap[s]) > 1 {
|
||||
hasMultiValues = true
|
||||
}
|
||||
}
|
||||
}
|
||||
for k, v := range tempMap {
|
||||
if hasMultiValues {
|
||||
m[k] = v
|
||||
} else {
|
||||
m[k] = v[0]
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
26
internal/utils/utils_map.go
Normal file
26
internal/utils/utils_map.go
Normal file
@ -0,0 +1,26 @@
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package utils
|
||||
|
||||
// MapPossibleItemByKey tries to find the possible key-value pair for given key ignoring cases and symbols.
|
||||
//
|
||||
// Note that this function might be of low performance.
|
||||
func MapPossibleItemByKey(data map[string]interface{}, key string) (foundKey string, foundValue interface{}) {
|
||||
if len(data) == 0 {
|
||||
return
|
||||
}
|
||||
if v, ok := data[key]; ok {
|
||||
return key, v
|
||||
}
|
||||
// Loop checking.
|
||||
for k, v := range data {
|
||||
if EqualFoldWithoutChars(k, key) {
|
||||
return k, v
|
||||
}
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
61
internal/utils/utils_reflect.go
Normal file
61
internal/utils/utils_reflect.go
Normal file
@ -0,0 +1,61 @@
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package utils
|
||||
|
||||
import "reflect"
|
||||
|
||||
type OriginValueAndKindOutput struct {
|
||||
InputValue reflect.Value
|
||||
InputKind reflect.Kind
|
||||
OriginValue reflect.Value
|
||||
OriginKind reflect.Kind
|
||||
}
|
||||
|
||||
// OriginValueAndKind retrieves and returns the original reflect value and kind.
|
||||
func OriginValueAndKind(value interface{}) (out OriginValueAndKindOutput) {
|
||||
if v, ok := value.(reflect.Value); ok {
|
||||
out.InputValue = v
|
||||
} else {
|
||||
out.InputValue = reflect.ValueOf(value)
|
||||
}
|
||||
out.InputKind = out.InputValue.Kind()
|
||||
out.OriginValue = out.InputValue
|
||||
out.OriginKind = out.InputKind
|
||||
for out.OriginKind == reflect.Ptr {
|
||||
out.OriginValue = out.OriginValue.Elem()
|
||||
out.OriginKind = out.OriginValue.Kind()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type OriginTypeAndKindOutput struct {
|
||||
InputType reflect.Type
|
||||
InputKind reflect.Kind
|
||||
OriginType reflect.Type
|
||||
OriginKind reflect.Kind
|
||||
}
|
||||
|
||||
// OriginTypeAndKind retrieves and returns the original reflect type and kind.
|
||||
func OriginTypeAndKind(value interface{}) (out OriginTypeAndKindOutput) {
|
||||
if reflectType, ok := value.(reflect.Type); ok {
|
||||
out.InputType = reflectType
|
||||
} else {
|
||||
if reflectValue, ok := value.(reflect.Value); ok {
|
||||
out.InputType = reflectValue.Type()
|
||||
} else {
|
||||
out.InputType = reflect.TypeOf(value)
|
||||
}
|
||||
}
|
||||
out.InputKind = out.InputType.Kind()
|
||||
out.OriginType = out.InputType
|
||||
out.OriginKind = out.InputKind
|
||||
for out.OriginKind == reflect.Ptr {
|
||||
out.OriginType = out.OriginType.Elem()
|
||||
out.OriginKind = out.OriginType.Kind()
|
||||
}
|
||||
return
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user