mirror of
https://gitee.com/johng/gf.git
synced 2024-12-02 12:17:53 +08:00
Merge branch 'master' of github.com:gogf/gf
This commit is contained in:
commit
7c24449a24
9
.example/database/gdb/mysql/gdb_distinct.go
Normal file
9
.example/database/gdb/mysql/gdb_distinct.go
Normal file
@ -0,0 +1,9 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
)
|
||||
|
||||
func main() {
|
||||
g.DB().Model("user").Distinct().CountColumn("uid,name")
|
||||
}
|
27
.example/database/gdb/mysql/gdb_transaction.go
Normal file
27
.example/database/gdb/mysql/gdb_transaction.go
Normal file
@ -0,0 +1,27 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var (
|
||||
db = g.DB()
|
||||
table = "user"
|
||||
)
|
||||
tx, err := db.Begin()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err = tx.Begin(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
_, err = tx.Model(table).Data(g.Map{"id": 1, "name": "john"}).Insert()
|
||||
if err = tx.Rollback(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
_, err = tx.Model(table).Data(g.Map{"id": 2, "name": "smith"}).Insert()
|
||||
if err = tx.Commit(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
34
.example/database/gdb/mysql/gdb_transaction_closure.go
Normal file
34
.example/database/gdb/mysql/gdb_transaction_closure.go
Normal file
@ -0,0 +1,34 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/database/gdb"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var (
|
||||
err error
|
||||
db = g.DB()
|
||||
table = "user"
|
||||
)
|
||||
if err = db.Transaction(func(tx *gdb.TX) error {
|
||||
// Nested transaction 1.
|
||||
if err = tx.Transaction(func(tx *gdb.TX) error {
|
||||
_, err = tx.Model(table).Data(g.Map{"id": 1, "name": "john"}).Insert()
|
||||
return err
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
// Nested transaction 2, panic.
|
||||
if err = tx.Transaction(func(tx *gdb.TX) error {
|
||||
_, err = tx.Model(table).Data(g.Map{"id": 2, "name": "smith"}).Insert()
|
||||
// Create a panic that can make this transaction rollback automatically.
|
||||
panic("error")
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
40
.example/database/gdb/mysql/gdb_transaction_savepoint.go
Normal file
40
.example/database/gdb/mysql/gdb_transaction_savepoint.go
Normal file
@ -0,0 +1,40 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var (
|
||||
err error
|
||||
db = g.DB()
|
||||
table = "user"
|
||||
)
|
||||
tx, err := db.Begin()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
_ = tx.Rollback()
|
||||
}
|
||||
}()
|
||||
if _, err = tx.Model(table).Data(g.Map{"id": 1, "name": "john"}).Insert(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err = tx.SavePoint("MyPoint"); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if _, err = tx.Model(table).Data(g.Map{"id": 2, "name": "smith"}).Insert(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if _, err = tx.Model(table).Data(g.Map{"id": 3, "name": "green"}).Insert(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err = tx.RollbackTo("MyPoint"); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err = tx.Commit(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
66
.example/database/gdb/mysql/gdb_with_insert.go
Normal file
66
.example/database/gdb/mysql/gdb_with_insert.go
Normal file
@ -0,0 +1,66 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/database/gdb"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/util/gmeta"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type UserDetail struct {
|
||||
gmeta.Meta `orm:"table:user_detail"`
|
||||
Uid int `json:"uid"`
|
||||
Address string `json:"address"`
|
||||
}
|
||||
|
||||
type UserScore struct {
|
||||
gmeta.Meta `orm:"table:user_score"`
|
||||
Id int `json:"id"`
|
||||
Uid int `json:"uid"`
|
||||
Score int `json:"score"`
|
||||
}
|
||||
|
||||
type User struct {
|
||||
gmeta.Meta `orm:"table:user"`
|
||||
Id int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
UserDetail *UserDetail `orm:"with:uid=id"`
|
||||
UserScores []*UserScore `orm:"with:uid=id"`
|
||||
}
|
||||
|
||||
db := g.DB()
|
||||
db.Transaction(func(tx *gdb.TX) error {
|
||||
for i := 1; i <= 5; i++ {
|
||||
// User.
|
||||
user := User{
|
||||
Name: fmt.Sprintf(`name_%d`, i),
|
||||
}
|
||||
lastInsertId, err := db.Model(user).Data(user).OmitEmpty().InsertAndGetId()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Detail.
|
||||
userDetail := UserDetail{
|
||||
Uid: int(lastInsertId),
|
||||
Address: fmt.Sprintf(`address_%d`, lastInsertId),
|
||||
}
|
||||
_, err = db.Model(userDetail).Data(userDetail).OmitEmpty().Insert()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Scores.
|
||||
for j := 1; j <= 5; j++ {
|
||||
userScore := UserScore{
|
||||
Uid: int(lastInsertId),
|
||||
Score: j,
|
||||
}
|
||||
_, err = db.Model(userScore).Data(userScore).OmitEmpty().Insert()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
37
.example/database/gdb/mysql/gdb_with_slect.go
Normal file
37
.example/database/gdb/mysql/gdb_with_slect.go
Normal file
@ -0,0 +1,37 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/util/gmeta"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type UserDetail struct {
|
||||
gmeta.Meta `orm:"table:user_detail"`
|
||||
Uid int `json:"uid"`
|
||||
Address string `json:"address"`
|
||||
}
|
||||
|
||||
type UserScore struct {
|
||||
gmeta.Meta `orm:"table:user_score"`
|
||||
Id int `json:"id"`
|
||||
Uid int `json:"uid"`
|
||||
Score int `json:"score"`
|
||||
}
|
||||
|
||||
type User struct {
|
||||
gmeta.Meta `orm:"table:user"`
|
||||
Id int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
UserDetail *UserDetail `orm:"with:uid=id"`
|
||||
UserScores []*UserScore `orm:"with:uid=id"`
|
||||
}
|
||||
|
||||
db := g.DB()
|
||||
var user *User
|
||||
err := db.Model(user).WithAll().Where("id", 3).Scan(&user)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
g.Dump(user)
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/i18n/gi18n"
|
||||
@ -13,6 +14,6 @@ func main() {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(t.Translate(`hello`))
|
||||
fmt.Println(t.Translate(`{#hello}{#world}!`))
|
||||
fmt.Println(t.Translate(context.TODO(), `hello`))
|
||||
fmt.Println(t.Translate(context.TODO(), `{#hello}{#world}!`))
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/i18n/gi18n"
|
||||
@ -13,6 +14,6 @@ func main() {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(t.Translate(`hello`))
|
||||
fmt.Println(t.Translate(`{#hello}{#world}!`))
|
||||
fmt.Println(t.Translate(context.TODO(), `hello`))
|
||||
fmt.Println(t.Translate(context.TODO(), `{#hello}{#world}!`))
|
||||
}
|
||||
|
@ -1,8 +1,10 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/i18n/gi18n"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@ -10,6 +12,12 @@ func main() {
|
||||
orderId = 865271654
|
||||
orderAmount = 99.8
|
||||
)
|
||||
fmt.Println(g.I18n().Tfl(`en`, `{#OrderPaid}`, orderId, orderAmount))
|
||||
fmt.Println(g.I18n().Tfl(`zh-CN`, `{#OrderPaid}`, orderId, orderAmount))
|
||||
fmt.Println(g.I18n().Tf(
|
||||
gi18n.WithLanguage(context.TODO(), `en`),
|
||||
`{#OrderPaid}`, orderId, orderAmount,
|
||||
))
|
||||
fmt.Println(g.I18n().Tf(
|
||||
gi18n.WithLanguage(context.TODO(), `zh-CN`),
|
||||
`{#OrderPaid}`, orderId, orderAmount,
|
||||
))
|
||||
}
|
||||
|
@ -2,15 +2,19 @@ package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/i18n/gi18n"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
g.I18n().SetPath("/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/.example/i18n/gi18n/i18n")
|
||||
s := g.Server()
|
||||
s.BindHandler("/", func(r *ghttp.Request) {
|
||||
r.Response.WriteTplContent(`{#hello}{#world}!`, g.Map{
|
||||
"I18nLanguage": r.Get("lang", "zh-CN"),
|
||||
s.Group("/", func(group *ghttp.RouterGroup) {
|
||||
group.Middleware(func(r *ghttp.Request) {
|
||||
r.SetCtx(gi18n.WithLanguage(r.Context(), r.GetString("lang", "zh-CN")))
|
||||
r.Middleware.Next()
|
||||
})
|
||||
group.ALL("/", func(r *ghttp.Request) {
|
||||
r.Response.WriteTplContent(`{#hello}{#world}!`)
|
||||
})
|
||||
})
|
||||
s.SetPort(8199)
|
||||
|
@ -1 +1,3 @@
|
||||
OrderPaid = "您已成功完成订单号 #%d 支付,支付金额¥%.2f。"
|
||||
OrderPaid = "您已成功完成订单号 #%d 支付,支付金额¥%.2f。"
|
||||
hello = "你好"
|
||||
world = "世界"
|
64
.example/net/ghttp/client/middleware/client.go
Normal file
64
.example/net/ghttp/client/middleware/client.go
Normal file
@ -0,0 +1,64 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/container/garray"
|
||||
"github.com/gogf/gf/crypto/gmd5"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/internal/json"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
"github.com/gogf/gf/os/gtime"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
"github.com/gogf/gf/util/guid"
|
||||
"github.com/gogf/gf/util/gutil"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
const (
|
||||
appId = "123"
|
||||
appSecret = "456"
|
||||
)
|
||||
|
||||
// 注入统一的接口签名参数
|
||||
func injectSignature(jsonContent []byte) []byte {
|
||||
var m map[string]interface{}
|
||||
_ = json.Unmarshal(jsonContent, &m)
|
||||
if len(m) > 0 {
|
||||
m["appid"] = appId
|
||||
m["nonce"] = guid.S()
|
||||
m["timestamp"] = gtime.Timestamp()
|
||||
var (
|
||||
keyArray = garray.NewSortedStrArrayFrom(gutil.Keys(m))
|
||||
sigContent string
|
||||
)
|
||||
keyArray.Iterator(func(k int, v string) bool {
|
||||
sigContent += v
|
||||
sigContent += gconv.String(m[v])
|
||||
return true
|
||||
})
|
||||
m["signature"] = gmd5.MustEncryptString(gmd5.MustEncryptString(sigContent) + appSecret)
|
||||
jsonContent, _ = json.Marshal(m)
|
||||
}
|
||||
return jsonContent
|
||||
}
|
||||
|
||||
func main() {
|
||||
c := g.Client()
|
||||
c.Use(func(c *ghttp.Client, r *http.Request) (resp *ghttp.ClientResponse, err error) {
|
||||
bodyBytes, _ := ioutil.ReadAll(r.Body)
|
||||
if len(bodyBytes) > 0 {
|
||||
// 注入签名相关参数,修改Request原有的提交参数
|
||||
bodyBytes = injectSignature(bodyBytes)
|
||||
r.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes))
|
||||
r.ContentLength = int64(len(bodyBytes))
|
||||
}
|
||||
return c.Next(r)
|
||||
})
|
||||
content := c.ContentJson().PostContent("http://127.0.0.1:8199/", g.Map{
|
||||
"name": "goframe",
|
||||
"site": "https://goframe.org",
|
||||
})
|
||||
fmt.Println(content)
|
||||
}
|
17
.example/net/ghttp/client/middleware/server.go
Normal file
17
.example/net/ghttp/client/middleware/server.go
Normal file
@ -0,0 +1,17 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.Group("/", func(group *ghttp.RouterGroup) {
|
||||
group.ALL("/", func(r *ghttp.Request) {
|
||||
r.Response.Write(r.GetMap())
|
||||
})
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
@ -25,7 +25,7 @@ func main() {
|
||||
//fmt.Println(r.GetBody())
|
||||
if err := r.Parse(&req); err != nil {
|
||||
// Validation error.
|
||||
if v, ok := err.(*gvalid.Error); ok {
|
||||
if v, ok := err.(gvalid.Error); ok {
|
||||
r.Response.WriteJsonExit(RegisterRes{
|
||||
Code: 1,
|
||||
Error: v.FirstString(),
|
||||
|
@ -18,13 +18,13 @@ func main() {
|
||||
s.Group("/", func(rgroup *ghttp.RouterGroup) {
|
||||
rgroup.ALL("/user", func(r *ghttp.Request) {
|
||||
user := new(User)
|
||||
if err := r.GetToStruct(user); err != nil {
|
||||
if err := r.GetStruct(user); err != nil {
|
||||
r.Response.WriteJsonExit(g.Map{
|
||||
"message": err,
|
||||
"errcode": 1,
|
||||
})
|
||||
}
|
||||
if err := gvalid.CheckStruct(user, nil); err != nil {
|
||||
if err := gvalid.CheckStruct(r.Context(), user, nil); err != nil {
|
||||
r.Response.WriteJsonExit(g.Map{
|
||||
"message": err.Maps(),
|
||||
"errcode": 1,
|
||||
|
@ -24,7 +24,7 @@ func main() {
|
||||
var req *RegisterReq
|
||||
if err := r.Parse(&req); err != nil {
|
||||
// Validation error.
|
||||
if v, ok := err.(*gvalid.Error); ok {
|
||||
if v, ok := err.(gvalid.Error); ok {
|
||||
r.Response.WriteJsonExit(RegisterRes{
|
||||
Code: 1,
|
||||
Error: v.FirstString(),
|
36
.example/net/ghttp/server/session/redis/redis_bigint.go
Normal file
36
.example/net/ghttp/server/session/redis/redis_bigint.go
Normal file
@ -0,0 +1,36 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
"github.com/gogf/gf/os/gsession"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type User struct {
|
||||
Id int64
|
||||
Name string
|
||||
}
|
||||
s := g.Server()
|
||||
s.SetSessionStorage(gsession.NewStorageRedis(g.Redis()))
|
||||
s.Group("/", func(group *ghttp.RouterGroup) {
|
||||
group.GET("/set", func(r *ghttp.Request) {
|
||||
user := &User{
|
||||
Id: 1265476890672672808,
|
||||
Name: "john",
|
||||
}
|
||||
if err := r.Session.Set("user", user); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
r.Response.Write("ok")
|
||||
})
|
||||
group.GET("/get", func(r *ghttp.Request) {
|
||||
r.Response.WriteJson(r.Session.Get("user"))
|
||||
})
|
||||
group.GET("/clear", func(r *ghttp.Request) {
|
||||
r.Session.Clear()
|
||||
})
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
54
.example/os/gproc/signal/signal_handler.go
Normal file
54
.example/os/gproc/signal/signal_handler.go
Normal file
@ -0,0 +1,54 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
func signalHandlerForMQ() {
|
||||
var (
|
||||
sig os.Signal
|
||||
receivedChan = make(chan os.Signal)
|
||||
)
|
||||
signal.Notify(
|
||||
receivedChan,
|
||||
syscall.SIGINT,
|
||||
syscall.SIGQUIT,
|
||||
syscall.SIGKILL,
|
||||
syscall.SIGTERM,
|
||||
syscall.SIGABRT,
|
||||
)
|
||||
for {
|
||||
sig = <-receivedChan
|
||||
fmt.Println("MQ is shutting down due to signal:", sig.String())
|
||||
time.Sleep(time.Second)
|
||||
fmt.Println("MQ is shut down smoothly")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println("Process start, pid:", os.Getpid())
|
||||
go signalHandlerForMQ()
|
||||
|
||||
var (
|
||||
sig os.Signal
|
||||
receivedChan = make(chan os.Signal)
|
||||
)
|
||||
signal.Notify(
|
||||
receivedChan,
|
||||
syscall.SIGINT,
|
||||
syscall.SIGQUIT,
|
||||
syscall.SIGKILL,
|
||||
syscall.SIGTERM,
|
||||
syscall.SIGABRT,
|
||||
)
|
||||
for {
|
||||
sig = <-receivedChan
|
||||
fmt.Println("MainProcess is shutting down due to signal:", sig.String())
|
||||
return
|
||||
}
|
||||
}
|
27
.example/os/gproc/signal/signal_handler_gproc.go
Normal file
27
.example/os/gproc/signal/signal_handler_gproc.go
Normal file
@ -0,0 +1,27 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/os/gproc"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
func signalHandlerForMQ(sig os.Signal) {
|
||||
fmt.Println("MQ is shutting down due to signal:", sig.String())
|
||||
time.Sleep(time.Second)
|
||||
fmt.Println("MQ is shut down smoothly")
|
||||
}
|
||||
|
||||
func signalHandlerForMain(sig os.Signal) {
|
||||
fmt.Println("MainProcess is shutting down due to signal:", sig.String())
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println("Process start, pid:", os.Getpid())
|
||||
gproc.AddSigHandlerShutdown(
|
||||
signalHandlerForMQ,
|
||||
signalHandlerForMain,
|
||||
)
|
||||
gproc.Listen()
|
||||
}
|
14
.example/util/gvalid/config.toml
Normal file
14
.example/util/gvalid/config.toml
Normal file
@ -0,0 +1,14 @@
|
||||
|
||||
|
||||
|
||||
# MySQL.
|
||||
[database]
|
||||
[database.default]
|
||||
link = "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
|
||||
debug = true
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,31 +1,32 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/util/gvalid"
|
||||
)
|
||||
|
||||
func main() {
|
||||
//rule := "length:6,16"
|
||||
//if m := gvalid.Check("123456", rule, nil); m != nil {
|
||||
//if m := gvalid.Check(context.TODO(), "123456", rule, nil); m != nil {
|
||||
// fmt.Println(m)
|
||||
//}
|
||||
//if m := gvalid.Check("12345", rule, nil); m != nil {
|
||||
//if m := gvalid.Check(context.TODO(), "12345", rule, nil); m != nil {
|
||||
// fmt.Println(m)
|
||||
// // map[length:字段长度为6到16个字符]
|
||||
//}
|
||||
|
||||
//rule := "integer|between:6,16"
|
||||
//msgs := "请输入一个整数|参数大小不对啊老铁"
|
||||
//fmt.Println(gvalid.Check("5.66", rule, msgs))
|
||||
//fmt.Println(gvalid.Check(context.TODO(), "5.66", rule, msgs))
|
||||
//// map[integer:请输入一个整数 between:参数大小不对啊老铁]
|
||||
|
||||
//// 参数长度至少为6个数字或者6个字母,但是总长度不能超过16个字符
|
||||
//rule := `regex:\d{6,}|\D{6,}|max-length:16`
|
||||
//if m := gvalid.Check("123456", rule, nil); m != nil {
|
||||
//if m := gvalid.Check(context.TODO(), "123456", rule, nil); m != nil {
|
||||
// fmt.Println(m)
|
||||
//}
|
||||
//if m := gvalid.Check("abcde6", rule, nil); m != nil {
|
||||
//if m := gvalid.Check(context.TODO(), "abcde6", rule, nil); m != nil {
|
||||
// fmt.Println(m)
|
||||
// // map[regex:字段值不合法]
|
||||
//}
|
||||
@ -40,18 +41,20 @@ func main() {
|
||||
// "password" : "required|length:6,16|same:password2",
|
||||
// "password2" : "required|length:6,16",
|
||||
//}
|
||||
//fmt.Println(gvalid.CheckMap(params, rules))
|
||||
//fmt.Println(gvalid.CheckMap(context.TODO(), params, rules))
|
||||
//// map[passport:map[length:字段长度为6到16个字符] password:map[same:字段值不合法]]
|
||||
|
||||
params := map[string]interface{}{
|
||||
"passport": "john",
|
||||
"password": "123456",
|
||||
"password2": "1234567",
|
||||
"name": "gf",
|
||||
}
|
||||
rules := map[string]string{
|
||||
"passport": "required|length:6,16",
|
||||
"password": "required|length:6,16|same:password2",
|
||||
"password2": "required|length:6,16",
|
||||
"name": "size:5",
|
||||
}
|
||||
msgs := map[string]interface{}{
|
||||
"passport": "账号不能为空|账号长度应当在:min到:max之间",
|
||||
@ -59,8 +62,9 @@ func main() {
|
||||
"required": "密码不能为空",
|
||||
"same": "两次密码输入不相等",
|
||||
},
|
||||
"name": "名字长度必须为:size",
|
||||
}
|
||||
if e := gvalid.CheckMap(params, rules, msgs); e != nil {
|
||||
if e := gvalid.CheckMap(context.TODO(), params, rules, msgs); e != nil {
|
||||
g.Dump(e.Maps())
|
||||
}
|
||||
// map[passport:map[length:账号长度应当在6到16之间] password:map[same:两次密码输入不相等]]
|
||||
|
28
.example/util/gvalid/gvalid_checkstructwithdata.go
Normal file
28
.example/util/gvalid/gvalid_checkstructwithdata.go
Normal file
@ -0,0 +1,28 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
"github.com/gogf/gf/util/gvalid"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type User struct {
|
||||
Name string `v:"required#请输入用户姓名"`
|
||||
Type int `v:"required#请选择用户类型"`
|
||||
}
|
||||
data := g.Map{
|
||||
"name": "john",
|
||||
}
|
||||
user := User{}
|
||||
if err := gconv.Scan(data, &user); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
err := gvalid.CheckStructWithData(context.TODO(), user, data, nil)
|
||||
// 也可以使用
|
||||
// err := g.Validator().Data(data).CheckStruct(user)
|
||||
if err != nil {
|
||||
g.Dump(err.Items())
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/util/gvalid"
|
||||
@ -8,6 +9,6 @@ import (
|
||||
|
||||
func main() {
|
||||
g.I18n().SetLanguage("cn")
|
||||
err := gvalid.Check("", "required", nil)
|
||||
err := gvalid.Check(context.TODO(), "", "required", nil)
|
||||
fmt.Println(err.String())
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/util/gvalid"
|
||||
)
|
||||
@ -17,7 +18,7 @@ func main() {
|
||||
ConfiemPassword: "",
|
||||
}
|
||||
|
||||
e := gvalid.CheckStruct(user, nil)
|
||||
e := gvalid.CheckStruct(context.TODO(), user, nil)
|
||||
g.Dump(e.Map())
|
||||
g.Dump(e.Maps())
|
||||
g.Dump(e.String())
|
||||
|
38
.example/util/gvalid/gvalid_i18n.go
Normal file
38
.example/util/gvalid/gvalid_i18n.go
Normal file
@ -0,0 +1,38 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/i18n/gi18n"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type User struct {
|
||||
Name string `v:"required#ReuiredUserName"`
|
||||
Type int `v:"required#ReuiredUserType"`
|
||||
Project string `v:"size:10#MustSize"`
|
||||
}
|
||||
var (
|
||||
data = g.Map{
|
||||
"name": "john",
|
||||
"project": "gf",
|
||||
}
|
||||
user = User{}
|
||||
ctxEn = gi18n.WithLanguage(context.TODO(), "en")
|
||||
ctxCh = gi18n.WithLanguage(context.TODO(), "zh-CN")
|
||||
)
|
||||
|
||||
if err := gconv.Scan(data, &user); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// 英文
|
||||
if err := g.Validator().Ctx(ctxEn).Data(data).CheckStruct(user); err != nil {
|
||||
g.Dump(err.String())
|
||||
}
|
||||
// 中文
|
||||
if err := g.Validator().Ctx(ctxCh).Data(data).CheckStruct(user); err != nil {
|
||||
g.Dump(err.String())
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/util/gvalid"
|
||||
)
|
||||
@ -18,7 +19,7 @@ func main() {
|
||||
Pass2: "123",
|
||||
}
|
||||
|
||||
e := gvalid.CheckStruct(user, nil)
|
||||
e := gvalid.CheckStruct(context.TODO(), user, nil)
|
||||
g.Dump(e.String())
|
||||
g.Dump(e.FirstString())
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/util/gvalid"
|
||||
@ -17,7 +18,7 @@ func main() {
|
||||
"password@required|length:6,16|same:password2#密码不能为空}|两次密码输入不相等",
|
||||
"password2@required|length:6,16#",
|
||||
}
|
||||
if e := gvalid.CheckMap(params, rules); e != nil {
|
||||
if e := gvalid.CheckMap(context.TODO(), params, rules); e != nil {
|
||||
fmt.Println(e.Map())
|
||||
fmt.Println(e.FirstItem())
|
||||
fmt.Println(e.FirstString())
|
||||
|
@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/util/gvalid"
|
||||
)
|
||||
@ -20,7 +21,7 @@ func main() {
|
||||
}
|
||||
|
||||
// 使用结构体定义的校验规则和错误提示进行校验
|
||||
g.Dump(gvalid.CheckStruct(user, nil).Map())
|
||||
g.Dump(gvalid.CheckStruct(context.TODO(), user, nil).Map())
|
||||
|
||||
// 自定义校验规则和错误提示,对定义的特定校验规则和错误提示进行覆盖
|
||||
rules := map[string]string{
|
||||
@ -31,5 +32,5 @@ func main() {
|
||||
"password3": "名称不能为空",
|
||||
},
|
||||
}
|
||||
g.Dump(gvalid.CheckStruct(user, rules, msgs).Map())
|
||||
g.Dump(gvalid.CheckStruct(context.TODO(), user, rules, msgs).Map())
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/util/gvalid"
|
||||
)
|
||||
@ -13,5 +14,5 @@ func main() {
|
||||
|
||||
user := &User{}
|
||||
|
||||
g.Dump(gvalid.CheckStruct(user, nil))
|
||||
g.Dump(gvalid.CheckStruct(context.TODO(), user, nil))
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/util/gvalid"
|
||||
)
|
||||
@ -15,5 +16,5 @@ func main() {
|
||||
Pass: "1",
|
||||
}
|
||||
|
||||
g.Dump(gvalid.CheckStruct(user, nil).Maps())
|
||||
g.Dump(gvalid.CheckStruct(context.TODO(), user, nil).Maps())
|
||||
}
|
||||
|
40
.example/util/gvalid/gvalid_struct_meta.go
Normal file
40
.example/util/gvalid/gvalid_struct_meta.go
Normal file
@ -0,0 +1,40 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/errors/gerror"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/util/gmeta"
|
||||
)
|
||||
|
||||
type UserCreateReq struct {
|
||||
gmeta.Meta `v:"UserCreateReq"`
|
||||
Name string
|
||||
Pass string
|
||||
}
|
||||
|
||||
func UserCreateReqChecker(ctx context.Context, rule string, value interface{}, message string, data interface{}) error {
|
||||
user := &UserCreateReq{}
|
||||
if v, ok := data.(*UserCreateReq); ok {
|
||||
user = v
|
||||
}
|
||||
// SELECT COUNT(*) FROM `user` WHERE `name` = xxx
|
||||
count, err := g.Model("user").Ctx(ctx).Where("name", user.Name).Count()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if count > 0 {
|
||||
return gerror.Newf(`The name "%s" is already token`, user.Name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
user := &UserCreateReq{
|
||||
Name: "john",
|
||||
Pass: "123456",
|
||||
}
|
||||
err := g.Validator().RuleFunc("UserCreateReq", UserCreateReqChecker).CheckStruct(user)
|
||||
fmt.Println(err)
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
|
||||
|
||||
"gf.gvalid.required" = "字段不能为空"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
7
.example/util/gvalid/i18n/en.toml
Normal file
7
.example/util/gvalid/i18n/en.toml
Normal file
@ -0,0 +1,7 @@
|
||||
"gf.gvalid.required" = "字段不能为空"
|
||||
|
||||
|
||||
"ReuiredUserName" = "Please input user name"
|
||||
"ReuiredUserType" = "Please select user type"
|
||||
"MustSize" = "Size of :attribute must be :size"
|
||||
|
16
.example/util/gvalid/i18n/zh-CN.toml
Normal file
16
.example/util/gvalid/i18n/zh-CN.toml
Normal file
@ -0,0 +1,16 @@
|
||||
|
||||
|
||||
"gf.gvalid.required" = "字段不能为空"
|
||||
|
||||
"ReuiredUserName" = "请输入用户名称"
|
||||
"ReuiredUserType" = "请选择用户类型"
|
||||
"MustSize" = ":attribute长度必须为:size"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,4 +1,7 @@
|
||||
<!-- 为更高效率地交流并解决问题,请按照以下模板提交issue,感谢! -->
|
||||
<!-- 为高效处理您的疑问,如果觉得是BUG类问题,请您务必提供可复现该问题的最小可运行代码! -->
|
||||
<!-- 为高效处理您的疑问,如果觉得是BUG类问题,请您务必提供可复现该问题的最小可运行代码! -->
|
||||
<!-- 为高效处理您的疑问,如果觉得是BUG类问题,请您务必提供可复现该问题的最小可运行代码! -->
|
||||
<!-- 重要的事情说三遍! -->
|
||||
|
||||
### 1. 您当前使用的`Go`版本,及系统版本、系统架构?
|
||||
|
||||
|
7
.github/ISSUE_TEMPLATE.MD
vendored
7
.github/ISSUE_TEMPLATE.MD
vendored
@ -1,5 +1,10 @@
|
||||
<!-- Please answer these questions before submitting your issue. Thanks! -->
|
||||
|
||||
<!-- 为高效处理您的疑问,如果觉得是BUG类问题,请您务必提供可复现该问题的最小可运行代码! -->
|
||||
<!-- 为高效处理您的疑问,如果觉得是BUG类问题,请您务必提供可复现该问题的最小可运行代码! -->
|
||||
<!-- 为高效处理您的疑问,如果觉得是BUG类问题,请您务必提供可复现该问题的最小可运行代码! -->
|
||||
<!-- 重要的事情说三遍! -->
|
||||
|
||||
### 1. What version of `Go` and system type/arch are you using?
|
||||
|
||||
<!--
|
||||
@ -13,7 +18,7 @@ What expect to see is like: `go 1.12, linux/amd64`
|
||||
<!-- You can find the GF version from your `go.mod`, or from the `version.go` in `GF` -->
|
||||
|
||||
|
||||
### 3. Can this issue be reproduced with the latest release?
|
||||
### 3. Can this issue be re-produced with the latest release?
|
||||
|
||||
|
||||
|
||||
|
@ -736,7 +736,7 @@ func (a *Array) UnmarshalJSON(b []byte) error {
|
||||
}
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if err := json.Unmarshal(b, &a.array); err != nil {
|
||||
if err := json.UnmarshalUseNumber(b, &a.array); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
@ -748,7 +748,7 @@ func (a *Array) UnmarshalValue(value interface{}) error {
|
||||
defer a.mu.Unlock()
|
||||
switch value.(type) {
|
||||
case string, []byte:
|
||||
return json.Unmarshal(gconv.Bytes(value), &a.array)
|
||||
return json.UnmarshalUseNumber(gconv.Bytes(value), &a.array)
|
||||
default:
|
||||
a.array = gconv.SliceAny(value)
|
||||
}
|
||||
|
@ -735,7 +735,7 @@ func (a *IntArray) UnmarshalJSON(b []byte) error {
|
||||
}
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if err := json.Unmarshal(b, &a.array); err != nil {
|
||||
if err := json.UnmarshalUseNumber(b, &a.array); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
@ -747,7 +747,7 @@ func (a *IntArray) UnmarshalValue(value interface{}) error {
|
||||
defer a.mu.Unlock()
|
||||
switch value.(type) {
|
||||
case string, []byte:
|
||||
return json.Unmarshal(gconv.Bytes(value), &a.array)
|
||||
return json.UnmarshalUseNumber(gconv.Bytes(value), &a.array)
|
||||
default:
|
||||
a.array = gconv.SliceInt(value)
|
||||
}
|
||||
|
@ -750,7 +750,7 @@ func (a *StrArray) UnmarshalJSON(b []byte) error {
|
||||
}
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if err := json.Unmarshal(b, &a.array); err != nil {
|
||||
if err := json.UnmarshalUseNumber(b, &a.array); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
@ -762,7 +762,7 @@ func (a *StrArray) UnmarshalValue(value interface{}) error {
|
||||
defer a.mu.Unlock()
|
||||
switch value.(type) {
|
||||
case string, []byte:
|
||||
return json.Unmarshal(gconv.Bytes(value), &a.array)
|
||||
return json.UnmarshalUseNumber(gconv.Bytes(value), &a.array)
|
||||
default:
|
||||
a.array = gconv.SliceStr(value)
|
||||
}
|
||||
|
@ -685,7 +685,7 @@ func (a *SortedArray) UnmarshalJSON(b []byte) error {
|
||||
}
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if err := json.Unmarshal(b, &a.array); err != nil {
|
||||
if err := json.UnmarshalUseNumber(b, &a.array); err != nil {
|
||||
return err
|
||||
}
|
||||
if a.comparator != nil && a.array != nil {
|
||||
@ -706,7 +706,7 @@ func (a *SortedArray) UnmarshalValue(value interface{}) (err error) {
|
||||
defer a.mu.Unlock()
|
||||
switch value.(type) {
|
||||
case string, []byte:
|
||||
err = json.Unmarshal(gconv.Bytes(value), &a.array)
|
||||
err = json.UnmarshalUseNumber(gconv.Bytes(value), &a.array)
|
||||
default:
|
||||
a.array = gconv.SliceAny(value)
|
||||
}
|
||||
|
@ -658,7 +658,7 @@ func (a *SortedIntArray) UnmarshalJSON(b []byte) error {
|
||||
}
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if err := json.Unmarshal(b, &a.array); err != nil {
|
||||
if err := json.UnmarshalUseNumber(b, &a.array); err != nil {
|
||||
return err
|
||||
}
|
||||
if a.array != nil {
|
||||
@ -676,7 +676,7 @@ func (a *SortedIntArray) UnmarshalValue(value interface{}) (err error) {
|
||||
defer a.mu.Unlock()
|
||||
switch value.(type) {
|
||||
case string, []byte:
|
||||
err = json.Unmarshal(gconv.Bytes(value), &a.array)
|
||||
err = json.UnmarshalUseNumber(gconv.Bytes(value), &a.array)
|
||||
default:
|
||||
a.array = gconv.SliceInt(value)
|
||||
}
|
||||
|
@ -671,7 +671,7 @@ func (a *SortedStrArray) UnmarshalJSON(b []byte) error {
|
||||
}
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if err := json.Unmarshal(b, &a.array); err != nil {
|
||||
if err := json.UnmarshalUseNumber(b, &a.array); err != nil {
|
||||
return err
|
||||
}
|
||||
if a.array != nil {
|
||||
@ -689,7 +689,7 @@ func (a *SortedStrArray) UnmarshalValue(value interface{}) (err error) {
|
||||
defer a.mu.Unlock()
|
||||
switch value.(type) {
|
||||
case string, []byte:
|
||||
err = json.Unmarshal(gconv.Bytes(value), &a.array)
|
||||
err = json.UnmarshalUseNumber(gconv.Bytes(value), &a.array)
|
||||
default:
|
||||
a.array = gconv.SliceStr(value)
|
||||
}
|
||||
|
@ -570,12 +570,12 @@ func TestArray_Json(t *testing.T) {
|
||||
t.Assert(err1, err2)
|
||||
|
||||
a2 := garray.New()
|
||||
err2 = json.Unmarshal(b2, &a2)
|
||||
err2 = json.UnmarshalUseNumber(b2, &a2)
|
||||
t.Assert(err2, nil)
|
||||
t.Assert(a2.Slice(), s1)
|
||||
|
||||
var a3 garray.Array
|
||||
err := json.Unmarshal(b2, &a3)
|
||||
err := json.UnmarshalUseNumber(b2, &a3)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(a3.Slice(), s1)
|
||||
})
|
||||
@ -589,12 +589,12 @@ func TestArray_Json(t *testing.T) {
|
||||
t.Assert(err1, err2)
|
||||
|
||||
a2 := garray.New()
|
||||
err2 = json.Unmarshal(b2, &a2)
|
||||
err2 = json.UnmarshalUseNumber(b2, &a2)
|
||||
t.Assert(err2, nil)
|
||||
t.Assert(a2.Slice(), s1)
|
||||
|
||||
var a3 garray.Array
|
||||
err := json.Unmarshal(b2, &a3)
|
||||
err := json.UnmarshalUseNumber(b2, &a3)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(a3.Slice(), s1)
|
||||
})
|
||||
@ -612,7 +612,7 @@ func TestArray_Json(t *testing.T) {
|
||||
t.Assert(err, nil)
|
||||
|
||||
user := new(User)
|
||||
err = json.Unmarshal(b, user)
|
||||
err = json.UnmarshalUseNumber(b, user)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(user.Name, data["Name"])
|
||||
t.Assert(user.Scores, data["Scores"])
|
||||
@ -631,7 +631,7 @@ func TestArray_Json(t *testing.T) {
|
||||
t.Assert(err, nil)
|
||||
|
||||
user := new(User)
|
||||
err = json.Unmarshal(b, user)
|
||||
err = json.UnmarshalUseNumber(b, user)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(user.Name, data["Name"])
|
||||
t.Assert(user.Scores, data["Scores"])
|
||||
|
@ -615,11 +615,11 @@ func TestIntArray_Json(t *testing.T) {
|
||||
t.Assert(err1, err2)
|
||||
|
||||
a2 := garray.NewIntArray()
|
||||
err1 = json.Unmarshal(b2, &a2)
|
||||
err1 = json.UnmarshalUseNumber(b2, &a2)
|
||||
t.Assert(a2.Slice(), s1)
|
||||
|
||||
var a3 garray.IntArray
|
||||
err := json.Unmarshal(b2, &a3)
|
||||
err := json.UnmarshalUseNumber(b2, &a3)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(a3.Slice(), s1)
|
||||
})
|
||||
@ -633,11 +633,11 @@ func TestIntArray_Json(t *testing.T) {
|
||||
t.Assert(err1, err2)
|
||||
|
||||
a2 := garray.NewIntArray()
|
||||
err1 = json.Unmarshal(b2, &a2)
|
||||
err1 = json.UnmarshalUseNumber(b2, &a2)
|
||||
t.Assert(a2.Slice(), s1)
|
||||
|
||||
var a3 garray.IntArray
|
||||
err := json.Unmarshal(b2, &a3)
|
||||
err := json.UnmarshalUseNumber(b2, &a3)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(a3.Slice(), s1)
|
||||
})
|
||||
@ -655,7 +655,7 @@ func TestIntArray_Json(t *testing.T) {
|
||||
t.Assert(err, nil)
|
||||
|
||||
user := new(User)
|
||||
err = json.Unmarshal(b, user)
|
||||
err = json.UnmarshalUseNumber(b, user)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(user.Name, data["Name"])
|
||||
t.Assert(user.Scores, data["Scores"])
|
||||
@ -674,7 +674,7 @@ func TestIntArray_Json(t *testing.T) {
|
||||
t.Assert(err, nil)
|
||||
|
||||
user := new(User)
|
||||
err = json.Unmarshal(b, user)
|
||||
err = json.UnmarshalUseNumber(b, user)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(user.Name, data["Name"])
|
||||
t.Assert(user.Scores, data["Scores"])
|
||||
|
@ -614,11 +614,11 @@ func TestStrArray_Json(t *testing.T) {
|
||||
t.Assert(err1, err2)
|
||||
|
||||
a2 := garray.NewStrArray()
|
||||
err1 = json.Unmarshal(b2, &a2)
|
||||
err1 = json.UnmarshalUseNumber(b2, &a2)
|
||||
t.Assert(a2.Slice(), s1)
|
||||
|
||||
var a3 garray.StrArray
|
||||
err := json.Unmarshal(b2, &a3)
|
||||
err := json.UnmarshalUseNumber(b2, &a3)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(a3.Slice(), s1)
|
||||
})
|
||||
@ -632,11 +632,11 @@ func TestStrArray_Json(t *testing.T) {
|
||||
t.Assert(err1, err2)
|
||||
|
||||
a2 := garray.NewStrArray()
|
||||
err1 = json.Unmarshal(b2, &a2)
|
||||
err1 = json.UnmarshalUseNumber(b2, &a2)
|
||||
t.Assert(a2.Slice(), s1)
|
||||
|
||||
var a3 garray.StrArray
|
||||
err := json.Unmarshal(b2, &a3)
|
||||
err := json.UnmarshalUseNumber(b2, &a3)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(a3.Slice(), s1)
|
||||
})
|
||||
@ -654,7 +654,7 @@ func TestStrArray_Json(t *testing.T) {
|
||||
t.Assert(err, nil)
|
||||
|
||||
user := new(User)
|
||||
err = json.Unmarshal(b, user)
|
||||
err = json.UnmarshalUseNumber(b, user)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(user.Name, data["Name"])
|
||||
t.Assert(user.Scores, data["Scores"])
|
||||
@ -673,7 +673,7 @@ func TestStrArray_Json(t *testing.T) {
|
||||
t.Assert(err, nil)
|
||||
|
||||
user := new(User)
|
||||
err = json.Unmarshal(b, user)
|
||||
err = json.UnmarshalUseNumber(b, user)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(user.Name, data["Name"])
|
||||
t.Assert(user.Scores, data["Scores"])
|
||||
|
@ -656,11 +656,11 @@ func TestSortedArray_Json(t *testing.T) {
|
||||
t.Assert(err1, err2)
|
||||
|
||||
a2 := garray.NewSortedArray(gutil.ComparatorString)
|
||||
err1 = json.Unmarshal(b2, &a2)
|
||||
err1 = json.UnmarshalUseNumber(b2, &a2)
|
||||
t.Assert(a2.Slice(), s2)
|
||||
|
||||
var a3 garray.SortedArray
|
||||
err := json.Unmarshal(b2, &a3)
|
||||
err := json.UnmarshalUseNumber(b2, &a3)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(a3.Slice(), s1)
|
||||
t.Assert(a3.Interfaces(), s1)
|
||||
@ -676,11 +676,11 @@ func TestSortedArray_Json(t *testing.T) {
|
||||
t.Assert(err1, err2)
|
||||
|
||||
a2 := garray.NewSortedArray(gutil.ComparatorString)
|
||||
err1 = json.Unmarshal(b2, &a2)
|
||||
err1 = json.UnmarshalUseNumber(b2, &a2)
|
||||
t.Assert(a2.Slice(), s2)
|
||||
|
||||
var a3 garray.SortedArray
|
||||
err := json.Unmarshal(b2, &a3)
|
||||
err := json.UnmarshalUseNumber(b2, &a3)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(a3.Slice(), s1)
|
||||
t.Assert(a3.Interfaces(), s1)
|
||||
@ -699,7 +699,7 @@ func TestSortedArray_Json(t *testing.T) {
|
||||
t.Assert(err, nil)
|
||||
|
||||
user := new(User)
|
||||
err = json.Unmarshal(b, user)
|
||||
err = json.UnmarshalUseNumber(b, user)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(user.Name, data["Name"])
|
||||
t.AssertNE(user.Scores, nil)
|
||||
@ -735,7 +735,7 @@ func TestSortedArray_Json(t *testing.T) {
|
||||
t.Assert(err, nil)
|
||||
|
||||
user := new(User)
|
||||
err = json.Unmarshal(b, user)
|
||||
err = json.UnmarshalUseNumber(b, user)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(user.Name, data["Name"])
|
||||
t.AssertNE(user.Scores, nil)
|
||||
|
@ -557,11 +557,11 @@ func TestSortedIntArray_Json(t *testing.T) {
|
||||
t.Assert(err1, err2)
|
||||
|
||||
a2 := garray.NewSortedIntArray()
|
||||
err1 = json.Unmarshal(b2, &a2)
|
||||
err1 = json.UnmarshalUseNumber(b2, &a2)
|
||||
t.Assert(a2.Slice(), s2)
|
||||
|
||||
var a3 garray.SortedIntArray
|
||||
err := json.Unmarshal(b2, &a3)
|
||||
err := json.UnmarshalUseNumber(b2, &a3)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(a3.Slice(), s1)
|
||||
})
|
||||
@ -576,11 +576,11 @@ func TestSortedIntArray_Json(t *testing.T) {
|
||||
t.Assert(err1, err2)
|
||||
|
||||
a2 := garray.NewSortedIntArray()
|
||||
err1 = json.Unmarshal(b2, &a2)
|
||||
err1 = json.UnmarshalUseNumber(b2, &a2)
|
||||
t.Assert(a2.Slice(), s2)
|
||||
|
||||
var a3 garray.SortedIntArray
|
||||
err := json.Unmarshal(b2, &a3)
|
||||
err := json.UnmarshalUseNumber(b2, &a3)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(a3.Slice(), s1)
|
||||
})
|
||||
@ -598,7 +598,7 @@ func TestSortedIntArray_Json(t *testing.T) {
|
||||
t.Assert(err, nil)
|
||||
|
||||
user := new(User)
|
||||
err = json.Unmarshal(b, user)
|
||||
err = json.UnmarshalUseNumber(b, user)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(user.Name, data["Name"])
|
||||
t.Assert(user.Scores, []int{98, 99, 100})
|
||||
@ -617,7 +617,7 @@ func TestSortedIntArray_Json(t *testing.T) {
|
||||
t.Assert(err, nil)
|
||||
|
||||
user := new(User)
|
||||
err = json.Unmarshal(b, user)
|
||||
err = json.UnmarshalUseNumber(b, user)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(user.Name, data["Name"])
|
||||
t.Assert(user.Scores, []int{98, 99, 100})
|
||||
|
@ -577,12 +577,12 @@ func TestSortedStrArray_Json(t *testing.T) {
|
||||
t.Assert(err1, err2)
|
||||
|
||||
a2 := garray.NewSortedStrArray()
|
||||
err1 = json.Unmarshal(b2, &a2)
|
||||
err1 = json.UnmarshalUseNumber(b2, &a2)
|
||||
t.Assert(a2.Slice(), s2)
|
||||
t.Assert(a2.Interfaces(), s2)
|
||||
|
||||
var a3 garray.SortedStrArray
|
||||
err := json.Unmarshal(b2, &a3)
|
||||
err := json.UnmarshalUseNumber(b2, &a3)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(a3.Slice(), s1)
|
||||
t.Assert(a3.Interfaces(), s1)
|
||||
@ -598,12 +598,12 @@ func TestSortedStrArray_Json(t *testing.T) {
|
||||
t.Assert(err1, err2)
|
||||
|
||||
a2 := garray.NewSortedStrArray()
|
||||
err1 = json.Unmarshal(b2, &a2)
|
||||
err1 = json.UnmarshalUseNumber(b2, &a2)
|
||||
t.Assert(a2.Slice(), s2)
|
||||
t.Assert(a2.Interfaces(), s2)
|
||||
|
||||
var a3 garray.SortedStrArray
|
||||
err := json.Unmarshal(b2, &a3)
|
||||
err := json.UnmarshalUseNumber(b2, &a3)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(a3.Slice(), s1)
|
||||
t.Assert(a3.Interfaces(), s1)
|
||||
@ -622,7 +622,7 @@ func TestSortedStrArray_Json(t *testing.T) {
|
||||
t.Assert(err, nil)
|
||||
|
||||
user := new(User)
|
||||
err = json.Unmarshal(b, user)
|
||||
err = json.UnmarshalUseNumber(b, user)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(user.Name, data["Name"])
|
||||
t.Assert(user.Scores, []string{"A", "A", "A+"})
|
||||
@ -641,7 +641,7 @@ func TestSortedStrArray_Json(t *testing.T) {
|
||||
t.Assert(err, nil)
|
||||
|
||||
user := new(User)
|
||||
err = json.Unmarshal(b, user)
|
||||
err = json.UnmarshalUseNumber(b, user)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(user.Name, data["Name"])
|
||||
t.Assert(user.Scores, []string{"A", "A", "A+"})
|
||||
|
@ -519,7 +519,7 @@ func (l *List) UnmarshalJSON(b []byte) error {
|
||||
l.list = list.New()
|
||||
}
|
||||
var array []interface{}
|
||||
if err := json.Unmarshal(b, &array); err != nil {
|
||||
if err := json.UnmarshalUseNumber(b, &array); err != nil {
|
||||
return err
|
||||
}
|
||||
l.PushBacks(array)
|
||||
@ -536,7 +536,7 @@ func (l *List) UnmarshalValue(value interface{}) (err error) {
|
||||
var array []interface{}
|
||||
switch value.(type) {
|
||||
case string, []byte:
|
||||
err = json.Unmarshal(gconv.Bytes(value), &array)
|
||||
err = json.UnmarshalUseNumber(gconv.Bytes(value), &array)
|
||||
default:
|
||||
array = gconv.SliceAny(value)
|
||||
}
|
||||
|
@ -711,7 +711,7 @@ func TestList_Json(t *testing.T) {
|
||||
b, err := json.Marshal(a)
|
||||
t.Assert(err, nil)
|
||||
|
||||
err = json.Unmarshal(b, l)
|
||||
err = json.UnmarshalUseNumber(b, l)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(l.FrontAll(), a)
|
||||
})
|
||||
@ -721,7 +721,7 @@ func TestList_Json(t *testing.T) {
|
||||
b, err := json.Marshal(a)
|
||||
t.Assert(err, nil)
|
||||
|
||||
err = json.Unmarshal(b, &l)
|
||||
err = json.UnmarshalUseNumber(b, &l)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(l.FrontAll(), a)
|
||||
})
|
||||
|
@ -476,7 +476,7 @@ func (m *AnyAnyMap) UnmarshalJSON(b []byte) error {
|
||||
m.data = make(map[interface{}]interface{})
|
||||
}
|
||||
var data map[string]interface{}
|
||||
if err := json.Unmarshal(b, &data); err != nil {
|
||||
if err := json.UnmarshalUseNumber(b, &data); err != nil {
|
||||
return err
|
||||
}
|
||||
for k, v := range data {
|
||||
|
@ -475,7 +475,7 @@ func (m *IntAnyMap) UnmarshalJSON(b []byte) error {
|
||||
if m.data == nil {
|
||||
m.data = make(map[int]interface{})
|
||||
}
|
||||
if err := json.Unmarshal(b, &m.data); err != nil {
|
||||
if err := json.UnmarshalUseNumber(b, &m.data); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
@ -490,7 +490,7 @@ func (m *IntAnyMap) UnmarshalValue(value interface{}) (err error) {
|
||||
}
|
||||
switch value.(type) {
|
||||
case string, []byte:
|
||||
return json.Unmarshal(gconv.Bytes(value), &m.data)
|
||||
return json.UnmarshalUseNumber(gconv.Bytes(value), &m.data)
|
||||
default:
|
||||
for k, v := range gconv.Map(value) {
|
||||
m.data[gconv.Int(k)] = v
|
||||
|
@ -446,7 +446,7 @@ func (m *IntIntMap) UnmarshalJSON(b []byte) error {
|
||||
if m.data == nil {
|
||||
m.data = make(map[int]int)
|
||||
}
|
||||
if err := json.Unmarshal(b, &m.data); err != nil {
|
||||
if err := json.UnmarshalUseNumber(b, &m.data); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
@ -461,7 +461,7 @@ func (m *IntIntMap) UnmarshalValue(value interface{}) (err error) {
|
||||
}
|
||||
switch value.(type) {
|
||||
case string, []byte:
|
||||
return json.Unmarshal(gconv.Bytes(value), &m.data)
|
||||
return json.UnmarshalUseNumber(gconv.Bytes(value), &m.data)
|
||||
default:
|
||||
for k, v := range gconv.Map(value) {
|
||||
m.data[gconv.Int(k)] = gconv.Int(v)
|
||||
|
@ -446,7 +446,7 @@ func (m *IntStrMap) UnmarshalJSON(b []byte) error {
|
||||
if m.data == nil {
|
||||
m.data = make(map[int]string)
|
||||
}
|
||||
if err := json.Unmarshal(b, &m.data); err != nil {
|
||||
if err := json.UnmarshalUseNumber(b, &m.data); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
@ -461,7 +461,7 @@ func (m *IntStrMap) UnmarshalValue(value interface{}) (err error) {
|
||||
}
|
||||
switch value.(type) {
|
||||
case string, []byte:
|
||||
return json.Unmarshal(gconv.Bytes(value), &m.data)
|
||||
return json.UnmarshalUseNumber(gconv.Bytes(value), &m.data)
|
||||
default:
|
||||
for k, v := range gconv.Map(value) {
|
||||
m.data[gconv.Int(k)] = gconv.String(v)
|
||||
|
@ -471,7 +471,7 @@ func (m *StrAnyMap) UnmarshalJSON(b []byte) error {
|
||||
if m.data == nil {
|
||||
m.data = make(map[string]interface{})
|
||||
}
|
||||
if err := json.Unmarshal(b, &m.data); err != nil {
|
||||
if err := json.UnmarshalUseNumber(b, &m.data); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
@ -449,7 +449,7 @@ func (m *StrIntMap) UnmarshalJSON(b []byte) error {
|
||||
if m.data == nil {
|
||||
m.data = make(map[string]int)
|
||||
}
|
||||
if err := json.Unmarshal(b, &m.data); err != nil {
|
||||
if err := json.UnmarshalUseNumber(b, &m.data); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
@ -464,7 +464,7 @@ func (m *StrIntMap) UnmarshalValue(value interface{}) (err error) {
|
||||
}
|
||||
switch value.(type) {
|
||||
case string, []byte:
|
||||
return json.Unmarshal(gconv.Bytes(value), &m.data)
|
||||
return json.UnmarshalUseNumber(gconv.Bytes(value), &m.data)
|
||||
default:
|
||||
for k, v := range gconv.Map(value) {
|
||||
m.data[k] = gconv.Int(v)
|
||||
|
@ -449,7 +449,7 @@ func (m *StrStrMap) UnmarshalJSON(b []byte) error {
|
||||
if m.data == nil {
|
||||
m.data = make(map[string]string)
|
||||
}
|
||||
if err := json.Unmarshal(b, &m.data); err != nil {
|
||||
if err := json.UnmarshalUseNumber(b, &m.data); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
@ -530,7 +530,7 @@ func (m *ListMap) UnmarshalJSON(b []byte) error {
|
||||
m.list = glist.New()
|
||||
}
|
||||
var data map[string]interface{}
|
||||
if err := json.Unmarshal(b, &data); err != nil {
|
||||
if err := json.UnmarshalUseNumber(b, &data); err != nil {
|
||||
return err
|
||||
}
|
||||
for key, value := range data {
|
||||
|
@ -255,7 +255,7 @@ func Test_AnyAnyMap_Json(t *testing.T) {
|
||||
t.Assert(err, nil)
|
||||
|
||||
m := gmap.New()
|
||||
err = json.Unmarshal(b, m)
|
||||
err = json.UnmarshalUseNumber(b, m)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(m.Get("k1"), data["k1"])
|
||||
t.Assert(m.Get("k2"), data["k2"])
|
||||
@ -269,7 +269,7 @@ func Test_AnyAnyMap_Json(t *testing.T) {
|
||||
t.Assert(err, nil)
|
||||
|
||||
var m gmap.Map
|
||||
err = json.Unmarshal(b, &m)
|
||||
err = json.UnmarshalUseNumber(b, &m)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(m.Get("k1"), data["k1"])
|
||||
t.Assert(m.Get("k2"), data["k2"])
|
||||
|
@ -245,7 +245,7 @@ func Test_IntAnyMap_Json(t *testing.T) {
|
||||
t.Assert(err, nil)
|
||||
|
||||
m := gmap.NewIntAnyMap()
|
||||
err = json.Unmarshal(b, m)
|
||||
err = json.UnmarshalUseNumber(b, m)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(m.Get(1), data[1])
|
||||
t.Assert(m.Get(2), data[2])
|
||||
|
@ -251,7 +251,7 @@ func Test_IntIntMap_Json(t *testing.T) {
|
||||
t.Assert(err, nil)
|
||||
|
||||
m := gmap.NewIntIntMap()
|
||||
err = json.Unmarshal(b, m)
|
||||
err = json.UnmarshalUseNumber(b, m)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(m.Get(1), data[1])
|
||||
t.Assert(m.Get(2), data[2])
|
||||
|
@ -249,7 +249,7 @@ func Test_IntStrMap_Json(t *testing.T) {
|
||||
t.Assert(err, nil)
|
||||
|
||||
m := gmap.NewIntStrMap()
|
||||
err = json.Unmarshal(b, m)
|
||||
err = json.UnmarshalUseNumber(b, m)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(m.Get(1), data[1])
|
||||
t.Assert(m.Get(2), data[2])
|
||||
|
@ -204,7 +204,7 @@ func Test_ListMap_Json(t *testing.T) {
|
||||
t.Assert(err, nil)
|
||||
|
||||
m := gmap.NewListMap()
|
||||
err = json.Unmarshal(b, m)
|
||||
err = json.UnmarshalUseNumber(b, m)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(m.Get("k1"), data["k1"])
|
||||
t.Assert(m.Get("k2"), data["k2"])
|
||||
@ -219,7 +219,7 @@ func Test_ListMap_Json(t *testing.T) {
|
||||
t.Assert(err, nil)
|
||||
|
||||
var m gmap.ListMap
|
||||
err = json.Unmarshal(b, &m)
|
||||
err = json.UnmarshalUseNumber(b, &m)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(m.Get("k1"), data["k1"])
|
||||
t.Assert(m.Get("k2"), data["k2"])
|
||||
|
@ -243,7 +243,7 @@ func Test_StrAnyMap_Json(t *testing.T) {
|
||||
t.Assert(err, nil)
|
||||
|
||||
m := gmap.NewStrAnyMap()
|
||||
err = json.Unmarshal(b, m)
|
||||
err = json.UnmarshalUseNumber(b, m)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(m.Get("k1"), data["k1"])
|
||||
t.Assert(m.Get("k2"), data["k2"])
|
||||
@ -257,7 +257,7 @@ func Test_StrAnyMap_Json(t *testing.T) {
|
||||
t.Assert(err, nil)
|
||||
|
||||
var m gmap.StrAnyMap
|
||||
err = json.Unmarshal(b, &m)
|
||||
err = json.UnmarshalUseNumber(b, &m)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(m.Get("k1"), data["k1"])
|
||||
t.Assert(m.Get("k2"), data["k2"])
|
||||
|
@ -247,7 +247,7 @@ func Test_StrIntMap_Json(t *testing.T) {
|
||||
t.Assert(err, nil)
|
||||
|
||||
m := gmap.NewStrIntMap()
|
||||
err = json.Unmarshal(b, m)
|
||||
err = json.UnmarshalUseNumber(b, m)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(m.Get("k1"), data["k1"])
|
||||
t.Assert(m.Get("k2"), data["k2"])
|
||||
@ -261,7 +261,7 @@ func Test_StrIntMap_Json(t *testing.T) {
|
||||
t.Assert(err, nil)
|
||||
|
||||
var m gmap.StrIntMap
|
||||
err = json.Unmarshal(b, &m)
|
||||
err = json.UnmarshalUseNumber(b, &m)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(m.Get("k1"), data["k1"])
|
||||
t.Assert(m.Get("k2"), data["k2"])
|
||||
|
@ -244,7 +244,7 @@ func Test_StrStrMap_Json(t *testing.T) {
|
||||
t.Assert(err, nil)
|
||||
|
||||
m := gmap.NewStrStrMap()
|
||||
err = json.Unmarshal(b, m)
|
||||
err = json.UnmarshalUseNumber(b, m)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(m.Get("k1"), data["k1"])
|
||||
t.Assert(m.Get("k2"), data["k2"])
|
||||
@ -258,7 +258,7 @@ func Test_StrStrMap_Json(t *testing.T) {
|
||||
t.Assert(err, nil)
|
||||
|
||||
var m gmap.StrStrMap
|
||||
err = json.Unmarshal(b, &m)
|
||||
err = json.UnmarshalUseNumber(b, &m)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(m.Get("k1"), data["k1"])
|
||||
t.Assert(m.Get("k2"), data["k2"])
|
||||
|
@ -188,7 +188,7 @@ func Test_TreeMap_Json(t *testing.T) {
|
||||
t.Assert(err, nil)
|
||||
|
||||
m := gmap.NewTreeMap(gutil.ComparatorString)
|
||||
err = json.Unmarshal(b, m)
|
||||
err = json.UnmarshalUseNumber(b, m)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(m.Get("k1"), data["k1"])
|
||||
t.Assert(m.Get("k2"), data["k2"])
|
||||
@ -202,7 +202,7 @@ func Test_TreeMap_Json(t *testing.T) {
|
||||
t.Assert(err, nil)
|
||||
|
||||
var m gmap.TreeMap
|
||||
err = json.Unmarshal(b, &m)
|
||||
err = json.UnmarshalUseNumber(b, &m)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(m.Get("k1"), data["k1"])
|
||||
t.Assert(m.Get("k2"), data["k2"])
|
||||
|
@ -129,7 +129,7 @@ func (q *Queue) Close() {
|
||||
|
||||
// Len returns the length of the queue.
|
||||
// Note that the result might not be accurate as there's a
|
||||
// asynchronize channel reading the list constantly.
|
||||
// asynchronous channel reading the list constantly.
|
||||
func (q *Queue) Len() (length int) {
|
||||
if q.list != nil {
|
||||
length += q.list.Len()
|
||||
|
@ -477,7 +477,7 @@ func (set *Set) UnmarshalJSON(b []byte) error {
|
||||
set.data = make(map[interface{}]struct{})
|
||||
}
|
||||
var array []interface{}
|
||||
if err := json.Unmarshal(b, &array); err != nil {
|
||||
if err := json.UnmarshalUseNumber(b, &array); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, v := range array {
|
||||
@ -496,7 +496,7 @@ func (set *Set) UnmarshalValue(value interface{}) (err error) {
|
||||
var array []interface{}
|
||||
switch value.(type) {
|
||||
case string, []byte:
|
||||
err = json.Unmarshal(gconv.Bytes(value), &array)
|
||||
err = json.UnmarshalUseNumber(gconv.Bytes(value), &array)
|
||||
default:
|
||||
array = gconv.SliceAny(value)
|
||||
}
|
||||
|
@ -437,7 +437,7 @@ func (set *IntSet) UnmarshalJSON(b []byte) error {
|
||||
set.data = make(map[int]struct{})
|
||||
}
|
||||
var array []int
|
||||
if err := json.Unmarshal(b, &array); err != nil {
|
||||
if err := json.UnmarshalUseNumber(b, &array); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, v := range array {
|
||||
@ -456,7 +456,7 @@ func (set *IntSet) UnmarshalValue(value interface{}) (err error) {
|
||||
var array []int
|
||||
switch value.(type) {
|
||||
case string, []byte:
|
||||
err = json.Unmarshal(gconv.Bytes(value), &array)
|
||||
err = json.UnmarshalUseNumber(gconv.Bytes(value), &array)
|
||||
default:
|
||||
array = gconv.SliceInt(value)
|
||||
}
|
||||
|
@ -465,7 +465,7 @@ func (set *StrSet) UnmarshalJSON(b []byte) error {
|
||||
set.data = make(map[string]struct{})
|
||||
}
|
||||
var array []string
|
||||
if err := json.Unmarshal(b, &array); err != nil {
|
||||
if err := json.UnmarshalUseNumber(b, &array); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, v := range array {
|
||||
@ -484,7 +484,7 @@ func (set *StrSet) UnmarshalValue(value interface{}) (err error) {
|
||||
var array []string
|
||||
switch value.(type) {
|
||||
case string, []byte:
|
||||
err = json.Unmarshal(gconv.Bytes(value), &array)
|
||||
err = json.UnmarshalUseNumber(gconv.Bytes(value), &array)
|
||||
default:
|
||||
array = gconv.SliceStr(value)
|
||||
}
|
||||
|
@ -327,7 +327,7 @@ func TestSet_Json(t *testing.T) {
|
||||
t.Assert(err1, err2)
|
||||
|
||||
a2 := gset.New()
|
||||
err2 = json.Unmarshal(b2, &a2)
|
||||
err2 = json.UnmarshalUseNumber(b2, &a2)
|
||||
t.Assert(err2, nil)
|
||||
t.Assert(a2.Contains("a"), true)
|
||||
t.Assert(a2.Contains("b"), true)
|
||||
@ -336,7 +336,7 @@ func TestSet_Json(t *testing.T) {
|
||||
t.Assert(a2.Contains("e"), false)
|
||||
|
||||
var a3 gset.Set
|
||||
err := json.Unmarshal(b2, &a3)
|
||||
err := json.UnmarshalUseNumber(b2, &a3)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(a3.Contains("a"), true)
|
||||
t.Assert(a3.Contains("b"), true)
|
||||
|
@ -358,7 +358,7 @@ func TestIntSet_Json(t *testing.T) {
|
||||
t.Assert(err1, err2)
|
||||
|
||||
a2 := gset.NewIntSet()
|
||||
err2 = json.Unmarshal(b2, &a2)
|
||||
err2 = json.UnmarshalUseNumber(b2, &a2)
|
||||
t.Assert(err2, nil)
|
||||
t.Assert(a2.Contains(1), true)
|
||||
t.Assert(a2.Contains(2), true)
|
||||
@ -367,7 +367,7 @@ func TestIntSet_Json(t *testing.T) {
|
||||
t.Assert(a2.Contains(5), false)
|
||||
|
||||
var a3 gset.IntSet
|
||||
err := json.Unmarshal(b2, &a3)
|
||||
err := json.UnmarshalUseNumber(b2, &a3)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(a2.Contains(1), true)
|
||||
t.Assert(a2.Contains(2), true)
|
||||
|
@ -404,7 +404,7 @@ func TestStrSet_Json(t *testing.T) {
|
||||
t.Assert(err1, err2)
|
||||
|
||||
a2 := gset.NewStrSet()
|
||||
err2 = json.Unmarshal(b2, &a2)
|
||||
err2 = json.UnmarshalUseNumber(b2, &a2)
|
||||
t.Assert(err2, nil)
|
||||
t.Assert(a2.Contains("a"), true)
|
||||
t.Assert(a2.Contains("b"), true)
|
||||
@ -413,7 +413,7 @@ func TestStrSet_Json(t *testing.T) {
|
||||
t.Assert(a2.Contains("e"), false)
|
||||
|
||||
var a3 gset.StrSet
|
||||
err := json.Unmarshal(b2, &a3)
|
||||
err := json.UnmarshalUseNumber(b2, &a3)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(a3.Contains("a"), true)
|
||||
t.Assert(a3.Contains("b"), true)
|
||||
|
@ -937,7 +937,7 @@ func (tree *RedBlackTree) UnmarshalJSON(b []byte) error {
|
||||
tree.comparator = gutil.ComparatorString
|
||||
}
|
||||
var data map[string]interface{}
|
||||
if err := json.Unmarshal(b, &data); err != nil {
|
||||
if err := json.UnmarshalUseNumber(b, &data); err != nil {
|
||||
return err
|
||||
}
|
||||
for k, v := range data {
|
||||
|
@ -58,7 +58,7 @@ func (v *Interface) MarshalJSON() ([]byte, error) {
|
||||
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
|
||||
func (v *Interface) UnmarshalJSON(b []byte) error {
|
||||
var i interface{}
|
||||
err := json.Unmarshal(b, &i)
|
||||
err := json.UnmarshalUseNumber(b, &i)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -55,16 +55,16 @@ func Test_Bool_JSON(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var err error
|
||||
i := gtype.NewBool()
|
||||
err = json.Unmarshal([]byte("true"), &i)
|
||||
err = json.UnmarshalUseNumber([]byte("true"), &i)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(i.Val(), true)
|
||||
err = json.Unmarshal([]byte("false"), &i)
|
||||
err = json.UnmarshalUseNumber([]byte("false"), &i)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(i.Val(), false)
|
||||
err = json.Unmarshal([]byte("1"), &i)
|
||||
err = json.UnmarshalUseNumber([]byte("1"), &i)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(i.Val(), true)
|
||||
err = json.Unmarshal([]byte("0"), &i)
|
||||
err = json.UnmarshalUseNumber([]byte("0"), &i)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(i.Val(), false)
|
||||
})
|
||||
@ -78,7 +78,7 @@ func Test_Bool_JSON(t *testing.T) {
|
||||
t.Assert(b1, b2)
|
||||
|
||||
i2 := gtype.NewBool()
|
||||
err := json.Unmarshal(b2, &i2)
|
||||
err := json.UnmarshalUseNumber(b2, &i2)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(i2.Val(), i.Val())
|
||||
})
|
||||
@ -91,7 +91,7 @@ func Test_Bool_JSON(t *testing.T) {
|
||||
t.Assert(b1, b2)
|
||||
|
||||
i2 := gtype.NewBool()
|
||||
err := json.Unmarshal(b2, &i2)
|
||||
err := json.UnmarshalUseNumber(b2, &i2)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(i2.Val(), i.Val())
|
||||
})
|
||||
|
@ -53,7 +53,7 @@ func Test_Byte_JSON(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var err error
|
||||
i := gtype.NewByte()
|
||||
err = json.Unmarshal([]byte("49"), &i)
|
||||
err = json.UnmarshalUseNumber([]byte("49"), &i)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(i.Val(), "49")
|
||||
})
|
||||
|
@ -39,7 +39,7 @@ func Test_Bytes_JSON(t *testing.T) {
|
||||
t.Assert(b1, b2)
|
||||
|
||||
i2 := gtype.NewBytes()
|
||||
err := json.Unmarshal(b2, &i2)
|
||||
err := json.UnmarshalUseNumber(b2, &i2)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(i2.Val(), b)
|
||||
})
|
||||
|
@ -40,7 +40,7 @@ func Test_Float32_JSON(t *testing.T) {
|
||||
t.Assert(b1, b2)
|
||||
|
||||
i2 := gtype.NewFloat32()
|
||||
err := json.Unmarshal(b2, &i2)
|
||||
err := json.UnmarshalUseNumber(b2, &i2)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(i2.Val(), v)
|
||||
})
|
||||
|
@ -38,7 +38,7 @@ func Test_Float64_JSON(t *testing.T) {
|
||||
t.Assert(b1, b2)
|
||||
|
||||
i2 := gtype.NewFloat64()
|
||||
err := json.Unmarshal(b2, &i2)
|
||||
err := json.UnmarshalUseNumber(b2, &i2)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(i2.Val(), v)
|
||||
})
|
||||
|
@ -51,7 +51,7 @@ func Test_Int32_JSON(t *testing.T) {
|
||||
t.Assert(b1, b2)
|
||||
|
||||
i2 := gtype.NewInt32()
|
||||
err := json.Unmarshal(b2, &i2)
|
||||
err := json.UnmarshalUseNumber(b2, &i2)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(i2.Val(), v)
|
||||
})
|
||||
|
@ -50,7 +50,7 @@ func Test_Int64_JSON(t *testing.T) {
|
||||
t.Assert(b1, b2)
|
||||
|
||||
i2 := gtype.NewInt64()
|
||||
err := json.Unmarshal(b2, &i2)
|
||||
err := json.UnmarshalUseNumber(b2, &i2)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(i2.Val(), i)
|
||||
})
|
||||
|
@ -50,7 +50,7 @@ func Test_Int_JSON(t *testing.T) {
|
||||
t.Assert(b1, b2)
|
||||
|
||||
i2 := gtype.NewInt()
|
||||
err := json.Unmarshal(b2, &i2)
|
||||
err := json.UnmarshalUseNumber(b2, &i2)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(i2.Val(), v)
|
||||
})
|
||||
|
@ -40,7 +40,7 @@ func Test_Interface_JSON(t *testing.T) {
|
||||
t.Assert(b1, b2)
|
||||
|
||||
i2 := gtype.New()
|
||||
err := json.Unmarshal(b2, &i2)
|
||||
err := json.UnmarshalUseNumber(b2, &i2)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(i2.Val(), s)
|
||||
})
|
||||
|
@ -38,7 +38,7 @@ func Test_String_JSON(t *testing.T) {
|
||||
t.Assert(b1, b2)
|
||||
|
||||
i2 := gtype.NewString()
|
||||
err := json.Unmarshal(b2, &i2)
|
||||
err := json.UnmarshalUseNumber(b2, &i2)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(i2.Val(), s)
|
||||
})
|
||||
|
@ -50,7 +50,7 @@ func Test_Uint32_JSON(t *testing.T) {
|
||||
t.Assert(b1, b2)
|
||||
|
||||
i2 := gtype.NewUint32()
|
||||
err := json.Unmarshal(b2, &i2)
|
||||
err := json.UnmarshalUseNumber(b2, &i2)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(i2.Val(), i)
|
||||
})
|
||||
|
@ -55,7 +55,7 @@ func Test_Uint64_JSON(t *testing.T) {
|
||||
t.Assert(b1, b2)
|
||||
|
||||
i2 := gtype.NewUint64()
|
||||
err := json.Unmarshal(b2, &i2)
|
||||
err := json.UnmarshalUseNumber(b2, &i2)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(i2.Val(), i)
|
||||
})
|
||||
|
@ -49,7 +49,7 @@ func Test_Uint_JSON(t *testing.T) {
|
||||
t.Assert(b1, b2)
|
||||
|
||||
i2 := gtype.NewUint()
|
||||
err := json.Unmarshal(b2, &i2)
|
||||
err := json.UnmarshalUseNumber(b2, &i2)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(i2.Val(), i)
|
||||
})
|
||||
|
@ -189,7 +189,7 @@ func (v *Var) MarshalJSON() ([]byte, error) {
|
||||
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
|
||||
func (v *Var) UnmarshalJSON(b []byte) error {
|
||||
var i interface{}
|
||||
err := json.Unmarshal(b, &i)
|
||||
err := json.UnmarshalUseNumber(b, &i)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ func TestVar_Json(t *testing.T) {
|
||||
b, err := json.Marshal(s)
|
||||
t.Assert(err, nil)
|
||||
|
||||
err = json.Unmarshal(b, v)
|
||||
err = json.UnmarshalUseNumber(b, v)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(v.String(), s)
|
||||
})
|
||||
@ -52,7 +52,7 @@ func TestVar_Json(t *testing.T) {
|
||||
b, err := json.Marshal(s)
|
||||
t.Assert(err, nil)
|
||||
|
||||
err = json.Unmarshal(b, &v)
|
||||
err = json.UnmarshalUseNumber(b, &v)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(v.String(), s)
|
||||
})
|
||||
|
@ -11,9 +11,10 @@ import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/errors/gerror"
|
||||
"github.com/gogf/gf/os/gcmd"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/container/gvar"
|
||||
"github.com/gogf/gf/internal/intlog"
|
||||
@ -32,12 +33,12 @@ type DB interface {
|
||||
// Model creation.
|
||||
// ===========================================================================
|
||||
|
||||
// Table function is deprecated, use Model instead.
|
||||
// The DB interface is designed not only for
|
||||
// relational databases but also for NoSQL databases in the future. The name
|
||||
// "Table" is not proper for that purpose any more.
|
||||
// Also see Core.Table.
|
||||
// Deprecated, use Model instead.
|
||||
Table(table ...string) *Model
|
||||
// Also see Core.Table.
|
||||
Table(tableNameOrStruct ...interface{}) *Model
|
||||
|
||||
// Model creates and returns a new ORM model from given schema.
|
||||
// The parameter `table` can be more than one table names, and also alias name, like:
|
||||
@ -48,7 +49,7 @@ type DB interface {
|
||||
// Model("user u, user_detail ud")
|
||||
// 2. Model name with alias: Model("user", "u")
|
||||
// Also see Core.Model.
|
||||
Model(table ...string) *Model
|
||||
Model(tableNameOrStruct ...interface{}) *Model
|
||||
|
||||
// Schema creates and returns a schema.
|
||||
// Also see Core.Schema.
|
||||
@ -56,7 +57,7 @@ type DB interface {
|
||||
|
||||
// With creates and returns an ORM model based on meta data of given object.
|
||||
// Also see Core.With.
|
||||
With(object interface{}) *Model
|
||||
With(objects ...interface{}) *Model
|
||||
|
||||
// Open creates a raw connection object for database with given node configuration.
|
||||
// Note that it is not recommended using the this function manually.
|
||||
@ -84,6 +85,7 @@ type DB interface {
|
||||
|
||||
Insert(table string, data interface{}, batch ...int) (sql.Result, error) // See Core.Insert.
|
||||
InsertIgnore(table string, data interface{}, batch ...int) (sql.Result, error) // See Core.InsertIgnore.
|
||||
InsertAndGetId(table string, data interface{}, batch ...int) (int64, error) // See Core.InsertAndGetId.
|
||||
Replace(table string, data interface{}, batch ...int) (sql.Result, error) // See Core.Replace.
|
||||
Save(table string, data interface{}, batch ...int) (sql.Result, error) // See Core.Save.
|
||||
|
||||
@ -94,19 +96,6 @@ type DB interface {
|
||||
Update(table string, data interface{}, condition interface{}, args ...interface{}) (sql.Result, error) // See Core.Update.
|
||||
Delete(table string, condition interface{}, args ...interface{}) (sql.Result, error) // See Core.Delete.
|
||||
|
||||
// ===========================================================================
|
||||
// Internal APIs for CURD, which can be overwrote for custom CURD implements.
|
||||
// ===========================================================================
|
||||
|
||||
DoQuery(link Link, sql string, args ...interface{}) (rows *sql.Rows, err error) // See Core.DoQuery.
|
||||
DoGetAll(link Link, sql string, args ...interface{}) (result Result, err error) // See Core.DoGetAll.
|
||||
DoExec(link Link, sql string, args ...interface{}) (result sql.Result, err error) // See Core.DoExec.
|
||||
DoPrepare(link Link, sql string) (*Stmt, error) // See Core.DoPrepare.
|
||||
DoInsert(link Link, table string, data interface{}, option int, batch ...int) (result sql.Result, err error) // See Core.DoInsert.
|
||||
DoBatchInsert(link Link, table string, list interface{}, option int, batch ...int) (result sql.Result, err error) // See Core.DoBatchInsert.
|
||||
DoUpdate(link Link, table string, data interface{}, condition string, args ...interface{}) (result sql.Result, err error) // See Core.DoUpdate.
|
||||
DoDelete(link Link, table string, condition string, args ...interface{}) (result sql.Result, err error) // See Core.DoDelete.
|
||||
|
||||
// ===========================================================================
|
||||
// Query APIs for convenience purpose.
|
||||
// ===========================================================================
|
||||
@ -124,8 +113,8 @@ type DB interface {
|
||||
// Master/Slave specification support.
|
||||
// ===========================================================================
|
||||
|
||||
Master() (*sql.DB, error) // See Core.Master.
|
||||
Slave() (*sql.DB, error) // See Core.Slave.
|
||||
Master(schema ...string) (*sql.DB, error) // See Core.Master.
|
||||
Slave(schema ...string) (*sql.DB, error) // See Core.Slave.
|
||||
|
||||
// ===========================================================================
|
||||
// Ping-Pong.
|
||||
@ -138,8 +127,8 @@ type DB interface {
|
||||
// Transaction.
|
||||
// ===========================================================================
|
||||
|
||||
Begin() (*TX, error) // See Core.Begin.
|
||||
Transaction(f func(tx *TX) error) (err error) // See Core.Transaction.
|
||||
Begin() (*TX, error) // See Core.Begin.
|
||||
Transaction(ctx context.Context, f func(ctx context.Context, tx *TX) error) error // See Core.Transaction.
|
||||
|
||||
// ===========================================================================
|
||||
// Configuration methods.
|
||||
@ -165,38 +154,25 @@ type DB interface {
|
||||
// Utility methods.
|
||||
// ===========================================================================
|
||||
|
||||
GetCtx() context.Context // See Core.GetCtx.
|
||||
GetChars() (charLeft string, charRight string) // See Core.GetChars.
|
||||
GetMaster(schema ...string) (*sql.DB, error) // See Core.GetMaster.
|
||||
GetSlave(schema ...string) (*sql.DB, error) // See Core.GetSlave.
|
||||
QuoteWord(s string) string // See Core.QuoteWord.
|
||||
QuoteString(s string) string // See Core.QuoteString.
|
||||
QuotePrefixTableName(table string) string // See Core.QuotePrefixTableName.
|
||||
Tables(schema ...string) (tables []string, err error) // See Core.Tables.
|
||||
TableFields(link Link, table string, schema ...string) (map[string]*TableField, error) // See Core.TableFields.
|
||||
HasTable(name string) (bool, error) // See Core.HasTable.
|
||||
FilteredLinkInfo() string // See Core.FilteredLinkInfo.
|
||||
GetCtx() context.Context // See Core.GetCtx.
|
||||
GetCore() *Core // See Core.GetCore
|
||||
GetChars() (charLeft string, charRight string) // See Core.GetChars.
|
||||
Tables(ctx context.Context, schema ...string) (tables []string, err error) // See Core.Tables.
|
||||
TableFields(ctx context.Context, table string, schema ...string) (map[string]*TableField, error) // See Core.TableFields.
|
||||
FilteredLinkInfo() string // See Core.FilteredLinkInfo.
|
||||
|
||||
// HandleSqlBeforeCommit is a hook function, which deals with the sql string before
|
||||
// it's committed to underlying driver. The parameter `link` specifies the current
|
||||
// database connection operation object. You can modify the sql string `sql` and its
|
||||
// arguments `args` as you wish before they're committed to driver.
|
||||
// Also see Core.HandleSqlBeforeCommit.
|
||||
HandleSqlBeforeCommit(link Link, sql string, args []interface{}) (string, []interface{})
|
||||
|
||||
// ===========================================================================
|
||||
// Internal methods, for internal usage purpose, you do not need consider it.
|
||||
// ===========================================================================
|
||||
|
||||
mappingAndFilterData(schema, table string, data map[string]interface{}, filter bool) (map[string]interface{}, error) // See Core.mappingAndFilterData.
|
||||
convertFieldValueToLocalValue(fieldValue interface{}, fieldType string) interface{} // See Core.convertFieldValueToLocalValue.
|
||||
convertRowsToResult(rows *sql.Rows) (Result, error) // See Core.convertRowsToResult.
|
||||
HandleSqlBeforeCommit(ctx context.Context, link Link, sql string, args []interface{}) (string, []interface{})
|
||||
}
|
||||
|
||||
// Core is the base struct for database management.
|
||||
type Core struct {
|
||||
db DB // DB interface object.
|
||||
ctx context.Context // Context for chaining operation only.
|
||||
ctx context.Context // Context for chaining operation only. Do not set a default value in Core initialization.
|
||||
group string // Configuration group name.
|
||||
debug *gtype.Bool // Enable debug mode for the database, which can be changed in runtime.
|
||||
cache *gcache.Cache // Cache manager, SQL result cache only.
|
||||
@ -211,16 +187,28 @@ type Driver interface {
|
||||
New(core *Core, node *ConfigNode) (DB, error)
|
||||
}
|
||||
|
||||
// Link is a common database function wrapper interface.
|
||||
type Link interface {
|
||||
Query(sql string, args ...interface{}) (*sql.Rows, error)
|
||||
Exec(sql string, args ...interface{}) (sql.Result, error)
|
||||
Prepare(sql string) (*sql.Stmt, error)
|
||||
QueryContext(ctx context.Context, sql string, args ...interface{}) (*sql.Rows, error)
|
||||
ExecContext(ctx context.Context, sql string, args ...interface{}) (sql.Result, error)
|
||||
PrepareContext(ctx context.Context, sql string) (*sql.Stmt, error)
|
||||
IsTransaction() bool
|
||||
}
|
||||
|
||||
// Sql is the sql recording struct.
|
||||
type Sql struct {
|
||||
Sql string // SQL string(may contain reserved char '?').
|
||||
Type string // SQL operation type.
|
||||
Args []interface{} // Arguments for this sql.
|
||||
Format string // Formatted sql which contains arguments in the sql.
|
||||
Error error // Execution result.
|
||||
Start int64 // Start execution timestamp in milliseconds.
|
||||
End int64 // End execution timestamp in milliseconds.
|
||||
Group string // Group is the group name of the configuration that the sql is executed from.
|
||||
Sql string // SQL string(may contain reserved char '?').
|
||||
Type string // SQL operation type.
|
||||
Args []interface{} // Arguments for this sql.
|
||||
Format string // Formatted sql which contains arguments in the sql.
|
||||
Error error // Execution result.
|
||||
Start int64 // Start execution timestamp in milliseconds.
|
||||
End int64 // End execution timestamp in milliseconds.
|
||||
Group string // Group is the group name of the configuration that the sql is executed from.
|
||||
IsTransaction bool // IsTransaction marks whether this sql is executed in transaction.
|
||||
}
|
||||
|
||||
// TableField is the struct for table field.
|
||||
@ -235,16 +223,6 @@ type TableField struct {
|
||||
Comment string // Comment.
|
||||
}
|
||||
|
||||
// Link is a common database function wrapper interface.
|
||||
type Link interface {
|
||||
Query(sql string, args ...interface{}) (*sql.Rows, error)
|
||||
Exec(sql string, args ...interface{}) (sql.Result, error)
|
||||
Prepare(sql string) (*sql.Stmt, error)
|
||||
QueryContext(ctx context.Context, sql string, args ...interface{}) (*sql.Rows, error)
|
||||
ExecContext(ctx context.Context, sql string, args ...interface{}) (sql.Result, error)
|
||||
PrepareContext(ctx context.Context, sql string) (*sql.Stmt, error)
|
||||
}
|
||||
|
||||
// Counter is the type for update count.
|
||||
type Counter struct {
|
||||
Field string
|
||||
@ -296,12 +274,12 @@ var (
|
||||
|
||||
// regularFieldNameRegPattern is the regular expression pattern for a string
|
||||
// which is a regular field name of table.
|
||||
regularFieldNameRegPattern = `^[\w\.\-\_]+$`
|
||||
regularFieldNameRegPattern = `^[\w\.\-]+$`
|
||||
|
||||
// regularFieldNameWithoutDotRegPattern is similar to regularFieldNameRegPattern but not allows '.'.
|
||||
// Note that, although some databases allow char '.' in the field name, but it here does not allow '.'
|
||||
// in the field name as it conflicts with "db.table.field" pattern in SOME situations.
|
||||
regularFieldNameWithoutDotRegPattern = `^[\w\-\_]+$`
|
||||
regularFieldNameWithoutDotRegPattern = `^[\w\-]+$`
|
||||
|
||||
// internalCache is the memory cache for internal usage.
|
||||
internalCache = gcache.New()
|
||||
@ -337,7 +315,7 @@ func New(group ...string) (db DB, err error) {
|
||||
defer configs.RUnlock()
|
||||
|
||||
if len(configs.config) < 1 {
|
||||
return nil, gerror.New("empty database configuration")
|
||||
return nil, gerror.New("database configuration is empty, please set the database configuration before using")
|
||||
}
|
||||
if _, ok := configs.config[groupName]; ok {
|
||||
if node, err := getConfigNodeByGroup(groupName, true); err == nil {
|
||||
@ -356,13 +334,19 @@ func New(group ...string) (db DB, err error) {
|
||||
}
|
||||
return c.db, nil
|
||||
} else {
|
||||
return nil, gerror.New(fmt.Sprintf(`unsupported database type "%s"`, node.Type))
|
||||
return nil, gerror.Newf(
|
||||
`cannot find database driver for specified database type "%s", did you misspell type name "%s" or forget importing the database driver?`,
|
||||
node.Type, node.Type,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
return nil, gerror.New(fmt.Sprintf(`database configuration node "%s" is not found`, groupName))
|
||||
return nil, gerror.Newf(
|
||||
`database configuration node "%s" is not found, did you misspell group name "%s" or miss the database configuration?`,
|
||||
groupName, groupName,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,19 +11,23 @@ import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/errors/gerror"
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/errors/gerror"
|
||||
"github.com/gogf/gf/internal/utils"
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
|
||||
"github.com/gogf/gf/container/gvar"
|
||||
"github.com/gogf/gf/os/gtime"
|
||||
"github.com/gogf/gf/text/gregex"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
)
|
||||
|
||||
// GetCore returns the underlying *Core object.
|
||||
func (c *Core) GetCore() *Core {
|
||||
return c
|
||||
}
|
||||
|
||||
// Ctx is a chaining function, which creates and returns a new DB that is a shallow copy
|
||||
// of current DB object and with given context in it.
|
||||
// Note that this returned DB object can be used only once, so do not assign it to
|
||||
@ -32,6 +36,11 @@ func (c *Core) Ctx(ctx context.Context) DB {
|
||||
if ctx == nil {
|
||||
return c.db
|
||||
}
|
||||
// It is already set context in previous chaining operation.
|
||||
if c.ctx != nil {
|
||||
return c.db
|
||||
}
|
||||
// It makes a shallow copy of current db and changes its context for next chaining operation.
|
||||
var (
|
||||
err error
|
||||
newCore = &Core{}
|
||||
@ -39,10 +48,12 @@ func (c *Core) Ctx(ctx context.Context) DB {
|
||||
)
|
||||
*newCore = *c
|
||||
newCore.ctx = ctx
|
||||
// It creates a new DB object, which is commonly a wrapper for object `Core`.
|
||||
newCore.db, err = driverMap[configNode.Type].New(newCore, configNode)
|
||||
// Seldom error, just log it.
|
||||
if err != nil {
|
||||
c.db.GetLogger().Ctx(ctx).Error(err)
|
||||
// It is really a serious error here.
|
||||
// Do not let it continue.
|
||||
panic(err)
|
||||
}
|
||||
return newCore.db
|
||||
}
|
||||
@ -53,13 +64,13 @@ func (c *Core) GetCtx() context.Context {
|
||||
if c.ctx != nil {
|
||||
return c.ctx
|
||||
}
|
||||
return context.Background()
|
||||
return context.TODO()
|
||||
}
|
||||
|
||||
// GetCtxTimeout returns the context and cancel function for specified timeout type.
|
||||
func (c *Core) GetCtxTimeout(timeoutType int, ctx context.Context) (context.Context, context.CancelFunc) {
|
||||
if ctx == nil {
|
||||
ctx = c.db.GetCtx()
|
||||
ctx = c.GetCtx()
|
||||
} else {
|
||||
ctx = context.WithValue(ctx, "WrappedByGetCtxTimeout", nil)
|
||||
}
|
||||
@ -84,183 +95,41 @@ func (c *Core) GetCtxTimeout(timeoutType int, ctx context.Context) (context.Cont
|
||||
|
||||
// Master creates and returns a connection from master node if master-slave configured.
|
||||
// It returns the default connection if master-slave not configured.
|
||||
func (c *Core) Master() (*sql.DB, error) {
|
||||
return c.getSqlDb(true, c.schema.Val())
|
||||
func (c *Core) Master(schema ...string) (*sql.DB, error) {
|
||||
useSchema := ""
|
||||
if len(schema) > 0 && schema[0] != "" {
|
||||
useSchema = schema[0]
|
||||
} else {
|
||||
useSchema = c.schema.Val()
|
||||
}
|
||||
return c.getSqlDb(true, useSchema)
|
||||
}
|
||||
|
||||
// Slave creates and returns a connection from slave node if master-slave configured.
|
||||
// It returns the default connection if master-slave not configured.
|
||||
func (c *Core) Slave() (*sql.DB, error) {
|
||||
return c.getSqlDb(false, c.schema.Val())
|
||||
}
|
||||
|
||||
// Query commits one query SQL to underlying driver and returns the execution result.
|
||||
// It is most commonly used for data querying.
|
||||
func (c *Core) Query(sql string, args ...interface{}) (rows *sql.Rows, err error) {
|
||||
link, err := c.db.Slave()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.db.DoQuery(link, sql, args...)
|
||||
}
|
||||
|
||||
// DoQuery commits the sql string and its arguments to underlying driver
|
||||
// through given link object and returns the execution result.
|
||||
func (c *Core) DoQuery(link Link, sql string, args ...interface{}) (rows *sql.Rows, err error) {
|
||||
sql, args = formatSql(sql, args)
|
||||
sql, args = c.db.HandleSqlBeforeCommit(link, sql, args)
|
||||
ctx := c.db.GetCtx()
|
||||
if c.GetConfig().QueryTimeout > 0 {
|
||||
ctx, _ = context.WithTimeout(ctx, c.GetConfig().QueryTimeout)
|
||||
}
|
||||
mTime1 := gtime.TimestampMilli()
|
||||
rows, err = link.QueryContext(ctx, sql, args...)
|
||||
mTime2 := gtime.TimestampMilli()
|
||||
sqlObj := &Sql{
|
||||
Sql: sql,
|
||||
Type: "DB.QueryContext",
|
||||
Args: args,
|
||||
Format: FormatSqlWithArgs(sql, args),
|
||||
Error: err,
|
||||
Start: mTime1,
|
||||
End: mTime2,
|
||||
Group: c.db.GetGroup(),
|
||||
}
|
||||
c.addSqlToTracing(ctx, sqlObj)
|
||||
if c.db.GetDebug() {
|
||||
c.writeSqlToLogger(sqlObj)
|
||||
}
|
||||
if err == nil {
|
||||
return rows, nil
|
||||
func (c *Core) Slave(schema ...string) (*sql.DB, error) {
|
||||
useSchema := ""
|
||||
if len(schema) > 0 && schema[0] != "" {
|
||||
useSchema = schema[0]
|
||||
} else {
|
||||
err = formatError(err, sql, args...)
|
||||
useSchema = c.schema.Val()
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Exec commits one query SQL to underlying driver and returns the execution result.
|
||||
// It is most commonly used for data inserting and updating.
|
||||
func (c *Core) Exec(sql string, args ...interface{}) (result sql.Result, err error) {
|
||||
link, err := c.db.Master()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.db.DoExec(link, sql, args...)
|
||||
}
|
||||
|
||||
// DoExec commits the sql string and its arguments to underlying driver
|
||||
// through given link object and returns the execution result.
|
||||
func (c *Core) DoExec(link Link, sql string, args ...interface{}) (result sql.Result, err error) {
|
||||
sql, args = formatSql(sql, args)
|
||||
sql, args = c.db.HandleSqlBeforeCommit(link, sql, args)
|
||||
ctx := c.db.GetCtx()
|
||||
if c.GetConfig().ExecTimeout > 0 {
|
||||
var cancelFunc context.CancelFunc
|
||||
ctx, cancelFunc = context.WithTimeout(ctx, c.GetConfig().ExecTimeout)
|
||||
defer cancelFunc()
|
||||
}
|
||||
|
||||
mTime1 := gtime.TimestampMilli()
|
||||
if !c.db.GetDryRun() {
|
||||
result, err = link.ExecContext(ctx, sql, args...)
|
||||
} else {
|
||||
result = new(SqlResult)
|
||||
}
|
||||
mTime2 := gtime.TimestampMilli()
|
||||
sqlObj := &Sql{
|
||||
Sql: sql,
|
||||
Type: "DB.ExecContext",
|
||||
Args: args,
|
||||
Format: FormatSqlWithArgs(sql, args),
|
||||
Error: err,
|
||||
Start: mTime1,
|
||||
End: mTime2,
|
||||
Group: c.db.GetGroup(),
|
||||
}
|
||||
c.addSqlToTracing(ctx, sqlObj)
|
||||
if c.db.GetDebug() {
|
||||
c.writeSqlToLogger(sqlObj)
|
||||
}
|
||||
return result, formatError(err, sql, args...)
|
||||
}
|
||||
|
||||
// Prepare creates a prepared statement for later queries or executions.
|
||||
// Multiple queries or executions may be run concurrently from the
|
||||
// returned statement.
|
||||
// The caller must call the statement's Close method
|
||||
// when the statement is no longer needed.
|
||||
//
|
||||
// The parameter `execOnMaster` specifies whether executing the sql on master node,
|
||||
// or else it executes the sql on slave node if master-slave configured.
|
||||
func (c *Core) Prepare(sql string, execOnMaster ...bool) (*Stmt, error) {
|
||||
var (
|
||||
err error
|
||||
link Link
|
||||
)
|
||||
if len(execOnMaster) > 0 && execOnMaster[0] {
|
||||
if link, err = c.db.Master(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
if link, err = c.db.Slave(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return c.db.DoPrepare(link, sql)
|
||||
}
|
||||
|
||||
// doPrepare calls prepare function on given link object and returns the statement object.
|
||||
func (c *Core) DoPrepare(link Link, sql string) (*Stmt, error) {
|
||||
ctx := c.db.GetCtx()
|
||||
if c.GetConfig().PrepareTimeout > 0 {
|
||||
// DO NOT USE cancel function in prepare statement.
|
||||
ctx, _ = context.WithTimeout(ctx, c.GetConfig().PrepareTimeout)
|
||||
}
|
||||
var (
|
||||
mTime1 = gtime.TimestampMilli()
|
||||
stmt, err = link.PrepareContext(ctx, sql)
|
||||
mTime2 = gtime.TimestampMilli()
|
||||
sqlObj = &Sql{
|
||||
Sql: sql,
|
||||
Type: "DB.PrepareContext",
|
||||
Args: nil,
|
||||
Format: FormatSqlWithArgs(sql, nil),
|
||||
Error: err,
|
||||
Start: mTime1,
|
||||
End: mTime2,
|
||||
Group: c.db.GetGroup(),
|
||||
}
|
||||
)
|
||||
c.addSqlToTracing(ctx, sqlObj)
|
||||
if c.db.GetDebug() {
|
||||
c.writeSqlToLogger(sqlObj)
|
||||
}
|
||||
return &Stmt{
|
||||
Stmt: stmt,
|
||||
core: c,
|
||||
sql: sql,
|
||||
}, err
|
||||
return c.getSqlDb(false, useSchema)
|
||||
}
|
||||
|
||||
// GetAll queries and returns data records from database.
|
||||
func (c *Core) GetAll(sql string, args ...interface{}) (Result, error) {
|
||||
return c.db.DoGetAll(nil, sql, args...)
|
||||
return c.DoGetAll(c.GetCtx(), nil, sql, args...)
|
||||
}
|
||||
|
||||
// DoGetAll queries and returns data records from database.
|
||||
func (c *Core) DoGetAll(link Link, sql string, args ...interface{}) (result Result, err error) {
|
||||
if link == nil {
|
||||
link, err = c.db.Slave()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
rows, err := c.db.DoQuery(link, sql, args...)
|
||||
func (c *Core) DoGetAll(ctx context.Context, link Link, sql string, args ...interface{}) (result Result, err error) {
|
||||
rows, err := c.DoQuery(ctx, link, sql, args...)
|
||||
if err != nil || rows == nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
return c.db.convertRowsToResult(rows)
|
||||
return c.convertRowsToResult(rows)
|
||||
}
|
||||
|
||||
// GetOne queries and returns one record from database.
|
||||
@ -278,7 +147,7 @@ func (c *Core) GetOne(sql string, args ...interface{}) (Record, error) {
|
||||
// GetArray queries and returns data values as slice from database.
|
||||
// Note that if there are multiple columns in the result, it returns just one column values randomly.
|
||||
func (c *Core) GetArray(sql string, args ...interface{}) ([]Value, error) {
|
||||
all, err := c.db.DoGetAll(nil, sql, args...)
|
||||
all, err := c.DoGetAll(c.GetCtx(), nil, sql, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -373,65 +242,6 @@ func (c *Core) PingSlave() error {
|
||||
}
|
||||
}
|
||||
|
||||
// Begin starts and returns the transaction object.
|
||||
// You should call Commit or Rollback functions of the transaction object
|
||||
// if you no longer use the transaction. Commit or Rollback functions will also
|
||||
// close the transaction automatically.
|
||||
func (c *Core) Begin() (*TX, error) {
|
||||
if master, err := c.db.Master(); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
//ctx := c.db.GetCtx()
|
||||
//if c.GetConfig().TranTimeout > 0 {
|
||||
// var cancelFunc context.CancelFunc
|
||||
// ctx, cancelFunc = context.WithTimeout(ctx, c.GetConfig().TranTimeout)
|
||||
// defer cancelFunc()
|
||||
//}
|
||||
if tx, err := master.Begin(); err == nil {
|
||||
return &TX{
|
||||
db: c.db,
|
||||
tx: tx,
|
||||
master: master,
|
||||
}, nil
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Transaction wraps the transaction logic using function `f`.
|
||||
// It rollbacks the transaction and returns the error from function `f` if
|
||||
// it returns non-nil error. It commits the transaction and returns nil if
|
||||
// function `f` returns nil.
|
||||
//
|
||||
// Note that, you should not Commit or Rollback the transaction in function `f`
|
||||
// as it is automatically handled by this function.
|
||||
func (c *Core) Transaction(f func(tx *TX) error) (err error) {
|
||||
var tx *TX
|
||||
tx, err = c.db.Begin()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err == nil {
|
||||
if e := recover(); e != nil {
|
||||
err = fmt.Errorf("%v", e)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
if e := tx.Rollback(); e != nil {
|
||||
err = e
|
||||
}
|
||||
} else {
|
||||
if e := tx.Commit(); e != nil {
|
||||
err = e
|
||||
}
|
||||
}
|
||||
}()
|
||||
err = f(tx)
|
||||
return
|
||||
}
|
||||
|
||||
// Insert does "INSERT INTO ..." statement for the table.
|
||||
// If there's already one unique record of the data in the table, it returns error.
|
||||
//
|
||||
@ -464,6 +274,14 @@ func (c *Core) InsertIgnore(table string, data interface{}, batch ...int) (sql.R
|
||||
return c.Model(table).Data(data).InsertIgnore()
|
||||
}
|
||||
|
||||
// InsertAndGetId performs action Insert and returns the last insert id that automatically generated.
|
||||
func (c *Core) InsertAndGetId(table string, data interface{}, batch ...int) (int64, error) {
|
||||
if len(batch) > 0 {
|
||||
return c.Model(table).Data(data).Batch(batch[0]).InsertAndGetId()
|
||||
}
|
||||
return c.Model(table).Data(data).InsertAndGetId()
|
||||
}
|
||||
|
||||
// Replace does "REPLACE INTO ..." statement for the table.
|
||||
// If there's already one unique record of the data in the table, it deletes the record
|
||||
// and inserts a new one.
|
||||
@ -501,7 +319,7 @@ func (c *Core) Save(table string, data interface{}, batch ...int) (sql.Result, e
|
||||
return c.Model(table).Data(data).Save()
|
||||
}
|
||||
|
||||
// doInsert inserts or updates data for given table.
|
||||
// DoInsert inserts or updates data for given table.
|
||||
// This function is usually used for custom interface definition, you do not need call it manually.
|
||||
// The parameter `data` can be type of map/gmap/struct/*struct/[]map/[]struct, etc.
|
||||
// Eg:
|
||||
@ -513,8 +331,8 @@ func (c *Core) Save(table string, data interface{}, batch ...int) (sql.Result, e
|
||||
// 1: replace: if there's unique/primary key in the data, it deletes it from table and inserts a new one;
|
||||
// 2: save: if there's unique/primary key in the data, it updates it or else inserts a new one;
|
||||
// 3: ignore: if there's unique/primary key in the data, it ignores the inserting;
|
||||
func (c *Core) DoInsert(link Link, table string, data interface{}, option int, batch ...int) (result sql.Result, err error) {
|
||||
table = c.db.QuotePrefixTableName(table)
|
||||
func (c *Core) DoInsert(ctx context.Context, link Link, table string, data interface{}, option int, batch ...int) (result sql.Result, err error) {
|
||||
table = c.QuotePrefixTableName(table)
|
||||
var (
|
||||
fields []string
|
||||
values []string
|
||||
@ -529,10 +347,10 @@ func (c *Core) DoInsert(link Link, table string, data interface{}, option int, b
|
||||
}
|
||||
switch reflectKind {
|
||||
case reflect.Slice, reflect.Array:
|
||||
return c.db.DoBatchInsert(link, table, data, option, batch...)
|
||||
return c.DoBatchInsert(ctx, link, table, data, option, batch...)
|
||||
case reflect.Struct:
|
||||
if _, ok := data.(apiInterfaces); ok {
|
||||
return c.db.DoBatchInsert(link, table, data, option, batch...)
|
||||
return c.DoBatchInsert(ctx, link, table, data, option, batch...)
|
||||
} else {
|
||||
dataMap = ConvertDataForTableRecord(data)
|
||||
}
|
||||
@ -577,19 +395,15 @@ func (c *Core) DoInsert(link Link, table string, data interface{}, option int, b
|
||||
updateStr = fmt.Sprintf("ON DUPLICATE KEY UPDATE %s", updateStr)
|
||||
}
|
||||
if link == nil {
|
||||
if link, err = c.db.Master(); err != nil {
|
||||
if link, err = c.MasterLink(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return c.db.DoExec(
|
||||
link,
|
||||
fmt.Sprintf(
|
||||
"%s INTO %s(%s) VALUES(%s) %s",
|
||||
operation, table, strings.Join(fields, ","),
|
||||
strings.Join(values, ","), updateStr,
|
||||
),
|
||||
params...,
|
||||
)
|
||||
return c.DoExec(ctx, link, fmt.Sprintf(
|
||||
"%s INTO %s(%s) VALUES(%s) %s",
|
||||
operation, table, strings.Join(fields, ","),
|
||||
strings.Join(values, ","), updateStr,
|
||||
), params...)
|
||||
}
|
||||
|
||||
// BatchInsert batch inserts data.
|
||||
@ -630,8 +444,8 @@ func (c *Core) BatchSave(table string, list interface{}, batch ...int) (sql.Resu
|
||||
|
||||
// DoBatchInsert batch inserts/replaces/saves data.
|
||||
// This function is usually used for custom interface definition, you do not need call it manually.
|
||||
func (c *Core) DoBatchInsert(link Link, table string, list interface{}, option int, batch ...int) (result sql.Result, err error) {
|
||||
table = c.db.QuotePrefixTableName(table)
|
||||
func (c *Core) DoBatchInsert(ctx context.Context, link Link, table string, list interface{}, option int, batch ...int) (result sql.Result, err error) {
|
||||
table = c.QuotePrefixTableName(table)
|
||||
var (
|
||||
keys []string // Field names.
|
||||
values []string // Value holder string array, like: (?,?,?)
|
||||
@ -686,7 +500,7 @@ func (c *Core) DoBatchInsert(link Link, table string, list interface{}, option i
|
||||
return result, gerror.New("data list cannot be empty")
|
||||
}
|
||||
if link == nil {
|
||||
if link, err = c.db.Master(); err != nil {
|
||||
if link, err = c.MasterLink(); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -742,16 +556,12 @@ func (c *Core) DoBatchInsert(link Link, table string, list interface{}, option i
|
||||
}
|
||||
valueHolder = append(valueHolder, "("+gstr.Join(values, ",")+")")
|
||||
if len(valueHolder) == batchNum || (i == listMapLen-1 && len(valueHolder) > 0) {
|
||||
r, err := c.db.DoExec(
|
||||
link,
|
||||
fmt.Sprintf(
|
||||
"%s INTO %s(%s) VALUES%s %s",
|
||||
operation, table, keysStr,
|
||||
gstr.Join(valueHolder, ","),
|
||||
updateStr,
|
||||
),
|
||||
params...,
|
||||
)
|
||||
r, err := c.DoExec(ctx, link, fmt.Sprintf(
|
||||
"%s INTO %s(%s) VALUES%s %s",
|
||||
operation, table, keysStr,
|
||||
gstr.Join(valueHolder, ","),
|
||||
updateStr,
|
||||
), params...)
|
||||
if err != nil {
|
||||
return r, err
|
||||
}
|
||||
@ -786,10 +596,10 @@ func (c *Core) Update(table string, data interface{}, condition interface{}, arg
|
||||
return c.Model(table).Data(data).Where(condition, args...).Update()
|
||||
}
|
||||
|
||||
// doUpdate does "UPDATE ... " statement for the table.
|
||||
// DoUpdate does "UPDATE ... " statement for the table.
|
||||
// This function is usually used for custom interface definition, you do not need call it manually.
|
||||
func (c *Core) DoUpdate(link Link, table string, data interface{}, condition string, args ...interface{}) (result sql.Result, err error) {
|
||||
table = c.db.QuotePrefixTableName(table)
|
||||
func (c *Core) DoUpdate(ctx context.Context, link Link, table string, data interface{}, condition string, args ...interface{}) (result sql.Result, err error) {
|
||||
table = c.QuotePrefixTableName(table)
|
||||
var (
|
||||
rv = reflect.ValueOf(data)
|
||||
kind = rv.Kind()
|
||||
@ -812,24 +622,29 @@ func (c *Core) DoUpdate(link Link, table string, data interface{}, condition str
|
||||
switch value := v.(type) {
|
||||
case *Counter:
|
||||
if value.Value != 0 {
|
||||
column := c.db.QuoteWord(value.Field)
|
||||
column := k
|
||||
if value.Field != "" {
|
||||
column = c.QuoteWord(value.Field)
|
||||
}
|
||||
fields = append(fields, fmt.Sprintf("%s=%s+?", column, column))
|
||||
params = append(params, value.Value)
|
||||
}
|
||||
case Counter:
|
||||
if value.Value != 0 {
|
||||
column := c.db.QuoteWord(value.Field)
|
||||
column := k
|
||||
if value.Field != "" {
|
||||
column = c.QuoteWord(value.Field)
|
||||
}
|
||||
fields = append(fields, fmt.Sprintf("%s=%s+?", column, column))
|
||||
params = append(params, value.Value)
|
||||
}
|
||||
default:
|
||||
if s, ok := v.(Raw); ok {
|
||||
fields = append(fields, c.db.QuoteWord(k)+"="+gconv.String(s))
|
||||
fields = append(fields, c.QuoteWord(k)+"="+gconv.String(s))
|
||||
} else {
|
||||
fields = append(fields, c.db.QuoteWord(k)+"=?")
|
||||
fields = append(fields, c.QuoteWord(k)+"=?")
|
||||
params = append(params, v)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
updates = strings.Join(fields, ",")
|
||||
@ -844,15 +659,11 @@ func (c *Core) DoUpdate(link Link, table string, data interface{}, condition str
|
||||
}
|
||||
// If no link passed, it then uses the master link.
|
||||
if link == nil {
|
||||
if link, err = c.db.Master(); err != nil {
|
||||
if link, err = c.MasterLink(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return c.db.DoExec(
|
||||
link,
|
||||
fmt.Sprintf("UPDATE %s SET %s%s", table, updates, condition),
|
||||
args...,
|
||||
)
|
||||
return c.DoExec(ctx, link, fmt.Sprintf("UPDATE %s SET %s%s", table, updates, condition), args...)
|
||||
}
|
||||
|
||||
// Delete does "DELETE FROM ... " statement for the table.
|
||||
@ -872,14 +683,14 @@ func (c *Core) Delete(table string, condition interface{}, args ...interface{})
|
||||
|
||||
// DoDelete does "DELETE FROM ... " statement for the table.
|
||||
// This function is usually used for custom interface definition, you do not need call it manually.
|
||||
func (c *Core) DoDelete(link Link, table string, condition string, args ...interface{}) (result sql.Result, err error) {
|
||||
func (c *Core) DoDelete(ctx context.Context, link Link, table string, condition string, args ...interface{}) (result sql.Result, err error) {
|
||||
if link == nil {
|
||||
if link, err = c.db.Master(); err != nil {
|
||||
if link, err = c.MasterLink(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
table = c.db.QuotePrefixTableName(table)
|
||||
return c.db.DoExec(link, fmt.Sprintf("DELETE FROM %s%s", table, condition), args...)
|
||||
table = c.QuotePrefixTableName(table)
|
||||
return c.DoExec(ctx, link, fmt.Sprintf("DELETE FROM %s%s", table, condition), args...)
|
||||
}
|
||||
|
||||
// convertRowsToResult converts underlying data record type sql.Rows to Result type.
|
||||
@ -915,7 +726,7 @@ func (c *Core) convertRowsToResult(rows *sql.Rows) (Result, error) {
|
||||
if value == nil {
|
||||
row[columnNames[i]] = gvar.New(nil)
|
||||
} else {
|
||||
row[columnNames[i]] = gvar.New(c.db.convertFieldValueToLocalValue(value, columnTypes[i]))
|
||||
row[columnNames[i]] = gvar.New(c.convertFieldValueToLocalValue(value, columnTypes[i]))
|
||||
}
|
||||
}
|
||||
records = append(records, row)
|
||||
@ -937,19 +748,25 @@ func (c *Core) MarshalJSON() ([]byte, error) {
|
||||
|
||||
// writeSqlToLogger outputs the sql object to logger.
|
||||
// It is enabled only if configuration "debug" is true.
|
||||
func (c *Core) writeSqlToLogger(v *Sql) {
|
||||
s := fmt.Sprintf("[%3d ms] [%s] %s", v.End-v.Start, v.Group, v.Format)
|
||||
if v.Error != nil {
|
||||
s += "\nError: " + v.Error.Error()
|
||||
c.logger.Ctx(c.db.GetCtx()).Error(s)
|
||||
func (c *Core) writeSqlToLogger(ctx context.Context, sql *Sql) {
|
||||
var transactionIdStr string
|
||||
if sql.IsTransaction {
|
||||
if v := ctx.Value(transactionIdForLoggerCtx); v != nil {
|
||||
transactionIdStr = fmt.Sprintf(`[%d] `, v.(uint64))
|
||||
}
|
||||
}
|
||||
s := fmt.Sprintf("[%3d ms] [%s] %s%s", sql.End-sql.Start, sql.Group, transactionIdStr, sql.Format)
|
||||
if sql.Error != nil {
|
||||
s += "\nError: " + sql.Error.Error()
|
||||
c.logger.Ctx(ctx).Error(s)
|
||||
} else {
|
||||
c.logger.Ctx(c.db.GetCtx()).Debug(s)
|
||||
c.logger.Ctx(ctx).Debug(s)
|
||||
}
|
||||
}
|
||||
|
||||
// HasTable determine whether the table name exists in the database.
|
||||
func (c *Core) HasTable(name string) (bool, error) {
|
||||
tableList, err := c.db.Tables()
|
||||
tableList, err := c.db.Tables(c.GetCtx())
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
@ -8,15 +8,12 @@ package gdb
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/os/gcache"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/os/glog"
|
||||
)
|
||||
"github.com/gogf/gf/os/gcache"
|
||||
|
||||
const (
|
||||
DefaultGroupName = "default" // Default group name.
|
||||
"github.com/gogf/gf/os/glog"
|
||||
)
|
||||
|
||||
// Config is the configuration management object.
|
||||
@ -53,6 +50,10 @@ type ConfigNode struct {
|
||||
TimeMaintainDisabled bool `json:"timeMaintainDisabled"` // (Optional) Disable the automatic time maintaining feature.
|
||||
}
|
||||
|
||||
const (
|
||||
DefaultGroupName = "default" // Default group name.
|
||||
)
|
||||
|
||||
// configs is internal used configuration object.
|
||||
var configs struct {
|
||||
sync.RWMutex
|
||||
|
31
database/gdb/gdb_core_link.go
Normal file
31
database/gdb/gdb_core_link.go
Normal file
@ -0,0 +1,31 @@
|
||||
// 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 (
|
||||
"database/sql"
|
||||
)
|
||||
|
||||
// dbLink is used to implement interface Link for DB.
|
||||
type dbLink struct {
|
||||
*sql.DB
|
||||
}
|
||||
|
||||
// txLink is used to implement interface Link for TX.
|
||||
type txLink struct {
|
||||
*sql.Tx
|
||||
}
|
||||
|
||||
// IsTransaction returns if current Link is a transaction.
|
||||
func (*dbLink) IsTransaction() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsTransaction returns if current Link is a transaction.
|
||||
func (*txLink) IsTransaction() bool {
|
||||
return true
|
||||
}
|
@ -7,10 +7,11 @@
|
||||
package gdb
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/util/gutil"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/util/gutil"
|
||||
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
|
||||
"github.com/gogf/gf/os/gtime"
|
||||
@ -99,7 +100,8 @@ func (c *Core) convertFieldValueToLocalValue(fieldValue interface{}, fieldType s
|
||||
|
||||
case
|
||||
"datetime",
|
||||
"timestamp":
|
||||
"timestamp",
|
||||
"timestamptz":
|
||||
if t, ok := fieldValue.(time.Time); ok {
|
||||
return gtime.NewFromTime(t)
|
||||
}
|
||||
@ -149,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(nil, table, schema); err == nil {
|
||||
if fieldsMap, err := c.db.TableFields(c.GetCtx(), table, schema); err == nil {
|
||||
fieldsKeyMap := make(map[string]interface{}, len(fieldsMap))
|
||||
for k, _ := range fieldsMap {
|
||||
fieldsKeyMap[k] = nil
|
||||
|
573
database/gdb/gdb_core_transaction.go
Normal file
573
database/gdb/gdb_core_transaction.go
Normal file
@ -0,0 +1,573 @@
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package gdb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/gogf/gf/container/gtype"
|
||||
"github.com/gogf/gf/os/gtime"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
"github.com/gogf/gf/util/guid"
|
||||
|
||||
"github.com/gogf/gf/text/gregex"
|
||||
)
|
||||
|
||||
// TX is the struct for transaction management.
|
||||
type TX struct {
|
||||
db DB // db is the current gdb database manager.
|
||||
tx *sql.Tx // tx is the raw and underlying transaction manager.
|
||||
ctx context.Context // ctx is the context for this transaction only.
|
||||
master *sql.DB // master is the raw and underlying database manager.
|
||||
transactionId string // transactionId is an unique id generated by this object for this transaction.
|
||||
transactionCount int // transactionCount marks the times that Begins.
|
||||
}
|
||||
|
||||
const (
|
||||
transactionPointerPrefix = "transaction"
|
||||
contextTransactionKeyPrefix = "TransactionObjectForGroup_"
|
||||
transactionIdForLoggerCtx = "TransactionId"
|
||||
)
|
||||
|
||||
var (
|
||||
transactionIdGenerator = gtype.NewUint64()
|
||||
)
|
||||
|
||||
// Begin starts and returns the transaction object.
|
||||
// You should call Commit or Rollback functions of the transaction object
|
||||
// if you no longer use the transaction. Commit or Rollback functions will also
|
||||
// close the transaction automatically.
|
||||
func (c *Core) Begin() (tx *TX, err error) {
|
||||
return c.doBeginCtx(c.GetCtx())
|
||||
}
|
||||
|
||||
func (c *Core) doBeginCtx(ctx context.Context) (*TX, error) {
|
||||
if master, err := c.db.Master(); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
var (
|
||||
tx *TX
|
||||
sqlStr = "BEGIN"
|
||||
mTime1 = gtime.TimestampMilli()
|
||||
rawTx, err = master.Begin()
|
||||
mTime2 = gtime.TimestampMilli()
|
||||
sqlObj = &Sql{
|
||||
Sql: sqlStr,
|
||||
Type: "DB.Begin",
|
||||
Args: nil,
|
||||
Format: sqlStr,
|
||||
Error: err,
|
||||
Start: mTime1,
|
||||
End: mTime2,
|
||||
Group: c.db.GetGroup(),
|
||||
IsTransaction: true,
|
||||
}
|
||||
)
|
||||
if err == nil {
|
||||
tx = &TX{
|
||||
db: c.db,
|
||||
tx: rawTx,
|
||||
ctx: context.WithValue(ctx, transactionIdForLoggerCtx, transactionIdGenerator.Add(1)),
|
||||
master: master,
|
||||
transactionId: guid.S(),
|
||||
}
|
||||
ctx = tx.ctx
|
||||
}
|
||||
// Tracing and logging.
|
||||
c.addSqlToTracing(ctx, sqlObj)
|
||||
if c.db.GetDebug() {
|
||||
c.writeSqlToLogger(ctx, sqlObj)
|
||||
}
|
||||
return tx, err
|
||||
}
|
||||
}
|
||||
|
||||
// Transaction wraps the transaction logic using function `f`.
|
||||
// It rollbacks the transaction and returns the error from function `f` if
|
||||
// it returns non-nil error. It commits the transaction and returns nil if
|
||||
// function `f` returns nil.
|
||||
//
|
||||
// Note that, you should not Commit or Rollback the transaction in function `f`
|
||||
// as it is automatically handled by this function.
|
||||
func (c *Core) Transaction(ctx context.Context, f func(ctx context.Context, tx *TX) error) (err error) {
|
||||
var (
|
||||
tx *TX
|
||||
)
|
||||
if ctx == nil {
|
||||
ctx = c.GetCtx()
|
||||
}
|
||||
// Check transaction object from context.
|
||||
tx = TXFromCtx(ctx, c.db.GetGroup())
|
||||
if tx != nil {
|
||||
return tx.Transaction(ctx, f)
|
||||
}
|
||||
tx, err = c.doBeginCtx(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Inject transaction object into context.
|
||||
tx.ctx = WithTX(tx.ctx, tx)
|
||||
defer func() {
|
||||
if err == nil {
|
||||
if e := recover(); e != nil {
|
||||
err = fmt.Errorf("%v", e)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
if e := tx.Rollback(); e != nil {
|
||||
err = e
|
||||
}
|
||||
} else {
|
||||
if e := tx.Commit(); e != nil {
|
||||
err = e
|
||||
}
|
||||
}
|
||||
}()
|
||||
err = f(tx.ctx, tx)
|
||||
return
|
||||
}
|
||||
|
||||
// WithTX injects given transaction object into context and returns a new context.
|
||||
func WithTX(ctx context.Context, tx *TX) context.Context {
|
||||
if tx == nil {
|
||||
return ctx
|
||||
}
|
||||
// Check repeat injection from given.
|
||||
group := tx.db.GetGroup()
|
||||
if tx := TXFromCtx(ctx, group); tx != nil && tx.db.GetGroup() == group {
|
||||
return ctx
|
||||
}
|
||||
dbCtx := tx.db.GetCtx()
|
||||
if tx := TXFromCtx(dbCtx, group); tx != nil && tx.db.GetGroup() == group {
|
||||
return dbCtx
|
||||
}
|
||||
// Inject transaction object and id into context.
|
||||
ctx = context.WithValue(ctx, transactionKeyForContext(group), tx)
|
||||
return ctx
|
||||
}
|
||||
|
||||
// TXFromCtx retrieves and returns transaction object from context.
|
||||
// It is usually used in nested transaction feature, and it returns nil if it is not set previously.
|
||||
func TXFromCtx(ctx context.Context, group string) *TX {
|
||||
if ctx == nil {
|
||||
return nil
|
||||
}
|
||||
v := ctx.Value(transactionKeyForContext(group))
|
||||
if v != nil {
|
||||
tx := v.(*TX)
|
||||
tx.ctx = ctx
|
||||
return tx
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// transactionKeyForContext forms and returns a string for storing transaction object of certain database group into context.
|
||||
func transactionKeyForContext(group string) string {
|
||||
return contextTransactionKeyPrefix + group
|
||||
}
|
||||
|
||||
// transactionKeyForNestedPoint forms and returns the transaction key at current save point.
|
||||
func (tx *TX) transactionKeyForNestedPoint() string {
|
||||
return tx.db.GetCore().QuoteWord(transactionPointerPrefix + gconv.String(tx.transactionCount))
|
||||
}
|
||||
|
||||
// Ctx sets the context for current transaction.
|
||||
func (tx *TX) Ctx(ctx context.Context) *TX {
|
||||
tx.ctx = ctx
|
||||
return tx
|
||||
}
|
||||
|
||||
// Commit commits current transaction.
|
||||
// Note that it releases previous saved transaction point if it's in a nested transaction procedure,
|
||||
// or else it commits the hole transaction.
|
||||
func (tx *TX) Commit() error {
|
||||
if tx.transactionCount > 0 {
|
||||
tx.transactionCount--
|
||||
_, err := tx.Exec("RELEASE SAVEPOINT " + tx.transactionKeyForNestedPoint())
|
||||
return err
|
||||
}
|
||||
var (
|
||||
sqlStr = "COMMIT"
|
||||
mTime1 = gtime.TimestampMilli()
|
||||
err = tx.tx.Commit()
|
||||
mTime2 = gtime.TimestampMilli()
|
||||
sqlObj = &Sql{
|
||||
Sql: sqlStr,
|
||||
Type: "TX.Commit",
|
||||
Args: nil,
|
||||
Format: sqlStr,
|
||||
Error: err,
|
||||
Start: mTime1,
|
||||
End: mTime2,
|
||||
Group: tx.db.GetGroup(),
|
||||
IsTransaction: true,
|
||||
}
|
||||
)
|
||||
tx.db.GetCore().addSqlToTracing(tx.ctx, sqlObj)
|
||||
if tx.db.GetDebug() {
|
||||
tx.db.GetCore().writeSqlToLogger(tx.ctx, sqlObj)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Rollback aborts current transaction.
|
||||
// Note that it aborts current transaction if it's in a nested transaction procedure,
|
||||
// or else it aborts the hole transaction.
|
||||
func (tx *TX) Rollback() error {
|
||||
if tx.transactionCount > 0 {
|
||||
tx.transactionCount--
|
||||
_, err := tx.Exec("ROLLBACK TO SAVEPOINT " + tx.transactionKeyForNestedPoint())
|
||||
return err
|
||||
}
|
||||
var (
|
||||
sqlStr = "ROLLBACK"
|
||||
mTime1 = gtime.TimestampMilli()
|
||||
err = tx.tx.Rollback()
|
||||
mTime2 = gtime.TimestampMilli()
|
||||
sqlObj = &Sql{
|
||||
Sql: sqlStr,
|
||||
Type: "TX.Rollback",
|
||||
Args: nil,
|
||||
Format: sqlStr,
|
||||
Error: err,
|
||||
Start: mTime1,
|
||||
End: mTime2,
|
||||
Group: tx.db.GetGroup(),
|
||||
IsTransaction: true,
|
||||
}
|
||||
)
|
||||
tx.db.GetCore().addSqlToTracing(tx.ctx, sqlObj)
|
||||
if tx.db.GetDebug() {
|
||||
tx.db.GetCore().writeSqlToLogger(tx.ctx, sqlObj)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Begin starts a nested transaction procedure.
|
||||
func (tx *TX) Begin() error {
|
||||
_, err := tx.Exec("SAVEPOINT " + tx.transactionKeyForNestedPoint())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tx.transactionCount++
|
||||
return nil
|
||||
}
|
||||
|
||||
// SavePoint performs `SAVEPOINT xxx` SQL statement that saves transaction at current point.
|
||||
// The parameter `point` specifies the point name that will be saved to server.
|
||||
func (tx *TX) SavePoint(point string) error {
|
||||
_, err := tx.Exec("SAVEPOINT " + tx.db.GetCore().QuoteWord(point))
|
||||
return err
|
||||
}
|
||||
|
||||
// RollbackTo performs `ROLLBACK TO SAVEPOINT xxx` SQL statement that rollbacks to specified saved transaction.
|
||||
// The parameter `point` specifies the point name that was saved previously.
|
||||
func (tx *TX) RollbackTo(point string) error {
|
||||
_, err := tx.Exec("ROLLBACK TO SAVEPOINT " + tx.db.GetCore().QuoteWord(point))
|
||||
return err
|
||||
}
|
||||
|
||||
// Transaction wraps the transaction logic using function `f`.
|
||||
// It rollbacks the transaction and returns the error from function `f` if
|
||||
// it returns non-nil error. It commits the transaction and returns nil if
|
||||
// function `f` returns nil.
|
||||
//
|
||||
// Note that, you should not Commit or Rollback the transaction in function `f`
|
||||
// as it is automatically handled by this function.
|
||||
func (tx *TX) Transaction(ctx context.Context, f func(ctx context.Context, tx *TX) error) (err error) {
|
||||
if ctx != nil {
|
||||
tx.ctx = ctx
|
||||
}
|
||||
// Check transaction object from context.
|
||||
if TXFromCtx(tx.ctx, tx.db.GetGroup()) == nil {
|
||||
// Inject transaction object into context.
|
||||
tx.ctx = WithTX(tx.ctx, tx)
|
||||
}
|
||||
err = tx.Begin()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err == nil {
|
||||
if e := recover(); e != nil {
|
||||
err = fmt.Errorf("%v", e)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
if e := tx.Rollback(); e != nil {
|
||||
err = e
|
||||
}
|
||||
} else {
|
||||
if e := tx.Commit(); e != nil {
|
||||
err = e
|
||||
}
|
||||
}
|
||||
}()
|
||||
err = f(tx.ctx, tx)
|
||||
return
|
||||
}
|
||||
|
||||
// Query does query operation on transaction.
|
||||
// See Core.Query.
|
||||
func (tx *TX) Query(sql string, args ...interface{}) (rows *sql.Rows, err error) {
|
||||
return tx.db.GetCore().DoQuery(tx.ctx, &txLink{tx.tx}, sql, args...)
|
||||
}
|
||||
|
||||
// Exec does none query operation on transaction.
|
||||
// See Core.Exec.
|
||||
func (tx *TX) Exec(sql string, args ...interface{}) (sql.Result, error) {
|
||||
return tx.db.GetCore().DoExec(tx.ctx, &txLink{tx.tx}, sql, args...)
|
||||
}
|
||||
|
||||
// Prepare creates a prepared statement for later queries or executions.
|
||||
// Multiple queries or executions may be run concurrently from the
|
||||
// returned statement.
|
||||
// The caller must call the statement's Close method
|
||||
// when the statement is no longer needed.
|
||||
func (tx *TX) Prepare(sql string) (*Stmt, error) {
|
||||
return tx.db.GetCore().DoPrepare(tx.ctx, &txLink{tx.tx}, sql)
|
||||
}
|
||||
|
||||
// GetAll queries and returns data records from database.
|
||||
func (tx *TX) GetAll(sql string, args ...interface{}) (Result, error) {
|
||||
rows, err := tx.Query(sql, args...)
|
||||
if err != nil || rows == nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
return tx.db.GetCore().convertRowsToResult(rows)
|
||||
}
|
||||
|
||||
// GetOne queries and returns one record from database.
|
||||
func (tx *TX) GetOne(sql string, args ...interface{}) (Record, error) {
|
||||
list, err := tx.GetAll(sql, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(list) > 0 {
|
||||
return list[0], nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// GetStruct queries one record from database and converts it to given struct.
|
||||
// The parameter `pointer` should be a pointer to struct.
|
||||
func (tx *TX) GetStruct(obj interface{}, sql string, args ...interface{}) error {
|
||||
one, err := tx.GetOne(sql, args...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return one.Struct(obj)
|
||||
}
|
||||
|
||||
// GetStructs queries records from database and converts them to given struct.
|
||||
// The parameter `pointer` should be type of struct slice: []struct/[]*struct.
|
||||
func (tx *TX) GetStructs(objPointerSlice interface{}, sql string, args ...interface{}) error {
|
||||
all, err := tx.GetAll(sql, args...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return all.Structs(objPointerSlice)
|
||||
}
|
||||
|
||||
// GetScan queries one or more records from database and converts them to given struct or
|
||||
// struct array.
|
||||
//
|
||||
// If parameter `pointer` is type of struct pointer, it calls GetStruct internally for
|
||||
// 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 fmt.Errorf("params should be type of pointer, but got: %v", k)
|
||||
}
|
||||
k = t.Elem().Kind()
|
||||
switch k {
|
||||
case reflect.Array, reflect.Slice:
|
||||
return tx.GetStructs(pointer, sql, args...)
|
||||
case reflect.Struct:
|
||||
return tx.GetStruct(pointer, sql, args...)
|
||||
default:
|
||||
return fmt.Errorf("element type should be type of struct/slice, unsupported: %v", k)
|
||||
}
|
||||
}
|
||||
|
||||
// GetValue queries and returns the field value from database.
|
||||
// The sql should queries only one field from database, or else it returns only one
|
||||
// field of the result.
|
||||
func (tx *TX) GetValue(sql string, args ...interface{}) (Value, error) {
|
||||
one, err := tx.GetOne(sql, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, v := range one {
|
||||
return v, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// GetCount queries and returns the count from database.
|
||||
func (tx *TX) GetCount(sql string, args ...interface{}) (int, error) {
|
||||
if !gregex.IsMatchString(`(?i)SELECT\s+COUNT\(.+\)\s+FROM`, sql) {
|
||||
sql, _ = gregex.ReplaceString(`(?i)(SELECT)\s+(.+)\s+(FROM)`, `$1 COUNT($2) $3`, sql)
|
||||
}
|
||||
value, err := tx.GetValue(sql, args...)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return value.Int(), nil
|
||||
}
|
||||
|
||||
// Insert does "INSERT INTO ..." statement for the table.
|
||||
// If there's already one unique record of the data in the table, it returns error.
|
||||
//
|
||||
// The parameter `data` can be type of map/gmap/struct/*struct/[]map/[]struct, etc.
|
||||
// Eg:
|
||||
// Data(g.Map{"uid": 10000, "name":"john"})
|
||||
// Data(g.Slice{g.Map{"uid": 10000, "name":"john"}, g.Map{"uid": 20000, "name":"smith"})
|
||||
//
|
||||
// The parameter `batch` specifies the batch operation count when given data is slice.
|
||||
func (tx *TX) Insert(table string, data interface{}, batch ...int) (sql.Result, error) {
|
||||
if len(batch) > 0 {
|
||||
return tx.Model(table).Ctx(tx.ctx).Data(data).Batch(batch[0]).Insert()
|
||||
}
|
||||
return tx.Model(table).Ctx(tx.ctx).Data(data).Insert()
|
||||
}
|
||||
|
||||
// InsertIgnore does "INSERT IGNORE INTO ..." statement for the table.
|
||||
// If there's already one unique record of the data in the table, it ignores the inserting.
|
||||
//
|
||||
// The parameter `data` can be type of map/gmap/struct/*struct/[]map/[]struct, etc.
|
||||
// Eg:
|
||||
// Data(g.Map{"uid": 10000, "name":"john"})
|
||||
// Data(g.Slice{g.Map{"uid": 10000, "name":"john"}, g.Map{"uid": 20000, "name":"smith"})
|
||||
//
|
||||
// The parameter `batch` specifies the batch operation count when given data is slice.
|
||||
func (tx *TX) InsertIgnore(table string, data interface{}, batch ...int) (sql.Result, error) {
|
||||
if len(batch) > 0 {
|
||||
return tx.Model(table).Ctx(tx.ctx).Data(data).Batch(batch[0]).InsertIgnore()
|
||||
}
|
||||
return tx.Model(table).Ctx(tx.ctx).Data(data).InsertIgnore()
|
||||
}
|
||||
|
||||
// InsertAndGetId performs action Insert and returns the last insert id that automatically generated.
|
||||
func (tx *TX) InsertAndGetId(table string, data interface{}, batch ...int) (int64, error) {
|
||||
if len(batch) > 0 {
|
||||
return tx.Model(table).Ctx(tx.ctx).Data(data).Batch(batch[0]).InsertAndGetId()
|
||||
}
|
||||
return tx.Model(table).Ctx(tx.ctx).Data(data).InsertAndGetId()
|
||||
}
|
||||
|
||||
// Replace does "REPLACE INTO ..." statement for the table.
|
||||
// If there's already one unique record of the data in the table, it deletes the record
|
||||
// and inserts a new one.
|
||||
//
|
||||
// The parameter `data` can be type of map/gmap/struct/*struct/[]map/[]struct, etc.
|
||||
// Eg:
|
||||
// Data(g.Map{"uid": 10000, "name":"john"})
|
||||
// Data(g.Slice{g.Map{"uid": 10000, "name":"john"}, g.Map{"uid": 20000, "name":"smith"})
|
||||
//
|
||||
// The parameter `data` can be type of map/gmap/struct/*struct/[]map/[]struct, etc.
|
||||
// If given data is type of slice, it then does batch replacing, and the optional parameter
|
||||
// `batch` specifies the batch operation count.
|
||||
func (tx *TX) Replace(table string, data interface{}, batch ...int) (sql.Result, error) {
|
||||
if len(batch) > 0 {
|
||||
return tx.Model(table).Ctx(tx.ctx).Data(data).Batch(batch[0]).Replace()
|
||||
}
|
||||
return tx.Model(table).Ctx(tx.ctx).Data(data).Replace()
|
||||
}
|
||||
|
||||
// Save does "INSERT INTO ... ON DUPLICATE KEY UPDATE..." statement for the table.
|
||||
// It updates the record if there's primary or unique index in the saving data,
|
||||
// or else it inserts a new record into the table.
|
||||
//
|
||||
// The parameter `data` can be type of map/gmap/struct/*struct/[]map/[]struct, etc.
|
||||
// Eg:
|
||||
// Data(g.Map{"uid": 10000, "name":"john"})
|
||||
// Data(g.Slice{g.Map{"uid": 10000, "name":"john"}, g.Map{"uid": 20000, "name":"smith"})
|
||||
//
|
||||
// If given data is type of slice, it then does batch saving, and the optional parameter
|
||||
// `batch` specifies the batch operation count.
|
||||
func (tx *TX) Save(table string, data interface{}, batch ...int) (sql.Result, error) {
|
||||
if len(batch) > 0 {
|
||||
return tx.Model(table).Ctx(tx.ctx).Data(data).Batch(batch[0]).Save()
|
||||
}
|
||||
return tx.Model(table).Ctx(tx.ctx).Data(data).Save()
|
||||
}
|
||||
|
||||
// BatchInsert batch inserts data.
|
||||
// The parameter `list` must be type of slice of map or struct.
|
||||
func (tx *TX) BatchInsert(table string, list interface{}, batch ...int) (sql.Result, error) {
|
||||
if len(batch) > 0 {
|
||||
return tx.Model(table).Ctx(tx.ctx).Data(list).Batch(batch[0]).Insert()
|
||||
}
|
||||
return tx.Model(table).Ctx(tx.ctx).Data(list).Insert()
|
||||
}
|
||||
|
||||
// BatchInsertIgnore batch inserts data with ignore option.
|
||||
// The parameter `list` must be type of slice of map or struct.
|
||||
func (tx *TX) BatchInsertIgnore(table string, list interface{}, batch ...int) (sql.Result, error) {
|
||||
if len(batch) > 0 {
|
||||
return tx.Model(table).Ctx(tx.ctx).Data(list).Batch(batch[0]).InsertIgnore()
|
||||
}
|
||||
return tx.Model(table).Ctx(tx.ctx).Data(list).InsertIgnore()
|
||||
}
|
||||
|
||||
// BatchReplace batch replaces data.
|
||||
// The parameter `list` must be type of slice of map or struct.
|
||||
func (tx *TX) BatchReplace(table string, list interface{}, batch ...int) (sql.Result, error) {
|
||||
if len(batch) > 0 {
|
||||
return tx.Model(table).Ctx(tx.ctx).Data(list).Batch(batch[0]).Replace()
|
||||
}
|
||||
return tx.Model(table).Ctx(tx.ctx).Data(list).Replace()
|
||||
}
|
||||
|
||||
// BatchSave batch replaces data.
|
||||
// The parameter `list` must be type of slice of map or struct.
|
||||
func (tx *TX) BatchSave(table string, list interface{}, batch ...int) (sql.Result, error) {
|
||||
if len(batch) > 0 {
|
||||
return tx.Model(table).Ctx(tx.ctx).Data(list).Batch(batch[0]).Save()
|
||||
}
|
||||
return tx.Model(table).Ctx(tx.ctx).Data(list).Save()
|
||||
}
|
||||
|
||||
// Update does "UPDATE ... " statement for the table.
|
||||
//
|
||||
// The parameter `data` can be type of string/map/gmap/struct/*struct, etc.
|
||||
// Eg: "uid=10000", "uid", 10000, g.Map{"uid": 10000, "name":"john"}
|
||||
//
|
||||
// The parameter `condition` can be type of string/map/gmap/slice/struct/*struct, etc.
|
||||
// It is commonly used with parameter `args`.
|
||||
// Eg:
|
||||
// "uid=10000",
|
||||
// "uid", 10000
|
||||
// "money>? AND name like ?", 99999, "vip_%"
|
||||
// "status IN (?)", g.Slice{1,2,3}
|
||||
// "age IN(?,?)", 18, 50
|
||||
// User{ Id : 1, UserName : "john"}
|
||||
func (tx *TX) Update(table string, data interface{}, condition interface{}, args ...interface{}) (sql.Result, error) {
|
||||
return tx.Model(table).Ctx(tx.ctx).Data(data).Where(condition, args...).Update()
|
||||
}
|
||||
|
||||
// Delete does "DELETE FROM ... " statement for the table.
|
||||
//
|
||||
// The parameter `condition` can be type of string/map/gmap/slice/struct/*struct, etc.
|
||||
// It is commonly used with parameter `args`.
|
||||
// Eg:
|
||||
// "uid=10000",
|
||||
// "uid", 10000
|
||||
// "money>? AND name like ?", 99999, "vip_%"
|
||||
// "status IN (?)", g.Slice{1,2,3}
|
||||
// "age IN(?,?)", 18, 50
|
||||
// User{ Id : 1, UserName : "john"}
|
||||
func (tx *TX) Delete(table string, condition interface{}, args ...interface{}) (sql.Result, error) {
|
||||
return tx.Model(table).Ctx(tx.ctx).Where(condition, args...).Delete()
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user