Compare commits

..

156 Commits

Author SHA1 Message Date
1a7450b9e9 v2.0.0-beta 2021-11-14 11:36:59 +08:00
684fa9b9c9 Merge pull request #1467 from 564104865/zhiwei
update cache
2021-11-11 23:53:45 +08:00
4e91039254 Update gcache_z_example_cache_test.go 2021-11-11 23:37:01 +08:00
195e167502 Update gcache_z_example_cache_test.go 2021-11-11 23:29:29 +08:00
01a50b06cb Update gcache_z_example_cache_test.go 2021-11-11 22:32:08 +08:00
9b663b4c2b Update gcache_z_example_cache_test.go 2021-11-11 22:18:01 +08:00
655426c322 Update gcache_z_example_cache_test.go 2021-11-11 21:19:33 +08:00
ae27afaeb4 Merge branch 'zhiwei' of https://github.com/564104865/gf into zhiwei 2021-11-10 16:46:20 +08:00
30f462288e Update gcache_z_example_cache_test.go 2021-11-10 16:39:26 +08:00
4862505c5e Merge branch 'gogf:master' into zhiwei 2021-11-10 16:37:56 +08:00
31d793fafb improve example for package gqueue 2021-11-10 00:20:00 +08:00
be274478d0 Merge branch 'zhiwei' of https://github.com/564104865/gf into zhiwei 2021-11-09 20:47:28 +08:00
5b8c91a877 Merge branch 'gogf:master' into zhiwei 2021-11-09 20:46:12 +08:00
95a4690e69 improve error feature for package gvalid 2021-11-09 17:50:14 +08:00
e0a0fcbde2 improve cache feature for package gdb 2021-11-09 16:06:31 +08:00
02e1d01f29 improve RuleFunc for package gvalid 2021-11-09 15:22:17 +08:00
e0db3c87cf improve RuleFunc for package gvalid 2021-11-09 14:31:16 +08:00
903299728f update Must Cache 2021-11-09 11:46:53 +08:00
c617ad6a04 Merge branch 'gogf:master' into zhiwei 2021-11-09 11:38:05 +08:00
814649e7a3 Merge branch 'master' of https://github.com/gogf/gf 2021-11-08 19:51:45 +08:00
d1b69142c4 improve unit testing case for package gcache 2021-11-08 19:51:32 +08:00
2d1593f78e Merge branch 'zhiwei' of https://github.com/564104865/gf into zhiwei 2021-11-08 12:12:15 +08:00
d61f7af60c update cache adapter 2021-11-08 12:12:10 +08:00
65140d1293 Merge branch 'gogf:master' into zhiwei 2021-11-08 12:11:19 +08:00
85299cd447 Merge pull request #1466 from mingzaily/master
add examples for container gqueue
2021-11-07 21:53:24 +08:00
091df972f1 improve example for package gcache 2021-11-07 21:52:27 +08:00
748040fb0b improve group router for package ghttp 2021-11-07 21:31:33 +08:00
df02ca764f add size example for gqueue 2021-11-07 16:52:28 +08:00
6f64c26349 Merge branch 'gogf:master' into master 2021-11-07 16:40:20 +08:00
072355dc2c Merge branch 'zhiwei' of https://github.com/564104865/gf into zhiwei 2021-11-07 16:05:17 +08:00
3ca2cad449 improve gutil.Dump 2021-11-07 00:32:16 +08:00
05bb81cd71 Merge branch 'master' of https://github.com/gogf/gf 2021-11-07 00:16:52 +08:00
fd9246358a Merge branch 'feature/gconv.ScanList' into develop 2021-11-07 00:16:26 +08:00
42c4b32720 add gconv.ScanList 2021-11-07 00:16:14 +08:00
2757647211 Revert "11"
This reverts commit 45787dd8e4.
2021-11-06 20:31:47 +08:00
45787dd8e4 11 2021-11-06 20:31:16 +08:00
38b797b42f finish example for gqueue 2021-11-06 16:27:17 +08:00
e8f6ebc154 Merge branch 'gogf:master' into master 2021-11-06 16:12:38 +08:00
e715ce0625 Merge pull request #1450 from DGuang21/feature-regex-example
add examples for package gregex
2021-11-06 11:35:15 +08:00
aceb586bef Merge pull request #1461 from Evil-king/master
add examples for InitSet of package gset
2021-11-06 11:34:17 +08:00
15f9b69b36 fix 2021-11-06 06:38:28 +08:00
b036767fc0 📝 add example 2021-11-06 01:47:00 +08:00
b967cf6224 📝 add example 2021-11-06 01:16:51 +08:00
1a596fe84d 📝 add example 2021-11-06 00:54:10 +08:00
64fa8d5282 📝 add example 2021-11-06 00:49:15 +08:00
99d2186c8c 📝 add example 2021-11-06 00:06:56 +08:00
24f759e00e 📝 add example 2021-11-05 23:56:08 +08:00
66731c9c66 Merge pull request #1459 from visualsun/master
Create garray_z_example_sorted_str_test.go
2021-11-05 23:27:56 +08:00
e5ec9cd676 Merge pull request #1452 from 564104865/zhiwei
gcache Examples
2021-11-05 23:24:20 +08:00
e7b63839c8 Update garray_z_example_sorted_str_test.go 2021-11-05 19:31:11 +08:00
2511c378f2 Create garray_z_example_int_test.go 2021-11-05 17:02:28 +08:00
12514a0311 Update garray_z_example_sorted_str_test.go 2021-11-05 14:45:04 +08:00
5b83b2375e Update gcache_z_example_cache_test.go 2021-11-05 09:41:49 +08:00
98d72fae25 Merge branch 'gogf:master' into zhiwei 2021-11-05 09:38:41 +08:00
4f2a22dd0e Merge branch 'master' of https://github.com/gogf/gf 2021-11-05 01:15:30 +08:00
4acc0e9876 gconv.ScanList 2021-11-05 01:15:11 +08:00
7be24776d5 Merge branch 'develop' of https://github.com/gogf/gf into develop 2021-11-05 01:07:19 +08:00
485706a676 improve ScanList feature for package gdb 2021-11-05 01:07:06 +08:00
ea7d963f20 IntSet 2021-11-05 00:56:59 +08:00
613958a4b6 IntSet finish 2021-11-05 00:50:44 +08:00
44023ea91d Merge pull request #1453 from Evil-king/master
gstrset Example Finish
2021-11-05 00:21:15 +08:00
ef7f7e35f8 update review 2021-11-05 00:04:24 +08:00
613a50428b Update gcache_z_example_cache_test.go 2021-11-04 23:23:40 +08:00
3091f61a26 update ExampleStrSet_Remove 2021-11-04 22:26:17 +08:00
5776b2596d Create garray_z_example_sorted_str_test.go 2021-11-04 22:17:32 +08:00
430102c995 update 2021-11-04 22:11:09 +08:00
2a2bb4f1e1 improve the example document 2021-11-04 21:39:28 +08:00
205243e8b9 update 2021-11-04 21:02:54 +08:00
d16ce643fd Merge branch 'zhiwei' of https://github.com/564104865/gf into zhiwei 2021-11-04 20:58:19 +08:00
e94eb8f668 Merge branch 'gogf:master' into zhiwei 2021-11-04 20:56:02 +08:00
357084e788 update cache 2021-11-04 20:55:01 +08:00
9a757acc88 Merge pull request #1438 from danvinhe/bugfix/i1435
Bugfix/i1435
2021-11-04 20:38:58 +08:00
3fb1c07eac Merge pull request #1454 from visualsun/master
Update garray_z_example_str_test.go
2021-11-04 20:29:33 +08:00
6050b14087 Update garray_z_example_str_test.go 2021-11-04 20:11:54 +08:00
58c1c1bb16 Merge pull request #1455 from huangqian1985/develop
Validator Rule Example
2021-11-04 19:33:06 +08:00
b6f6ab17f9 go fmt 2021-11-03 23:50:57 +08:00
7bcba437a0 update cache values 2021-11-03 23:44:16 +08:00
abf199bf61 Merge branch 'gogf:master' into zhiwei 2021-11-03 23:29:31 +08:00
9ea2db5c81 fix 2021-11-03 23:17:04 +08:00
7a6fb4a807 Merge branch 'master' of https://github.com/gogf/gf 2021-11-03 23:14:08 +08:00
c3a75f5568 logging content update for package gdb 2021-11-03 23:13:11 +08:00
c850c420fd fixCi 2021-11-03 23:06:24 +08:00
e045aaaf07 Merge branch 'master' of https://github.com/gogf/gf into develop 2021-11-03 23:05:23 +08:00
0cd40caf0c Merge branch 'gogf:master' into master 2021-11-03 22:57:44 +08:00
f2bb9d65c3 edit review 2021-11-03 22:49:30 +08:00
4e05795642 Modify variable name 2021-11-03 22:38:31 +08:00
1df52637e8 Merge pull request #1429 from osgochina/master 2021-11-03 22:38:21 +08:00
b83362cc2e Update garray_z_example_str_test.go 2021-11-03 22:34:43 +08:00
274052511c Complete the following verification rule example method
1.mac 2.url 3.domain 4.size 5.length 6.min-length 7.max-length 8.between 9.min 10.max 11.json 12.integer 13.float 14.boolean 15.regex
2021-11-03 22:20:05 +08:00
32bc1ec064 Merge pull request #1432 from danvinhe/hotfix/i1421
Hotfix/i1421
2021-11-03 22:08:30 +08:00
5fa62e02c6 Update garray_z_example_str_test.go 2021-11-03 18:08:44 +08:00
bf3c3367a6 Update garray_z_example_str_test.go 2021-11-03 17:14:49 +08:00
9c05682605 change some example for gqueue 2021-11-03 16:16:03 +08:00
8f090739d9 go fmt 2021-11-03 15:23:51 +08:00
7971177c58 newredis 2021-11-03 15:16:07 +08:00
5707763758 Merge branch 'gogf:master' into zhiwei 2021-11-03 15:07:32 +08:00
35a786d765 Update gdb_func.go 2021-11-03 15:05:25 +08:00
12fe41e34d Merge branch 'master' into bugfix/i1435 2021-11-03 15:04:22 +08:00
5ffd362b6e Update glog_logger.go
多了个空格
2021-11-03 15:02:21 +08:00
a423fba2a8 comment or be unexported
exported method Redis.UpdateExpire should have comment or be unexported
2021-11-03 14:59:28 +08:00
41d0832fa5 Merge branch 'master' into hotfix/i1421 2021-11-03 14:55:02 +08:00
5e7b0c9303 Merge branch 'master' of https://github.com/gogf/gf 2021-11-03 13:27:49 +08:00
0c43e7986f improve function gutil.Dump/DumpWithType 2021-11-03 13:27:37 +08:00
bc1d76a796 add example for gqueue 2021-11-03 11:41:34 +08:00
6b9f72d973 📝 add example 2021-11-03 11:28:54 +08:00
d980cff663 📝 add example 2021-11-03 11:22:17 +08:00
7de69db707 232234 2021-11-03 10:16:41 +08:00
5e34aee2d7 example over 2021-11-03 00:49:06 +08:00
797719d8d5 Complete the following verification rule example method
1. passport 2.password 3.password2 4.password3 5.postcode 6.resident-id 7.bank-card 8.qq 9.ip 10.ipv4 11.ipv6
2021-11-02 23:47:25 +08:00
6c3aa6ede5 📝 add example 2021-11-02 20:08:15 +08:00
18459ec1bc Merge pull request #1449 from mingzaily/master
Example for glist
2021-11-02 19:37:47 +08:00
e727788f42 Merge branch 'gogf:master' into master 2021-11-02 14:33:13 +08:00
3df7711e74 complete example for glist 2021-11-02 14:31:34 +08:00
c1f856fa8e update 2021-11-02 13:27:54 +08:00
a3eff53c69 Modify "date" rule Example 2021-11-02 11:22:34 +08:00
56c12ad7c3 fix unit testing case for pakage gfile 2021-11-02 09:56:53 +08:00
77a0f59cd3 add automatic adding OmitNil option for data and where filtering if given struct name is defined like 'xxxForDao' 2021-11-02 09:55:37 +08:00
94768530cc Complete the following verification rule example method
1. datetime 2.date-format 3.email 4.phone 5.phone-loose 6.telephone
2021-11-02 00:03:44 +08:00
79a233eb78 example&comment update 2021-11-01 19:46:39 +08:00
183d800f4c 📝 add example 2021-11-01 12:17:53 +08:00
191ad20436 Complete the following verification rule example method
1. date
2021-10-31 23:16:54 +08:00
c0c68d1e46 rename Println -> Print for package glog 2021-10-30 20:47:38 +08:00
ac6968edf1 improve Dump feature 2021-10-30 20:35:55 +08:00
e22e1d0e4a remove function Println from package glog 2021-10-30 19:44:22 +08:00
42e27dd14c add context parameter for package grpool 2021-10-30 18:09:58 +08:00
d817047c98 remove Logger interface from package gdb 2021-10-30 16:12:51 +08:00
e15cd6ae89 fix issue in package gcache 2021-10-30 16:00:38 +08:00
17e6063c5c add neccessary parameter context for package gcron/gtimer 2021-10-30 15:36:10 +08:00
a8b2a2ff33 Merge remote-tracking branch 'origin/develop' into develop 2021-10-29 22:46:00 +08:00
4b3eb09492 Complete the following verification rule example method
1. required 2.required-if 3.required-unless 4.required-with 5.required-with-all 6.required-without 7.required-without-all 8.same 9.different 10.in 11.not-in
2021-10-29 22:44:35 +08:00
d1c09cb21d 完成以下校验规则示例方法
1. required 2.required-if 3.required-unless 4.required-with 5.required-with-all 6.required-without 7.required-without-all 8.same 9.different 10.in 11.not-in
2021-10-29 22:37:38 +08:00
1188793f8f automatically add column prefix for where conditions 2021-10-29 16:57:56 +08:00
09b8df1818 add WherePrefix/WhereOrPrefix for gdb.Model 2021-10-29 15:49:08 +08:00
6192d32501 add LeftJoinOnField/InnerJoinOnField/InnerJoinOnField/FieldsPrefix/FieldsExPrefix for package gdb 2021-10-29 15:12:31 +08:00
a6a8d787e4 merge IgnoreEmptySliceWhere feature into OmitEmptyWhere 2021-10-29 10:50:14 +08:00
e5c6d3f777 fix issue in unit testing cases for package gjson 2021-10-28 23:46:24 +08:00
1bfa792ea9 fix context canceled error while propagate context from http.Request 2021-10-28 23:37:51 +08:00
8ef4f68215 add IgnoreEmptySliceWhere feature for package gdb; add OriginValueAndKind/OriginTypeAndKind functions for package internal/utils 2021-10-28 23:18:23 +08:00
493f5dcff2 remove unused functions for package gdb 2021-10-27 15:41:15 +08:00
2cf84e020f add automatically detectting feature for 'in' attribute of parameters for package goai;add 'datetime' rule for package gvalid 2021-10-27 15:33:29 +08:00
a19ba3d530 add embedded struct fields overwrite feature for package internal/structs 2021-10-26 21:57:56 +08:00
e0674ee7fe improve openapi implements 2021-10-25 21:23:47 +08:00
2481435829 improve openapi implements 2021-10-25 21:06:24 +08:00
e48b565e18 improve openapi implements 2021-10-25 20:36:09 +08:00
f6c2206b88 improve logging content field name from selected/updated to rows 2021-10-25 19:50:52 +08:00
4717e01708 replace gopkg.in/yaml.v2 with gopkg.in/yaml.v3 2021-10-25 19:17:56 +08:00
17861fc45d add short tags for default for package goai 2021-10-25 14:25:35 +08:00
a92c31168a add short tags for summary/description for package goai 2021-10-25 10:50:01 +08:00
f901f19714 Parameters of type gdb.Raw do not require special treatment 2021-10-15 17:45:30 +08:00
e0c4f7ccbf Fixed: #1421 2021-10-09 18:32:59 +08:00
5a5809bd95 修复gini的bug。
当ini的配置值中含有"="时候,不能正确解析。
2021-10-08 16:17:58 +08:00
b826ed6b03 Merge branch 'gogf:master' into master 2021-09-24 10:25:38 +08:00
2891c8e29d Merge branch 'gogf:master' into master 2021-09-23 19:05:53 +08:00
5820e6ebe1 Merge branch 'gogf:master' into master 2021-09-13 15:11:01 +08:00
799e8214f8 Merge remote-tracking branch 'upstream/master' 2020-12-28 11:06:38 +08:00
e3b8f374e5 Merge pull request #1 from gogf/master
pr from gf
2020-07-17 16:27:51 +08:00
195 changed files with 9698 additions and 1795 deletions

View File

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

View File

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

View File

@ -17,6 +17,6 @@ func Error2() error {
}
func main() {
glog.Println(Error1())
glog.Println(Error2())
glog.Print(Error1())
glog.Print(Error2())
}

View File

@ -12,7 +12,7 @@ func MiddlewareCORS(r *ghttp.Request) {
}
func Order(r *ghttp.Request) {
glog.Println("order")
glog.Print("order")
r.Response.Write("GET")
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -8,7 +8,7 @@ import (
)
func test() {
glog.Println(111)
glog.Print(111)
}
func main() {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -26,5 +26,5 @@ package main
// MaxChunkSizeLan : 1337,
// }),
// })
// glog.Println("test log")
// glog.Print("test log")
//}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

View File

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

View File

@ -416,7 +416,7 @@ func (l *List) RemoveAll() {
l.mu.Unlock()
}
// See RemoveAll().
// Clear is alias of RemoveAll.
func (l *List) Clear() {
l.RemoveAll()
}

View File

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

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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]), `'`) + `'`

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

@ -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 != "" {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View 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`)
})
}

View 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")
})
}

View 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")
})
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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{})["呵呵"], "值")

View File

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

View File

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

View File

@ -48,10 +48,10 @@ func Example_conversionNormalFormats() {
// ======================
// YAML:
// users:
// array:
// - John
// - Ming
// count: 1
// array:
// - John
// - Ming
// count: 1
//
// ======================
// TOML:

View File

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

View File

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

View File

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

View File

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

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

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

View File

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

View File

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

View File

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

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

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

View 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