mirror of
https://github.com/astaxie/beego.git
synced 2024-11-25 12:20:55 +00:00
150 lines
3.5 KiB
Go
150 lines
3.5 KiB
Go
package param
|
|
|
|
import (
|
|
"encoding/json"
|
|
"reflect"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
type paramParser interface {
|
|
parse(value string, toType reflect.Type) (interface{}, error)
|
|
}
|
|
|
|
func getParser(param *MethodParam, t reflect.Type) paramParser {
|
|
switch t.Kind() {
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
|
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
|
return intParser{}
|
|
case reflect.Slice:
|
|
if t.Elem().Kind() == reflect.Uint8 { //treat []byte as string
|
|
return stringParser{}
|
|
}
|
|
if param.in == body {
|
|
return jsonParser{}
|
|
}
|
|
elemParser := getParser(param, t.Elem())
|
|
if elemParser == (jsonParser{}) {
|
|
return elemParser
|
|
}
|
|
return sliceParser(elemParser)
|
|
case reflect.Bool:
|
|
return boolParser{}
|
|
case reflect.String:
|
|
return stringParser{}
|
|
case reflect.Float32, reflect.Float64:
|
|
return floatParser{}
|
|
case reflect.Ptr:
|
|
elemParser := getParser(param, t.Elem())
|
|
if elemParser == (jsonParser{}) {
|
|
return elemParser
|
|
}
|
|
return ptrParser(elemParser)
|
|
default:
|
|
if t.PkgPath() == "time" && t.Name() == "Time" {
|
|
return timeParser{}
|
|
}
|
|
return jsonParser{}
|
|
}
|
|
}
|
|
|
|
type parserFunc func(value string, toType reflect.Type) (interface{}, error)
|
|
|
|
func (f parserFunc) parse(value string, toType reflect.Type) (interface{}, error) {
|
|
return f(value, toType)
|
|
}
|
|
|
|
type boolParser struct {
|
|
}
|
|
|
|
func (p boolParser) parse(value string, toType reflect.Type) (interface{}, error) {
|
|
return strconv.ParseBool(value)
|
|
}
|
|
|
|
type stringParser struct {
|
|
}
|
|
|
|
func (p stringParser) parse(value string, toType reflect.Type) (interface{}, error) {
|
|
return value, nil
|
|
}
|
|
|
|
type intParser struct {
|
|
}
|
|
|
|
func (p intParser) parse(value string, toType reflect.Type) (interface{}, error) {
|
|
return strconv.Atoi(value)
|
|
}
|
|
|
|
type floatParser struct {
|
|
}
|
|
|
|
func (p floatParser) parse(value string, toType reflect.Type) (interface{}, error) {
|
|
if toType.Kind() == reflect.Float32 {
|
|
res, err := strconv.ParseFloat(value, 32)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return float32(res), nil
|
|
}
|
|
return strconv.ParseFloat(value, 64)
|
|
}
|
|
|
|
type timeParser struct {
|
|
}
|
|
|
|
func (p timeParser) parse(value string, toType reflect.Type) (result interface{}, err error) {
|
|
result, err = time.Parse(time.RFC3339, value)
|
|
if err != nil {
|
|
result, err = time.Parse("2006-01-02", value)
|
|
}
|
|
return
|
|
}
|
|
|
|
type jsonParser struct {
|
|
}
|
|
|
|
func (p jsonParser) parse(value string, toType reflect.Type) (interface{}, error) {
|
|
pResult := reflect.New(toType)
|
|
v := pResult.Interface()
|
|
err := json.Unmarshal([]byte(value), v)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return pResult.Elem().Interface(), nil
|
|
}
|
|
|
|
func sliceParser(elemParser paramParser) paramParser {
|
|
return parserFunc(func(value string, toType reflect.Type) (interface{}, error) {
|
|
values := strings.Split(value, ",")
|
|
result := reflect.MakeSlice(toType, 0, len(values))
|
|
elemType := toType.Elem()
|
|
for _, v := range values {
|
|
parsedValue, err := elemParser.parse(v, elemType)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
result = reflect.Append(result, reflect.ValueOf(parsedValue))
|
|
}
|
|
return result.Interface(), nil
|
|
})
|
|
}
|
|
|
|
func ptrParser(elemParser paramParser) paramParser {
|
|
return parserFunc(func(value string, toType reflect.Type) (interface{}, error) {
|
|
parsedValue, err := elemParser.parse(value, toType.Elem())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
newValPtr := reflect.New(toType.Elem())
|
|
newVal := reflect.Indirect(newValPtr)
|
|
convertedVal, err := safeConvert(reflect.ValueOf(parsedValue), toType.Elem())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
newVal.Set(convertedVal)
|
|
return newValPtr.Interface(), nil
|
|
})
|
|
}
|