diff --git a/.travis.yml b/.travis.yml index 44d5ee308..d1c566aa1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,8 @@ language: go go: -- "1.11.x" + - "1.11.x" + - "1.12.x" branches: only: @@ -9,25 +10,27 @@ branches: - develop env: -- GO111MODULE=on + - GO111MODULE=on services: -- mysql + - mysql before_install: -- pwd + - sudo mysql -e "use mysql; update user set authentication_string=PASSWORD('12345678') where User='root'; update user set plugin='mysql_native_password';FLUSH PRIVILEGES;" + - sudo mysql_upgrade -u root -p12345678 + - sudo service mysql restart install: -- pwd + - pwd script: -- cd g -- GOARCH=386 go test -v ./... -- GOARCH=amd64 go test -v ./... -race -coverprofile=coverage.txt -covermode=atomic + - cd g + - GOARCH=386 go test -v ./... + - GOARCH=amd64 go test -v ./... -race -coverprofile=coverage.txt -covermode=atomic after_success: -- bash <(curl -s https://codecov.io/bash) + - bash <(curl -s https://codecov.io/bash) diff --git a/TODO.MD b/TODO.MD index 01a25882e..4249fef30 100644 --- a/TODO.MD +++ b/TODO.MD @@ -54,7 +54,7 @@ 1. gdb的Data方法支持struct参数传入; 1. gfcache依旧使用gcache作为缓存控制对象,不要使用gmap; 1. 增加对ghttp路由注册的{.struct}/{.method}单元测试; - +1. 更新跨域请求CORS相关功能文档; diff --git a/g/database/gdb/gdb_func.go b/g/database/gdb/gdb_func.go index 7cd203bd5..d0636c685 100644 --- a/g/database/gdb/gdb_func.go +++ b/g/database/gdb/gdb_func.go @@ -12,16 +12,15 @@ import ( "fmt" "github.com/gogf/gf/g/os/glog" "github.com/gogf/gf/g/os/gtime" - "github.com/gogf/gf/g/util/gconv" "github.com/gogf/gf/g/text/gregex" - "github.com/gogf/gf/g/text/gstr" + "github.com/gogf/gf/g/util/gconv" _ "github.com/gogf/gf/third/github.com/go-sql-driver/mysql" "reflect" "strings" ) // 格式化SQL查询条件 -func formatCondition(where interface{}, args []interface{}) (string, []interface{}) { +func formatCondition(where interface{}, args []interface{}) (newWhere string, newArgs []interface{}) { // 条件字符串处理 buffer := bytes.NewBuffer(nil) // 使用反射进行类型判断 @@ -32,29 +31,25 @@ func formatCondition(where interface{}, args []interface{}) (string, []interface kind = rv.Kind() } switch kind { + // 注意当where为map/struct类型时,args参数必须为空。 case reflect.Map: fallthrough case reflect.Struct: for k, v := range gconv.Map(where) { - key := gconv.String(k) - value := gconv.String(v) if buffer.Len() > 0 { buffer.WriteString(" AND ") } - if gstr.IsNumeric(value) || value == "?" { - buffer.WriteString(key + "=" + value) - } else { - buffer.WriteString(key + "='" + value + "'") - } + buffer.WriteString(k + "=?") + newArgs = append(newArgs, v) } + newWhere = buffer.String() default: buffer.WriteString(gconv.String(where)) } if buffer.Len() == 0 { buffer.WriteString("1=1") } - // 查询条件处理 - newWhere := buffer.String() - newArgs := make([]interface{}, 0) + // 查询条件参数处理,主要处理slice参数类型 + newWhere = buffer.String() if len(args) > 0 { for index, arg := range args { rv := reflect.ValueOf(arg) @@ -64,7 +59,8 @@ func formatCondition(where interface{}, args []interface{}) (string, []interface kind = rv.Kind() } switch kind { - // Where条件参数支持slice类型 + // '?'占位符支持slice类型, + // 这里会将slice参数拆散,并更新原有占位符'?'为多个'?',使用','符号连接。 case reflect.Slice: fallthrough case reflect.Array: for i := 0; i < rv.Len(); i++ { @@ -83,7 +79,7 @@ func formatCondition(where interface{}, args []interface{}) (string, []interface } } } - return newWhere, newArgs + return } // 打印SQL对象(仅在debug=true时有效) diff --git a/g/database/gdb/gdb_unit_init_test.go b/g/database/gdb/gdb_unit_init_test.go index 0300fa8f0..182382170 100644 --- a/g/database/gdb/gdb_unit_init_test.go +++ b/g/database/gdb/gdb_unit_init_test.go @@ -17,7 +17,7 @@ func init() { Host: "127.0.0.1", Port: "3306", User: "root", - Pass: "", + Pass: "12345678", Name: "", Type: "mysql", Role: "master", diff --git a/g/database/gdb/gdb_unit_model_test.go b/g/database/gdb/gdb_unit_model_test.go index fe41a4108..a534aadeb 100644 --- a/g/database/gdb/gdb_unit_model_test.go +++ b/g/database/gdb/gdb_unit_model_test.go @@ -255,8 +255,51 @@ func TestModel_GroupBy(t *testing.T) { gtest.Assert(result[0]["nickname"].String(), "T111") } -// slice -func TestModel_Where1(t *testing.T) { +// where string +func TestModel_WhereString(t *testing.T) { + gtest.Case(t, func() { + result, err := db.Table("user").Where("id=? and nickname=?", 3, "T3").One() + if err != nil { + gtest.Fatal(err) + } + gtest.Assert(result["id"].Int(), 3) + }) +} + +// where map +func TestModel_WhereMap(t *testing.T) { + gtest.Case(t, func() { + result, err := db.Table("user").Where(g.Map{"id" : 3, "nickname" : "T3"}).One() + if err != nil { + gtest.Fatal(err) + } + gtest.Assert(result["id"].Int(), 3) + }) +} + +// where struct +func TestModel_WhereStruct(t *testing.T) { + gtest.Case(t, func() { + type User struct { + Id int `json:"id"` + Nickname string `gconv:"nickname"` + } + result, err := db.Table("user").Where(User{3, "T3"}).One() + if err != nil { + gtest.Fatal(err) + } + gtest.Assert(result["id"].Int(), 3) + + result, err = db.Table("user").Where(&User{3, "T3"}).One() + if err != nil { + gtest.Fatal(err) + } + gtest.Assert(result["id"].Int(), 3) + }) +} + +// where slice +func TestModel_WhereSlice1(t *testing.T) { result, err := db.Table("user").Where("id IN(?)", g.Slice{1,3}).OrderBy("id ASC").All() if err != nil { gtest.Fatal(err) @@ -266,8 +309,8 @@ func TestModel_Where1(t *testing.T) { gtest.Assert(result[1]["id"].Int(), 3) } -// slice -func TestModel_Where2(t *testing.T) { +// where slice +func TestModel_WhereSlice2(t *testing.T) { result, err := db.Table("user").Where("nickname=? AND id IN(?)", "T3", g.Slice{1,3}).OrderBy("id ASC").All() if err != nil { gtest.Fatal(err)