fix: 4086

This commit is contained in:
John Guo
2025-02-27 16:57:37 +08:00
parent 4f069ef5f4
commit 67bb75a2d9
19 changed files with 101 additions and 639 deletions

View File

@ -17,8 +17,7 @@ import (
"github.com/gogf/gf/v2/container/garray"
"github.com/gogf/gf/v2/container/gmap"
"github.com/gogf/gf/v2/container/gtype"
"github.com/gogf/gf/v2/database/gdb/internal/defines"
"github.com/gogf/gf/v2/database/gdb/internal/fieldvar"
"github.com/gogf/gf/v2/container/gvar"
"github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/os/gcache"
@ -669,7 +668,7 @@ type (
Raw string
// Value is the field value type.
Value = *fieldvar.Var
Value = *gvar.Var
// Record is the row record of the table.
Record map[string]Value
@ -770,30 +769,32 @@ const (
SqlTypeStmtQueryRowContext SqlType = "DB.Statement.QueryRowContext"
)
type LocalType = defines.LocalType
// LocalType is a type that defines the local storage type of a field value.
// It is used to specify how the field value should be processed locally.
type LocalType string
const (
LocalTypeUndefined = defines.LocalTypeUndefined
LocalTypeString = defines.LocalTypeString
LocalTypeTime = defines.LocalTypeTime
LocalTypeDate = defines.LocalTypeDate
LocalTypeDatetime = defines.LocalTypeDatetime
LocalTypeInt = defines.LocalTypeInt
LocalTypeUint = defines.LocalTypeUint
LocalTypeInt64 = defines.LocalTypeInt64
LocalTypeUint64 = defines.LocalTypeUint64
LocalTypeIntSlice = defines.LocalTypeIntSlice
LocalTypeInt64Slice = defines.LocalTypeInt64Slice
LocalTypeUint64Slice = defines.LocalTypeUint64Slice
LocalTypeStringSlice = defines.LocalTypeStringSlice
LocalTypeInt64Bytes = defines.LocalTypeInt64Bytes
LocalTypeUint64Bytes = defines.LocalTypeUint64Bytes
LocalTypeFloat32 = defines.LocalTypeFloat32
LocalTypeFloat64 = defines.LocalTypeFloat64
LocalTypeBytes = defines.LocalTypeBytes
LocalTypeBool = defines.LocalTypeBool
LocalTypeJson = defines.LocalTypeJson
LocalTypeJsonb = defines.LocalTypeJsonb
LocalTypeUndefined LocalType = ""
LocalTypeString LocalType = "string"
LocalTypeTime LocalType = "time"
LocalTypeDate LocalType = "date"
LocalTypeDatetime LocalType = "datetime"
LocalTypeInt LocalType = "int"
LocalTypeUint LocalType = "uint"
LocalTypeInt64 LocalType = "int64"
LocalTypeUint64 LocalType = "uint64"
LocalTypeIntSlice LocalType = "[]int"
LocalTypeInt64Slice LocalType = "[]int64"
LocalTypeUint64Slice LocalType = "[]uint64"
LocalTypeStringSlice LocalType = "[]string"
LocalTypeInt64Bytes LocalType = "int64-bytes"
LocalTypeUint64Bytes LocalType = "uint64-bytes"
LocalTypeFloat32 LocalType = "float32"
LocalTypeFloat64 LocalType = "float64"
LocalTypeBytes LocalType = "[]byte"
LocalTypeBool LocalType = "bool"
LocalTypeJson LocalType = "json"
LocalTypeJsonb LocalType = "jsonb"
)
const (

View File

@ -16,6 +16,7 @@ import (
"github.com/gogf/gf/v2/container/gmap"
"github.com/gogf/gf/v2/container/gset"
"github.com/gogf/gf/v2/container/gvar"
"github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/internal/intlog"
@ -239,12 +240,12 @@ func (c *Core) GetScan(ctx context.Context, pointer interface{}, sql string, arg
func (c *Core) GetValue(ctx context.Context, sql string, args ...interface{}) (Value, error) {
one, err := c.db.GetOne(ctx, sql, args...)
if err != nil {
return NewValue(nil), err
return gvar.New(nil), err
}
for _, v := range one {
return v, nil
}
return NewValue(nil), nil
return gvar.New(nil), nil
}
// GetCount queries and returns the count from database.

View File

@ -13,6 +13,7 @@ import (
"fmt"
"reflect"
"github.com/gogf/gf/v2/container/gvar"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/trace"
@ -480,16 +481,11 @@ func (c *Core) RowsToResult(ctx context.Context, rows *sql.Rows) (Result, error)
var (
convertedValue interface{}
columnType = columnTypes[i]
localType = LocalTypeUndefined
)
if convertedValue, err = c.columnValueToLocalValue(ctx, value, columnType); err != nil {
return nil, err
}
localType, err = c.getLocalTypeForFieldWithCache(ctx, columnType.DatabaseTypeName(), convertedValue)
if err != nil {
return nil, err
}
record[columnTypes[i].Name()] = NewValueWithType(convertedValue, localType)
record[columnTypes[i].Name()] = gvar.New(convertedValue)
}
}
result = append(result, record)

View File

@ -10,6 +10,7 @@ import (
"database/sql"
"math"
"github.com/gogf/gf/v2/container/gvar"
"github.com/gogf/gf/v2/encoding/gjson"
"github.com/gogf/gf/v2/internal/empty"
"github.com/gogf/gf/v2/util/gconv"
@ -102,13 +103,11 @@ func (r Result) MapKeyValue(key string) map[string]Value {
s string
m = make(map[string]Value)
tempMap = make(map[string][]interface{})
localType LocalType
hasMultiValues bool
)
for _, item := range r {
if k, ok := item[key]; ok {
s = k.String()
localType = k.LocalType()
tempMap[s] = append(tempMap[s], item)
if len(tempMap[s]) > 1 {
hasMultiValues = true
@ -117,9 +116,9 @@ func (r Result) MapKeyValue(key string) map[string]Value {
}
for k, v := range tempMap {
if hasMultiValues {
m[k] = NewValue(v)
m[k] = gvar.New(v)
} else {
m[k] = NewValueWithType(v[0], localType)
m[k] = gvar.New(v[0])
}
}
return m

View File

@ -1,19 +0,0 @@
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package gdb
import "github.com/gogf/gf/v2/database/gdb/internal/fieldvar"
// NewValue creates and returns a new Value object.
func NewValue(value any) Value {
return fieldvar.New(value)
}
// NewValueWithType creates and returns a new Value object with specified local type.
func NewValueWithType(value any, localType LocalType) Value {
return fieldvar.NewWithType(value, localType)
}

View File

@ -1,36 +0,0 @@
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
// Package defines provides some common definitions for gdb package.
package defines
// LocalType is a type that defines the local storage type of a field value.
// It is used to specify how the field value should be processed locally.
type LocalType string
const (
LocalTypeUndefined LocalType = ""
LocalTypeString LocalType = "string"
LocalTypeTime LocalType = "time"
LocalTypeDate LocalType = "date"
LocalTypeDatetime LocalType = "datetime"
LocalTypeInt LocalType = "int"
LocalTypeUint LocalType = "uint"
LocalTypeInt64 LocalType = "int64"
LocalTypeUint64 LocalType = "uint64"
LocalTypeIntSlice LocalType = "[]int"
LocalTypeInt64Slice LocalType = "[]int64"
LocalTypeUint64Slice LocalType = "[]uint64"
LocalTypeStringSlice LocalType = "[]string"
LocalTypeInt64Bytes LocalType = "int64-bytes"
LocalTypeUint64Bytes LocalType = "uint64-bytes"
LocalTypeFloat32 LocalType = "float32"
LocalTypeFloat64 LocalType = "float64"
LocalTypeBytes LocalType = "[]byte"
LocalTypeBool LocalType = "bool"
LocalTypeJson LocalType = "json"
LocalTypeJsonb LocalType = "jsonb"
)

View File

@ -1,63 +0,0 @@
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
// Package fieldvar provides a variable wrapper for field value in database operations.
// It is used for field value storage and conversion in database operations.
package fieldvar
import (
"github.com/gogf/gf/v2/database/gdb/internal/defines"
"github.com/gogf/gf/v2/internal/json"
)
// Var is a wrapper for any type of value, which is used for field variable.
// Note that, do not embed *gvar.Var into Var but use it as an attribute, as there issue in nil pointer receiver
// when calling methods that is not defined directly on Var.
type Var struct {
value any
localType defines.LocalType
}
// New creates and returns a new Var object.
func New(value any) *Var {
return &Var{
value: value,
}
}
// NewWithType creates and returns a new Var object with specified local type.
func NewWithType(value any, localType defines.LocalType) *Var {
return &Var{
value: value,
localType: localType,
}
}
// LocalType returns the local type of the value.
func (v *Var) LocalType() defines.LocalType {
return v.localType
}
// MarshalJSON implements the interface MarshalJSON for json.Marshal.
func (v *Var) MarshalJSON() ([]byte, error) {
return json.Marshal(v.Val())
}
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
func (v *Var) UnmarshalJSON(b []byte) error {
var i interface{}
if err := json.UnmarshalUseNumber(b, &i); err != nil {
return err
}
v.Set(i)
return nil
}
// UnmarshalValue is an interface implement which sets any type of value for Var.
func (v *Var) UnmarshalValue(value interface{}) error {
v.Set(value)
return nil
}

View File

@ -1,99 +0,0 @@
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package fieldvar
import (
"github.com/gogf/gf/v2/util/gconv"
)
// Val returns the current value of `v`.
func (v *Var) Val() interface{} {
if v == nil {
return nil
}
return v.value
}
// Interface is alias of Val.
func (v *Var) Interface() interface{} {
return v.Val()
}
// Bytes converts and returns `v` as []byte.
func (v *Var) Bytes() []byte {
return gconv.Bytes(v.Val())
}
// String converts and returns `v` as string.
func (v *Var) String() string {
return gconv.String(v.Val())
}
// Bool converts and returns `v` as bool.
func (v *Var) Bool() bool {
return gconv.Bool(v.Val())
}
// Int converts and returns `v` as int.
func (v *Var) Int() int {
return gconv.Int(v.Val())
}
// Int8 converts and returns `v` as int8.
func (v *Var) Int8() int8 {
return gconv.Int8(v.Val())
}
// Int16 converts and returns `v` as int16.
func (v *Var) Int16() int16 {
return gconv.Int16(v.Val())
}
// Int32 converts and returns `v` as int32.
func (v *Var) Int32() int32 {
return gconv.Int32(v.Val())
}
// Int64 converts and returns `v` as int64.
func (v *Var) Int64() int64 {
return gconv.Int64(v.Val())
}
// Uint converts and returns `v` as uint.
func (v *Var) Uint() uint {
return gconv.Uint(v.Val())
}
// Uint8 converts and returns `v` as uint8.
func (v *Var) Uint8() uint8 {
return gconv.Uint8(v.Val())
}
// Uint16 converts and returns `v` as uint16.
func (v *Var) Uint16() uint16 {
return gconv.Uint16(v.Val())
}
// Uint32 converts and returns `v` as uint32.
func (v *Var) Uint32() uint32 {
return gconv.Uint32(v.Val())
}
// Uint64 converts and returns `v` as uint64.
func (v *Var) Uint64() uint64 {
return gconv.Uint64(v.Val())
}
// Float32 converts and returns `v` as float32.
func (v *Var) Float32() float32 {
return gconv.Float32(v.Val())
}
// Float64 converts and returns `v` as float64.
func (v *Var) Float64() float64 {
return gconv.Float64(v.Val())
}

View File

@ -1,30 +0,0 @@
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package fieldvar
import (
"github.com/gogf/gf/v2/internal/deepcopy"
"github.com/gogf/gf/v2/util/gutil"
)
// Copy does a deep copy of current Var and returns a pointer to this Var.
func (v *Var) Copy() *Var {
return NewWithType(gutil.Copy(v.Val()), v.localType)
}
// Clone does a shallow copy of current Var and returns a pointer to this Var.
func (v *Var) Clone() *Var {
return NewWithType(v.Val(), v.localType)
}
// DeepCopy implements interface for deep copy of current type.
func (v *Var) DeepCopy() interface{} {
if v == nil {
return nil
}
return NewWithType(deepcopy.Copy(v.Val()), v.localType)
}

View File

@ -1,51 +0,0 @@
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package fieldvar
import (
"github.com/gogf/gf/v2/internal/utils"
)
// IsNil checks whether `v` is nil.
func (v *Var) IsNil() bool {
return utils.IsNil(v.Val())
}
// IsEmpty checks whether `v` is empty.
func (v *Var) IsEmpty() bool {
return utils.IsEmpty(v.Val())
}
// IsInt checks whether `v` is type of int.
func (v *Var) IsInt() bool {
return utils.IsInt(v.Val())
}
// IsUint checks whether `v` is type of uint.
func (v *Var) IsUint() bool {
return utils.IsUint(v.Val())
}
// IsFloat checks whether `v` is type of float.
func (v *Var) IsFloat() bool {
return utils.IsFloat(v.Val())
}
// IsSlice checks whether `v` is type of slice.
func (v *Var) IsSlice() bool {
return utils.IsSlice(v.Val())
}
// IsMap checks whether `v` is type of map.
func (v *Var) IsMap() bool {
return utils.IsMap(v.Val())
}
// IsStruct checks whether `v` is type of struct.
func (v *Var) IsStruct() bool {
return utils.IsStruct(v.Val())
}

View File

@ -1,65 +0,0 @@
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package fieldvar
import "github.com/gogf/gf/v2/util/gconv"
// MapOption specifies the option for map converting.
type MapOption = gconv.MapOption
// Map converts and returns `v` as map[string]interface{}.
func (v *Var) Map(option ...MapOption) map[string]interface{} {
return gconv.Map(v.Val(), option...)
}
// MapStrAny is like function Map, but implements the interface of MapStrAny.
func (v *Var) MapStrAny(option ...MapOption) map[string]interface{} {
return v.Map(option...)
}
// MapStrStr converts and returns `v` as map[string]string.
func (v *Var) MapStrStr(option ...MapOption) map[string]string {
return gconv.MapStrStr(v.Val(), option...)
}
// MapStrVar converts and returns `v` as map[string]Var.
func (v *Var) MapStrVar(option ...MapOption) map[string]*Var {
m := v.Map(option...)
if len(m) > 0 {
vMap := make(map[string]*Var, len(m))
for k, v := range m {
vMap[k] = New(v)
}
return vMap
}
return nil
}
// Maps converts and returns `v` as map[string]string.
// See gconv.Maps.
func (v *Var) Maps(option ...MapOption) []map[string]interface{} {
return gconv.Maps(v.Val(), option...)
}
// MapToMap converts any map type variable `params` to another map type variable `pointer`.
// See gconv.MapToMap.
func (v *Var) MapToMap(pointer interface{}, mapping ...map[string]string) (err error) {
return gconv.MapToMap(v.Val(), pointer, mapping...)
}
// MapToMaps converts any map type variable `params` to another map type variable `pointer`.
// See gconv.MapToMaps.
func (v *Var) MapToMaps(pointer interface{}, mapping ...map[string]string) (err error) {
return gconv.MapToMaps(v.Val(), pointer, mapping...)
}
// MapToMapsDeep converts any map type variable `params` to another map type variable
// `pointer` recursively.
// See gconv.MapToMapsDeep.
func (v *Var) MapToMapsDeep(pointer interface{}, mapping ...map[string]string) (err error) {
return gconv.MapToMaps(v.Val(), pointer, mapping...)
}

View File

@ -1,18 +0,0 @@
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package fieldvar
import (
"github.com/gogf/gf/v2/util/gconv"
)
// Scan automatically checks the type of `pointer` and converts value of Var to `pointer`.
//
// See gconv.Scan.
func (v *Var) Scan(pointer interface{}, mapping ...map[string]string) error {
return gconv.Scan(v.Val(), pointer, mapping...)
}

View File

@ -1,14 +0,0 @@
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package fieldvar
// Set sets `value` to `v`, and returns the old value.
func (v *Var) Set(value interface{}) (old interface{}) {
old = v.value
v.value = value
return
}

View File

@ -1,86 +0,0 @@
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package fieldvar
import (
"github.com/gogf/gf/v2/database/gdb/internal/defines"
"github.com/gogf/gf/v2/internal/json"
"github.com/gogf/gf/v2/util/gconv"
)
// Ints converts and returns `v` as []int.
func (v *Var) Ints() []int {
return gconv.Ints(v.Val())
}
// Int64s converts and returns `v` as []int64.
func (v *Var) Int64s() []int64 {
return gconv.Int64s(v.Val())
}
// Uints converts and returns `v` as []uint.
func (v *Var) Uints() []uint {
return gconv.Uints(v.Val())
}
// Uint64s converts and returns `v` as []uint64.
func (v *Var) Uint64s() []uint64 {
return gconv.Uint64s(v.Val())
}
// Floats is alias of Float64s.
func (v *Var) Floats() []float64 {
return gconv.Floats(v.Val())
}
// Float32s converts and returns `v` as []float32.
func (v *Var) Float32s() []float32 {
return gconv.Float32s(v.Val())
}
// Float64s converts and returns `v` as []float64.
func (v *Var) Float64s() []float64 {
return gconv.Float64s(v.Val())
}
// Strings converts and returns `v` as []string.
func (v *Var) Strings() []string {
if v.localType == defines.LocalTypeJson {
var s []string
_ = json.Unmarshal(v.Bytes(), &s)
return s
}
return gconv.Strings(v.Val())
}
// Interfaces converts and returns `v` as []interfaces{}.
func (v *Var) Interfaces() []interface{} {
return gconv.Interfaces(v.Val())
}
// Slice is alias of Interfaces.
func (v *Var) Slice() []interface{} {
return v.Interfaces()
}
// Array is alias of Interfaces.
func (v *Var) Array() []interface{} {
return v.Interfaces()
}
// Vars converts and returns `v` as []Var.
func (v *Var) Vars() []*Var {
array := gconv.Interfaces(v.Val())
if len(array) == 0 {
return nil
}
vars := make([]*Var, len(array))
for k, v := range array {
vars[k] = New(v)
}
return vars
}

View File

@ -1,23 +0,0 @@
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package fieldvar
import (
"github.com/gogf/gf/v2/util/gconv"
)
// Struct maps value of `v` to `pointer`.
// The parameter `pointer` should be a pointer to a struct instance.
// The parameter `mapping` is used to specify the key-to-attribute mapping rules.
func (v *Var) Struct(pointer interface{}, mapping ...map[string]string) error {
return gconv.Struct(v.Val(), pointer, mapping...)
}
// Structs converts and returns `v` as given struct slice.
func (v *Var) Structs(pointer interface{}, mapping ...map[string]string) error {
return gconv.Structs(v.Val(), pointer, mapping...)
}

View File

@ -1,34 +0,0 @@
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package fieldvar
import (
"time"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/gconv"
)
// Time converts and returns `v` as time.Time.
// The parameter `format` specifies the format of the time string using gtime,
// Example: Y-m-d H:i:s.
func (v *Var) Time(format ...string) time.Time {
return gconv.Time(v.Val(), format...)
}
// Duration converts and returns `v` as time.Duration.
// If value of `v` is string, then it uses time.ParseDuration for conversion.
func (v *Var) Duration() time.Duration {
return gconv.Duration(v.Val())
}
// GTime converts and returns `v` as *gtime.Time.
// The parameter `format` specifies the format of the time string using gtime,
// Example: Y-m-d H:i:s.
func (v *Var) GTime(format ...string) *gtime.Time {
return gconv.GTime(v.Val(), format...)
}