forked from Mirrors/jsonapi
extract type handling
This commit is contained in:
parent
ebb7923313
commit
e13a19922d
297
request.go
297
request.go
|
@ -118,6 +118,7 @@ func UnmarshalManyPayload(in io.Reader, t reflect.Type) ([]interface{}, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func unmarshalNode(data *Node, model reflect.Value, included *map[string]*Node) (err error) {
|
func unmarshalNode(data *Node, model reflect.Value, included *map[string]*Node) (err error) {
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
err = fmt.Errorf("data is not a jsonapi representation of '%v'", model.Type())
|
err = fmt.Errorf("data is not a jsonapi representation of '%v'", model.Type())
|
||||||
|
@ -248,122 +249,59 @@ func unmarshalNode(data *Node, model reflect.Value, included *map[string]*Node)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
var iso8601 bool
|
var isIso8601 bool
|
||||||
|
|
||||||
if len(args) > 2 {
|
if len(args) > 2 {
|
||||||
for _, arg := range args[2:] {
|
for _, arg := range args[2:] {
|
||||||
if arg == annotationISO8601 {
|
if arg == annotationISO8601 {
|
||||||
iso8601 = true
|
isIso8601 = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val := attributes[args[1]]
|
attribute := attributes[args[1]]
|
||||||
|
|
||||||
// continue if the attribute was not included in the request
|
// continue if the attribute was not included in the request
|
||||||
if val == nil {
|
if attribute == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
v := reflect.ValueOf(val)
|
value := reflect.ValueOf(attribute)
|
||||||
|
|
||||||
|
// Handle field of type []string
|
||||||
|
if fieldValue.Type() == reflect.TypeOf([]string{}) {
|
||||||
|
values := handleStringSlice(value)
|
||||||
|
assign(fieldValue, reflect.ValueOf(values))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
// Handle field of type time.Time
|
// Handle field of type time.Time
|
||||||
if fieldValue.Type() == reflect.TypeOf(time.Time{}) {
|
if fieldValue.Type() == reflect.TypeOf(time.Time{}) {
|
||||||
if iso8601 {
|
var time time.Time
|
||||||
var tm string
|
if time, err = handleTime(value, isIso8601); err != nil {
|
||||||
if v.Kind() == reflect.String {
|
er = err
|
||||||
tm = v.Interface().(string)
|
|
||||||
} else {
|
|
||||||
er = ErrInvalidISO8601
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
t, err := time.Parse(iso8601TimeFormat, tm)
|
assign(fieldValue, reflect.ValueOf(time))
|
||||||
if err != nil {
|
|
||||||
er = ErrInvalidISO8601
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
fieldValue.Set(reflect.ValueOf(t))
|
|
||||||
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
var at int64
|
|
||||||
|
|
||||||
if v.Kind() == reflect.Float64 {
|
|
||||||
at = int64(v.Interface().(float64))
|
|
||||||
} else if v.Kind() == reflect.Int {
|
|
||||||
at = v.Int()
|
|
||||||
} else {
|
|
||||||
return ErrInvalidTime
|
|
||||||
}
|
|
||||||
|
|
||||||
t := time.Unix(at, 0)
|
|
||||||
|
|
||||||
fieldValue.Set(reflect.ValueOf(t))
|
|
||||||
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if fieldValue.Type() == reflect.TypeOf([]string{}) {
|
|
||||||
values := make([]string, v.Len())
|
|
||||||
for i := 0; i < v.Len(); i++ {
|
|
||||||
values[i] = v.Index(i).Interface().(string)
|
|
||||||
}
|
|
||||||
|
|
||||||
fieldValue.Set(reflect.ValueOf(values))
|
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle field of type *time.Time
|
||||||
if fieldValue.Type() == reflect.TypeOf(new(time.Time)) {
|
if fieldValue.Type() == reflect.TypeOf(new(time.Time)) {
|
||||||
if iso8601 {
|
var time time.Time
|
||||||
var tm string
|
if time, err = handleTime(value, isIso8601); err != nil {
|
||||||
if v.Kind() == reflect.String {
|
er = err
|
||||||
tm = v.Interface().(string)
|
|
||||||
} else {
|
|
||||||
er = ErrInvalidISO8601
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
v, err := time.Parse(iso8601TimeFormat, tm)
|
assign(fieldValue, reflect.ValueOf(&time))
|
||||||
if err != nil {
|
|
||||||
er = ErrInvalidISO8601
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
t := &v
|
|
||||||
|
|
||||||
fieldValue.Set(reflect.ValueOf(t))
|
|
||||||
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
var at int64
|
|
||||||
|
|
||||||
if v.Kind() == reflect.Float64 {
|
|
||||||
at = int64(v.Interface().(float64))
|
|
||||||
} else if v.Kind() == reflect.Int {
|
|
||||||
at = v.Int()
|
|
||||||
} else {
|
|
||||||
return ErrInvalidTime
|
|
||||||
}
|
|
||||||
|
|
||||||
v := time.Unix(at, 0)
|
|
||||||
t := &v
|
|
||||||
|
|
||||||
fieldValue.Set(reflect.ValueOf(t))
|
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// JSON value was a float (numeric)
|
// JSON value was a float (numeric)
|
||||||
if v.Kind() == reflect.Float64 {
|
if value.Kind() == reflect.Float64 {
|
||||||
floatValue := v.Interface().(float64)
|
|
||||||
|
|
||||||
// The field may or may not be a pointer to a numeric; the kind var
|
|
||||||
// will not contain a pointer type
|
|
||||||
var kind reflect.Kind
|
var kind reflect.Kind
|
||||||
if fieldValue.Kind() == reflect.Ptr {
|
if fieldValue.Kind() == reflect.Ptr {
|
||||||
kind = fieldType.Type.Elem().Kind()
|
kind = fieldType.Type.Elem().Kind()
|
||||||
|
@ -371,47 +309,11 @@ func unmarshalNode(data *Node, model reflect.Value, included *map[string]*Node)
|
||||||
kind = fieldType.Type.Kind()
|
kind = fieldType.Type.Kind()
|
||||||
}
|
}
|
||||||
|
|
||||||
var numericValue reflect.Value
|
numericValue, err := handleNumeric(value, kind)
|
||||||
|
|
||||||
switch kind {
|
if err != nil {
|
||||||
case reflect.Int:
|
er = err
|
||||||
n := int(floatValue)
|
break
|
||||||
numericValue = reflect.ValueOf(&n)
|
|
||||||
case reflect.Int8:
|
|
||||||
n := int8(floatValue)
|
|
||||||
numericValue = reflect.ValueOf(&n)
|
|
||||||
case reflect.Int16:
|
|
||||||
n := int16(floatValue)
|
|
||||||
numericValue = reflect.ValueOf(&n)
|
|
||||||
case reflect.Int32:
|
|
||||||
n := int32(floatValue)
|
|
||||||
numericValue = reflect.ValueOf(&n)
|
|
||||||
case reflect.Int64:
|
|
||||||
n := int64(floatValue)
|
|
||||||
numericValue = reflect.ValueOf(&n)
|
|
||||||
case reflect.Uint:
|
|
||||||
n := uint(floatValue)
|
|
||||||
numericValue = reflect.ValueOf(&n)
|
|
||||||
case reflect.Uint8:
|
|
||||||
n := uint8(floatValue)
|
|
||||||
numericValue = reflect.ValueOf(&n)
|
|
||||||
case reflect.Uint16:
|
|
||||||
n := uint16(floatValue)
|
|
||||||
numericValue = reflect.ValueOf(&n)
|
|
||||||
case reflect.Uint32:
|
|
||||||
n := uint32(floatValue)
|
|
||||||
numericValue = reflect.ValueOf(&n)
|
|
||||||
case reflect.Uint64:
|
|
||||||
n := uint64(floatValue)
|
|
||||||
numericValue = reflect.ValueOf(&n)
|
|
||||||
case reflect.Float32:
|
|
||||||
n := float32(floatValue)
|
|
||||||
numericValue = reflect.ValueOf(&n)
|
|
||||||
case reflect.Float64:
|
|
||||||
n := floatValue
|
|
||||||
numericValue = reflect.ValueOf(&n)
|
|
||||||
default:
|
|
||||||
return ErrUnknownFieldNumberType
|
|
||||||
}
|
}
|
||||||
|
|
||||||
assign(fieldValue, numericValue)
|
assign(fieldValue, numericValue)
|
||||||
|
@ -420,36 +322,23 @@ func unmarshalNode(data *Node, model reflect.Value, included *map[string]*Node)
|
||||||
|
|
||||||
// Field was a Pointer type
|
// Field was a Pointer type
|
||||||
if fieldValue.Kind() == reflect.Ptr {
|
if fieldValue.Kind() == reflect.Ptr {
|
||||||
var concreteVal reflect.Value
|
|
||||||
|
|
||||||
switch cVal := val.(type) {
|
concreteVal, err := handlePointer(attribute, fieldValue.Type())
|
||||||
case string:
|
|
||||||
concreteVal = reflect.ValueOf(&cVal)
|
if err != nil {
|
||||||
case bool:
|
er = err
|
||||||
concreteVal = reflect.ValueOf(&cVal)
|
break
|
||||||
case complex64:
|
|
||||||
concreteVal = reflect.ValueOf(&cVal)
|
|
||||||
case complex128:
|
|
||||||
concreteVal = reflect.ValueOf(&cVal)
|
|
||||||
case uintptr:
|
|
||||||
concreteVal = reflect.ValueOf(&cVal)
|
|
||||||
default:
|
|
||||||
return ErrUnsupportedPtrType
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if fieldValue.Type() != concreteVal.Type() {
|
assign(fieldValue, concreteVal)
|
||||||
return ErrUnsupportedPtrType
|
|
||||||
}
|
|
||||||
|
|
||||||
fieldValue.Set(concreteVal)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// As a final catch-all, ensure types line up to avoid a runtime panic.
|
// As a final catch-all, ensure types line up to avoid a runtime panic.
|
||||||
if fieldValue.Kind() != v.Kind() {
|
if fieldValue.Kind() != value.Kind() {
|
||||||
return ErrInvalidType
|
return ErrInvalidType
|
||||||
}
|
}
|
||||||
fieldValue.Set(reflect.ValueOf(val))
|
assign(fieldValue, reflect.ValueOf(attribute))
|
||||||
|
|
||||||
} else if annotation == annotationRelation {
|
} else if annotation == annotationRelation {
|
||||||
isSlice := fieldValue.Type().Kind() == reflect.Slice
|
isSlice := fieldValue.Type().Kind() == reflect.Slice
|
||||||
|
@ -548,3 +437,119 @@ func assign(field, value reflect.Value) {
|
||||||
field.Set(reflect.Indirect(value))
|
field.Set(reflect.Indirect(value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func handleStringSlice(v reflect.Value) []string {
|
||||||
|
values := make([]string, v.Len())
|
||||||
|
for i := 0; i < v.Len(); i++ {
|
||||||
|
values[i] = v.Index(i).Interface().(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
return values
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleTime(v reflect.Value, isIso8601 bool) (time.Time, error) {
|
||||||
|
if isIso8601 {
|
||||||
|
var tm string
|
||||||
|
if v.Kind() == reflect.String {
|
||||||
|
tm = v.Interface().(string)
|
||||||
|
} else {
|
||||||
|
return time.Now(), ErrInvalidISO8601
|
||||||
|
}
|
||||||
|
|
||||||
|
t, err := time.Parse(iso8601TimeFormat, tm)
|
||||||
|
if err != nil {
|
||||||
|
return time.Now(), ErrInvalidISO8601
|
||||||
|
}
|
||||||
|
|
||||||
|
return t, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var at int64
|
||||||
|
|
||||||
|
if v.Kind() == reflect.Float64 {
|
||||||
|
at = int64(v.Interface().(float64))
|
||||||
|
} else if v.Kind() == reflect.Int {
|
||||||
|
at = v.Int()
|
||||||
|
} else {
|
||||||
|
return time.Now(), ErrInvalidTime
|
||||||
|
}
|
||||||
|
|
||||||
|
t := time.Unix(at, 0)
|
||||||
|
|
||||||
|
return t, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleNumeric(v reflect.Value, kind reflect.Kind) (reflect.Value, error) {
|
||||||
|
|
||||||
|
floatValue := v.Interface().(float64)
|
||||||
|
|
||||||
|
var numericValue reflect.Value
|
||||||
|
|
||||||
|
switch kind {
|
||||||
|
case reflect.Int:
|
||||||
|
n := int(floatValue)
|
||||||
|
numericValue = reflect.ValueOf(&n)
|
||||||
|
case reflect.Int8:
|
||||||
|
n := int8(floatValue)
|
||||||
|
numericValue = reflect.ValueOf(&n)
|
||||||
|
case reflect.Int16:
|
||||||
|
n := int16(floatValue)
|
||||||
|
numericValue = reflect.ValueOf(&n)
|
||||||
|
case reflect.Int32:
|
||||||
|
n := int32(floatValue)
|
||||||
|
numericValue = reflect.ValueOf(&n)
|
||||||
|
case reflect.Int64:
|
||||||
|
n := int64(floatValue)
|
||||||
|
numericValue = reflect.ValueOf(&n)
|
||||||
|
case reflect.Uint:
|
||||||
|
n := uint(floatValue)
|
||||||
|
numericValue = reflect.ValueOf(&n)
|
||||||
|
case reflect.Uint8:
|
||||||
|
n := uint8(floatValue)
|
||||||
|
numericValue = reflect.ValueOf(&n)
|
||||||
|
case reflect.Uint16:
|
||||||
|
n := uint16(floatValue)
|
||||||
|
numericValue = reflect.ValueOf(&n)
|
||||||
|
case reflect.Uint32:
|
||||||
|
n := uint32(floatValue)
|
||||||
|
numericValue = reflect.ValueOf(&n)
|
||||||
|
case reflect.Uint64:
|
||||||
|
n := uint64(floatValue)
|
||||||
|
numericValue = reflect.ValueOf(&n)
|
||||||
|
case reflect.Float32:
|
||||||
|
n := float32(floatValue)
|
||||||
|
numericValue = reflect.ValueOf(&n)
|
||||||
|
case reflect.Float64:
|
||||||
|
n := floatValue
|
||||||
|
numericValue = reflect.ValueOf(&n)
|
||||||
|
default:
|
||||||
|
return reflect.Value{}, ErrUnknownFieldNumberType
|
||||||
|
}
|
||||||
|
|
||||||
|
return numericValue, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func handlePointer(val interface{}, t reflect.Type) (reflect.Value, error) {
|
||||||
|
var concreteVal reflect.Value
|
||||||
|
|
||||||
|
switch cVal := val.(type) {
|
||||||
|
case string:
|
||||||
|
concreteVal = reflect.ValueOf(&cVal)
|
||||||
|
case bool:
|
||||||
|
concreteVal = reflect.ValueOf(&cVal)
|
||||||
|
case complex64:
|
||||||
|
concreteVal = reflect.ValueOf(&cVal)
|
||||||
|
case complex128:
|
||||||
|
concreteVal = reflect.ValueOf(&cVal)
|
||||||
|
case uintptr:
|
||||||
|
concreteVal = reflect.ValueOf(&cVal)
|
||||||
|
default:
|
||||||
|
return reflect.Value{}, ErrUnsupportedPtrType
|
||||||
|
}
|
||||||
|
|
||||||
|
if t != concreteVal.Type() {
|
||||||
|
return reflect.Value{}, ErrUnsupportedPtrType
|
||||||
|
}
|
||||||
|
|
||||||
|
return concreteVal, nil
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue