mirror of
https://gitee.com/johng/gf.git
synced 2024-12-02 12:17:53 +08:00
add ScanList feature for gdb.Model
This commit is contained in:
parent
3ae44185f4
commit
12d58e4d08
@ -13,6 +13,7 @@ import (
|
|||||||
"github.com/gogf/gf/internal/empty"
|
"github.com/gogf/gf/internal/empty"
|
||||||
"github.com/gogf/gf/internal/utils"
|
"github.com/gogf/gf/internal/utils"
|
||||||
"github.com/gogf/gf/os/gtime"
|
"github.com/gogf/gf/os/gtime"
|
||||||
|
"github.com/gogf/gf/util/gutil"
|
||||||
"reflect"
|
"reflect"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
@ -56,6 +57,12 @@ var (
|
|||||||
quoteWordReg = regexp.MustCompile(`^[a-zA-Z0-9\-_]+$`)
|
quoteWordReg = regexp.MustCompile(`^[a-zA-Z0-9\-_]+$`)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ListItemValues is alias for gutil.ListItemValues.
|
||||||
|
// See gutil.ListItemValues.
|
||||||
|
func ListItemValues(list interface{}, key interface{}, subKey ...interface{}) (values []interface{}) {
|
||||||
|
return gutil.ListItemValues(list, key, subKey...)
|
||||||
|
}
|
||||||
|
|
||||||
// GetInsertOperationByOption returns proper insert option with given parameter <option>.
|
// GetInsertOperationByOption returns proper insert option with given parameter <option>.
|
||||||
func GetInsertOperationByOption(option int) string {
|
func GetInsertOperationByOption(option int) string {
|
||||||
var operator string
|
var operator string
|
||||||
|
@ -234,6 +234,36 @@ func (m *Model) Scan(pointer interface{}, where ...interface{}) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ScanList converts <r> to struct slice which contains other complex struct attributes.
|
||||||
|
// Note that the parameter <listPointer> should be type of *[]struct/*[]*struct.
|
||||||
|
// Usage example:
|
||||||
|
//
|
||||||
|
// type Entity struct {
|
||||||
|
// User *EntityUser
|
||||||
|
// UserDetail *EntityUserDetail
|
||||||
|
// UserScores []*EntityUserScores
|
||||||
|
// }
|
||||||
|
// var users []*Entity
|
||||||
|
// or
|
||||||
|
// var users []Entity
|
||||||
|
//
|
||||||
|
// ScanList(&users, "User")
|
||||||
|
// ScanList(&users, "UserDetail", "User", "uid:Uid")
|
||||||
|
// ScanList(&users, "UserScores", "User", "uid:Uid")
|
||||||
|
// The parameters "User"/"UserDetail"/"UserScores" in the example codes specify the target attribute struct
|
||||||
|
// that current result will be bound to.
|
||||||
|
// The "uid" in the example codes is the table field name of the result, and the "Uid" is the relational
|
||||||
|
// struct attribute name. It automatically calculates the HasOne/HasMany relationship with given <relation>
|
||||||
|
// parameter.
|
||||||
|
// See the example or unit testing cases for clear understanding for this function.
|
||||||
|
func (m *Model) ScanList(listPointer interface{}, attributeName string, relation ...string) (err error) {
|
||||||
|
all, err := m.All()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return all.ScanList(listPointer, attributeName, relation...)
|
||||||
|
}
|
||||||
|
|
||||||
// Count does "SELECT COUNT(x) FROM ..." statement for the model.
|
// Count does "SELECT COUNT(x) FROM ..." statement for the model.
|
||||||
// The optional parameter <where> is the same as the parameter of Model.Where function,
|
// The optional parameter <where> is the same as the parameter of Model.Where function,
|
||||||
// see Model.Where.
|
// see Model.Where.
|
||||||
|
@ -8,12 +8,8 @@ package gdb
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gogf/gf/container/gvar"
|
"github.com/gogf/gf/container/gvar"
|
||||||
"github.com/gogf/gf/text/gstr"
|
|
||||||
"github.com/gogf/gf/util/gconv"
|
|
||||||
"github.com/gogf/gf/util/gutil"
|
|
||||||
"math"
|
"math"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
@ -245,211 +241,3 @@ func (r Result) Structs(pointer interface{}) (err error) {
|
|||||||
reflect.ValueOf(pointer).Elem().Set(array)
|
reflect.ValueOf(pointer).Elem().Set(array)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ScanList converts <r> to struct slice which contains other complex struct attributes.
|
|
||||||
// Note that the parameter <listPointer> should be type of *[]struct/*[]*struct.
|
|
||||||
func (r Result) ScanList(listPointer interface{}, attributeName string, relation ...string) (err error) {
|
|
||||||
// Necessary checks for parameters.
|
|
||||||
if attributeName == "" {
|
|
||||||
return errors.New(`attributeName should not be empty`)
|
|
||||||
}
|
|
||||||
if len(relation) > 0 {
|
|
||||||
if len(relation) < 2 {
|
|
||||||
return errors.New(`relation name and key should are both necessary`)
|
|
||||||
}
|
|
||||||
if relation[0] == "" || relation[1] == "" {
|
|
||||||
return errors.New(`relation name and key should not be empty`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
reflectValue = reflect.ValueOf(listPointer)
|
|
||||||
reflectKind = reflectValue.Kind()
|
|
||||||
)
|
|
||||||
if reflectKind == reflect.Interface {
|
|
||||||
reflectValue = reflectValue.Elem()
|
|
||||||
reflectKind = reflectValue.Kind()
|
|
||||||
}
|
|
||||||
if reflectKind != reflect.Ptr {
|
|
||||||
return fmt.Errorf("parameter should be type of *[]struct/*[]*struct, but got: %v", reflectKind)
|
|
||||||
}
|
|
||||||
reflectValue = reflectValue.Elem()
|
|
||||||
reflectKind = reflectValue.Kind()
|
|
||||||
if reflectKind != reflect.Slice && reflectKind != reflect.Array {
|
|
||||||
return fmt.Errorf("parameter should be type of *[]struct/*[]*struct, but got: %v", reflectKind)
|
|
||||||
}
|
|
||||||
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 (
|
|
||||||
arrayValue reflect.Value // Like: []*Entity
|
|
||||||
arrayItemType reflect.Type // Like: *Entity
|
|
||||||
reflectType = reflect.TypeOf(listPointer)
|
|
||||||
)
|
|
||||||
if reflectValue.Len() > 0 {
|
|
||||||
arrayValue = reflectValue
|
|
||||||
} else {
|
|
||||||
arrayValue = reflect.MakeSlice(reflectType.Elem(), length, length)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Slice element item.
|
|
||||||
arrayItemType = arrayValue.Index(0).Type()
|
|
||||||
|
|
||||||
// Relation variables.
|
|
||||||
var (
|
|
||||||
relationDataMap map[string]Value
|
|
||||||
relationFieldName string
|
|
||||||
relationAttrName string
|
|
||||||
)
|
|
||||||
if len(relation) > 0 {
|
|
||||||
array := gstr.Split(relation[1], ":")
|
|
||||||
if len(array) > 1 {
|
|
||||||
// Defined table field to relation attribute name.
|
|
||||||
// Like:
|
|
||||||
// uid:Uid
|
|
||||||
// uid:UserId
|
|
||||||
relationFieldName = array[0]
|
|
||||||
relationAttrName = array[1]
|
|
||||||
} else {
|
|
||||||
relationAttrName = relation[1]
|
|
||||||
// Find the possible map key by given only struct attribute name.
|
|
||||||
// Like:
|
|
||||||
// Uid
|
|
||||||
if k, _ := gutil.MapPossibleItemByKey(r[0].Map(), relation[1]); k != "" {
|
|
||||||
relationFieldName = k
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if relationFieldName != "" {
|
|
||||||
relationDataMap = r.MapKeyValue(relationFieldName)
|
|
||||||
}
|
|
||||||
if len(relationDataMap) == 0 {
|
|
||||||
return fmt.Errorf(`cannot find the relation data map, maybe invalid relation key given: %s`, relation[1])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Bind to target attribute.
|
|
||||||
var (
|
|
||||||
ok bool
|
|
||||||
attrValue reflect.Value
|
|
||||||
attrKind reflect.Kind
|
|
||||||
attrType reflect.Type
|
|
||||||
attrField reflect.StructField
|
|
||||||
)
|
|
||||||
if arrayItemType.Kind() == reflect.Ptr {
|
|
||||||
if attrField, ok = arrayItemType.Elem().FieldByName(attributeName); !ok {
|
|
||||||
return fmt.Errorf(`invalid field name: %s`, attributeName)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if attrField, ok = arrayItemType.FieldByName(attributeName); !ok {
|
|
||||||
return fmt.Errorf(`invalid field name: %s`, attributeName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
attrType = attrField.Type
|
|
||||||
attrKind = attrType.Kind()
|
|
||||||
|
|
||||||
// Bind to relation conditions.
|
|
||||||
var (
|
|
||||||
relationValue reflect.Value
|
|
||||||
relationField reflect.Value
|
|
||||||
)
|
|
||||||
for i := 0; i < arrayValue.Len(); i++ {
|
|
||||||
arrayElemValue := arrayValue.Index(i)
|
|
||||||
// The FieldByName should be called on non-pointer reflect.Value.
|
|
||||||
if arrayElemValue.Kind() == reflect.Ptr {
|
|
||||||
// Like: []*Entity
|
|
||||||
arrayElemValue = arrayElemValue.Elem()
|
|
||||||
if !arrayElemValue.IsValid() {
|
|
||||||
// The element is nil, then create one and set it to the slice.
|
|
||||||
// The "reflect.New(itemType.Elem())" creates a new element and returns the address of it.
|
|
||||||
// For example:
|
|
||||||
// reflect.New(itemType.Elem()) => *Entity
|
|
||||||
// reflect.New(itemType.Elem()).Elem() => Entity
|
|
||||||
arrayElemValue = reflect.New(arrayItemType.Elem()).Elem()
|
|
||||||
arrayValue.Index(i).Set(arrayElemValue.Addr())
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Like: []Entity
|
|
||||||
}
|
|
||||||
attrValue = arrayElemValue.FieldByName(attributeName)
|
|
||||||
if len(relation) > 0 {
|
|
||||||
relationValue = arrayElemValue.FieldByName(relation[0])
|
|
||||||
if relationValue.Kind() == reflect.Ptr {
|
|
||||||
relationValue = relationValue.Elem()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(relationDataMap) > 0 && !relationValue.IsValid() {
|
|
||||||
return fmt.Errorf(`invalid relation: %s, %s`, relation[0], relation[1])
|
|
||||||
}
|
|
||||||
switch attrKind {
|
|
||||||
case reflect.Array, reflect.Slice:
|
|
||||||
if len(relationDataMap) > 0 {
|
|
||||||
relationField = relationValue.FieldByName(relationAttrName)
|
|
||||||
if relationField.IsValid() {
|
|
||||||
if err = gconv.Structs(
|
|
||||||
relationDataMap[gconv.String(relationField.Interface())],
|
|
||||||
attrValue.Addr(),
|
|
||||||
); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// May be the attribute does not exist yet.
|
|
||||||
return fmt.Errorf(`invalid relation: %s, %s`, relation[0], relation[1])
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return fmt.Errorf(`relationKey should not be empty as field "%s" is slice`, attributeName)
|
|
||||||
}
|
|
||||||
|
|
||||||
case reflect.Ptr:
|
|
||||||
e := reflect.New(attrType.Elem()).Elem()
|
|
||||||
if len(relationDataMap) > 0 {
|
|
||||||
relationField = relationValue.FieldByName(relationAttrName)
|
|
||||||
if relationField.IsValid() {
|
|
||||||
if err = gconv.Struct(relationDataMap[gconv.String(relationField.Interface())], e); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// May be the attribute does not exist yet.
|
|
||||||
return fmt.Errorf(`invalid relation: %s, %s`, relation[0], relation[1])
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if err = gconv.Struct(r[i], e); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
attrValue.Set(e.Addr())
|
|
||||||
|
|
||||||
case reflect.Struct:
|
|
||||||
e := reflect.New(attrType).Elem()
|
|
||||||
if len(relationDataMap) > 0 {
|
|
||||||
relationField = relationValue.FieldByName(relationAttrName)
|
|
||||||
if relationField.IsValid() {
|
|
||||||
if err = gconv.Struct(relationDataMap[gconv.String(relationField.Interface())], e); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// May be the attribute does not exist yet.
|
|
||||||
return fmt.Errorf(`invalid relation: %s, %s`, relation[0], relation[1])
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if err = gconv.Struct(r[i], e); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
attrValue.Set(e)
|
|
||||||
|
|
||||||
case reflect.Map:
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
}
|
|
||||||
reflect.ValueOf(listPointer).Elem().Set(arrayValue)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
245
database/gdb/gdb_type_result_scanlist.go
Normal file
245
database/gdb/gdb_type_result_scanlist.go
Normal file
@ -0,0 +1,245 @@
|
|||||||
|
// Copyright 2020 gf Author(https://github.com/gogf/gf). 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"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"github.com/gogf/gf/text/gstr"
|
||||||
|
"github.com/gogf/gf/util/gconv"
|
||||||
|
"github.com/gogf/gf/util/gutil"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ScanList converts <r> to struct slice which contains other complex struct attributes.
|
||||||
|
// Note that the parameter <listPointer> should be type of *[]struct/*[]*struct.
|
||||||
|
// Usage example:
|
||||||
|
//
|
||||||
|
// type Entity struct {
|
||||||
|
// User *EntityUser
|
||||||
|
// UserDetail *EntityUserDetail
|
||||||
|
// UserScores []*EntityUserScores
|
||||||
|
// }
|
||||||
|
// var users []*Entity
|
||||||
|
// or
|
||||||
|
// var users []Entity
|
||||||
|
//
|
||||||
|
// ScanList(&users, "User")
|
||||||
|
// ScanList(&users, "UserDetail", "User", "uid:Uid")
|
||||||
|
// ScanList(&users, "UserScores", "User", "uid:Uid")
|
||||||
|
// The parameters "User"/"UserDetail"/"UserScores" in the example codes specify the target attribute struct
|
||||||
|
// that current result will be bound to.
|
||||||
|
// The "uid" in the example codes is the table field name of the result, and the "Uid" is the relational
|
||||||
|
// struct attribute name. It automatically calculates the HasOne/HasMany relationship with given <relation>
|
||||||
|
// parameter.
|
||||||
|
// See the example or unit testing cases for clear understanding for this function.
|
||||||
|
func (r Result) ScanList(listPointer interface{}, attributeName string, relation ...string) (err error) {
|
||||||
|
// Necessary checks for parameters.
|
||||||
|
if attributeName == "" {
|
||||||
|
return errors.New(`attributeName should not be empty`)
|
||||||
|
}
|
||||||
|
if len(relation) > 0 {
|
||||||
|
if len(relation) < 2 {
|
||||||
|
return errors.New(`relation name and key should are both necessary`)
|
||||||
|
}
|
||||||
|
if relation[0] == "" || relation[1] == "" {
|
||||||
|
return errors.New(`relation name and key should not be empty`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
reflectValue = reflect.ValueOf(listPointer)
|
||||||
|
reflectKind = reflectValue.Kind()
|
||||||
|
)
|
||||||
|
if reflectKind == reflect.Interface {
|
||||||
|
reflectValue = reflectValue.Elem()
|
||||||
|
reflectKind = reflectValue.Kind()
|
||||||
|
}
|
||||||
|
if reflectKind != reflect.Ptr {
|
||||||
|
return fmt.Errorf("parameter should be type of *[]struct/*[]*struct, but got: %v", reflectKind)
|
||||||
|
}
|
||||||
|
reflectValue = reflectValue.Elem()
|
||||||
|
reflectKind = reflectValue.Kind()
|
||||||
|
if reflectKind != reflect.Slice && reflectKind != reflect.Array {
|
||||||
|
return fmt.Errorf("parameter should be type of *[]struct/*[]*struct, but got: %v", reflectKind)
|
||||||
|
}
|
||||||
|
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 (
|
||||||
|
arrayValue reflect.Value // Like: []*Entity
|
||||||
|
arrayItemType reflect.Type // Like: *Entity
|
||||||
|
reflectType = reflect.TypeOf(listPointer)
|
||||||
|
)
|
||||||
|
if reflectValue.Len() > 0 {
|
||||||
|
arrayValue = reflectValue
|
||||||
|
} else {
|
||||||
|
arrayValue = reflect.MakeSlice(reflectType.Elem(), length, length)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Slice element item.
|
||||||
|
arrayItemType = arrayValue.Index(0).Type()
|
||||||
|
|
||||||
|
// Relation variables.
|
||||||
|
var (
|
||||||
|
relationDataMap map[string]Value
|
||||||
|
relationFieldName string
|
||||||
|
relationAttrName string
|
||||||
|
)
|
||||||
|
if len(relation) > 0 {
|
||||||
|
array := gstr.Split(relation[1], ":")
|
||||||
|
if len(array) > 1 {
|
||||||
|
// Defined table field to relation attribute name.
|
||||||
|
// Like:
|
||||||
|
// uid:Uid
|
||||||
|
// uid:UserId
|
||||||
|
relationFieldName = array[0]
|
||||||
|
relationAttrName = array[1]
|
||||||
|
} else {
|
||||||
|
relationAttrName = relation[1]
|
||||||
|
// Find the possible map key by given only struct attribute name.
|
||||||
|
// Like:
|
||||||
|
// Uid
|
||||||
|
if k, _ := gutil.MapPossibleItemByKey(r[0].Map(), relation[1]); k != "" {
|
||||||
|
relationFieldName = k
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if relationFieldName != "" {
|
||||||
|
relationDataMap = r.MapKeyValue(relationFieldName)
|
||||||
|
}
|
||||||
|
if len(relationDataMap) == 0 {
|
||||||
|
return fmt.Errorf(`cannot find the relation data map, maybe invalid relation key given: %s`, relation[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Bind to target attribute.
|
||||||
|
var (
|
||||||
|
ok bool
|
||||||
|
attrValue reflect.Value
|
||||||
|
attrKind reflect.Kind
|
||||||
|
attrType reflect.Type
|
||||||
|
attrField reflect.StructField
|
||||||
|
)
|
||||||
|
if arrayItemType.Kind() == reflect.Ptr {
|
||||||
|
if attrField, ok = arrayItemType.Elem().FieldByName(attributeName); !ok {
|
||||||
|
return fmt.Errorf(`invalid field name: %s`, attributeName)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if attrField, ok = arrayItemType.FieldByName(attributeName); !ok {
|
||||||
|
return fmt.Errorf(`invalid field name: %s`, attributeName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
attrType = attrField.Type
|
||||||
|
attrKind = attrType.Kind()
|
||||||
|
|
||||||
|
// Bind to relation conditions.
|
||||||
|
var (
|
||||||
|
relationValue reflect.Value
|
||||||
|
relationField reflect.Value
|
||||||
|
)
|
||||||
|
for i := 0; i < arrayValue.Len(); i++ {
|
||||||
|
arrayElemValue := arrayValue.Index(i)
|
||||||
|
// The FieldByName should be called on non-pointer reflect.Value.
|
||||||
|
if arrayElemValue.Kind() == reflect.Ptr {
|
||||||
|
// Like: []*Entity
|
||||||
|
arrayElemValue = arrayElemValue.Elem()
|
||||||
|
if !arrayElemValue.IsValid() {
|
||||||
|
// The element is nil, then create one and set it to the slice.
|
||||||
|
// The "reflect.New(itemType.Elem())" creates a new element and returns the address of it.
|
||||||
|
// For example:
|
||||||
|
// reflect.New(itemType.Elem()) => *Entity
|
||||||
|
// reflect.New(itemType.Elem()).Elem() => Entity
|
||||||
|
arrayElemValue = reflect.New(arrayItemType.Elem()).Elem()
|
||||||
|
arrayValue.Index(i).Set(arrayElemValue.Addr())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Like: []Entity
|
||||||
|
}
|
||||||
|
attrValue = arrayElemValue.FieldByName(attributeName)
|
||||||
|
if len(relation) > 0 {
|
||||||
|
relationValue = arrayElemValue.FieldByName(relation[0])
|
||||||
|
if relationValue.Kind() == reflect.Ptr {
|
||||||
|
relationValue = relationValue.Elem()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(relationDataMap) > 0 && !relationValue.IsValid() {
|
||||||
|
return fmt.Errorf(`invalid relation: %s, %s`, relation[0], relation[1])
|
||||||
|
}
|
||||||
|
switch attrKind {
|
||||||
|
case reflect.Array, reflect.Slice:
|
||||||
|
if len(relationDataMap) > 0 {
|
||||||
|
relationField = relationValue.FieldByName(relationAttrName)
|
||||||
|
if relationField.IsValid() {
|
||||||
|
if err = gconv.Structs(
|
||||||
|
relationDataMap[gconv.String(relationField.Interface())],
|
||||||
|
attrValue.Addr(),
|
||||||
|
); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// May be the attribute does not exist yet.
|
||||||
|
return fmt.Errorf(`invalid relation: %s, %s`, relation[0], relation[1])
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf(`relationKey should not be empty as field "%s" is slice`, attributeName)
|
||||||
|
}
|
||||||
|
|
||||||
|
case reflect.Ptr:
|
||||||
|
e := reflect.New(attrType.Elem()).Elem()
|
||||||
|
if len(relationDataMap) > 0 {
|
||||||
|
relationField = relationValue.FieldByName(relationAttrName)
|
||||||
|
if relationField.IsValid() {
|
||||||
|
if err = gconv.Struct(relationDataMap[gconv.String(relationField.Interface())], e); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// May be the attribute does not exist yet.
|
||||||
|
return fmt.Errorf(`invalid relation: %s, %s`, relation[0], relation[1])
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err = gconv.Struct(r[i], e); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
attrValue.Set(e.Addr())
|
||||||
|
|
||||||
|
case reflect.Struct:
|
||||||
|
e := reflect.New(attrType).Elem()
|
||||||
|
if len(relationDataMap) > 0 {
|
||||||
|
relationField = relationValue.FieldByName(relationAttrName)
|
||||||
|
if relationField.IsValid() {
|
||||||
|
if err = gconv.Struct(relationDataMap[gconv.String(relationField.Interface())], e); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// May be the attribute does not exist yet.
|
||||||
|
return fmt.Errorf(`invalid relation: %s, %s`, relation[0], relation[1])
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err = gconv.Struct(r[i], e); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
attrValue.Set(e)
|
||||||
|
|
||||||
|
case reflect.Map:
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reflect.ValueOf(listPointer).Elem().Set(arrayValue)
|
||||||
|
return nil
|
||||||
|
}
|
@ -23,8 +23,8 @@ const (
|
|||||||
SCHEMA1 = "test1"
|
SCHEMA1 = "test1"
|
||||||
SCHEMA2 = "test2"
|
SCHEMA2 = "test2"
|
||||||
PREFIX1 = "gf_"
|
PREFIX1 = "gf_"
|
||||||
USER = "john"
|
USER = "root"
|
||||||
PASS = "Nantish1986!"
|
PASS = "12345678"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -16,8 +16,8 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
SCHEMA = "test_internal"
|
SCHEMA = "test_internal"
|
||||||
USER = "john"
|
USER = "root"
|
||||||
PASS = "Nantish1986!"
|
PASS = "12345678"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -8,9 +8,9 @@ package gdb_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/gogf/gf/database/gdb"
|
||||||
"github.com/gogf/gf/frame/g"
|
"github.com/gogf/gf/frame/g"
|
||||||
"github.com/gogf/gf/util/gconv"
|
"github.com/gogf/gf/util/gconv"
|
||||||
"github.com/gogf/gf/util/gutil"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/gogf/gf/os/gtime"
|
"github.com/gogf/gf/os/gtime"
|
||||||
@ -131,14 +131,14 @@ CREATE TABLE %s (
|
|||||||
t.Assert(users[0].User, &EntityUser{3, "name_3"})
|
t.Assert(users[0].User, &EntityUser{3, "name_3"})
|
||||||
t.Assert(users[1].User, &EntityUser{4, "name_4"})
|
t.Assert(users[1].User, &EntityUser{4, "name_4"})
|
||||||
// Detail
|
// Detail
|
||||||
all, err = db.Table(tableUserDetail).Where("uid", gutil.ListItemValues(users, "User", "Uid")).Order("uid asc").All()
|
all, err = db.Table(tableUserDetail).Where("uid", gdb.ListItemValues(users, "User", "Uid")).Order("uid asc").All()
|
||||||
gtest.Assert(err, nil)
|
gtest.Assert(err, nil)
|
||||||
err = all.ScanList(&users, "UserDetail", "User", "uid:Uid")
|
err = all.ScanList(&users, "UserDetail", "User", "uid:Uid")
|
||||||
t.Assert(err, nil)
|
t.Assert(err, nil)
|
||||||
t.Assert(users[0].UserDetail, &EntityUserDetail{3, "address_3"})
|
t.Assert(users[0].UserDetail, &EntityUserDetail{3, "address_3"})
|
||||||
t.Assert(users[1].UserDetail, &EntityUserDetail{4, "address_4"})
|
t.Assert(users[1].UserDetail, &EntityUserDetail{4, "address_4"})
|
||||||
// Scores
|
// Scores
|
||||||
all, err = db.Table(tableUserScores).Where("uid", gutil.ListItemValues(users, "User", "Uid")).Order("id asc").All()
|
all, err = db.Table(tableUserScores).Where("uid", gdb.ListItemValues(users, "User", "Uid")).Order("id asc").All()
|
||||||
gtest.Assert(err, nil)
|
gtest.Assert(err, nil)
|
||||||
err = all.ScanList(&users, "UserScores", "User", "uid:Uid")
|
err = all.ScanList(&users, "UserScores", "User", "uid:Uid")
|
||||||
t.Assert(err, nil)
|
t.Assert(err, nil)
|
||||||
@ -164,14 +164,14 @@ CREATE TABLE %s (
|
|||||||
t.Assert(users[0].User, &EntityUser{3, "name_3"})
|
t.Assert(users[0].User, &EntityUser{3, "name_3"})
|
||||||
t.Assert(users[1].User, &EntityUser{4, "name_4"})
|
t.Assert(users[1].User, &EntityUser{4, "name_4"})
|
||||||
// Detail
|
// Detail
|
||||||
all, err = db.Table(tableUserDetail).Where("uid", gutil.ListItemValues(users, "User", "Uid")).Order("uid asc").All()
|
all, err = db.Table(tableUserDetail).Where("uid", gdb.ListItemValues(users, "User", "Uid")).Order("uid asc").All()
|
||||||
gtest.Assert(err, nil)
|
gtest.Assert(err, nil)
|
||||||
err = all.ScanList(&users, "UserDetail", "User", "uid:Uid")
|
err = all.ScanList(&users, "UserDetail", "User", "uid:Uid")
|
||||||
t.Assert(err, nil)
|
t.Assert(err, nil)
|
||||||
t.Assert(users[0].UserDetail, &EntityUserDetail{3, "address_3"})
|
t.Assert(users[0].UserDetail, &EntityUserDetail{3, "address_3"})
|
||||||
t.Assert(users[1].UserDetail, &EntityUserDetail{4, "address_4"})
|
t.Assert(users[1].UserDetail, &EntityUserDetail{4, "address_4"})
|
||||||
// Scores
|
// Scores
|
||||||
all, err = db.Table(tableUserScores).Where("uid", gutil.ListItemValues(users, "User", "Uid")).Order("id asc").All()
|
all, err = db.Table(tableUserScores).Where("uid", gdb.ListItemValues(users, "User", "Uid")).Order("id asc").All()
|
||||||
gtest.Assert(err, nil)
|
gtest.Assert(err, nil)
|
||||||
err = all.ScanList(&users, "UserScores", "User", "uid:Uid")
|
err = all.ScanList(&users, "UserScores", "User", "uid:Uid")
|
||||||
t.Assert(err, nil)
|
t.Assert(err, nil)
|
||||||
@ -215,14 +215,14 @@ CREATE TABLE %s (
|
|||||||
t.Assert(users[0].User, &EntityUser{3, "name_3"})
|
t.Assert(users[0].User, &EntityUser{3, "name_3"})
|
||||||
t.Assert(users[1].User, &EntityUser{4, "name_4"})
|
t.Assert(users[1].User, &EntityUser{4, "name_4"})
|
||||||
// Detail
|
// Detail
|
||||||
all, err = db.Table(tableUserDetail).Where("uid", gutil.ListItemValues(users, "User", "Uid")).Order("uid asc").All()
|
all, err = db.Table(tableUserDetail).Where("uid", gdb.ListItemValues(users, "User", "Uid")).Order("uid asc").All()
|
||||||
gtest.Assert(err, nil)
|
gtest.Assert(err, nil)
|
||||||
err = all.ScanList(&users, "UserDetail", "User", "uid:Uid")
|
err = all.ScanList(&users, "UserDetail", "User", "uid:Uid")
|
||||||
t.Assert(err, nil)
|
t.Assert(err, nil)
|
||||||
t.Assert(users[0].UserDetail, &EntityUserDetail{3, "address_3"})
|
t.Assert(users[0].UserDetail, &EntityUserDetail{3, "address_3"})
|
||||||
t.Assert(users[1].UserDetail, &EntityUserDetail{4, "address_4"})
|
t.Assert(users[1].UserDetail, &EntityUserDetail{4, "address_4"})
|
||||||
// Scores
|
// Scores
|
||||||
all, err = db.Table(tableUserScores).Where("uid", gutil.ListItemValues(users, "User", "Uid")).Order("id asc").All()
|
all, err = db.Table(tableUserScores).Where("uid", gdb.ListItemValues(users, "User", "Uid")).Order("id asc").All()
|
||||||
gtest.Assert(err, nil)
|
gtest.Assert(err, nil)
|
||||||
err = all.ScanList(&users, "UserScores", "User", "uid:Uid")
|
err = all.ScanList(&users, "UserScores", "User", "uid:Uid")
|
||||||
t.Assert(err, nil)
|
t.Assert(err, nil)
|
||||||
@ -267,14 +267,14 @@ CREATE TABLE %s (
|
|||||||
t.Assert(users[0].User, &EntityUser{3, "name_3"})
|
t.Assert(users[0].User, &EntityUser{3, "name_3"})
|
||||||
t.Assert(users[1].User, &EntityUser{4, "name_4"})
|
t.Assert(users[1].User, &EntityUser{4, "name_4"})
|
||||||
// Detail
|
// Detail
|
||||||
all, err = db.Table(tableUserDetail).Where("uid", gutil.ListItemValues(users, "User", "Uid")).Order("uid asc").All()
|
all, err = db.Table(tableUserDetail).Where("uid", gdb.ListItemValues(users, "User", "Uid")).Order("uid asc").All()
|
||||||
gtest.Assert(err, nil)
|
gtest.Assert(err, nil)
|
||||||
err = all.ScanList(&users, "UserDetail", "User", "uid:Uid")
|
err = all.ScanList(&users, "UserDetail", "User", "uid:Uid")
|
||||||
t.Assert(err, nil)
|
t.Assert(err, nil)
|
||||||
t.Assert(users[0].UserDetail, &EntityUserDetail{3, "address_3"})
|
t.Assert(users[0].UserDetail, &EntityUserDetail{3, "address_3"})
|
||||||
t.Assert(users[1].UserDetail, &EntityUserDetail{4, "address_4"})
|
t.Assert(users[1].UserDetail, &EntityUserDetail{4, "address_4"})
|
||||||
// Scores
|
// Scores
|
||||||
all, err = db.Table(tableUserScores).Where("uid", gutil.ListItemValues(users, "User", "Uid")).Order("id asc").All()
|
all, err = db.Table(tableUserScores).Where("uid", gdb.ListItemValues(users, "User", "Uid")).Order("id asc").All()
|
||||||
gtest.Assert(err, nil)
|
gtest.Assert(err, nil)
|
||||||
err = all.ScanList(&users, "UserScores", "User", "uid:Uid")
|
err = all.ScanList(&users, "UserScores", "User", "uid:Uid")
|
||||||
t.Assert(err, nil)
|
t.Assert(err, nil)
|
||||||
@ -287,4 +287,43 @@ CREATE TABLE %s (
|
|||||||
t.Assert(users[1].UserScores[0].Score, 1)
|
t.Assert(users[1].UserScores[0].Score, 1)
|
||||||
t.Assert(users[1].UserScores[4].Score, 5)
|
t.Assert(users[1].UserScores[4].Score, 5)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Model ScanList with pointer elements and pointer attributes.
|
||||||
|
gtest.C(t, func(t *gtest.T) {
|
||||||
|
var users []*Entity
|
||||||
|
// User
|
||||||
|
err := db.Table(tableUser).
|
||||||
|
Where("uid", g.Slice{3, 4}).
|
||||||
|
Order("uid asc").
|
||||||
|
ScanList(&users, "User")
|
||||||
|
t.Assert(err, nil)
|
||||||
|
// Detail
|
||||||
|
err = db.Table(tableUserDetail).
|
||||||
|
Where("uid", gdb.ListItemValues(users, "User", "Uid")).
|
||||||
|
Order("uid asc").
|
||||||
|
ScanList(&users, "UserDetail", "User", "uid:Uid")
|
||||||
|
gtest.Assert(err, nil)
|
||||||
|
// Scores
|
||||||
|
err = db.Table(tableUserScores).
|
||||||
|
Where("uid", gdb.ListItemValues(users, "User", "Uid")).
|
||||||
|
Order("id asc").
|
||||||
|
ScanList(&users, "UserScores", "User", "uid:Uid")
|
||||||
|
t.Assert(err, nil)
|
||||||
|
|
||||||
|
t.Assert(len(users), 2)
|
||||||
|
t.Assert(users[0].User, &EntityUser{3, "name_3"})
|
||||||
|
t.Assert(users[1].User, &EntityUser{4, "name_4"})
|
||||||
|
|
||||||
|
t.Assert(users[0].UserDetail, &EntityUserDetail{3, "address_3"})
|
||||||
|
t.Assert(users[1].UserDetail, &EntityUserDetail{4, "address_4"})
|
||||||
|
|
||||||
|
t.Assert(len(users[0].UserScores), 5)
|
||||||
|
t.Assert(len(users[1].UserScores), 5)
|
||||||
|
t.Assert(users[0].UserScores[0].Uid, 3)
|
||||||
|
t.Assert(users[0].UserScores[0].Score, 1)
|
||||||
|
t.Assert(users[0].UserScores[4].Score, 5)
|
||||||
|
t.Assert(users[1].UserScores[0].Uid, 4)
|
||||||
|
t.Assert(users[1].UserScores[0].Score, 1)
|
||||||
|
t.Assert(users[1].UserScores[4].Score, 5)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user