mirror of
https://gitee.com/johng/gf
synced 2026-07-08 22:40:30 +08:00
gofmt
This commit is contained in:
1668
database/gdb/gdb.go
1668
database/gdb/gdb.go
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -7,61 +7,61 @@
|
||||
package gdb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql/driver"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
"context"
|
||||
"database/sql/driver"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/v2/encoding/gbinary"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/internal/intlog"
|
||||
"github.com/gogf/gf/v2/internal/json"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"github.com/gogf/gf/v2/text/gregex"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"github.com/gogf/gf/v2/util/gutil"
|
||||
"github.com/gogf/gf/v2/encoding/gbinary"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/internal/intlog"
|
||||
"github.com/gogf/gf/v2/internal/json"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"github.com/gogf/gf/v2/text/gregex"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"github.com/gogf/gf/v2/util/gutil"
|
||||
)
|
||||
|
||||
// GetFieldTypeStr retrieves and returns the field type string for certain field by name.
|
||||
func (c *Core) GetFieldTypeStr(ctx context.Context, fieldName, table, schema string) string {
|
||||
field := c.GetFieldType(ctx, fieldName, table, schema)
|
||||
if field != nil {
|
||||
// Kinds of data type examples:
|
||||
// year(4)
|
||||
// datetime
|
||||
// varchar(64)
|
||||
// bigint(20)
|
||||
// int(10) unsigned
|
||||
typeName := gstr.StrTillEx(field.Type, "(") // int(10) unsigned -> int
|
||||
if typeName != "" {
|
||||
typeName = gstr.Trim(typeName)
|
||||
} else {
|
||||
typeName = field.Type
|
||||
}
|
||||
return typeName
|
||||
}
|
||||
return ""
|
||||
field := c.GetFieldType(ctx, fieldName, table, schema)
|
||||
if field != nil {
|
||||
// Kinds of data type examples:
|
||||
// year(4)
|
||||
// datetime
|
||||
// varchar(64)
|
||||
// bigint(20)
|
||||
// int(10) unsigned
|
||||
typeName := gstr.StrTillEx(field.Type, "(") // int(10) unsigned -> int
|
||||
if typeName != "" {
|
||||
typeName = gstr.Trim(typeName)
|
||||
} else {
|
||||
typeName = field.Type
|
||||
}
|
||||
return typeName
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetFieldType retrieves and returns the field type object for certain field by name.
|
||||
func (c *Core) GetFieldType(ctx context.Context, fieldName, table, schema string) *TableField {
|
||||
fieldsMap, err := c.db.TableFields(ctx, table, schema)
|
||||
if err != nil {
|
||||
intlog.Errorf(
|
||||
ctx,
|
||||
`TableFields failed for table "%s", schema "%s": %+v`,
|
||||
table, schema, err,
|
||||
)
|
||||
return nil
|
||||
}
|
||||
for tableFieldName, tableField := range fieldsMap {
|
||||
if tableFieldName == fieldName {
|
||||
return tableField
|
||||
}
|
||||
}
|
||||
return nil
|
||||
fieldsMap, err := c.db.TableFields(ctx, table, schema)
|
||||
if err != nil {
|
||||
intlog.Errorf(
|
||||
ctx,
|
||||
`TableFields failed for table "%s", schema "%s": %+v`,
|
||||
table, schema, err,
|
||||
)
|
||||
return nil
|
||||
}
|
||||
for tableFieldName, tableField := range fieldsMap {
|
||||
if tableFieldName == fieldName {
|
||||
return tableField
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ConvertDataForRecord is a very important function, which does converting for any data that
|
||||
@ -70,420 +70,420 @@ func (c *Core) GetFieldType(ctx context.Context, fieldName, table, schema string
|
||||
// The parameter `value` should be type of *map/map/*struct/struct.
|
||||
// It supports embedded struct definition for struct.
|
||||
func (c *Core) ConvertDataForRecord(ctx context.Context, value interface{}, table string) (map[string]interface{}, error) {
|
||||
var (
|
||||
err error
|
||||
data = MapOrStructToMapDeep(value, true)
|
||||
)
|
||||
for fieldName, fieldValue := range data {
|
||||
var fieldType = c.GetFieldTypeStr(ctx, fieldName, table, c.GetSchema())
|
||||
data[fieldName], err = c.db.ConvertValueForField(
|
||||
ctx,
|
||||
fieldType,
|
||||
fieldValue,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, gerror.Wrapf(err, `ConvertDataForRecord failed for value: %#v`, fieldValue)
|
||||
}
|
||||
}
|
||||
return data, nil
|
||||
var (
|
||||
err error
|
||||
data = MapOrStructToMapDeep(value, true)
|
||||
)
|
||||
for fieldName, fieldValue := range data {
|
||||
var fieldType = c.GetFieldTypeStr(ctx, fieldName, table, c.GetSchema())
|
||||
data[fieldName], err = c.db.ConvertValueForField(
|
||||
ctx,
|
||||
fieldType,
|
||||
fieldValue,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, gerror.Wrapf(err, `ConvertDataForRecord failed for value: %#v`, fieldValue)
|
||||
}
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// ConvertValueForField converts value to the type of the record field.
|
||||
// The parameter `fieldType` is the target record field.
|
||||
// The parameter `fieldValue` is the value that to be committed to record field.
|
||||
func (c *Core) ConvertValueForField(ctx context.Context, fieldType string, fieldValue interface{}) (interface{}, error) {
|
||||
var (
|
||||
err error
|
||||
convertedValue = fieldValue
|
||||
)
|
||||
switch fieldValue.(type) {
|
||||
case time.Time, *time.Time, gtime.Time, *gtime.Time:
|
||||
goto Default
|
||||
}
|
||||
// If `value` implements interface `driver.Valuer`, it then uses the interface for value converting.
|
||||
if valuer, ok := fieldValue.(driver.Valuer); ok {
|
||||
if convertedValue, err = valuer.Value(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return convertedValue, nil
|
||||
}
|
||||
var (
|
||||
err error
|
||||
convertedValue = fieldValue
|
||||
)
|
||||
switch fieldValue.(type) {
|
||||
case time.Time, *time.Time, gtime.Time, *gtime.Time:
|
||||
goto Default
|
||||
}
|
||||
// If `value` implements interface `driver.Valuer`, it then uses the interface for value converting.
|
||||
if valuer, ok := fieldValue.(driver.Valuer); ok {
|
||||
if convertedValue, err = valuer.Value(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return convertedValue, nil
|
||||
}
|
||||
Default:
|
||||
// Default value converting.
|
||||
var (
|
||||
rvValue = reflect.ValueOf(fieldValue)
|
||||
rvKind = rvValue.Kind()
|
||||
)
|
||||
for rvKind == reflect.Ptr {
|
||||
rvValue = rvValue.Elem()
|
||||
rvKind = rvValue.Kind()
|
||||
}
|
||||
switch rvKind {
|
||||
case reflect.Invalid:
|
||||
convertedValue = nil
|
||||
// Default value converting.
|
||||
var (
|
||||
rvValue = reflect.ValueOf(fieldValue)
|
||||
rvKind = rvValue.Kind()
|
||||
)
|
||||
for rvKind == reflect.Ptr {
|
||||
rvValue = rvValue.Elem()
|
||||
rvKind = rvValue.Kind()
|
||||
}
|
||||
switch rvKind {
|
||||
case reflect.Invalid:
|
||||
convertedValue = nil
|
||||
|
||||
case reflect.Slice, reflect.Array, reflect.Map:
|
||||
// It should ignore the bytes type.
|
||||
if _, ok := fieldValue.([]byte); !ok {
|
||||
// Convert the value to JSON.
|
||||
convertedValue, err = json.Marshal(fieldValue)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
case reflect.Struct:
|
||||
switch r := fieldValue.(type) {
|
||||
// If the time is zero, it then updates it to nil,
|
||||
// which will insert/update the value to database as "null".
|
||||
case time.Time:
|
||||
if r.IsZero() {
|
||||
convertedValue = nil
|
||||
} else {
|
||||
switch fieldType {
|
||||
case fieldTypeYear:
|
||||
convertedValue = r.Format("2006")
|
||||
case fieldTypeDate:
|
||||
convertedValue = r.Format("2006-01-02")
|
||||
case fieldTypeTime:
|
||||
convertedValue = r.Format("15:04:05")
|
||||
default:
|
||||
}
|
||||
}
|
||||
case reflect.Slice, reflect.Array, reflect.Map:
|
||||
// It should ignore the bytes type.
|
||||
if _, ok := fieldValue.([]byte); !ok {
|
||||
// Convert the value to JSON.
|
||||
convertedValue, err = json.Marshal(fieldValue)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
case reflect.Struct:
|
||||
switch r := fieldValue.(type) {
|
||||
// If the time is zero, it then updates it to nil,
|
||||
// which will insert/update the value to database as "null".
|
||||
case time.Time:
|
||||
if r.IsZero() {
|
||||
convertedValue = nil
|
||||
} else {
|
||||
switch fieldType {
|
||||
case fieldTypeYear:
|
||||
convertedValue = r.Format("2006")
|
||||
case fieldTypeDate:
|
||||
convertedValue = r.Format("2006-01-02")
|
||||
case fieldTypeTime:
|
||||
convertedValue = r.Format("15:04:05")
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
case *time.Time:
|
||||
if r == nil {
|
||||
// Nothing to do.
|
||||
} else {
|
||||
switch fieldType {
|
||||
case fieldTypeYear:
|
||||
convertedValue = r.Format("2006")
|
||||
case fieldTypeDate:
|
||||
convertedValue = r.Format("2006-01-02")
|
||||
case fieldTypeTime:
|
||||
convertedValue = r.Format("15:04:05")
|
||||
default:
|
||||
}
|
||||
}
|
||||
case *time.Time:
|
||||
if r == nil {
|
||||
// Nothing to do.
|
||||
} else {
|
||||
switch fieldType {
|
||||
case fieldTypeYear:
|
||||
convertedValue = r.Format("2006")
|
||||
case fieldTypeDate:
|
||||
convertedValue = r.Format("2006-01-02")
|
||||
case fieldTypeTime:
|
||||
convertedValue = r.Format("15:04:05")
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
case gtime.Time:
|
||||
if r.IsZero() {
|
||||
convertedValue = nil
|
||||
} else {
|
||||
switch fieldType {
|
||||
case fieldTypeYear:
|
||||
convertedValue = r.Layout("2006")
|
||||
case fieldTypeDate:
|
||||
convertedValue = r.Layout("2006-01-02")
|
||||
case fieldTypeTime:
|
||||
convertedValue = r.Layout("15:04:05")
|
||||
default:
|
||||
convertedValue = r.Time
|
||||
}
|
||||
}
|
||||
case gtime.Time:
|
||||
if r.IsZero() {
|
||||
convertedValue = nil
|
||||
} else {
|
||||
switch fieldType {
|
||||
case fieldTypeYear:
|
||||
convertedValue = r.Layout("2006")
|
||||
case fieldTypeDate:
|
||||
convertedValue = r.Layout("2006-01-02")
|
||||
case fieldTypeTime:
|
||||
convertedValue = r.Layout("15:04:05")
|
||||
default:
|
||||
convertedValue = r.Time
|
||||
}
|
||||
}
|
||||
|
||||
case *gtime.Time:
|
||||
if r.IsZero() {
|
||||
convertedValue = nil
|
||||
} else {
|
||||
switch fieldType {
|
||||
case fieldTypeYear:
|
||||
convertedValue = r.Layout("2006")
|
||||
case fieldTypeDate:
|
||||
convertedValue = r.Layout("2006-01-02")
|
||||
case fieldTypeTime:
|
||||
convertedValue = r.Layout("15:04:05")
|
||||
default:
|
||||
convertedValue = r.Time
|
||||
}
|
||||
}
|
||||
case *gtime.Time:
|
||||
if r.IsZero() {
|
||||
convertedValue = nil
|
||||
} else {
|
||||
switch fieldType {
|
||||
case fieldTypeYear:
|
||||
convertedValue = r.Layout("2006")
|
||||
case fieldTypeDate:
|
||||
convertedValue = r.Layout("2006-01-02")
|
||||
case fieldTypeTime:
|
||||
convertedValue = r.Layout("15:04:05")
|
||||
default:
|
||||
convertedValue = r.Time
|
||||
}
|
||||
}
|
||||
|
||||
case Counter, *Counter:
|
||||
// Nothing to do.
|
||||
case Counter, *Counter:
|
||||
// Nothing to do.
|
||||
|
||||
default:
|
||||
// If `value` implements interface iNil,
|
||||
// check its IsNil() function, if got ture,
|
||||
// which will insert/update the value to database as "null".
|
||||
if v, ok := fieldValue.(iNil); ok && v.IsNil() {
|
||||
convertedValue = nil
|
||||
} else if s, ok := fieldValue.(iString); ok {
|
||||
// Use string conversion in default.
|
||||
convertedValue = s.String()
|
||||
} else {
|
||||
// Convert the value to JSON.
|
||||
convertedValue, err = json.Marshal(fieldValue)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
}
|
||||
default:
|
||||
// If `value` implements interface iNil,
|
||||
// check its IsNil() function, if got ture,
|
||||
// which will insert/update the value to database as "null".
|
||||
if v, ok := fieldValue.(iNil); ok && v.IsNil() {
|
||||
convertedValue = nil
|
||||
} else if s, ok := fieldValue.(iString); ok {
|
||||
// Use string conversion in default.
|
||||
convertedValue = s.String()
|
||||
} else {
|
||||
// Convert the value to JSON.
|
||||
convertedValue, err = json.Marshal(fieldValue)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
}
|
||||
|
||||
return convertedValue, nil
|
||||
return convertedValue, nil
|
||||
}
|
||||
|
||||
// CheckLocalTypeForField checks and returns corresponding type for given db type.
|
||||
// The `fieldType` is retrieved from ColumnTypes of db driver, example:
|
||||
// UNSIGNED INT
|
||||
func (c *Core) CheckLocalTypeForField(ctx context.Context, fieldType string, _ interface{}) (LocalType, error) {
|
||||
var (
|
||||
typeName string
|
||||
typePattern string
|
||||
)
|
||||
match, _ := gregex.MatchString(`(.+?)\((.+)\)`, fieldType)
|
||||
if len(match) == 3 {
|
||||
typeName = gstr.Trim(match[1])
|
||||
typePattern = gstr.Trim(match[2])
|
||||
} else {
|
||||
var array = gstr.SplitAndTrim(fieldType, " ")
|
||||
if gstr.Equal(array[0], "unsigned") {
|
||||
typeName = array[1]
|
||||
} else {
|
||||
typeName = array[0]
|
||||
}
|
||||
}
|
||||
var (
|
||||
typeName string
|
||||
typePattern string
|
||||
)
|
||||
match, _ := gregex.MatchString(`(.+?)\((.+)\)`, fieldType)
|
||||
if len(match) == 3 {
|
||||
typeName = gstr.Trim(match[1])
|
||||
typePattern = gstr.Trim(match[2])
|
||||
} else {
|
||||
var array = gstr.SplitAndTrim(fieldType, " ")
|
||||
if gstr.Equal(array[0], "unsigned") {
|
||||
typeName = array[1]
|
||||
} else {
|
||||
typeName = array[0]
|
||||
}
|
||||
}
|
||||
|
||||
typeName = strings.ToLower(typeName)
|
||||
typeName = strings.ToLower(typeName)
|
||||
|
||||
switch typeName {
|
||||
case
|
||||
fieldTypeBinary,
|
||||
fieldTypeVarbinary,
|
||||
fieldTypeBlob,
|
||||
fieldTypeTinyblob,
|
||||
fieldTypeMediumblob,
|
||||
fieldTypeLongblob:
|
||||
return LocalTypeBytes, nil
|
||||
switch typeName {
|
||||
case
|
||||
fieldTypeBinary,
|
||||
fieldTypeVarbinary,
|
||||
fieldTypeBlob,
|
||||
fieldTypeTinyblob,
|
||||
fieldTypeMediumblob,
|
||||
fieldTypeLongblob:
|
||||
return LocalTypeBytes, nil
|
||||
|
||||
case
|
||||
fieldTypeInt,
|
||||
fieldTypeTinyint,
|
||||
fieldTypeSmallInt,
|
||||
fieldTypeSmallint,
|
||||
fieldTypeMediumInt,
|
||||
fieldTypeMediumint,
|
||||
fieldTypeSerial:
|
||||
if gstr.ContainsI(fieldType, "unsigned") {
|
||||
return LocalTypeUint, nil
|
||||
}
|
||||
return LocalTypeInt, nil
|
||||
case
|
||||
fieldTypeInt,
|
||||
fieldTypeTinyint,
|
||||
fieldTypeSmallInt,
|
||||
fieldTypeSmallint,
|
||||
fieldTypeMediumInt,
|
||||
fieldTypeMediumint,
|
||||
fieldTypeSerial:
|
||||
if gstr.ContainsI(fieldType, "unsigned") {
|
||||
return LocalTypeUint, nil
|
||||
}
|
||||
return LocalTypeInt, nil
|
||||
|
||||
case
|
||||
fieldTypeBigInt,
|
||||
fieldTypeBigint,
|
||||
fieldTypeBigserial:
|
||||
if gstr.ContainsI(fieldType, "unsigned") {
|
||||
return LocalTypeUint64, nil
|
||||
}
|
||||
return LocalTypeInt64, nil
|
||||
case
|
||||
fieldTypeBigInt,
|
||||
fieldTypeBigint,
|
||||
fieldTypeBigserial:
|
||||
if gstr.ContainsI(fieldType, "unsigned") {
|
||||
return LocalTypeUint64, nil
|
||||
}
|
||||
return LocalTypeInt64, nil
|
||||
|
||||
case
|
||||
fieldTypeReal:
|
||||
return LocalTypeFloat32, nil
|
||||
case
|
||||
fieldTypeReal:
|
||||
return LocalTypeFloat32, nil
|
||||
|
||||
case
|
||||
fieldTypeDecimal,
|
||||
fieldTypeMoney,
|
||||
fieldTypeNumeric,
|
||||
fieldTypeSmallmoney:
|
||||
return LocalTypeString, nil
|
||||
case
|
||||
fieldTypeFloat,
|
||||
fieldTypeDouble:
|
||||
return LocalTypeFloat64, nil
|
||||
case
|
||||
fieldTypeDecimal,
|
||||
fieldTypeMoney,
|
||||
fieldTypeNumeric,
|
||||
fieldTypeSmallmoney:
|
||||
return LocalTypeString, nil
|
||||
case
|
||||
fieldTypeFloat,
|
||||
fieldTypeDouble:
|
||||
return LocalTypeFloat64, nil
|
||||
|
||||
case
|
||||
fieldTypeBit:
|
||||
// It is suggested using bit(1) as boolean.
|
||||
if typePattern == "1" {
|
||||
return LocalTypeBool, nil
|
||||
}
|
||||
if gstr.ContainsI(fieldType, "unsigned") {
|
||||
return LocalTypeUint64Bytes, nil
|
||||
}
|
||||
return LocalTypeInt64Bytes, nil
|
||||
case
|
||||
fieldTypeBit:
|
||||
// It is suggested using bit(1) as boolean.
|
||||
if typePattern == "1" {
|
||||
return LocalTypeBool, nil
|
||||
}
|
||||
if gstr.ContainsI(fieldType, "unsigned") {
|
||||
return LocalTypeUint64Bytes, nil
|
||||
}
|
||||
return LocalTypeInt64Bytes, nil
|
||||
|
||||
case
|
||||
fieldTypeBool:
|
||||
return LocalTypeBool, nil
|
||||
case
|
||||
fieldTypeBool:
|
||||
return LocalTypeBool, nil
|
||||
|
||||
case
|
||||
fieldTypeDate:
|
||||
return LocalTypeDate, nil
|
||||
case
|
||||
fieldTypeDate:
|
||||
return LocalTypeDate, nil
|
||||
|
||||
case
|
||||
fieldTypeTime:
|
||||
return LocalTypeTime, nil
|
||||
case
|
||||
fieldTypeTime:
|
||||
return LocalTypeTime, nil
|
||||
|
||||
case
|
||||
fieldTypeDatetime,
|
||||
fieldTypeTimestamp,
|
||||
fieldTypeTimestampz:
|
||||
return LocalTypeDatetime, nil
|
||||
case
|
||||
fieldTypeDatetime,
|
||||
fieldTypeTimestamp,
|
||||
fieldTypeTimestampz:
|
||||
return LocalTypeDatetime, nil
|
||||
|
||||
case
|
||||
fieldTypeJson:
|
||||
return LocalTypeJson, nil
|
||||
case
|
||||
fieldTypeJson:
|
||||
return LocalTypeJson, nil
|
||||
|
||||
case
|
||||
fieldTypeJsonb:
|
||||
return LocalTypeJsonb, nil
|
||||
case
|
||||
fieldTypeJsonb:
|
||||
return LocalTypeJsonb, nil
|
||||
|
||||
default:
|
||||
// Auto-detect field type, using key match.
|
||||
switch {
|
||||
case strings.Contains(typeName, "text") || strings.Contains(typeName, "char") || strings.Contains(typeName, "character"):
|
||||
return LocalTypeString, nil
|
||||
default:
|
||||
// Auto-detect field type, using key match.
|
||||
switch {
|
||||
case strings.Contains(typeName, "text") || strings.Contains(typeName, "char") || strings.Contains(typeName, "character"):
|
||||
return LocalTypeString, nil
|
||||
|
||||
case strings.Contains(typeName, "float") || strings.Contains(typeName, "double") || strings.Contains(typeName, "numeric"):
|
||||
return LocalTypeFloat64, nil
|
||||
case strings.Contains(typeName, "float") || strings.Contains(typeName, "double") || strings.Contains(typeName, "numeric"):
|
||||
return LocalTypeFloat64, nil
|
||||
|
||||
case strings.Contains(typeName, "bool"):
|
||||
return LocalTypeBool, nil
|
||||
case strings.Contains(typeName, "bool"):
|
||||
return LocalTypeBool, nil
|
||||
|
||||
case strings.Contains(typeName, "binary") || strings.Contains(typeName, "blob"):
|
||||
return LocalTypeBytes, nil
|
||||
case strings.Contains(typeName, "binary") || strings.Contains(typeName, "blob"):
|
||||
return LocalTypeBytes, nil
|
||||
|
||||
case strings.Contains(typeName, "int"):
|
||||
if gstr.ContainsI(fieldType, "unsigned") {
|
||||
return LocalTypeUint, nil
|
||||
}
|
||||
return LocalTypeInt, nil
|
||||
case strings.Contains(typeName, "int"):
|
||||
if gstr.ContainsI(fieldType, "unsigned") {
|
||||
return LocalTypeUint, nil
|
||||
}
|
||||
return LocalTypeInt, nil
|
||||
|
||||
case strings.Contains(typeName, "time"):
|
||||
return LocalTypeDatetime, nil
|
||||
case strings.Contains(typeName, "time"):
|
||||
return LocalTypeDatetime, nil
|
||||
|
||||
case strings.Contains(typeName, "date"):
|
||||
return LocalTypeDatetime, nil
|
||||
case strings.Contains(typeName, "date"):
|
||||
return LocalTypeDatetime, nil
|
||||
|
||||
default:
|
||||
return LocalTypeString, nil
|
||||
}
|
||||
}
|
||||
default:
|
||||
return LocalTypeString, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ConvertValueForLocal converts value to local Golang type of value according field type name from database.
|
||||
// The parameter `fieldType` is in lower case, like:
|
||||
// `float(5,2)`, `unsigned double(5,2)`, `decimal(10,2)`, `char(45)`, `varchar(100)`, etc.
|
||||
func (c *Core) ConvertValueForLocal(
|
||||
ctx context.Context, fieldType string, fieldValue interface{},
|
||||
ctx context.Context, fieldType string, fieldValue interface{},
|
||||
) (interface{}, error) {
|
||||
// If there's no type retrieved, it returns the `fieldValue` directly
|
||||
// to use its original data type, as `fieldValue` is type of interface{}.
|
||||
if fieldType == "" {
|
||||
return fieldValue, nil
|
||||
}
|
||||
typeName, err := c.db.CheckLocalTypeForField(ctx, fieldType, fieldValue)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch typeName {
|
||||
case LocalTypeBytes:
|
||||
var typeNameStr = string(typeName)
|
||||
if strings.Contains(typeNameStr, "binary") || strings.Contains(typeNameStr, "blob") {
|
||||
return fieldValue, nil
|
||||
}
|
||||
return gconv.Bytes(fieldValue), nil
|
||||
// If there's no type retrieved, it returns the `fieldValue` directly
|
||||
// to use its original data type, as `fieldValue` is type of interface{}.
|
||||
if fieldType == "" {
|
||||
return fieldValue, nil
|
||||
}
|
||||
typeName, err := c.db.CheckLocalTypeForField(ctx, fieldType, fieldValue)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch typeName {
|
||||
case LocalTypeBytes:
|
||||
var typeNameStr = string(typeName)
|
||||
if strings.Contains(typeNameStr, "binary") || strings.Contains(typeNameStr, "blob") {
|
||||
return fieldValue, nil
|
||||
}
|
||||
return gconv.Bytes(fieldValue), nil
|
||||
|
||||
case LocalTypeInt:
|
||||
return gconv.Int(gconv.String(fieldValue)), nil
|
||||
case LocalTypeInt:
|
||||
return gconv.Int(gconv.String(fieldValue)), nil
|
||||
|
||||
case LocalTypeUint:
|
||||
return gconv.Uint(gconv.String(fieldValue)), nil
|
||||
case LocalTypeUint:
|
||||
return gconv.Uint(gconv.String(fieldValue)), nil
|
||||
|
||||
case LocalTypeInt64:
|
||||
return gconv.Int64(gconv.String(fieldValue)), nil
|
||||
case LocalTypeInt64:
|
||||
return gconv.Int64(gconv.String(fieldValue)), nil
|
||||
|
||||
case LocalTypeUint64:
|
||||
return gconv.Uint64(gconv.String(fieldValue)), nil
|
||||
case LocalTypeUint64:
|
||||
return gconv.Uint64(gconv.String(fieldValue)), nil
|
||||
|
||||
case LocalTypeInt64Bytes:
|
||||
return gbinary.BeDecodeToInt64(gconv.Bytes(fieldValue)), nil
|
||||
case LocalTypeInt64Bytes:
|
||||
return gbinary.BeDecodeToInt64(gconv.Bytes(fieldValue)), nil
|
||||
|
||||
case LocalTypeUint64Bytes:
|
||||
return gbinary.BeDecodeToUint64(gconv.Bytes(fieldValue)), nil
|
||||
case LocalTypeUint64Bytes:
|
||||
return gbinary.BeDecodeToUint64(gconv.Bytes(fieldValue)), nil
|
||||
|
||||
case LocalTypeFloat32:
|
||||
return gconv.Float32(gconv.String(fieldValue)), nil
|
||||
case LocalTypeFloat32:
|
||||
return gconv.Float32(gconv.String(fieldValue)), nil
|
||||
|
||||
case LocalTypeFloat64:
|
||||
return gconv.Float64(gconv.String(fieldValue)), nil
|
||||
case LocalTypeFloat64:
|
||||
return gconv.Float64(gconv.String(fieldValue)), nil
|
||||
|
||||
case LocalTypeBool:
|
||||
s := gconv.String(fieldValue)
|
||||
// mssql is true|false string.
|
||||
if strings.EqualFold(s, "true") {
|
||||
return 1, nil
|
||||
}
|
||||
if strings.EqualFold(s, "false") {
|
||||
return 0, nil
|
||||
}
|
||||
return gconv.Bool(fieldValue), nil
|
||||
case LocalTypeBool:
|
||||
s := gconv.String(fieldValue)
|
||||
// mssql is true|false string.
|
||||
if strings.EqualFold(s, "true") {
|
||||
return 1, nil
|
||||
}
|
||||
if strings.EqualFold(s, "false") {
|
||||
return 0, nil
|
||||
}
|
||||
return gconv.Bool(fieldValue), nil
|
||||
|
||||
case LocalTypeDate:
|
||||
if t, ok := fieldValue.(time.Time); ok {
|
||||
return gtime.NewFromTime(t).Format("Y-m-d"), nil
|
||||
}
|
||||
t, _ := gtime.StrToTime(gconv.String(fieldValue))
|
||||
return t.Format("Y-m-d"), nil
|
||||
case LocalTypeDate:
|
||||
if t, ok := fieldValue.(time.Time); ok {
|
||||
return gtime.NewFromTime(t).Format("Y-m-d"), nil
|
||||
}
|
||||
t, _ := gtime.StrToTime(gconv.String(fieldValue))
|
||||
return t.Format("Y-m-d"), nil
|
||||
|
||||
case LocalTypeTime:
|
||||
if t, ok := fieldValue.(time.Time); ok {
|
||||
return gtime.NewFromTime(t).Format("H:i:s"), nil
|
||||
}
|
||||
t, _ := gtime.StrToTime(gconv.String(fieldValue))
|
||||
return t.Format("H:i:s"), nil
|
||||
case LocalTypeTime:
|
||||
if t, ok := fieldValue.(time.Time); ok {
|
||||
return gtime.NewFromTime(t).Format("H:i:s"), nil
|
||||
}
|
||||
t, _ := gtime.StrToTime(gconv.String(fieldValue))
|
||||
return t.Format("H:i:s"), nil
|
||||
|
||||
case LocalTypeDatetime:
|
||||
if t, ok := fieldValue.(time.Time); ok {
|
||||
return gtime.NewFromTime(t), nil
|
||||
}
|
||||
t, _ := gtime.StrToTime(gconv.String(fieldValue))
|
||||
return t, nil
|
||||
case LocalTypeDatetime:
|
||||
if t, ok := fieldValue.(time.Time); ok {
|
||||
return gtime.NewFromTime(t), nil
|
||||
}
|
||||
t, _ := gtime.StrToTime(gconv.String(fieldValue))
|
||||
return t, nil
|
||||
|
||||
default:
|
||||
return gconv.String(fieldValue), nil
|
||||
}
|
||||
default:
|
||||
return gconv.String(fieldValue), nil
|
||||
}
|
||||
}
|
||||
|
||||
// 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(ctx context.Context, schema, table string, data map[string]interface{}, filter bool) (map[string]interface{}, error) {
|
||||
fieldsMap, err := c.db.TableFields(ctx, c.guessPrimaryTableName(table), schema)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(fieldsMap) == 0 {
|
||||
return nil, gerror.Newf(`The table %s may not exist, or the table contains no fields`, table)
|
||||
}
|
||||
fieldsKeyMap := make(map[string]interface{}, len(fieldsMap))
|
||||
for k := range fieldsMap {
|
||||
fieldsKeyMap[k] = nil
|
||||
}
|
||||
// Automatic data key to table field name mapping.
|
||||
var foundKey string
|
||||
for dataKey, dataValue := range data {
|
||||
if _, ok := fieldsKeyMap[dataKey]; !ok {
|
||||
foundKey, _ = gutil.MapPossibleItemByKey(fieldsKeyMap, dataKey)
|
||||
if foundKey != "" {
|
||||
if _, ok = data[foundKey]; !ok {
|
||||
data[foundKey] = dataValue
|
||||
}
|
||||
delete(data, dataKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Data filtering.
|
||||
// It deletes all key-value pairs that has incorrect field name.
|
||||
if filter {
|
||||
for dataKey := range data {
|
||||
if _, ok := fieldsMap[dataKey]; !ok {
|
||||
delete(data, dataKey)
|
||||
}
|
||||
}
|
||||
if len(data) == 0 {
|
||||
return nil, gerror.Newf(`input data match no fields in table %s`, table)
|
||||
}
|
||||
}
|
||||
return data, nil
|
||||
fieldsMap, err := c.db.TableFields(ctx, c.guessPrimaryTableName(table), schema)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(fieldsMap) == 0 {
|
||||
return nil, gerror.Newf(`The table %s may not exist, or the table contains no fields`, table)
|
||||
}
|
||||
fieldsKeyMap := make(map[string]interface{}, len(fieldsMap))
|
||||
for k := range fieldsMap {
|
||||
fieldsKeyMap[k] = nil
|
||||
}
|
||||
// Automatic data key to table field name mapping.
|
||||
var foundKey string
|
||||
for dataKey, dataValue := range data {
|
||||
if _, ok := fieldsKeyMap[dataKey]; !ok {
|
||||
foundKey, _ = gutil.MapPossibleItemByKey(fieldsKeyMap, dataKey)
|
||||
if foundKey != "" {
|
||||
if _, ok = data[foundKey]; !ok {
|
||||
data[foundKey] = dataValue
|
||||
}
|
||||
delete(data, dataKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Data filtering.
|
||||
// It deletes all key-value pairs that has incorrect field name.
|
||||
if filter {
|
||||
for dataKey := range data {
|
||||
if _, ok := fieldsMap[dataKey]; !ok {
|
||||
delete(data, dataKey)
|
||||
}
|
||||
}
|
||||
if len(data) == 0 {
|
||||
return nil, gerror.Newf(`input data match no fields in table %s`, table)
|
||||
}
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
@ -8,298 +8,298 @@
|
||||
package gdb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
|
||||
"github.com/gogf/gf/v2"
|
||||
"github.com/gogf/gf/v2/errors/gcode"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/internal/intlog"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"github.com/gogf/gf/v2/util/guid"
|
||||
"github.com/gogf/gf/v2"
|
||||
"github.com/gogf/gf/v2/errors/gcode"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/internal/intlog"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"github.com/gogf/gf/v2/util/guid"
|
||||
)
|
||||
|
||||
// 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(ctx context.Context, sql string, args ...interface{}) (result Result, err error) {
|
||||
return c.db.DoQuery(ctx, nil, sql, args...)
|
||||
return c.db.DoQuery(ctx, nil, 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(ctx context.Context, link Link, sql string, args ...interface{}) (result Result, err error) {
|
||||
// Transaction checks.
|
||||
if link == nil {
|
||||
if tx := TXFromCtx(ctx, c.db.GetGroup()); tx != nil {
|
||||
// Firstly, check and retrieve transaction link from context.
|
||||
link = &txLink{tx.GetSqlTX()}
|
||||
} else if link, err = c.SlaveLink(); err != nil {
|
||||
// Or else it creates one from master node.
|
||||
return nil, err
|
||||
}
|
||||
} else if !link.IsTransaction() {
|
||||
// If current link is not transaction link, it checks and retrieves transaction from context.
|
||||
if tx := TXFromCtx(ctx, c.db.GetGroup()); tx != nil {
|
||||
link = &txLink{tx.GetSqlTX()}
|
||||
}
|
||||
}
|
||||
// Transaction checks.
|
||||
if link == nil {
|
||||
if tx := TXFromCtx(ctx, c.db.GetGroup()); tx != nil {
|
||||
// Firstly, check and retrieve transaction link from context.
|
||||
link = &txLink{tx.GetSqlTX()}
|
||||
} else if link, err = c.SlaveLink(); err != nil {
|
||||
// Or else it creates one from master node.
|
||||
return nil, err
|
||||
}
|
||||
} else if !link.IsTransaction() {
|
||||
// If current link is not transaction link, it checks and retrieves transaction from context.
|
||||
if tx := TXFromCtx(ctx, c.db.GetGroup()); tx != nil {
|
||||
link = &txLink{tx.GetSqlTX()}
|
||||
}
|
||||
}
|
||||
|
||||
// Sql filtering.
|
||||
sql, args = c.FormatSqlBeforeExecuting(sql, args)
|
||||
sql, args, err = c.db.DoFilter(ctx, link, sql, args)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// SQL format and retrieve.
|
||||
if v := ctx.Value(ctxKeyCatchSQL); v != nil {
|
||||
var (
|
||||
manager = v.(*CatchSQLManager)
|
||||
formattedSql = FormatSqlWithArgs(sql, args)
|
||||
)
|
||||
manager.SQLArray.Append(formattedSql)
|
||||
if !manager.DoCommit && ctx.Value(ctxKeyInternalProducedSQL) == nil {
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
// Link execution.
|
||||
var out DoCommitOutput
|
||||
out, err = c.db.DoCommit(ctx, DoCommitInput{
|
||||
Link: link,
|
||||
Sql: sql,
|
||||
Args: args,
|
||||
Stmt: nil,
|
||||
Type: SqlTypeQueryContext,
|
||||
IsTransaction: link.IsTransaction(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out.Records, err
|
||||
// Sql filtering.
|
||||
sql, args = c.FormatSqlBeforeExecuting(sql, args)
|
||||
sql, args, err = c.db.DoFilter(ctx, link, sql, args)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// SQL format and retrieve.
|
||||
if v := ctx.Value(ctxKeyCatchSQL); v != nil {
|
||||
var (
|
||||
manager = v.(*CatchSQLManager)
|
||||
formattedSql = FormatSqlWithArgs(sql, args)
|
||||
)
|
||||
manager.SQLArray.Append(formattedSql)
|
||||
if !manager.DoCommit && ctx.Value(ctxKeyInternalProducedSQL) == nil {
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
// Link execution.
|
||||
var out DoCommitOutput
|
||||
out, err = c.db.DoCommit(ctx, DoCommitInput{
|
||||
Link: link,
|
||||
Sql: sql,
|
||||
Args: args,
|
||||
Stmt: nil,
|
||||
Type: SqlTypeQueryContext,
|
||||
IsTransaction: link.IsTransaction(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out.Records, 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(ctx context.Context, sql string, args ...interface{}) (result sql.Result, err error) {
|
||||
return c.db.DoExec(ctx, nil, sql, args...)
|
||||
return c.db.DoExec(ctx, nil, 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(ctx context.Context, link Link, sql string, args ...interface{}) (result sql.Result, err error) {
|
||||
// Transaction checks.
|
||||
if link == nil {
|
||||
if tx := TXFromCtx(ctx, c.db.GetGroup()); tx != nil {
|
||||
// Firstly, check and retrieve transaction link from context.
|
||||
link = &txLink{tx.GetSqlTX()}
|
||||
} else if link, err = c.MasterLink(); err != nil {
|
||||
// Or else it creates one from master node.
|
||||
return nil, err
|
||||
}
|
||||
} else if !link.IsTransaction() {
|
||||
// If current link is not transaction link, it checks and retrieves transaction from context.
|
||||
if tx := TXFromCtx(ctx, c.db.GetGroup()); tx != nil {
|
||||
link = &txLink{tx.GetSqlTX()}
|
||||
}
|
||||
}
|
||||
// Transaction checks.
|
||||
if link == nil {
|
||||
if tx := TXFromCtx(ctx, c.db.GetGroup()); tx != nil {
|
||||
// Firstly, check and retrieve transaction link from context.
|
||||
link = &txLink{tx.GetSqlTX()}
|
||||
} else if link, err = c.MasterLink(); err != nil {
|
||||
// Or else it creates one from master node.
|
||||
return nil, err
|
||||
}
|
||||
} else if !link.IsTransaction() {
|
||||
// If current link is not transaction link, it checks and retrieves transaction from context.
|
||||
if tx := TXFromCtx(ctx, c.db.GetGroup()); tx != nil {
|
||||
link = &txLink{tx.GetSqlTX()}
|
||||
}
|
||||
}
|
||||
|
||||
// SQL filtering.
|
||||
sql, args = c.FormatSqlBeforeExecuting(sql, args)
|
||||
sql, args, err = c.db.DoFilter(ctx, link, sql, args)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// SQL format and retrieve.
|
||||
if v := ctx.Value(ctxKeyCatchSQL); v != nil {
|
||||
var (
|
||||
manager = v.(*CatchSQLManager)
|
||||
formattedSql = FormatSqlWithArgs(sql, args)
|
||||
)
|
||||
manager.SQLArray.Append(formattedSql)
|
||||
if !manager.DoCommit && ctx.Value(ctxKeyInternalProducedSQL) == nil {
|
||||
return new(SqlResult), nil
|
||||
}
|
||||
}
|
||||
// Link execution.
|
||||
var out DoCommitOutput
|
||||
out, err = c.db.DoCommit(ctx, DoCommitInput{
|
||||
Link: link,
|
||||
Sql: sql,
|
||||
Args: args,
|
||||
Stmt: nil,
|
||||
Type: SqlTypeExecContext,
|
||||
IsTransaction: link.IsTransaction(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out.Result, err
|
||||
// SQL filtering.
|
||||
sql, args = c.FormatSqlBeforeExecuting(sql, args)
|
||||
sql, args, err = c.db.DoFilter(ctx, link, sql, args)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// SQL format and retrieve.
|
||||
if v := ctx.Value(ctxKeyCatchSQL); v != nil {
|
||||
var (
|
||||
manager = v.(*CatchSQLManager)
|
||||
formattedSql = FormatSqlWithArgs(sql, args)
|
||||
)
|
||||
manager.SQLArray.Append(formattedSql)
|
||||
if !manager.DoCommit && ctx.Value(ctxKeyInternalProducedSQL) == nil {
|
||||
return new(SqlResult), nil
|
||||
}
|
||||
}
|
||||
// Link execution.
|
||||
var out DoCommitOutput
|
||||
out, err = c.db.DoCommit(ctx, DoCommitInput{
|
||||
Link: link,
|
||||
Sql: sql,
|
||||
Args: args,
|
||||
Stmt: nil,
|
||||
Type: SqlTypeExecContext,
|
||||
IsTransaction: link.IsTransaction(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out.Result, err
|
||||
}
|
||||
|
||||
// DoFilter is a hook function, which filters the sql and its arguments 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.
|
||||
func (c *Core) DoFilter(
|
||||
ctx context.Context, link Link, sql string, args []interface{},
|
||||
ctx context.Context, link Link, sql string, args []interface{},
|
||||
) (newSql string, newArgs []interface{}, err error) {
|
||||
return sql, args, nil
|
||||
return sql, args, nil
|
||||
}
|
||||
|
||||
// DoCommit commits current sql and arguments to underlying sql driver.
|
||||
func (c *Core) DoCommit(ctx context.Context, in DoCommitInput) (out DoCommitOutput, err error) {
|
||||
var (
|
||||
sqlTx *sql.Tx
|
||||
sqlStmt *sql.Stmt
|
||||
sqlRows *sql.Rows
|
||||
sqlResult sql.Result
|
||||
stmtSqlRows *sql.Rows
|
||||
stmtSqlRow *sql.Row
|
||||
rowsAffected int64
|
||||
cancelFuncForTimeout context.CancelFunc
|
||||
formattedSql = FormatSqlWithArgs(in.Sql, in.Args)
|
||||
timestampMilli1 = gtime.TimestampMilli()
|
||||
)
|
||||
var (
|
||||
sqlTx *sql.Tx
|
||||
sqlStmt *sql.Stmt
|
||||
sqlRows *sql.Rows
|
||||
sqlResult sql.Result
|
||||
stmtSqlRows *sql.Rows
|
||||
stmtSqlRow *sql.Row
|
||||
rowsAffected int64
|
||||
cancelFuncForTimeout context.CancelFunc
|
||||
formattedSql = FormatSqlWithArgs(in.Sql, in.Args)
|
||||
timestampMilli1 = gtime.TimestampMilli()
|
||||
)
|
||||
|
||||
// Trace span start.
|
||||
tr := otel.GetTracerProvider().Tracer(traceInstrumentName, trace.WithInstrumentationVersion(gf.VERSION))
|
||||
ctx, span := tr.Start(ctx, string(in.Type), trace.WithSpanKind(trace.SpanKindInternal))
|
||||
defer span.End()
|
||||
// Trace span start.
|
||||
tr := otel.GetTracerProvider().Tracer(traceInstrumentName, trace.WithInstrumentationVersion(gf.VERSION))
|
||||
ctx, span := tr.Start(ctx, string(in.Type), trace.WithSpanKind(trace.SpanKindInternal))
|
||||
defer span.End()
|
||||
|
||||
// Execution by type.
|
||||
switch in.Type {
|
||||
case SqlTypeBegin:
|
||||
ctx, cancelFuncForTimeout = c.GetCtxTimeout(ctx, ctxTimeoutTypeTrans)
|
||||
formattedSql = fmt.Sprintf(
|
||||
`%s (IosolationLevel: %s, ReadOnly: %t)`,
|
||||
formattedSql, in.TxOptions.Isolation.String(), in.TxOptions.ReadOnly,
|
||||
)
|
||||
if sqlTx, err = in.Db.BeginTx(ctx, &in.TxOptions); err == nil {
|
||||
out.Tx = &TXCore{
|
||||
db: c.db,
|
||||
tx: sqlTx,
|
||||
ctx: context.WithValue(ctx, transactionIdForLoggerCtx, transactionIdGenerator.Add(1)),
|
||||
master: in.Db,
|
||||
transactionId: guid.S(),
|
||||
cancelFunc: cancelFuncForTimeout,
|
||||
}
|
||||
ctx = out.Tx.GetCtx()
|
||||
}
|
||||
out.RawResult = sqlTx
|
||||
// Execution by type.
|
||||
switch in.Type {
|
||||
case SqlTypeBegin:
|
||||
ctx, cancelFuncForTimeout = c.GetCtxTimeout(ctx, ctxTimeoutTypeTrans)
|
||||
formattedSql = fmt.Sprintf(
|
||||
`%s (IosolationLevel: %s, ReadOnly: %t)`,
|
||||
formattedSql, in.TxOptions.Isolation.String(), in.TxOptions.ReadOnly,
|
||||
)
|
||||
if sqlTx, err = in.Db.BeginTx(ctx, &in.TxOptions); err == nil {
|
||||
out.Tx = &TXCore{
|
||||
db: c.db,
|
||||
tx: sqlTx,
|
||||
ctx: context.WithValue(ctx, transactionIdForLoggerCtx, transactionIdGenerator.Add(1)),
|
||||
master: in.Db,
|
||||
transactionId: guid.S(),
|
||||
cancelFunc: cancelFuncForTimeout,
|
||||
}
|
||||
ctx = out.Tx.GetCtx()
|
||||
}
|
||||
out.RawResult = sqlTx
|
||||
|
||||
case SqlTypeTXCommit:
|
||||
if in.TxCancelFunc != nil {
|
||||
defer in.TxCancelFunc()
|
||||
}
|
||||
err = in.Tx.Commit()
|
||||
case SqlTypeTXCommit:
|
||||
if in.TxCancelFunc != nil {
|
||||
defer in.TxCancelFunc()
|
||||
}
|
||||
err = in.Tx.Commit()
|
||||
|
||||
case SqlTypeTXRollback:
|
||||
if in.TxCancelFunc != nil {
|
||||
defer in.TxCancelFunc()
|
||||
}
|
||||
err = in.Tx.Rollback()
|
||||
case SqlTypeTXRollback:
|
||||
if in.TxCancelFunc != nil {
|
||||
defer in.TxCancelFunc()
|
||||
}
|
||||
err = in.Tx.Rollback()
|
||||
|
||||
case SqlTypeExecContext:
|
||||
ctx, cancelFuncForTimeout = c.GetCtxTimeout(ctx, ctxTimeoutTypeExec)
|
||||
defer cancelFuncForTimeout()
|
||||
if c.db.GetDryRun() {
|
||||
sqlResult = new(SqlResult)
|
||||
} else {
|
||||
sqlResult, err = in.Link.ExecContext(ctx, in.Sql, in.Args...)
|
||||
}
|
||||
out.RawResult = sqlResult
|
||||
case SqlTypeExecContext:
|
||||
ctx, cancelFuncForTimeout = c.GetCtxTimeout(ctx, ctxTimeoutTypeExec)
|
||||
defer cancelFuncForTimeout()
|
||||
if c.db.GetDryRun() {
|
||||
sqlResult = new(SqlResult)
|
||||
} else {
|
||||
sqlResult, err = in.Link.ExecContext(ctx, in.Sql, in.Args...)
|
||||
}
|
||||
out.RawResult = sqlResult
|
||||
|
||||
case SqlTypeQueryContext:
|
||||
ctx, cancelFuncForTimeout = c.GetCtxTimeout(ctx, ctxTimeoutTypeQuery)
|
||||
defer cancelFuncForTimeout()
|
||||
sqlRows, err = in.Link.QueryContext(ctx, in.Sql, in.Args...)
|
||||
out.RawResult = sqlRows
|
||||
case SqlTypeQueryContext:
|
||||
ctx, cancelFuncForTimeout = c.GetCtxTimeout(ctx, ctxTimeoutTypeQuery)
|
||||
defer cancelFuncForTimeout()
|
||||
sqlRows, err = in.Link.QueryContext(ctx, in.Sql, in.Args...)
|
||||
out.RawResult = sqlRows
|
||||
|
||||
case SqlTypePrepareContext:
|
||||
ctx, cancelFuncForTimeout = c.GetCtxTimeout(ctx, ctxTimeoutTypePrepare)
|
||||
defer cancelFuncForTimeout()
|
||||
sqlStmt, err = in.Link.PrepareContext(ctx, in.Sql)
|
||||
out.RawResult = sqlStmt
|
||||
case SqlTypePrepareContext:
|
||||
ctx, cancelFuncForTimeout = c.GetCtxTimeout(ctx, ctxTimeoutTypePrepare)
|
||||
defer cancelFuncForTimeout()
|
||||
sqlStmt, err = in.Link.PrepareContext(ctx, in.Sql)
|
||||
out.RawResult = sqlStmt
|
||||
|
||||
case SqlTypeStmtExecContext:
|
||||
ctx, cancelFuncForTimeout = c.GetCtxTimeout(ctx, ctxTimeoutTypeExec)
|
||||
defer cancelFuncForTimeout()
|
||||
if c.db.GetDryRun() {
|
||||
sqlResult = new(SqlResult)
|
||||
} else {
|
||||
sqlResult, err = in.Stmt.ExecContext(ctx, in.Args...)
|
||||
}
|
||||
out.RawResult = sqlResult
|
||||
case SqlTypeStmtExecContext:
|
||||
ctx, cancelFuncForTimeout = c.GetCtxTimeout(ctx, ctxTimeoutTypeExec)
|
||||
defer cancelFuncForTimeout()
|
||||
if c.db.GetDryRun() {
|
||||
sqlResult = new(SqlResult)
|
||||
} else {
|
||||
sqlResult, err = in.Stmt.ExecContext(ctx, in.Args...)
|
||||
}
|
||||
out.RawResult = sqlResult
|
||||
|
||||
case SqlTypeStmtQueryContext:
|
||||
ctx, cancelFuncForTimeout = c.GetCtxTimeout(ctx, ctxTimeoutTypeQuery)
|
||||
defer cancelFuncForTimeout()
|
||||
stmtSqlRows, err = in.Stmt.QueryContext(ctx, in.Args...)
|
||||
out.RawResult = stmtSqlRows
|
||||
case SqlTypeStmtQueryContext:
|
||||
ctx, cancelFuncForTimeout = c.GetCtxTimeout(ctx, ctxTimeoutTypeQuery)
|
||||
defer cancelFuncForTimeout()
|
||||
stmtSqlRows, err = in.Stmt.QueryContext(ctx, in.Args...)
|
||||
out.RawResult = stmtSqlRows
|
||||
|
||||
case SqlTypeStmtQueryRowContext:
|
||||
ctx, cancelFuncForTimeout = c.GetCtxTimeout(ctx, ctxTimeoutTypeQuery)
|
||||
defer cancelFuncForTimeout()
|
||||
stmtSqlRow = in.Stmt.QueryRowContext(ctx, in.Args...)
|
||||
out.RawResult = stmtSqlRow
|
||||
case SqlTypeStmtQueryRowContext:
|
||||
ctx, cancelFuncForTimeout = c.GetCtxTimeout(ctx, ctxTimeoutTypeQuery)
|
||||
defer cancelFuncForTimeout()
|
||||
stmtSqlRow = in.Stmt.QueryRowContext(ctx, in.Args...)
|
||||
out.RawResult = stmtSqlRow
|
||||
|
||||
default:
|
||||
panic(gerror.NewCodef(gcode.CodeInvalidParameter, `invalid SqlType "%s"`, in.Type))
|
||||
}
|
||||
// Result handling.
|
||||
switch {
|
||||
case sqlResult != nil && !c.GetIgnoreResultFromCtx(ctx):
|
||||
rowsAffected, err = sqlResult.RowsAffected()
|
||||
out.Result = sqlResult
|
||||
default:
|
||||
panic(gerror.NewCodef(gcode.CodeInvalidParameter, `invalid SqlType "%s"`, in.Type))
|
||||
}
|
||||
// Result handling.
|
||||
switch {
|
||||
case sqlResult != nil && !c.GetIgnoreResultFromCtx(ctx):
|
||||
rowsAffected, err = sqlResult.RowsAffected()
|
||||
out.Result = sqlResult
|
||||
|
||||
case sqlRows != nil:
|
||||
out.Records, err = c.RowsToResult(ctx, sqlRows)
|
||||
rowsAffected = int64(len(out.Records))
|
||||
case sqlRows != nil:
|
||||
out.Records, err = c.RowsToResult(ctx, sqlRows)
|
||||
rowsAffected = int64(len(out.Records))
|
||||
|
||||
case sqlStmt != nil:
|
||||
out.Stmt = &Stmt{
|
||||
Stmt: sqlStmt,
|
||||
core: c,
|
||||
link: in.Link,
|
||||
sql: in.Sql,
|
||||
}
|
||||
}
|
||||
var (
|
||||
timestampMilli2 = gtime.TimestampMilli()
|
||||
sqlObj = &Sql{
|
||||
Sql: in.Sql,
|
||||
Type: in.Type,
|
||||
Args: in.Args,
|
||||
Format: formattedSql,
|
||||
Error: err,
|
||||
Start: timestampMilli1,
|
||||
End: timestampMilli2,
|
||||
Group: c.db.GetGroup(),
|
||||
Schema: c.db.GetSchema(),
|
||||
RowsAffected: rowsAffected,
|
||||
IsTransaction: in.IsTransaction,
|
||||
}
|
||||
)
|
||||
case sqlStmt != nil:
|
||||
out.Stmt = &Stmt{
|
||||
Stmt: sqlStmt,
|
||||
core: c,
|
||||
link: in.Link,
|
||||
sql: in.Sql,
|
||||
}
|
||||
}
|
||||
var (
|
||||
timestampMilli2 = gtime.TimestampMilli()
|
||||
sqlObj = &Sql{
|
||||
Sql: in.Sql,
|
||||
Type: in.Type,
|
||||
Args: in.Args,
|
||||
Format: formattedSql,
|
||||
Error: err,
|
||||
Start: timestampMilli1,
|
||||
End: timestampMilli2,
|
||||
Group: c.db.GetGroup(),
|
||||
Schema: c.db.GetSchema(),
|
||||
RowsAffected: rowsAffected,
|
||||
IsTransaction: in.IsTransaction,
|
||||
}
|
||||
)
|
||||
|
||||
// Tracing.
|
||||
c.traceSpanEnd(ctx, span, sqlObj)
|
||||
// Tracing.
|
||||
c.traceSpanEnd(ctx, span, sqlObj)
|
||||
|
||||
// Logging.
|
||||
if c.db.GetDebug() {
|
||||
c.writeSqlToLogger(ctx, sqlObj)
|
||||
}
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
err = gerror.WrapCode(
|
||||
gcode.CodeDbOperationError,
|
||||
err,
|
||||
FormatSqlWithArgs(in.Sql, in.Args),
|
||||
)
|
||||
}
|
||||
return out, err
|
||||
// Logging.
|
||||
if c.db.GetDebug() {
|
||||
c.writeSqlToLogger(ctx, sqlObj)
|
||||
}
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
err = gerror.WrapCode(
|
||||
gcode.CodeDbOperationError,
|
||||
err,
|
||||
FormatSqlWithArgs(in.Sql, in.Args),
|
||||
)
|
||||
}
|
||||
return out, err
|
||||
}
|
||||
|
||||
// Prepare creates a prepared statement for later queries or executions.
|
||||
@ -311,200 +311,200 @@ func (c *Core) DoCommit(ctx context.Context, in DoCommitInput) (out DoCommitOutp
|
||||
// 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(ctx context.Context, sql string, execOnMaster ...bool) (*Stmt, error) {
|
||||
var (
|
||||
err error
|
||||
link Link
|
||||
)
|
||||
if len(execOnMaster) > 0 && execOnMaster[0] {
|
||||
if link, err = c.MasterLink(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
if link, err = c.SlaveLink(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return c.db.DoPrepare(ctx, link, sql)
|
||||
var (
|
||||
err error
|
||||
link Link
|
||||
)
|
||||
if len(execOnMaster) > 0 && execOnMaster[0] {
|
||||
if link, err = c.MasterLink(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
if link, err = c.SlaveLink(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return c.db.DoPrepare(ctx, link, sql)
|
||||
}
|
||||
|
||||
// DoPrepare calls prepare function on given link object and returns the statement object.
|
||||
func (c *Core) DoPrepare(ctx context.Context, link Link, sql string) (stmt *Stmt, err error) {
|
||||
// Transaction checks.
|
||||
if link == nil {
|
||||
if tx := TXFromCtx(ctx, c.db.GetGroup()); tx != nil {
|
||||
// Firstly, check and retrieve transaction link from context.
|
||||
link = &txLink{tx.GetSqlTX()}
|
||||
} else {
|
||||
// Or else it creates one from master node.
|
||||
if link, err = c.MasterLink(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
} else if !link.IsTransaction() {
|
||||
// If current link is not transaction link, it checks and retrieves transaction from context.
|
||||
if tx := TXFromCtx(ctx, c.db.GetGroup()); tx != nil {
|
||||
link = &txLink{tx.GetSqlTX()}
|
||||
}
|
||||
}
|
||||
// Transaction checks.
|
||||
if link == nil {
|
||||
if tx := TXFromCtx(ctx, c.db.GetGroup()); tx != nil {
|
||||
// Firstly, check and retrieve transaction link from context.
|
||||
link = &txLink{tx.GetSqlTX()}
|
||||
} else {
|
||||
// Or else it creates one from master node.
|
||||
if link, err = c.MasterLink(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
} else if !link.IsTransaction() {
|
||||
// If current link is not transaction link, it checks and retrieves transaction from context.
|
||||
if tx := TXFromCtx(ctx, c.db.GetGroup()); tx != nil {
|
||||
link = &txLink{tx.GetSqlTX()}
|
||||
}
|
||||
}
|
||||
|
||||
if c.db.GetConfig().PrepareTimeout > 0 {
|
||||
// DO NOT USE cancel function in prepare statement.
|
||||
var cancelFunc context.CancelFunc
|
||||
ctx, cancelFunc = context.WithTimeout(ctx, c.db.GetConfig().PrepareTimeout)
|
||||
defer cancelFunc()
|
||||
}
|
||||
if c.db.GetConfig().PrepareTimeout > 0 {
|
||||
// DO NOT USE cancel function in prepare statement.
|
||||
var cancelFunc context.CancelFunc
|
||||
ctx, cancelFunc = context.WithTimeout(ctx, c.db.GetConfig().PrepareTimeout)
|
||||
defer cancelFunc()
|
||||
}
|
||||
|
||||
// Link execution.
|
||||
var out DoCommitOutput
|
||||
out, err = c.db.DoCommit(ctx, DoCommitInput{
|
||||
Link: link,
|
||||
Sql: sql,
|
||||
Type: SqlTypePrepareContext,
|
||||
IsTransaction: link.IsTransaction(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out.Stmt, err
|
||||
// Link execution.
|
||||
var out DoCommitOutput
|
||||
out, err = c.db.DoCommit(ctx, DoCommitInput{
|
||||
Link: link,
|
||||
Sql: sql,
|
||||
Type: SqlTypePrepareContext,
|
||||
IsTransaction: link.IsTransaction(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out.Stmt, err
|
||||
}
|
||||
|
||||
// FormatUpsert formats and returns SQL clause part for upsert statement.
|
||||
// In default implements, this function performs upsert statement for MySQL like:
|
||||
// `INSERT INTO ... ON DUPLICATE KEY UPDATE x=VALUES(z),m=VALUES(y)...`
|
||||
func (c *Core) FormatUpsert(columns []string, list List, option DoInsertOption) (string, error) {
|
||||
var onDuplicateStr string
|
||||
if option.OnDuplicateStr != "" {
|
||||
onDuplicateStr = option.OnDuplicateStr
|
||||
} else if len(option.OnDuplicateMap) > 0 {
|
||||
for k, v := range option.OnDuplicateMap {
|
||||
if len(onDuplicateStr) > 0 {
|
||||
onDuplicateStr += ","
|
||||
}
|
||||
switch v.(type) {
|
||||
case Raw, *Raw:
|
||||
onDuplicateStr += fmt.Sprintf(
|
||||
"%s=%s",
|
||||
c.QuoteWord(k),
|
||||
v,
|
||||
)
|
||||
default:
|
||||
onDuplicateStr += fmt.Sprintf(
|
||||
"%s=VALUES(%s)",
|
||||
c.QuoteWord(k),
|
||||
c.QuoteWord(gconv.String(v)),
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for _, column := range columns {
|
||||
// If it's `SAVE` operation, do not automatically update the creating time.
|
||||
if c.IsSoftCreatedFieldName(column) {
|
||||
continue
|
||||
}
|
||||
if len(onDuplicateStr) > 0 {
|
||||
onDuplicateStr += ","
|
||||
}
|
||||
onDuplicateStr += fmt.Sprintf(
|
||||
"%s=VALUES(%s)",
|
||||
c.QuoteWord(column),
|
||||
c.QuoteWord(column),
|
||||
)
|
||||
}
|
||||
}
|
||||
var onDuplicateStr string
|
||||
if option.OnDuplicateStr != "" {
|
||||
onDuplicateStr = option.OnDuplicateStr
|
||||
} else if len(option.OnDuplicateMap) > 0 {
|
||||
for k, v := range option.OnDuplicateMap {
|
||||
if len(onDuplicateStr) > 0 {
|
||||
onDuplicateStr += ","
|
||||
}
|
||||
switch v.(type) {
|
||||
case Raw, *Raw:
|
||||
onDuplicateStr += fmt.Sprintf(
|
||||
"%s=%s",
|
||||
c.QuoteWord(k),
|
||||
v,
|
||||
)
|
||||
default:
|
||||
onDuplicateStr += fmt.Sprintf(
|
||||
"%s=VALUES(%s)",
|
||||
c.QuoteWord(k),
|
||||
c.QuoteWord(gconv.String(v)),
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for _, column := range columns {
|
||||
// If it's `SAVE` operation, do not automatically update the creating time.
|
||||
if c.IsSoftCreatedFieldName(column) {
|
||||
continue
|
||||
}
|
||||
if len(onDuplicateStr) > 0 {
|
||||
onDuplicateStr += ","
|
||||
}
|
||||
onDuplicateStr += fmt.Sprintf(
|
||||
"%s=VALUES(%s)",
|
||||
c.QuoteWord(column),
|
||||
c.QuoteWord(column),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return InsertOnDuplicateKeyUpdate + " " + onDuplicateStr, nil
|
||||
return InsertOnDuplicateKeyUpdate + " " + onDuplicateStr, nil
|
||||
}
|
||||
|
||||
// RowsToResult converts underlying data record type sql.Rows to Result type.
|
||||
func (c *Core) RowsToResult(ctx context.Context, rows *sql.Rows) (Result, error) {
|
||||
if rows == nil {
|
||||
return nil, nil
|
||||
}
|
||||
defer func() {
|
||||
if err := rows.Close(); err != nil {
|
||||
intlog.Errorf(ctx, `%+v`, err)
|
||||
}
|
||||
}()
|
||||
if !rows.Next() {
|
||||
return nil, nil
|
||||
}
|
||||
// Column names and types.
|
||||
columnTypes, err := rows.ColumnTypes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if rows == nil {
|
||||
return nil, nil
|
||||
}
|
||||
defer func() {
|
||||
if err := rows.Close(); err != nil {
|
||||
intlog.Errorf(ctx, `%+v`, err)
|
||||
}
|
||||
}()
|
||||
if !rows.Next() {
|
||||
return nil, nil
|
||||
}
|
||||
// Column names and types.
|
||||
columnTypes, err := rows.ColumnTypes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(columnTypes) > 0 {
|
||||
if internalData := c.getInternalColumnFromCtx(ctx); internalData != nil {
|
||||
internalData.FirstResultColumn = columnTypes[0].Name()
|
||||
}
|
||||
}
|
||||
var (
|
||||
values = make([]interface{}, len(columnTypes))
|
||||
result = make(Result, 0)
|
||||
scanArgs = make([]interface{}, len(values))
|
||||
)
|
||||
for i := range values {
|
||||
scanArgs[i] = &values[i]
|
||||
}
|
||||
for {
|
||||
if err = rows.Scan(scanArgs...); err != nil {
|
||||
return result, err
|
||||
}
|
||||
record := Record{}
|
||||
for i, value := range values {
|
||||
if value == nil {
|
||||
// DO NOT use `gvar.New(nil)` here as it creates an initialized object
|
||||
// which will cause struct converting issue.
|
||||
record[columnTypes[i].Name()] = nil
|
||||
} else {
|
||||
var (
|
||||
convertedValue interface{}
|
||||
columnType = columnTypes[i]
|
||||
localType = LocalTypeUndefined
|
||||
)
|
||||
if convertedValue, err = c.columnValueToLocalValue(ctx, value, columnType); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
localType, err = c.db.CheckLocalTypeForField(ctx, columnType.DatabaseTypeName(), value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
record[columnTypes[i].Name()] = NewValueWithType(convertedValue, localType)
|
||||
}
|
||||
}
|
||||
result = append(result, record)
|
||||
if !rows.Next() {
|
||||
break
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
if len(columnTypes) > 0 {
|
||||
if internalData := c.getInternalColumnFromCtx(ctx); internalData != nil {
|
||||
internalData.FirstResultColumn = columnTypes[0].Name()
|
||||
}
|
||||
}
|
||||
var (
|
||||
values = make([]interface{}, len(columnTypes))
|
||||
result = make(Result, 0)
|
||||
scanArgs = make([]interface{}, len(values))
|
||||
)
|
||||
for i := range values {
|
||||
scanArgs[i] = &values[i]
|
||||
}
|
||||
for {
|
||||
if err = rows.Scan(scanArgs...); err != nil {
|
||||
return result, err
|
||||
}
|
||||
record := Record{}
|
||||
for i, value := range values {
|
||||
if value == nil {
|
||||
// DO NOT use `gvar.New(nil)` here as it creates an initialized object
|
||||
// which will cause struct converting issue.
|
||||
record[columnTypes[i].Name()] = nil
|
||||
} else {
|
||||
var (
|
||||
convertedValue interface{}
|
||||
columnType = columnTypes[i]
|
||||
localType = LocalTypeUndefined
|
||||
)
|
||||
if convertedValue, err = c.columnValueToLocalValue(ctx, value, columnType); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
localType, err = c.db.CheckLocalTypeForField(ctx, columnType.DatabaseTypeName(), value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
record[columnTypes[i].Name()] = NewValueWithType(convertedValue, localType)
|
||||
}
|
||||
}
|
||||
result = append(result, record)
|
||||
if !rows.Next() {
|
||||
break
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// OrderRandomFunction returns the SQL function for random ordering.
|
||||
func (c *Core) OrderRandomFunction() string {
|
||||
return "RAND()"
|
||||
return "RAND()"
|
||||
}
|
||||
|
||||
func (c *Core) columnValueToLocalValue(
|
||||
ctx context.Context, value interface{}, columnType *sql.ColumnType,
|
||||
ctx context.Context, value interface{}, columnType *sql.ColumnType,
|
||||
) (interface{}, error) {
|
||||
var scanType = columnType.ScanType()
|
||||
if scanType != nil {
|
||||
// Common basic builtin types.
|
||||
switch scanType.Kind() {
|
||||
case
|
||||
reflect.Bool,
|
||||
reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
||||
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
|
||||
reflect.Float32, reflect.Float64:
|
||||
return gconv.Convert(
|
||||
gconv.String(value),
|
||||
columnType.ScanType().String(),
|
||||
), nil
|
||||
default:
|
||||
}
|
||||
}
|
||||
// Other complex types, especially custom types.
|
||||
return c.db.ConvertValueForLocal(ctx, columnType.DatabaseTypeName(), value)
|
||||
var scanType = columnType.ScanType()
|
||||
if scanType != nil {
|
||||
// Common basic builtin types.
|
||||
switch scanType.Kind() {
|
||||
case
|
||||
reflect.Bool,
|
||||
reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
||||
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
|
||||
reflect.Float32, reflect.Float64:
|
||||
return gconv.Convert(
|
||||
gconv.String(value),
|
||||
columnType.ScanType().String(),
|
||||
), nil
|
||||
default:
|
||||
}
|
||||
}
|
||||
// Other complex types, especially custom types.
|
||||
return c.db.ConvertValueForLocal(ctx, columnType.DatabaseTypeName(), value)
|
||||
}
|
||||
|
||||
@ -7,199 +7,199 @@
|
||||
package gdb
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"math"
|
||||
"database/sql"
|
||||
"math"
|
||||
|
||||
"github.com/gogf/gf/v2/encoding/gjson"
|
||||
"github.com/gogf/gf/v2/internal/empty"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"github.com/gogf/gf/v2/encoding/gjson"
|
||||
"github.com/gogf/gf/v2/internal/empty"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
// IsEmpty checks and returns whether `r` is empty.
|
||||
func (r Result) IsEmpty() bool {
|
||||
return r == nil || r.Len() == 0
|
||||
return r == nil || r.Len() == 0
|
||||
}
|
||||
|
||||
// Len returns the length of result list.
|
||||
func (r Result) Len() int {
|
||||
return len(r)
|
||||
return len(r)
|
||||
}
|
||||
|
||||
// Size is alias of function Len.
|
||||
func (r Result) Size() int {
|
||||
return r.Len()
|
||||
return r.Len()
|
||||
}
|
||||
|
||||
// Chunk splits a Result into multiple Results,
|
||||
// the size of each array is determined by `size`.
|
||||
// The last chunk may contain less than size elements.
|
||||
func (r Result) Chunk(size int) []Result {
|
||||
if size < 1 {
|
||||
return nil
|
||||
}
|
||||
length := len(r)
|
||||
chunks := int(math.Ceil(float64(length) / float64(size)))
|
||||
var n []Result
|
||||
for i, end := 0, 0; chunks > 0; chunks-- {
|
||||
end = (i + 1) * size
|
||||
if end > length {
|
||||
end = length
|
||||
}
|
||||
n = append(n, r[i*size:end])
|
||||
i++
|
||||
}
|
||||
return n
|
||||
if size < 1 {
|
||||
return nil
|
||||
}
|
||||
length := len(r)
|
||||
chunks := int(math.Ceil(float64(length) / float64(size)))
|
||||
var n []Result
|
||||
for i, end := 0, 0; chunks > 0; chunks-- {
|
||||
end = (i + 1) * size
|
||||
if end > length {
|
||||
end = length
|
||||
}
|
||||
n = append(n, r[i*size:end])
|
||||
i++
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// Json converts `r` to JSON format content.
|
||||
func (r Result) Json() string {
|
||||
content, _ := gjson.New(r.List()).ToJsonString()
|
||||
return content
|
||||
content, _ := gjson.New(r.List()).ToJsonString()
|
||||
return content
|
||||
}
|
||||
|
||||
// Xml converts `r` to XML format content.
|
||||
func (r Result) Xml(rootTag ...string) string {
|
||||
content, _ := gjson.New(r.List()).ToXmlString(rootTag...)
|
||||
return content
|
||||
content, _ := gjson.New(r.List()).ToXmlString(rootTag...)
|
||||
return content
|
||||
}
|
||||
|
||||
// List converts `r` to a List.
|
||||
func (r Result) List() List {
|
||||
list := make(List, len(r))
|
||||
for k, v := range r {
|
||||
list[k] = v.Map()
|
||||
}
|
||||
return list
|
||||
list := make(List, len(r))
|
||||
for k, v := range r {
|
||||
list[k] = v.Map()
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
// Array retrieves and returns specified column values as slice.
|
||||
// The parameter `field` is optional is the column field is only one.
|
||||
// The default `field` is the first field name of the first item in `Result` if parameter `field` is not given.
|
||||
func (r Result) Array(field ...string) []Value {
|
||||
array := make([]Value, len(r))
|
||||
if len(r) == 0 {
|
||||
return array
|
||||
}
|
||||
key := ""
|
||||
if len(field) > 0 && field[0] != "" {
|
||||
key = field[0]
|
||||
} else {
|
||||
for k := range r[0] {
|
||||
key = k
|
||||
break
|
||||
}
|
||||
}
|
||||
for k, v := range r {
|
||||
array[k] = v[key]
|
||||
}
|
||||
return array
|
||||
array := make([]Value, len(r))
|
||||
if len(r) == 0 {
|
||||
return array
|
||||
}
|
||||
key := ""
|
||||
if len(field) > 0 && field[0] != "" {
|
||||
key = field[0]
|
||||
} else {
|
||||
for k := range r[0] {
|
||||
key = k
|
||||
break
|
||||
}
|
||||
}
|
||||
for k, v := range r {
|
||||
array[k] = v[key]
|
||||
}
|
||||
return array
|
||||
}
|
||||
|
||||
// MapKeyValue converts `r` to a map[string]Value of which key is specified by `key`.
|
||||
// Note that the item value may be type of slice.
|
||||
func (r Result) MapKeyValue(key string) map[string]Value {
|
||||
var (
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
for k, v := range tempMap {
|
||||
if hasMultiValues {
|
||||
m[k] = NewValue(v)
|
||||
} else {
|
||||
m[k] = NewValueWithType(v[0], localType)
|
||||
}
|
||||
}
|
||||
return m
|
||||
var (
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
for k, v := range tempMap {
|
||||
if hasMultiValues {
|
||||
m[k] = NewValue(v)
|
||||
} else {
|
||||
m[k] = NewValueWithType(v[0], localType)
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// MapKeyStr converts `r` to a map[string]Map of which key is specified by `key`.
|
||||
func (r Result) MapKeyStr(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
|
||||
m := make(map[string]Map)
|
||||
for _, item := range r {
|
||||
if v, ok := item[key]; ok {
|
||||
m[v.String()] = item.Map()
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// MapKeyInt converts `r` to a map[int]Map of which key is specified by `key`.
|
||||
func (r Result) MapKeyInt(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
|
||||
m := make(map[int]Map)
|
||||
for _, item := range r {
|
||||
if v, ok := item[key]; ok {
|
||||
m[v.Int()] = item.Map()
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// MapKeyUint converts `r` to a map[uint]Map of which key is specified by `key`.
|
||||
func (r Result) MapKeyUint(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
|
||||
m := make(map[uint]Map)
|
||||
for _, item := range r {
|
||||
if v, ok := item[key]; ok {
|
||||
m[v.Uint()] = item.Map()
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// RecordKeyStr converts `r` to a map[string]Record of which key is specified by `key`.
|
||||
func (r Result) RecordKeyStr(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
|
||||
m := make(map[string]Record)
|
||||
for _, item := range r {
|
||||
if v, ok := item[key]; ok {
|
||||
m[v.String()] = item
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// RecordKeyInt converts `r` to a map[int]Record of which key is specified by `key`.
|
||||
func (r Result) RecordKeyInt(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
|
||||
m := make(map[int]Record)
|
||||
for _, item := range r {
|
||||
if v, ok := item[key]; ok {
|
||||
m[v.Int()] = item
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// RecordKeyUint converts `r` to a map[uint]Record of which key is specified by `key`.
|
||||
func (r Result) RecordKeyUint(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
|
||||
m := make(map[uint]Record)
|
||||
for _, item := range r {
|
||||
if v, ok := item[key]; ok {
|
||||
m[v.Uint()] = item
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// 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) {
|
||||
// If the result is empty and the target pointer is not empty, it returns error.
|
||||
if r.IsEmpty() {
|
||||
if !empty.IsEmpty(pointer, true) {
|
||||
return sql.ErrNoRows
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return gconv.StructsTag(r, pointer, OrmTagForStruct)
|
||||
// If the result is empty and the target pointer is not empty, it returns error.
|
||||
if r.IsEmpty() {
|
||||
if !empty.IsEmpty(pointer, true) {
|
||||
return sql.ErrNoRows
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return gconv.StructsTag(r, pointer, OrmTagForStruct)
|
||||
}
|
||||
|
||||
@ -10,10 +10,10 @@ 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)
|
||||
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)
|
||||
return fieldvar.NewWithType(value, localType)
|
||||
}
|
||||
|
||||
@ -7,93 +7,93 @@
|
||||
package fieldvar
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"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
|
||||
if v == nil {
|
||||
return nil
|
||||
}
|
||||
return v.value
|
||||
}
|
||||
|
||||
// Interface is alias of Val.
|
||||
func (v *Var) Interface() interface{} {
|
||||
return v.Val()
|
||||
return v.Val()
|
||||
}
|
||||
|
||||
// Bytes converts and returns `v` as []byte.
|
||||
func (v *Var) Bytes() []byte {
|
||||
return gconv.Bytes(v.Val())
|
||||
return gconv.Bytes(v.Val())
|
||||
}
|
||||
|
||||
// String converts and returns `v` as string.
|
||||
func (v *Var) String() string {
|
||||
return gconv.String(v.Val())
|
||||
return gconv.String(v.Val())
|
||||
}
|
||||
|
||||
// Bool converts and returns `v` as bool.
|
||||
func (v *Var) Bool() bool {
|
||||
return gconv.Bool(v.Val())
|
||||
return gconv.Bool(v.Val())
|
||||
}
|
||||
|
||||
// Int converts and returns `v` as int.
|
||||
func (v *Var) Int() int {
|
||||
return gconv.Int(v.Val())
|
||||
return gconv.Int(v.Val())
|
||||
}
|
||||
|
||||
// Int8 converts and returns `v` as int8.
|
||||
func (v *Var) Int8() int8 {
|
||||
return gconv.Int8(v.Val())
|
||||
return gconv.Int8(v.Val())
|
||||
}
|
||||
|
||||
// Int16 converts and returns `v` as int16.
|
||||
func (v *Var) Int16() int16 {
|
||||
return gconv.Int16(v.Val())
|
||||
return gconv.Int16(v.Val())
|
||||
}
|
||||
|
||||
// Int32 converts and returns `v` as int32.
|
||||
func (v *Var) Int32() int32 {
|
||||
return gconv.Int32(v.Val())
|
||||
return gconv.Int32(v.Val())
|
||||
}
|
||||
|
||||
// Int64 converts and returns `v` as int64.
|
||||
func (v *Var) Int64() int64 {
|
||||
return gconv.Int64(v.Val())
|
||||
return gconv.Int64(v.Val())
|
||||
}
|
||||
|
||||
// Uint converts and returns `v` as uint.
|
||||
func (v *Var) Uint() uint {
|
||||
return gconv.Uint(v.Val())
|
||||
return gconv.Uint(v.Val())
|
||||
}
|
||||
|
||||
// Uint8 converts and returns `v` as uint8.
|
||||
func (v *Var) Uint8() uint8 {
|
||||
return gconv.Uint8(v.Val())
|
||||
return gconv.Uint8(v.Val())
|
||||
}
|
||||
|
||||
// Uint16 converts and returns `v` as uint16.
|
||||
func (v *Var) Uint16() uint16 {
|
||||
return gconv.Uint16(v.Val())
|
||||
return gconv.Uint16(v.Val())
|
||||
}
|
||||
|
||||
// Uint32 converts and returns `v` as uint32.
|
||||
func (v *Var) Uint32() uint32 {
|
||||
return gconv.Uint32(v.Val())
|
||||
return gconv.Uint32(v.Val())
|
||||
}
|
||||
|
||||
// Uint64 converts and returns `v` as uint64.
|
||||
func (v *Var) Uint64() uint64 {
|
||||
return gconv.Uint64(v.Val())
|
||||
return gconv.Uint64(v.Val())
|
||||
}
|
||||
|
||||
// Float32 converts and returns `v` as float32.
|
||||
func (v *Var) Float32() float32 {
|
||||
return gconv.Float32(v.Val())
|
||||
return gconv.Float32(v.Val())
|
||||
}
|
||||
|
||||
// Float64 converts and returns `v` as float64.
|
||||
func (v *Var) Float64() float64 {
|
||||
return gconv.Float64(v.Val())
|
||||
return gconv.Float64(v.Val())
|
||||
}
|
||||
|
||||
@ -7,24 +7,24 @@
|
||||
package fieldvar
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/internal/deepcopy"
|
||||
"github.com/gogf/gf/v2/util/gutil"
|
||||
"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)
|
||||
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)
|
||||
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)
|
||||
if v == nil {
|
||||
return nil
|
||||
}
|
||||
return NewWithType(deepcopy.Copy(v.Val()), v.localType)
|
||||
}
|
||||
|
||||
@ -13,53 +13,53 @@ 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...)
|
||||
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...)
|
||||
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...)
|
||||
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
|
||||
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...)
|
||||
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...)
|
||||
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...)
|
||||
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...)
|
||||
return gconv.MapToMaps(v.Val(), pointer, mapping...)
|
||||
}
|
||||
|
||||
@ -7,80 +7,80 @@
|
||||
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"
|
||||
"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())
|
||||
return gconv.Ints(v.Val())
|
||||
}
|
||||
|
||||
// Int64s converts and returns `v` as []int64.
|
||||
func (v *Var) Int64s() []int64 {
|
||||
return gconv.Int64s(v.Val())
|
||||
return gconv.Int64s(v.Val())
|
||||
}
|
||||
|
||||
// Uints converts and returns `v` as []uint.
|
||||
func (v *Var) Uints() []uint {
|
||||
return gconv.Uints(v.Val())
|
||||
return gconv.Uints(v.Val())
|
||||
}
|
||||
|
||||
// Uint64s converts and returns `v` as []uint64.
|
||||
func (v *Var) Uint64s() []uint64 {
|
||||
return gconv.Uint64s(v.Val())
|
||||
return gconv.Uint64s(v.Val())
|
||||
}
|
||||
|
||||
// Floats is alias of Float64s.
|
||||
func (v *Var) Floats() []float64 {
|
||||
return gconv.Floats(v.Val())
|
||||
return gconv.Floats(v.Val())
|
||||
}
|
||||
|
||||
// Float32s converts and returns `v` as []float32.
|
||||
func (v *Var) Float32s() []float32 {
|
||||
return gconv.Float32s(v.Val())
|
||||
return gconv.Float32s(v.Val())
|
||||
}
|
||||
|
||||
// Float64s converts and returns `v` as []float64.
|
||||
func (v *Var) Float64s() []float64 {
|
||||
return gconv.Float64s(v.Val())
|
||||
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())
|
||||
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())
|
||||
return gconv.Interfaces(v.Val())
|
||||
}
|
||||
|
||||
// Slice is alias of Interfaces.
|
||||
func (v *Var) Slice() []interface{} {
|
||||
return v.Interfaces()
|
||||
return v.Interfaces()
|
||||
}
|
||||
|
||||
// Array is alias of Interfaces.
|
||||
func (v *Var) Array() []interface{} {
|
||||
return v.Interfaces()
|
||||
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
|
||||
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
|
||||
}
|
||||
|
||||
@ -7,17 +7,17 @@
|
||||
package fieldvar
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"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...)
|
||||
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...)
|
||||
return gconv.Structs(v.Val(), pointer, mapping...)
|
||||
}
|
||||
|
||||
@ -7,28 +7,28 @@
|
||||
package fieldvar
|
||||
|
||||
import (
|
||||
"time"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"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...)
|
||||
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())
|
||||
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...)
|
||||
return gconv.GTime(v.Val(), format...)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user