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
 | |
| 	})
 | |
| }
 |