mirror of
https://gitee.com/johng/gf.git
synced 2024-12-02 12:17:53 +08:00
improve struct conversion of empty result/record for package gdb
This commit is contained in:
parent
1eeeeb853e
commit
a123a2c086
@ -203,9 +203,6 @@ func (c *Core) GetStruct(pointer interface{}, sql string, args ...interface{}) e
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(one) == 0 {
|
||||
return ErrNoRows
|
||||
}
|
||||
return one.Struct(pointer)
|
||||
}
|
||||
|
||||
@ -216,9 +213,6 @@ func (c *Core) GetStructs(pointer interface{}, sql string, args ...interface{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(all) == 0 {
|
||||
return ErrNoRows
|
||||
}
|
||||
return all.Structs(pointer)
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,6 @@
|
||||
package gdb
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
"reflect"
|
||||
@ -171,9 +170,6 @@ func (m *Model) Struct(pointer interface{}, where ...interface{}) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(one) == 0 {
|
||||
return sql.ErrNoRows
|
||||
}
|
||||
return one.Struct(pointer)
|
||||
}
|
||||
|
||||
@ -198,9 +194,6 @@ func (m *Model) Structs(pointer interface{}, where ...interface{}) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(all) == 0 {
|
||||
return sql.ErrNoRows
|
||||
}
|
||||
return all.Structs(pointer)
|
||||
}
|
||||
|
||||
|
@ -8,10 +8,11 @@ package gdb
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"github.com/gogf/gf/container/gmap"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
|
||||
"github.com/gogf/gf/encoding/gparser"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// Json converts <r> to JSON format content.
|
||||
@ -42,8 +43,31 @@ func (r Record) GMap() *gmap.StrAnyMap {
|
||||
|
||||
// Struct converts <r> to a struct.
|
||||
// Note that the parameter <pointer> should be type of *struct/**struct.
|
||||
//
|
||||
// Note that if returns error if <r> is nil an given <pointer> is a pointer to an existing
|
||||
// struct.
|
||||
func (r Record) Struct(pointer interface{}) error {
|
||||
if r == nil {
|
||||
// Special handling for parameter type: reflect.Value
|
||||
if _, ok := pointer.(reflect.Value); ok {
|
||||
return mapToStruct(r.Map(), pointer)
|
||||
}
|
||||
var (
|
||||
reflectValue = reflect.ValueOf(pointer)
|
||||
reflectKind = reflectValue.Kind()
|
||||
)
|
||||
if reflectKind != reflect.Ptr {
|
||||
return errors.New("parameter should be type of *struct/**struct")
|
||||
}
|
||||
reflectValue = reflectValue.Elem()
|
||||
reflectKind = reflectValue.Kind()
|
||||
if reflectKind == reflect.Invalid {
|
||||
return errors.New("parameter is an invalid pointer, maybe nil")
|
||||
}
|
||||
if reflectKind != reflect.Ptr && reflectKind != reflect.Struct {
|
||||
return errors.New("parameter should be type of *struct/**struct")
|
||||
}
|
||||
// If the record is nil, check if returning error.
|
||||
if r == nil && reflectKind == reflect.Struct {
|
||||
return sql.ErrNoRows
|
||||
}
|
||||
return mapToStruct(r.Map(), pointer)
|
||||
|
@ -6,36 +6,22 @@
|
||||
|
||||
package gdb
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"github.com/gogf/gf/encoding/gparser"
|
||||
)
|
||||
|
||||
// Deprecated.
|
||||
func (r Record) ToJson() string {
|
||||
content, _ := gparser.VarToJson(r.Map())
|
||||
return string(content)
|
||||
return r.Json()
|
||||
}
|
||||
|
||||
// Deprecated.
|
||||
func (r Record) ToXml(rootTag ...string) string {
|
||||
content, _ := gparser.VarToXml(r.Map(), rootTag...)
|
||||
return string(content)
|
||||
return r.Xml(rootTag...)
|
||||
}
|
||||
|
||||
// Deprecated.
|
||||
func (r Record) ToMap() Map {
|
||||
m := make(map[string]interface{})
|
||||
for k, v := range r {
|
||||
m[k] = v.Val()
|
||||
}
|
||||
return m
|
||||
return r.Map()
|
||||
}
|
||||
|
||||
// Deprecated.
|
||||
func (r Record) ToStruct(pointer interface{}) error {
|
||||
if r == nil {
|
||||
return sql.ErrNoRows
|
||||
}
|
||||
return mapToStruct(r.Map(), pointer)
|
||||
return r.Struct(pointer)
|
||||
}
|
||||
|
@ -148,27 +148,48 @@ func (r Result) RecordKeyUint(key string) map[uint]Record {
|
||||
// Structs converts <r> to struct slice.
|
||||
// Note that the parameter <pointer> should be type of *[]struct/*[]*struct.
|
||||
func (r Result) Structs(pointer interface{}) (err error) {
|
||||
l := len(r)
|
||||
if l == 0 {
|
||||
return sql.ErrNoRows
|
||||
var (
|
||||
reflectValue = reflect.ValueOf(pointer)
|
||||
reflectKind = reflectValue.Kind()
|
||||
)
|
||||
if reflectKind != reflect.Ptr {
|
||||
return fmt.Errorf("pointer should be type of pointer to struct slice, but got: %v", reflectKind)
|
||||
}
|
||||
t := reflect.TypeOf(pointer)
|
||||
if t.Kind() != reflect.Ptr {
|
||||
return fmt.Errorf("pointer should be type of pointer, but got: %v", t.Kind())
|
||||
reflectValue = reflectValue.Elem()
|
||||
reflectKind = reflectValue.Kind()
|
||||
if reflectKind != reflect.Slice && reflectKind != reflect.Array {
|
||||
return fmt.Errorf("pointer should be type of pointer to struct slice, but got: %v", reflectKind)
|
||||
}
|
||||
array := reflect.MakeSlice(t.Elem(), l, l)
|
||||
itemType := array.Index(0).Type()
|
||||
for i := 0; i < l; i++ {
|
||||
if itemType.Kind() == reflect.Ptr {
|
||||
length := len(r)
|
||||
if length == 0 {
|
||||
// The pointed slice is not empty.
|
||||
if reflectValue.Len() > 0 {
|
||||
// It here checks if it has struct item, which is already initialized.
|
||||
// It then returns error to warn the developer its empty and no conversion.
|
||||
if v := reflectValue.Index(0); v.Kind() != reflect.Ptr {
|
||||
return sql.ErrNoRows
|
||||
}
|
||||
}
|
||||
// Do nothing for empty struct slice.
|
||||
return nil
|
||||
}
|
||||
var (
|
||||
reflectType = reflect.TypeOf(pointer)
|
||||
array = reflect.MakeSlice(reflectType.Elem(), length, length)
|
||||
itemType = array.Index(0).Type()
|
||||
itemKind = itemType.Kind()
|
||||
)
|
||||
for i := 0; i < length; i++ {
|
||||
if itemKind == reflect.Ptr {
|
||||
e := reflect.New(itemType.Elem()).Elem()
|
||||
if err = r[i].Struct(e); err != nil {
|
||||
return err
|
||||
return fmt.Errorf(`slice element conversion failed: %s`, err.Error())
|
||||
}
|
||||
array.Index(i).Set(e.Addr())
|
||||
} else {
|
||||
e := reflect.New(itemType).Elem()
|
||||
if err = r[i].Struct(e); err != nil {
|
||||
return err
|
||||
return fmt.Errorf(`slice element conversion failed: %s`, err.Error())
|
||||
}
|
||||
array.Index(i).Set(e)
|
||||
}
|
||||
|
@ -6,128 +6,52 @@
|
||||
|
||||
package gdb
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/gogf/gf/encoding/gparser"
|
||||
)
|
||||
|
||||
// Deprecated.
|
||||
func (r Result) ToJson() string {
|
||||
content, _ := gparser.VarToJson(r.List())
|
||||
return string(content)
|
||||
return r.Json()
|
||||
}
|
||||
|
||||
// Deprecated.
|
||||
func (r Result) ToXml(rootTag ...string) string {
|
||||
content, _ := gparser.VarToXml(r.List(), rootTag...)
|
||||
return string(content)
|
||||
return r.Xml(rootTag...)
|
||||
}
|
||||
|
||||
// Deprecated.
|
||||
func (r Result) ToList() List {
|
||||
l := make(List, len(r))
|
||||
for k, v := range r {
|
||||
l[k] = v.Map()
|
||||
}
|
||||
return l
|
||||
return r.List()
|
||||
}
|
||||
|
||||
// Deprecated.
|
||||
func (r Result) ToStringMap(key string) map[string]Map {
|
||||
m := make(map[string]Map)
|
||||
for _, item := range r {
|
||||
if v, ok := item[key]; ok {
|
||||
m[v.String()] = item.Map()
|
||||
}
|
||||
}
|
||||
return m
|
||||
return r.MapKeyStr(key)
|
||||
}
|
||||
|
||||
// Deprecated.
|
||||
func (r Result) ToIntMap(key string) map[int]Map {
|
||||
m := make(map[int]Map)
|
||||
for _, item := range r {
|
||||
if v, ok := item[key]; ok {
|
||||
m[v.Int()] = item.Map()
|
||||
}
|
||||
}
|
||||
return m
|
||||
return r.MapKeyInt(key)
|
||||
}
|
||||
|
||||
// Deprecated.
|
||||
func (r Result) ToUintMap(key string) map[uint]Map {
|
||||
m := make(map[uint]Map)
|
||||
for _, item := range r {
|
||||
if v, ok := item[key]; ok {
|
||||
m[v.Uint()] = item.Map()
|
||||
}
|
||||
}
|
||||
return m
|
||||
return r.MapKeyUint(key)
|
||||
}
|
||||
|
||||
// Deprecated.
|
||||
func (r Result) ToStringRecord(key string) map[string]Record {
|
||||
m := make(map[string]Record)
|
||||
for _, item := range r {
|
||||
if v, ok := item[key]; ok {
|
||||
m[v.String()] = item
|
||||
}
|
||||
}
|
||||
return m
|
||||
return r.RecordKeyStr(key)
|
||||
}
|
||||
|
||||
// Deprecated.
|
||||
func (r Result) ToIntRecord(key string) map[int]Record {
|
||||
m := make(map[int]Record)
|
||||
for _, item := range r {
|
||||
if v, ok := item[key]; ok {
|
||||
m[v.Int()] = item
|
||||
}
|
||||
}
|
||||
return m
|
||||
return r.RecordKeyInt(key)
|
||||
}
|
||||
|
||||
// Deprecated.
|
||||
func (r Result) ToUintRecord(key string) map[uint]Record {
|
||||
m := make(map[uint]Record)
|
||||
for _, item := range r {
|
||||
if v, ok := item[key]; ok {
|
||||
m[v.Uint()] = item
|
||||
}
|
||||
}
|
||||
return m
|
||||
return r.RecordKeyUint(key)
|
||||
}
|
||||
|
||||
// Deprecated.
|
||||
func (r Result) ToStructs(pointer interface{}) (err error) {
|
||||
l := len(r)
|
||||
if l == 0 {
|
||||
return sql.ErrNoRows
|
||||
}
|
||||
t := reflect.TypeOf(pointer)
|
||||
if t.Kind() != reflect.Ptr {
|
||||
return fmt.Errorf("pointer should be type of pointer, but got: %v", t.Kind())
|
||||
}
|
||||
array := reflect.MakeSlice(t.Elem(), l, l)
|
||||
itemType := array.Index(0).Type()
|
||||
for i := 0; i < l; i++ {
|
||||
if itemType.Kind() == reflect.Ptr {
|
||||
e := reflect.New(itemType.Elem()).Elem()
|
||||
if err = r[i].Struct(e); err != nil {
|
||||
return err
|
||||
}
|
||||
array.Index(i).Set(e.Addr())
|
||||
} else {
|
||||
e := reflect.New(itemType).Elem()
|
||||
if err = r[i].Struct(e); err != nil {
|
||||
return err
|
||||
}
|
||||
array.Index(i).Set(e)
|
||||
}
|
||||
}
|
||||
reflect.ValueOf(pointer).Elem().Set(array)
|
||||
return nil
|
||||
return r.Structs(pointer)
|
||||
}
|
||||
|
@ -820,7 +820,7 @@ func Test_Model_Structs(t *testing.T) {
|
||||
}
|
||||
var users []*User
|
||||
err := db.Table(table).Where("id<0").Structs(&users)
|
||||
t.Assert(err, sql.ErrNoRows)
|
||||
t.Assert(err, nil)
|
||||
})
|
||||
}
|
||||
|
||||
@ -905,12 +905,14 @@ func Test_Model_Scan(t *testing.T) {
|
||||
NickName string
|
||||
CreateTime *gtime.Time
|
||||
}
|
||||
user := new(User)
|
||||
users := new([]*User)
|
||||
var (
|
||||
user = new(User)
|
||||
users = new([]*User)
|
||||
)
|
||||
err1 := db.Table(table).Where("id < 0").Scan(user)
|
||||
err2 := db.Table(table).Where("id < 0").Scan(users)
|
||||
t.Assert(err1, sql.ErrNoRows)
|
||||
t.Assert(err2, sql.ErrNoRows)
|
||||
t.Assert(err2, nil)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -94,5 +94,87 @@ func Test_Model_Inherit_MapToStruct(t *testing.T) {
|
||||
t.Assert(user.CreateTime, data["create_time"])
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func Test_Struct_Empty(t *testing.T) {
|
||||
table := createTable()
|
||||
defer dropTable(table)
|
||||
|
||||
type User struct {
|
||||
Id int
|
||||
Passport string
|
||||
Password string
|
||||
Nickname string
|
||||
}
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
one, err := db.Table(table).Where("id=100").One()
|
||||
t.Assert(err, nil)
|
||||
user := new(User)
|
||||
t.AssertNE(one.Struct(user), nil)
|
||||
})
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
one, err := db.Table(table).Where("id=100").One()
|
||||
t.Assert(err, nil)
|
||||
var user *User
|
||||
t.Assert(one.Struct(&user), nil)
|
||||
})
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
one, err := db.Table(table).Where("id=100").One()
|
||||
t.Assert(err, nil)
|
||||
var user *User
|
||||
t.AssertNE(one.Struct(user), nil)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Structs_Empty(t *testing.T) {
|
||||
table := createTable()
|
||||
defer dropTable(table)
|
||||
|
||||
type User struct {
|
||||
Id int
|
||||
Passport string
|
||||
Password string
|
||||
Nickname string
|
||||
}
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
all, err := db.Table(table).Where("id>100").All()
|
||||
t.Assert(err, nil)
|
||||
users := make([]User, 0)
|
||||
t.Assert(all.Structs(&users), nil)
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
all, err := db.Table(table).Where("id>100").All()
|
||||
t.Assert(err, nil)
|
||||
users := make([]User, 10)
|
||||
t.AssertNE(all.Structs(&users), nil)
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
all, err := db.Table(table).Where("id>100").All()
|
||||
t.Assert(err, nil)
|
||||
var users []User
|
||||
t.Assert(all.Structs(&users), nil)
|
||||
})
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
all, err := db.Table(table).Where("id>100").All()
|
||||
t.Assert(err, nil)
|
||||
users := make([]*User, 0)
|
||||
t.Assert(all.Structs(&users), nil)
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
all, err := db.Table(table).Where("id>100").All()
|
||||
t.Assert(err, nil)
|
||||
users := make([]*User, 10)
|
||||
t.Assert(all.Structs(&users), nil)
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
all, err := db.Table(table).Where("id>100").All()
|
||||
t.Assert(err, nil)
|
||||
var users []*User
|
||||
t.Assert(all.Structs(&users), nil)
|
||||
})
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user