2022-05-28 05:42:28 +03:00
|
|
|
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
|
2015-03-31 18:51:10 +03:00
|
|
|
// Use of this source code is governed by a MIT style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
package binding
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
2019-03-14 08:34:56 +03:00
|
|
|
"fmt"
|
2024-02-05 05:46:35 +03:00
|
|
|
"mime/multipart"
|
2015-03-31 18:51:10 +03:00
|
|
|
"reflect"
|
|
|
|
"strconv"
|
2018-04-25 11:24:03 +03:00
|
|
|
"strings"
|
2017-02-17 16:32:36 +03:00
|
|
|
"time"
|
2019-03-05 01:46:18 +03:00
|
|
|
|
2020-01-17 19:32:50 +03:00
|
|
|
"github.com/gin-gonic/gin/internal/bytesconv"
|
2019-03-05 01:46:18 +03:00
|
|
|
"github.com/gin-gonic/gin/internal/json"
|
2015-03-31 18:51:10 +03:00
|
|
|
)
|
|
|
|
|
2021-06-02 02:35:30 +03:00
|
|
|
var (
|
|
|
|
errUnknownType = errors.New("unknown type")
|
|
|
|
|
2022-10-16 04:41:14 +03:00
|
|
|
// ErrConvertMapStringSlice can not convert to map[string][]string
|
2021-06-02 02:35:30 +03:00
|
|
|
ErrConvertMapStringSlice = errors.New("can not convert to map slices of strings")
|
|
|
|
|
|
|
|
// ErrConvertToMapString can not convert to map[string]string
|
|
|
|
ErrConvertToMapString = errors.New("can not convert to map of strings")
|
|
|
|
)
|
2019-03-03 09:39:43 +03:00
|
|
|
|
2022-03-21 04:43:17 +03:00
|
|
|
func mapURI(ptr any, m map[string][]string) error {
|
2018-11-22 04:29:48 +03:00
|
|
|
return mapFormByTag(ptr, m, "uri")
|
|
|
|
}
|
|
|
|
|
2022-03-21 04:43:17 +03:00
|
|
|
func mapForm(ptr any, form map[string][]string) error {
|
2018-11-22 04:29:48 +03:00
|
|
|
return mapFormByTag(ptr, form, "form")
|
|
|
|
}
|
|
|
|
|
2022-03-21 04:43:17 +03:00
|
|
|
func MapFormWithTag(ptr any, form map[string][]string, tag string) error {
|
2021-06-29 19:53:56 +03:00
|
|
|
return mapFormByTag(ptr, form, tag)
|
|
|
|
}
|
|
|
|
|
2019-03-03 09:39:43 +03:00
|
|
|
var emptyField = reflect.StructField{}
|
|
|
|
|
2022-03-21 04:43:17 +03:00
|
|
|
func mapFormByTag(ptr any, form map[string][]string, tag string) error {
|
2020-10-31 02:20:47 +03:00
|
|
|
// Check if ptr is a map
|
|
|
|
ptrVal := reflect.ValueOf(ptr)
|
2022-03-21 04:43:17 +03:00
|
|
|
var pointed any
|
2020-10-31 02:20:47 +03:00
|
|
|
if ptrVal.Kind() == reflect.Ptr {
|
|
|
|
ptrVal = ptrVal.Elem()
|
|
|
|
pointed = ptrVal.Interface()
|
|
|
|
}
|
|
|
|
if ptrVal.Kind() == reflect.Map &&
|
|
|
|
ptrVal.Type().Key().Kind() == reflect.String {
|
|
|
|
if pointed != nil {
|
|
|
|
ptr = pointed
|
|
|
|
}
|
|
|
|
return setFormMap(ptr, form)
|
|
|
|
}
|
|
|
|
|
2019-04-02 04:01:34 +03:00
|
|
|
return mappingByPtr(ptr, formSource(form), tag)
|
|
|
|
}
|
|
|
|
|
|
|
|
// setter tries to set value on a walking by fields of a struct
|
|
|
|
type setter interface {
|
2021-09-30 05:04:28 +03:00
|
|
|
TrySet(value reflect.Value, field reflect.StructField, key string, opt setOptions) (isSet bool, err error)
|
2019-04-02 04:01:34 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
type formSource map[string][]string
|
|
|
|
|
|
|
|
var _ setter = formSource(nil)
|
|
|
|
|
|
|
|
// TrySet tries to set a value by request's form source (like map[string][]string)
|
2021-09-30 05:04:28 +03:00
|
|
|
func (form formSource) TrySet(value reflect.Value, field reflect.StructField, tagValue string, opt setOptions) (isSet bool, err error) {
|
2019-04-02 04:01:34 +03:00
|
|
|
return setByForm(value, field, form, tagValue, opt)
|
|
|
|
}
|
|
|
|
|
2022-03-21 04:43:17 +03:00
|
|
|
func mappingByPtr(ptr any, setter setter, tag string) error {
|
2019-04-02 04:01:34 +03:00
|
|
|
_, err := mapping(reflect.ValueOf(ptr), emptyField, setter, tag)
|
2019-03-03 09:39:43 +03:00
|
|
|
return err
|
|
|
|
}
|
2015-03-31 18:51:10 +03:00
|
|
|
|
2019-04-02 04:01:34 +03:00
|
|
|
func mapping(value reflect.Value, field reflect.StructField, setter setter, tag string) (bool, error) {
|
2019-11-01 05:47:40 +03:00
|
|
|
if field.Tag.Get(tag) == "-" { // just ignoring this field
|
|
|
|
return false, nil
|
|
|
|
}
|
|
|
|
|
2021-08-19 10:46:31 +03:00
|
|
|
vKind := value.Kind()
|
2019-03-03 09:39:43 +03:00
|
|
|
|
|
|
|
if vKind == reflect.Ptr {
|
|
|
|
var isNew bool
|
|
|
|
vPtr := value
|
|
|
|
if value.IsNil() {
|
|
|
|
isNew = true
|
|
|
|
vPtr = reflect.New(value.Type().Elem())
|
2018-04-25 11:24:03 +03:00
|
|
|
}
|
2021-09-30 05:04:28 +03:00
|
|
|
isSet, err := mapping(vPtr.Elem(), field, setter, tag)
|
2019-03-03 09:39:43 +03:00
|
|
|
if err != nil {
|
|
|
|
return false, err
|
2019-02-22 07:23:52 +03:00
|
|
|
}
|
2021-09-30 05:04:28 +03:00
|
|
|
if isNew && isSet {
|
2019-03-03 09:39:43 +03:00
|
|
|
value.Set(vPtr)
|
2015-03-31 18:51:10 +03:00
|
|
|
}
|
2021-09-30 05:04:28 +03:00
|
|
|
return isSet, nil
|
2019-03-03 09:39:43 +03:00
|
|
|
}
|
2018-04-25 11:24:03 +03:00
|
|
|
|
2019-05-13 05:17:31 +03:00
|
|
|
if vKind != reflect.Struct || !field.Anonymous {
|
|
|
|
ok, err := tryToSetValue(value, field, setter, tag)
|
|
|
|
if err != nil {
|
|
|
|
return false, err
|
|
|
|
}
|
|
|
|
if ok {
|
|
|
|
return true, nil
|
|
|
|
}
|
2019-03-03 09:39:43 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if vKind == reflect.Struct {
|
|
|
|
tValue := value.Type()
|
|
|
|
|
2021-09-30 05:04:28 +03:00
|
|
|
var isSet bool
|
2019-03-03 09:39:43 +03:00
|
|
|
for i := 0; i < value.NumField(); i++ {
|
2019-05-13 05:17:31 +03:00
|
|
|
sf := tValue.Field(i)
|
|
|
|
if sf.PkgPath != "" && !sf.Anonymous { // unexported
|
2018-04-25 11:24:03 +03:00
|
|
|
continue
|
|
|
|
}
|
2021-06-02 02:35:30 +03:00
|
|
|
ok, err := mapping(value.Field(i), sf, setter, tag)
|
2019-03-03 09:39:43 +03:00
|
|
|
if err != nil {
|
|
|
|
return false, err
|
|
|
|
}
|
2021-09-30 05:04:28 +03:00
|
|
|
isSet = isSet || ok
|
2015-03-31 18:51:10 +03:00
|
|
|
}
|
2021-09-30 05:04:28 +03:00
|
|
|
return isSet, nil
|
2019-03-03 09:39:43 +03:00
|
|
|
}
|
|
|
|
return false, nil
|
|
|
|
}
|
2015-03-31 18:51:10 +03:00
|
|
|
|
2019-04-02 04:01:34 +03:00
|
|
|
type setOptions struct {
|
|
|
|
isDefaultExists bool
|
|
|
|
defaultValue string
|
|
|
|
}
|
|
|
|
|
|
|
|
func tryToSetValue(value reflect.Value, field reflect.StructField, setter setter, tag string) (bool, error) {
|
|
|
|
var tagValue string
|
|
|
|
var setOpt setOptions
|
2019-03-03 09:39:43 +03:00
|
|
|
|
|
|
|
tagValue = field.Tag.Get(tag)
|
|
|
|
tagValue, opts := head(tagValue, ",")
|
|
|
|
|
|
|
|
if tagValue == "" { // default value is FieldName
|
|
|
|
tagValue = field.Name
|
|
|
|
}
|
|
|
|
if tagValue == "" { // when field is "emptyField" variable
|
|
|
|
return false, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
var opt string
|
|
|
|
for len(opts) > 0 {
|
|
|
|
opt, opts = head(opts, ",")
|
|
|
|
|
2019-05-21 18:08:52 +03:00
|
|
|
if k, v := head(opt, "="); k == "default" {
|
2019-04-02 04:01:34 +03:00
|
|
|
setOpt.isDefaultExists = true
|
|
|
|
setOpt.defaultValue = v
|
2018-08-20 16:49:24 +03:00
|
|
|
}
|
2019-03-03 09:39:43 +03:00
|
|
|
}
|
|
|
|
|
2019-04-02 04:01:34 +03:00
|
|
|
return setter.TrySet(value, field, tagValue, setOpt)
|
|
|
|
}
|
|
|
|
|
2024-05-07 04:43:15 +03:00
|
|
|
// BindUnmarshaler is the interface used to wrap the UnmarshalParam method.
|
|
|
|
type BindUnmarshaler interface {
|
|
|
|
// UnmarshalParam decodes and assigns a value from an form or query param.
|
|
|
|
UnmarshalParam(param string) error
|
|
|
|
}
|
|
|
|
|
|
|
|
// trySetCustom tries to set a custom type value
|
|
|
|
// If the value implements the BindUnmarshaler interface, it will be used to set the value, we will return `true`
|
|
|
|
// to skip the default value setting.
|
|
|
|
func trySetCustom(val string, value reflect.Value) (isSet bool, err error) {
|
|
|
|
switch v := value.Addr().Interface().(type) {
|
|
|
|
case BindUnmarshaler:
|
|
|
|
return true, v.UnmarshalParam(val)
|
|
|
|
}
|
|
|
|
return false, nil
|
|
|
|
}
|
|
|
|
|
2021-09-30 05:04:28 +03:00
|
|
|
func setByForm(value reflect.Value, field reflect.StructField, form map[string][]string, tagValue string, opt setOptions) (isSet bool, err error) {
|
2019-03-03 09:39:43 +03:00
|
|
|
vs, ok := form[tagValue]
|
2019-04-02 04:01:34 +03:00
|
|
|
if !ok && !opt.isDefaultExists {
|
2019-03-03 09:39:43 +03:00
|
|
|
return false, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
switch value.Kind() {
|
|
|
|
case reflect.Slice:
|
|
|
|
if !ok {
|
2019-04-02 04:01:34 +03:00
|
|
|
vs = []string{opt.defaultValue}
|
2018-08-20 16:49:24 +03:00
|
|
|
}
|
2024-05-23 05:16:11 +03:00
|
|
|
|
|
|
|
if ok, err = trySetCustom(vs[0], value); ok {
|
|
|
|
return ok, err
|
|
|
|
}
|
|
|
|
|
2019-03-03 09:39:43 +03:00
|
|
|
return true, setSlice(vs, value, field)
|
2019-03-14 08:34:56 +03:00
|
|
|
case reflect.Array:
|
|
|
|
if !ok {
|
2019-04-02 04:01:34 +03:00
|
|
|
vs = []string{opt.defaultValue}
|
2019-03-14 08:34:56 +03:00
|
|
|
}
|
2024-05-23 05:16:11 +03:00
|
|
|
|
|
|
|
if ok, err = trySetCustom(vs[0], value); ok {
|
|
|
|
return ok, err
|
|
|
|
}
|
|
|
|
|
2019-03-14 08:34:56 +03:00
|
|
|
if len(vs) != value.Len() {
|
|
|
|
return false, fmt.Errorf("%q is not valid value for %s", vs, value.Type().String())
|
|
|
|
}
|
2024-05-23 05:16:11 +03:00
|
|
|
|
2019-03-14 08:34:56 +03:00
|
|
|
return true, setArray(vs, value, field)
|
2019-03-03 09:39:43 +03:00
|
|
|
default:
|
|
|
|
var val string
|
|
|
|
if !ok {
|
2019-04-02 04:01:34 +03:00
|
|
|
val = opt.defaultValue
|
2019-03-03 09:39:43 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if len(vs) > 0 {
|
|
|
|
val = vs[0]
|
2015-03-31 18:51:10 +03:00
|
|
|
}
|
2024-05-07 04:43:15 +03:00
|
|
|
if ok, err := trySetCustom(val, value); ok {
|
|
|
|
return ok, err
|
|
|
|
}
|
2019-03-03 09:39:43 +03:00
|
|
|
return true, setWithProperType(val, value, field)
|
2015-03-31 18:51:10 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-03 09:39:43 +03:00
|
|
|
func setWithProperType(val string, value reflect.Value, field reflect.StructField) error {
|
|
|
|
switch value.Kind() {
|
2015-03-31 18:51:10 +03:00
|
|
|
case reflect.Int:
|
2019-03-03 09:39:43 +03:00
|
|
|
return setIntField(val, 0, value)
|
2015-03-31 18:51:10 +03:00
|
|
|
case reflect.Int8:
|
2019-03-03 09:39:43 +03:00
|
|
|
return setIntField(val, 8, value)
|
2015-03-31 18:51:10 +03:00
|
|
|
case reflect.Int16:
|
2019-03-03 09:39:43 +03:00
|
|
|
return setIntField(val, 16, value)
|
2015-03-31 18:51:10 +03:00
|
|
|
case reflect.Int32:
|
2019-03-03 09:39:43 +03:00
|
|
|
return setIntField(val, 32, value)
|
2015-03-31 18:51:10 +03:00
|
|
|
case reflect.Int64:
|
2019-03-04 06:37:46 +03:00
|
|
|
switch value.Interface().(type) {
|
|
|
|
case time.Duration:
|
2021-08-21 09:59:17 +03:00
|
|
|
return setTimeDuration(val, value)
|
2019-03-04 06:37:46 +03:00
|
|
|
}
|
2019-03-03 09:39:43 +03:00
|
|
|
return setIntField(val, 64, value)
|
2015-03-31 18:51:10 +03:00
|
|
|
case reflect.Uint:
|
2019-03-03 09:39:43 +03:00
|
|
|
return setUintField(val, 0, value)
|
2015-03-31 18:51:10 +03:00
|
|
|
case reflect.Uint8:
|
2019-03-03 09:39:43 +03:00
|
|
|
return setUintField(val, 8, value)
|
2015-03-31 18:51:10 +03:00
|
|
|
case reflect.Uint16:
|
2019-03-03 09:39:43 +03:00
|
|
|
return setUintField(val, 16, value)
|
2015-03-31 18:51:10 +03:00
|
|
|
case reflect.Uint32:
|
2019-03-03 09:39:43 +03:00
|
|
|
return setUintField(val, 32, value)
|
2015-03-31 18:51:10 +03:00
|
|
|
case reflect.Uint64:
|
2019-03-03 09:39:43 +03:00
|
|
|
return setUintField(val, 64, value)
|
2015-03-31 18:51:10 +03:00
|
|
|
case reflect.Bool:
|
2019-03-03 09:39:43 +03:00
|
|
|
return setBoolField(val, value)
|
2015-03-31 18:51:10 +03:00
|
|
|
case reflect.Float32:
|
2019-03-03 09:39:43 +03:00
|
|
|
return setFloatField(val, 32, value)
|
2015-03-31 18:51:10 +03:00
|
|
|
case reflect.Float64:
|
2019-03-03 09:39:43 +03:00
|
|
|
return setFloatField(val, 64, value)
|
2015-03-31 18:51:10 +03:00
|
|
|
case reflect.String:
|
2019-03-03 09:39:43 +03:00
|
|
|
value.SetString(val)
|
|
|
|
case reflect.Struct:
|
|
|
|
switch value.Interface().(type) {
|
|
|
|
case time.Time:
|
|
|
|
return setTimeField(val, field, value)
|
2024-02-05 05:46:35 +03:00
|
|
|
case multipart.FileHeader:
|
|
|
|
return nil
|
2018-04-26 17:09:34 +03:00
|
|
|
}
|
2020-01-17 19:32:50 +03:00
|
|
|
return json.Unmarshal(bytesconv.StringToBytes(val), value.Addr().Interface())
|
2019-03-03 09:39:43 +03:00
|
|
|
case reflect.Map:
|
2020-01-17 19:32:50 +03:00
|
|
|
return json.Unmarshal(bytesconv.StringToBytes(val), value.Addr().Interface())
|
2023-11-16 18:46:43 +03:00
|
|
|
case reflect.Ptr:
|
|
|
|
if !value.Elem().IsValid() {
|
|
|
|
value.Set(reflect.New(value.Type().Elem()))
|
|
|
|
}
|
|
|
|
return setWithProperType(val, value.Elem(), field)
|
2015-03-31 18:51:10 +03:00
|
|
|
default:
|
2019-03-03 09:39:43 +03:00
|
|
|
return errUnknownType
|
2015-03-31 18:51:10 +03:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func setIntField(val string, bitSize int, field reflect.Value) error {
|
|
|
|
if val == "" {
|
|
|
|
val = "0"
|
|
|
|
}
|
|
|
|
intVal, err := strconv.ParseInt(val, 10, bitSize)
|
|
|
|
if err == nil {
|
|
|
|
field.SetInt(intVal)
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
func setUintField(val string, bitSize int, field reflect.Value) error {
|
|
|
|
if val == "" {
|
|
|
|
val = "0"
|
|
|
|
}
|
|
|
|
uintVal, err := strconv.ParseUint(val, 10, bitSize)
|
|
|
|
if err == nil {
|
|
|
|
field.SetUint(uintVal)
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
func setBoolField(val string, field reflect.Value) error {
|
|
|
|
if val == "" {
|
|
|
|
val = "false"
|
|
|
|
}
|
|
|
|
boolVal, err := strconv.ParseBool(val)
|
|
|
|
if err == nil {
|
|
|
|
field.SetBool(boolVal)
|
|
|
|
}
|
2018-05-11 17:40:33 +03:00
|
|
|
return err
|
2015-03-31 18:51:10 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func setFloatField(val string, bitSize int, field reflect.Value) error {
|
|
|
|
if val == "" {
|
|
|
|
val = "0.0"
|
|
|
|
}
|
|
|
|
floatVal, err := strconv.ParseFloat(val, bitSize)
|
|
|
|
if err == nil {
|
|
|
|
field.SetFloat(floatVal)
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2017-02-17 16:32:36 +03:00
|
|
|
func setTimeField(val string, structField reflect.StructField, value reflect.Value) error {
|
|
|
|
timeFormat := structField.Tag.Get("time_format")
|
|
|
|
if timeFormat == "" {
|
2018-08-17 04:41:56 +03:00
|
|
|
timeFormat = time.RFC3339
|
2017-02-17 16:32:36 +03:00
|
|
|
}
|
2017-06-13 05:50:42 +03:00
|
|
|
|
binding: support unix time (#1980)
* binding: support unix time
ref:#1979
* binding: support unix time
add test file
modify readme
```golang
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"time"
)
type shareTime struct {
CreateTime time.Time `form:"createTime" time_format:"unixNano"`
UnixTime time.Time `form:"unixTime" time_format:"unix"`
}
func main() {
r := gin.Default()
unix := r.Group("/unix")
testCT := time.Date(2019, 7, 6, 16, 0, 33, 123, time.Local)
fmt.Printf("%d\n", testCT.UnixNano())
testUT := time.Date(2019, 7, 6, 16, 0, 33, 0, time.Local)
fmt.Printf("%d\n", testUT.Unix())
unix.GET("/nano", func(c *gin.Context) {
s := shareTime{}
c.ShouldBindQuery(&s)
if !testCT.Equal(s.CreateTime) {
c.String(500, "want %d got %d", testCT.UnixNano(), s.CreateTime)
return
}
c.JSON(200, s)
})
unix.GET("/sec", func(c *gin.Context) {
s := shareTime{}
c.ShouldBindQuery(&s)
if !testUT.Equal(s.UnixTime) {
c.String(500, "want %d got %d", testCT.Unix(), s.UnixTime)
return
}
c.JSON(200, s)
})
r.Run()
}
```
* Contraction variable scope
2019-07-10 08:02:40 +03:00
|
|
|
switch tf := strings.ToLower(timeFormat); tf {
|
|
|
|
case "unix", "unixnano":
|
2020-08-08 12:31:08 +03:00
|
|
|
tv, err := strconv.ParseInt(val, 10, 64)
|
binding: support unix time (#1980)
* binding: support unix time
ref:#1979
* binding: support unix time
add test file
modify readme
```golang
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"time"
)
type shareTime struct {
CreateTime time.Time `form:"createTime" time_format:"unixNano"`
UnixTime time.Time `form:"unixTime" time_format:"unix"`
}
func main() {
r := gin.Default()
unix := r.Group("/unix")
testCT := time.Date(2019, 7, 6, 16, 0, 33, 123, time.Local)
fmt.Printf("%d\n", testCT.UnixNano())
testUT := time.Date(2019, 7, 6, 16, 0, 33, 0, time.Local)
fmt.Printf("%d\n", testUT.Unix())
unix.GET("/nano", func(c *gin.Context) {
s := shareTime{}
c.ShouldBindQuery(&s)
if !testCT.Equal(s.CreateTime) {
c.String(500, "want %d got %d", testCT.UnixNano(), s.CreateTime)
return
}
c.JSON(200, s)
})
unix.GET("/sec", func(c *gin.Context) {
s := shareTime{}
c.ShouldBindQuery(&s)
if !testUT.Equal(s.UnixTime) {
c.String(500, "want %d got %d", testCT.Unix(), s.UnixTime)
return
}
c.JSON(200, s)
})
r.Run()
}
```
* Contraction variable scope
2019-07-10 08:02:40 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
d := time.Duration(1)
|
|
|
|
if tf == "unixnano" {
|
|
|
|
d = time.Second
|
|
|
|
}
|
|
|
|
|
|
|
|
t := time.Unix(tv/int64(d), tv%int64(d))
|
|
|
|
value.Set(reflect.ValueOf(t))
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-05-04 04:22:00 +03:00
|
|
|
if val == "" {
|
|
|
|
value.Set(reflect.ValueOf(time.Time{}))
|
|
|
|
return nil
|
|
|
|
}
|
2017-02-17 16:32:36 +03:00
|
|
|
|
|
|
|
l := time.Local
|
|
|
|
if isUTC, _ := strconv.ParseBool(structField.Tag.Get("time_utc")); isUTC {
|
|
|
|
l = time.UTC
|
|
|
|
}
|
|
|
|
|
2017-09-28 17:23:18 +03:00
|
|
|
if locTag := structField.Tag.Get("time_location"); locTag != "" {
|
|
|
|
loc, err := time.LoadLocation(locTag)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
l = loc
|
|
|
|
}
|
|
|
|
|
2017-02-17 16:32:36 +03:00
|
|
|
t, err := time.ParseInLocation(timeFormat, val, l)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
value.Set(reflect.ValueOf(t))
|
|
|
|
return nil
|
|
|
|
}
|
2019-03-03 09:39:43 +03:00
|
|
|
|
2019-03-14 08:34:56 +03:00
|
|
|
func setArray(vals []string, value reflect.Value, field reflect.StructField) error {
|
2019-03-03 09:39:43 +03:00
|
|
|
for i, s := range vals {
|
2019-03-14 08:34:56 +03:00
|
|
|
err := setWithProperType(s, value.Index(i), field)
|
2019-03-03 09:39:43 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
2019-03-14 08:34:56 +03:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func setSlice(vals []string, value reflect.Value, field reflect.StructField) error {
|
|
|
|
slice := reflect.MakeSlice(value.Type(), len(vals), len(vals))
|
|
|
|
err := setArray(vals, slice, field)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-03-03 09:39:43 +03:00
|
|
|
value.Set(slice)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-08-21 09:59:17 +03:00
|
|
|
func setTimeDuration(val string, value reflect.Value) error {
|
2019-03-04 06:37:46 +03:00
|
|
|
d, err := time.ParseDuration(val)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
value.Set(reflect.ValueOf(d))
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-03-03 09:39:43 +03:00
|
|
|
func head(str, sep string) (head string, tail string) {
|
2024-05-08 01:28:15 +03:00
|
|
|
head, tail, _ = strings.Cut(str, sep)
|
|
|
|
return head, tail
|
2019-03-03 09:39:43 +03:00
|
|
|
}
|
2020-10-31 02:20:47 +03:00
|
|
|
|
2022-03-21 04:43:17 +03:00
|
|
|
func setFormMap(ptr any, form map[string][]string) error {
|
2020-10-31 02:20:47 +03:00
|
|
|
el := reflect.TypeOf(ptr).Elem()
|
|
|
|
|
|
|
|
if el.Kind() == reflect.Slice {
|
|
|
|
ptrMap, ok := ptr.(map[string][]string)
|
|
|
|
if !ok {
|
2021-06-02 02:35:30 +03:00
|
|
|
return ErrConvertMapStringSlice
|
2020-10-31 02:20:47 +03:00
|
|
|
}
|
|
|
|
for k, v := range form {
|
|
|
|
ptrMap[k] = v
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
ptrMap, ok := ptr.(map[string]string)
|
|
|
|
if !ok {
|
2021-06-02 02:35:30 +03:00
|
|
|
return ErrConvertToMapString
|
2020-10-31 02:20:47 +03:00
|
|
|
}
|
|
|
|
for k, v := range form {
|
|
|
|
ptrMap[k] = v[len(v)-1] // pick last
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|