github.com/wfusion/gofusion@v1.1.14/http/parser/form_mapping.go (about)

     1  // Fork from github.com/gin-gonic/gin@v1.7.7/binding/form_mapping.go
     2  
     3  // Copyright 2014 Manu Martinez-Almeida.  All rights reserved.
     4  // Use of this source code is governed by a MIT style
     5  // license that can be found in the LICENSE file.
     6  
     7  package parser
     8  
     9  import (
    10  	"errors"
    11  	"fmt"
    12  	"reflect"
    13  	"strconv"
    14  	"strings"
    15  	"time"
    16  
    17  	"github.com/wfusion/gofusion/common/utils"
    18  	"github.com/wfusion/gofusion/common/utils/serialize/json"
    19  )
    20  
    21  var errUnknownType = errors.New("unknown type")
    22  
    23  var (
    24  	emptyField                  = reflect.StructField{}
    25  	mapStringInterfaceSliceType = reflect.TypeOf(([]map[string]any)(nil))
    26  )
    27  
    28  func MapFormByTag(ptr any, form map[string][]string, tag string) error {
    29  	// Check if ptr is a map
    30  	ptrVal := reflect.ValueOf(ptr)
    31  	var pointed any
    32  	if ptrVal.Kind() == reflect.Ptr {
    33  		ptrVal = ptrVal.Elem()
    34  		pointed = ptr
    35  	}
    36  	if ptrVal.Type() == mapStringInterfaceSliceType ||
    37  		(ptrVal.Kind() == reflect.Map && ptrVal.Type().Key().Kind() == reflect.String) {
    38  		if pointed != nil {
    39  			ptr = pointed
    40  		}
    41  		return setFormMap(ptr, form)
    42  	}
    43  
    44  	return mappingByPtr(ptr, formSource(form), tag)
    45  }
    46  
    47  // setter tries to set value on a walking by fields of a struct
    48  type setter interface {
    49  	TrySet(value reflect.Value, field reflect.StructField, key string, opt setOptions) (isSetted bool, err error)
    50  }
    51  
    52  type formSource map[string][]string
    53  
    54  var _ setter = formSource(nil)
    55  
    56  // TrySet tries to set a value by request's form source (like map[string][]string)
    57  func (form formSource) TrySet(value reflect.Value, field reflect.StructField,
    58  	tagValue string, opt setOptions) (isSetted bool, err error) {
    59  	return setByForm(value, field, form, tagValue, opt)
    60  }
    61  
    62  func mappingByPtr(ptr any, setter setter, tag string) error {
    63  	_, err := mapping(reflect.ValueOf(ptr), emptyField, setter, tag)
    64  	return err
    65  }
    66  
    67  func mapping(value reflect.Value, field reflect.StructField, setter setter, tag string) (bool, error) {
    68  	if field.Tag.Get(tag) == "-" { // just ignoring this field
    69  		return false, nil
    70  	}
    71  
    72  	var vKind = value.Kind()
    73  
    74  	if vKind == reflect.Ptr {
    75  		var isNew bool
    76  		vPtr := value
    77  		if value.IsNil() {
    78  			isNew = true
    79  			vPtr = reflect.New(value.Type().Elem())
    80  		}
    81  		isSetted, err := mapping(vPtr.Elem(), field, setter, tag)
    82  		if err != nil {
    83  			return false, err
    84  		}
    85  		if isNew && isSetted {
    86  			value.Set(vPtr)
    87  		}
    88  		return isSetted, nil
    89  	}
    90  
    91  	if vKind != reflect.Struct || !field.Anonymous {
    92  		ok, err := tryToSetValue(value, field, setter, tag)
    93  		if err != nil {
    94  			return false, err
    95  		}
    96  		if ok {
    97  			return true, nil
    98  		}
    99  	}
   100  
   101  	if vKind == reflect.Struct {
   102  		tValue := value.Type()
   103  
   104  		var isSetted bool
   105  		for i := 0; i < value.NumField(); i++ {
   106  			sf := tValue.Field(i)
   107  			if sf.PkgPath != "" && !sf.Anonymous { // unexported
   108  				continue
   109  			}
   110  			ok, err := mapping(value.Field(i), tValue.Field(i), setter, tag)
   111  			if err != nil {
   112  				return false, err
   113  			}
   114  			isSetted = isSetted || ok
   115  		}
   116  		return isSetted, nil
   117  	}
   118  	return false, nil
   119  }
   120  
   121  type setOptions struct {
   122  	isDefaultExists bool
   123  	defaultValue    string
   124  }
   125  
   126  func tryToSetValue(value reflect.Value, field reflect.StructField, setter setter, tag string) (bool, error) {
   127  	var tagValue string
   128  	var setOpt setOptions
   129  
   130  	tagValue = field.Tag.Get(tag)
   131  	tagValue, opts := head(tagValue, ",")
   132  
   133  	if tagValue == "" { // default value is FieldName
   134  		tagValue = field.Name
   135  	}
   136  	if tagValue == "" { // when field is "emptyField" variable
   137  		return false, nil
   138  	}
   139  
   140  	var opt string
   141  	for len(opts) > 0 {
   142  		opt, opts = head(opts, ",")
   143  
   144  		if k, v := head(opt, "="); k == "default" {
   145  			setOpt.isDefaultExists = true
   146  			setOpt.defaultValue = v
   147  		}
   148  	}
   149  
   150  	return setter.TrySet(value, field, tagValue, setOpt)
   151  }
   152  
   153  func setByForm(value reflect.Value, field reflect.StructField, form map[string][]string,
   154  	tagValue string, opt setOptions) (isSetted bool, err error) {
   155  	vs, ok := form[tagValue]
   156  	if !ok && !opt.isDefaultExists {
   157  		return false, nil
   158  	}
   159  
   160  	switch value.Kind() {
   161  	case reflect.Slice:
   162  		if !ok {
   163  			vs = []string{opt.defaultValue}
   164  		}
   165  		return true, setSlice(vs, value, field)
   166  	case reflect.Array:
   167  		if !ok {
   168  			vs = []string{opt.defaultValue}
   169  		}
   170  		if len(vs) != value.Len() {
   171  			return false, fmt.Errorf("%q is not valid value for %s", vs, value.Type().String())
   172  		}
   173  		return true, setArray(vs, value, field)
   174  	default:
   175  		var val string
   176  		if !ok {
   177  			val = opt.defaultValue
   178  		}
   179  
   180  		if len(vs) > 0 {
   181  			val = vs[0]
   182  		}
   183  		return true, setWithProperType(val, value, field)
   184  	}
   185  }
   186  
   187  func setWithProperType(val string, value reflect.Value, field reflect.StructField) error {
   188  	switch value.Kind() {
   189  	case reflect.Int:
   190  		return setIntField(val, 0, value)
   191  	case reflect.Int8:
   192  		return setIntField(val, 8, value)
   193  	case reflect.Int16:
   194  		return setIntField(val, 16, value)
   195  	case reflect.Int32:
   196  		return setIntField(val, 32, value)
   197  	case reflect.Int64:
   198  		switch value.Interface().(type) {
   199  		case time.Duration:
   200  			return setTimeDuration(val, value, field)
   201  		}
   202  		return setIntField(val, 64, value)
   203  	case reflect.Uint:
   204  		return setUintField(val, 0, value)
   205  	case reflect.Uint8:
   206  		return setUintField(val, 8, value)
   207  	case reflect.Uint16:
   208  		return setUintField(val, 16, value)
   209  	case reflect.Uint32:
   210  		return setUintField(val, 32, value)
   211  	case reflect.Uint64:
   212  		return setUintField(val, 64, value)
   213  	case reflect.Bool:
   214  		return setBoolField(val, value)
   215  	case reflect.Float32:
   216  		return setFloatField(val, 32, value)
   217  	case reflect.Float64:
   218  		return setFloatField(val, 64, value)
   219  	case reflect.String:
   220  		value.SetString(val)
   221  	case reflect.Struct:
   222  		switch value.Interface().(type) {
   223  		case time.Time:
   224  			return setTimeField(val, field, value)
   225  		}
   226  		return json.Unmarshal(utils.UnsafeStringToBytes(val), value.Addr().Interface())
   227  	case reflect.Map:
   228  		return json.Unmarshal(utils.UnsafeStringToBytes(val), value.Addr().Interface())
   229  	default:
   230  		return errUnknownType
   231  	}
   232  	return nil
   233  }
   234  
   235  func setIntField(val string, bitSize int, field reflect.Value) error {
   236  	if val == "" {
   237  		val = "0"
   238  	}
   239  	intVal, err := strconv.ParseInt(val, 10, bitSize)
   240  	if err == nil {
   241  		field.SetInt(intVal)
   242  	}
   243  	return err
   244  }
   245  
   246  func setUintField(val string, bitSize int, field reflect.Value) error {
   247  	if val == "" {
   248  		val = "0"
   249  	}
   250  	uintVal, err := strconv.ParseUint(val, 10, bitSize)
   251  	if err == nil {
   252  		field.SetUint(uintVal)
   253  	}
   254  	return err
   255  }
   256  
   257  func setBoolField(val string, field reflect.Value) error {
   258  	if val == "" {
   259  		val = "false"
   260  	}
   261  	boolVal, err := strconv.ParseBool(val)
   262  	if err == nil {
   263  		field.SetBool(boolVal)
   264  	}
   265  	return err
   266  }
   267  
   268  func setFloatField(val string, bitSize int, field reflect.Value) error {
   269  	if val == "" {
   270  		val = "0.0"
   271  	}
   272  	floatVal, err := strconv.ParseFloat(val, bitSize)
   273  	if err == nil {
   274  		field.SetFloat(floatVal)
   275  	}
   276  	return err
   277  }
   278  
   279  func setTimeField(val string, structField reflect.StructField, value reflect.Value) error {
   280  	timeFormat := structField.Tag.Get("time_format")
   281  	if timeFormat == "" {
   282  		timeFormat = time.RFC3339
   283  	}
   284  
   285  	switch tf := strings.ToLower(timeFormat); tf {
   286  	case "unix", "unixnano":
   287  		tv, err := strconv.ParseInt(val, 10, 64)
   288  		if err != nil {
   289  			return err
   290  		}
   291  
   292  		d := time.Duration(1)
   293  		if tf == "unixnano" {
   294  			d = time.Second
   295  		}
   296  
   297  		t := time.Unix(tv/int64(d), tv%int64(d))
   298  		value.Set(reflect.ValueOf(t))
   299  		return nil
   300  
   301  	}
   302  
   303  	if val == "" {
   304  		value.Set(reflect.ValueOf(time.Time{}))
   305  		return nil
   306  	}
   307  
   308  	l := time.Local
   309  	if isUTC, _ := strconv.ParseBool(structField.Tag.Get("time_utc")); isUTC {
   310  		l = time.UTC
   311  	}
   312  
   313  	if locTag := structField.Tag.Get("time_location"); locTag != "" {
   314  		loc, err := time.LoadLocation(locTag)
   315  		if err != nil {
   316  			return err
   317  		}
   318  		l = loc
   319  	}
   320  
   321  	t, err := time.ParseInLocation(timeFormat, val, l)
   322  	if err != nil {
   323  		return err
   324  	}
   325  
   326  	value.Set(reflect.ValueOf(t))
   327  	return nil
   328  }
   329  
   330  func setArray(vals []string, value reflect.Value, field reflect.StructField) error {
   331  	for i, s := range vals {
   332  		err := setWithProperType(s, value.Index(i), field)
   333  		if err != nil {
   334  			return err
   335  		}
   336  	}
   337  	return nil
   338  }
   339  
   340  func setSlice(vals []string, value reflect.Value, field reflect.StructField) error {
   341  	slice := reflect.MakeSlice(value.Type(), len(vals), len(vals))
   342  	err := setArray(vals, slice, field)
   343  	if err != nil {
   344  		return err
   345  	}
   346  	value.Set(slice)
   347  	return nil
   348  }
   349  
   350  func setTimeDuration(val string, value reflect.Value, field reflect.StructField) error {
   351  	d, err := time.ParseDuration(val)
   352  	if err != nil {
   353  		return err
   354  	}
   355  	value.Set(reflect.ValueOf(d))
   356  	return nil
   357  }
   358  
   359  func head(str, sep string) (head string, tail string) {
   360  	idx := strings.Index(str, sep)
   361  	if idx < 0 {
   362  		return str, ""
   363  	}
   364  	return str[:idx], str[idx+len(sep):]
   365  }
   366  
   367  func setFormMap(ptr any, form map[string][]string) error {
   368  	switch ptrMap := ptr.(type) {
   369  	case *map[string]any:
   370  		*ptrMap = make(map[string]any, len(form))
   371  		for k, v := range form {
   372  			(*ptrMap)[k] = v
   373  		}
   374  	case *[]map[string]any:
   375  		*ptrMap = make([]map[string]any, 0, 1)
   376  		tmp := make(map[string]any, len(form))
   377  		for k, v := range form {
   378  			tmp[k] = v
   379  		}
   380  		*ptrMap = append(*ptrMap, tmp)
   381  	case *map[string][]string:
   382  		*ptrMap = make(map[string][]string, len(form))
   383  		for k, v := range form {
   384  			(*ptrMap)[k] = v
   385  		}
   386  	case *map[string]string:
   387  		*ptrMap = make(map[string]string, len(form))
   388  		for k, v := range form {
   389  			(*ptrMap)[k] = v[len(v)-1] // pick last
   390  		}
   391  	default:
   392  		return errors.New("cannot convert to map slices of strings")
   393  	}
   394  
   395  	return nil
   396  }