Skip to content

Commit e13a199

Browse files
committed
extract type handling
1 parent ebb7923 commit e13a199

File tree

1 file changed

+153
-148
lines changed

1 file changed

+153
-148
lines changed

request.go

Lines changed: 153 additions & 148 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ func UnmarshalManyPayload(in io.Reader, t reflect.Type) ([]interface{}, error) {
118118
}
119119

120120
func unmarshalNode(data *Node, model reflect.Value, included *map[string]*Node) (err error) {
121+
121122
defer func() {
122123
if r := recover(); r != nil {
123124
err = fmt.Errorf("data is not a jsonapi representation of '%v'", model.Type())
@@ -248,170 +249,71 @@ func unmarshalNode(data *Node, model reflect.Value, included *map[string]*Node)
248249
continue
249250
}
250251

251-
var iso8601 bool
252+
var isIso8601 bool
252253

253254
if len(args) > 2 {
254255
for _, arg := range args[2:] {
255256
if arg == annotationISO8601 {
256-
iso8601 = true
257+
isIso8601 = true
257258
}
258259
}
259260
}
260261

261-
val := attributes[args[1]]
262+
attribute := attributes[args[1]]
262263

263264
// continue if the attribute was not included in the request
264-
if val == nil {
265+
if attribute == nil {
265266
continue
266267
}
267268

268-
v := reflect.ValueOf(val)
269-
270-
// Handle field of type time.Time
271-
if fieldValue.Type() == reflect.TypeOf(time.Time{}) {
272-
if iso8601 {
273-
var tm string
274-
if v.Kind() == reflect.String {
275-
tm = v.Interface().(string)
276-
} else {
277-
er = ErrInvalidISO8601
278-
break
279-
}
280-
281-
t, err := time.Parse(iso8601TimeFormat, tm)
282-
if err != nil {
283-
er = ErrInvalidISO8601
284-
break
285-
}
286-
287-
fieldValue.Set(reflect.ValueOf(t))
288-
289-
continue
290-
}
291-
292-
var at int64
293-
294-
if v.Kind() == reflect.Float64 {
295-
at = int64(v.Interface().(float64))
296-
} else if v.Kind() == reflect.Int {
297-
at = v.Int()
298-
} else {
299-
return ErrInvalidTime
300-
}
301-
302-
t := time.Unix(at, 0)
303-
304-
fieldValue.Set(reflect.ValueOf(t))
269+
value := reflect.ValueOf(attribute)
305270

271+
// Handle field of type []string
272+
if fieldValue.Type() == reflect.TypeOf([]string{}) {
273+
values := handleStringSlice(value)
274+
assign(fieldValue, reflect.ValueOf(values))
306275
continue
307276
}
308277

309-
if fieldValue.Type() == reflect.TypeOf([]string{}) {
310-
values := make([]string, v.Len())
311-
for i := 0; i < v.Len(); i++ {
312-
values[i] = v.Index(i).Interface().(string)
278+
// Handle field of type time.Time
279+
if fieldValue.Type() == reflect.TypeOf(time.Time{}) {
280+
var time time.Time
281+
if time, err = handleTime(value, isIso8601); err != nil {
282+
er = err
283+
break
313284
}
314285

315-
fieldValue.Set(reflect.ValueOf(values))
316-
286+
assign(fieldValue, reflect.ValueOf(time))
317287
continue
318288
}
319289

290+
// Handle field of type *time.Time
320291
if fieldValue.Type() == reflect.TypeOf(new(time.Time)) {
321-
if iso8601 {
322-
var tm string
323-
if v.Kind() == reflect.String {
324-
tm = v.Interface().(string)
325-
} else {
326-
er = ErrInvalidISO8601
327-
break
328-
}
329-
330-
v, err := time.Parse(iso8601TimeFormat, tm)
331-
if err != nil {
332-
er = ErrInvalidISO8601
333-
break
334-
}
335-
336-
t := &v
337-
338-
fieldValue.Set(reflect.ValueOf(t))
339-
340-
continue
341-
}
342-
343-
var at int64
344-
345-
if v.Kind() == reflect.Float64 {
346-
at = int64(v.Interface().(float64))
347-
} else if v.Kind() == reflect.Int {
348-
at = v.Int()
349-
} else {
350-
return ErrInvalidTime
292+
var time time.Time
293+
if time, err = handleTime(value, isIso8601); err != nil {
294+
er = err
295+
break
351296
}
352297

353-
v := time.Unix(at, 0)
354-
t := &v
355-
356-
fieldValue.Set(reflect.ValueOf(t))
357-
298+
assign(fieldValue, reflect.ValueOf(&time))
358299
continue
359300
}
360301

361302
// JSON value was a float (numeric)
362-
if v.Kind() == reflect.Float64 {
363-
floatValue := v.Interface().(float64)
303+
if value.Kind() == reflect.Float64 {
364304

365-
// The field may or may not be a pointer to a numeric; the kind var
366-
// will not contain a pointer type
367305
var kind reflect.Kind
368306
if fieldValue.Kind() == reflect.Ptr {
369307
kind = fieldType.Type.Elem().Kind()
370308
} else {
371309
kind = fieldType.Type.Kind()
372310
}
373311

374-
var numericValue reflect.Value
375-
376-
switch kind {
377-
case reflect.Int:
378-
n := int(floatValue)
379-
numericValue = reflect.ValueOf(&n)
380-
case reflect.Int8:
381-
n := int8(floatValue)
382-
numericValue = reflect.ValueOf(&n)
383-
case reflect.Int16:
384-
n := int16(floatValue)
385-
numericValue = reflect.ValueOf(&n)
386-
case reflect.Int32:
387-
n := int32(floatValue)
388-
numericValue = reflect.ValueOf(&n)
389-
case reflect.Int64:
390-
n := int64(floatValue)
391-
numericValue = reflect.ValueOf(&n)
392-
case reflect.Uint:
393-
n := uint(floatValue)
394-
numericValue = reflect.ValueOf(&n)
395-
case reflect.Uint8:
396-
n := uint8(floatValue)
397-
numericValue = reflect.ValueOf(&n)
398-
case reflect.Uint16:
399-
n := uint16(floatValue)
400-
numericValue = reflect.ValueOf(&n)
401-
case reflect.Uint32:
402-
n := uint32(floatValue)
403-
numericValue = reflect.ValueOf(&n)
404-
case reflect.Uint64:
405-
n := uint64(floatValue)
406-
numericValue = reflect.ValueOf(&n)
407-
case reflect.Float32:
408-
n := float32(floatValue)
409-
numericValue = reflect.ValueOf(&n)
410-
case reflect.Float64:
411-
n := floatValue
412-
numericValue = reflect.ValueOf(&n)
413-
default:
414-
return ErrUnknownFieldNumberType
312+
numericValue, err := handleNumeric(value, kind)
313+
314+
if err != nil {
315+
er = err
316+
break
415317
}
416318

417319
assign(fieldValue, numericValue)
@@ -420,36 +322,23 @@ func unmarshalNode(data *Node, model reflect.Value, included *map[string]*Node)
420322

421323
// Field was a Pointer type
422324
if fieldValue.Kind() == reflect.Ptr {
423-
var concreteVal reflect.Value
424-
425-
switch cVal := val.(type) {
426-
case string:
427-
concreteVal = reflect.ValueOf(&cVal)
428-
case bool:
429-
concreteVal = reflect.ValueOf(&cVal)
430-
case complex64:
431-
concreteVal = reflect.ValueOf(&cVal)
432-
case complex128:
433-
concreteVal = reflect.ValueOf(&cVal)
434-
case uintptr:
435-
concreteVal = reflect.ValueOf(&cVal)
436-
default:
437-
return ErrUnsupportedPtrType
438-
}
439325

440-
if fieldValue.Type() != concreteVal.Type() {
441-
return ErrUnsupportedPtrType
326+
concreteVal, err := handlePointer(attribute, fieldValue.Type())
327+
328+
if err != nil {
329+
er = err
330+
break
442331
}
443332

444-
fieldValue.Set(concreteVal)
333+
assign(fieldValue, concreteVal)
445334
continue
446335
}
447336

448337
// As a final catch-all, ensure types line up to avoid a runtime panic.
449-
if fieldValue.Kind() != v.Kind() {
338+
if fieldValue.Kind() != value.Kind() {
450339
return ErrInvalidType
451340
}
452-
fieldValue.Set(reflect.ValueOf(val))
341+
assign(fieldValue, reflect.ValueOf(attribute))
453342

454343
} else if annotation == annotationRelation {
455344
isSlice := fieldValue.Type().Kind() == reflect.Slice
@@ -548,3 +437,119 @@ func assign(field, value reflect.Value) {
548437
field.Set(reflect.Indirect(value))
549438
}
550439
}
440+
441+
func handleStringSlice(v reflect.Value) []string {
442+
values := make([]string, v.Len())
443+
for i := 0; i < v.Len(); i++ {
444+
values[i] = v.Index(i).Interface().(string)
445+
}
446+
447+
return values
448+
}
449+
450+
func handleTime(v reflect.Value, isIso8601 bool) (time.Time, error) {
451+
if isIso8601 {
452+
var tm string
453+
if v.Kind() == reflect.String {
454+
tm = v.Interface().(string)
455+
} else {
456+
return time.Now(), ErrInvalidISO8601
457+
}
458+
459+
t, err := time.Parse(iso8601TimeFormat, tm)
460+
if err != nil {
461+
return time.Now(), ErrInvalidISO8601
462+
}
463+
464+
return t, nil
465+
}
466+
467+
var at int64
468+
469+
if v.Kind() == reflect.Float64 {
470+
at = int64(v.Interface().(float64))
471+
} else if v.Kind() == reflect.Int {
472+
at = v.Int()
473+
} else {
474+
return time.Now(), ErrInvalidTime
475+
}
476+
477+
t := time.Unix(at, 0)
478+
479+
return t, nil
480+
}
481+
482+
func handleNumeric(v reflect.Value, kind reflect.Kind) (reflect.Value, error) {
483+
484+
floatValue := v.Interface().(float64)
485+
486+
var numericValue reflect.Value
487+
488+
switch kind {
489+
case reflect.Int:
490+
n := int(floatValue)
491+
numericValue = reflect.ValueOf(&n)
492+
case reflect.Int8:
493+
n := int8(floatValue)
494+
numericValue = reflect.ValueOf(&n)
495+
case reflect.Int16:
496+
n := int16(floatValue)
497+
numericValue = reflect.ValueOf(&n)
498+
case reflect.Int32:
499+
n := int32(floatValue)
500+
numericValue = reflect.ValueOf(&n)
501+
case reflect.Int64:
502+
n := int64(floatValue)
503+
numericValue = reflect.ValueOf(&n)
504+
case reflect.Uint:
505+
n := uint(floatValue)
506+
numericValue = reflect.ValueOf(&n)
507+
case reflect.Uint8:
508+
n := uint8(floatValue)
509+
numericValue = reflect.ValueOf(&n)
510+
case reflect.Uint16:
511+
n := uint16(floatValue)
512+
numericValue = reflect.ValueOf(&n)
513+
case reflect.Uint32:
514+
n := uint32(floatValue)
515+
numericValue = reflect.ValueOf(&n)
516+
case reflect.Uint64:
517+
n := uint64(floatValue)
518+
numericValue = reflect.ValueOf(&n)
519+
case reflect.Float32:
520+
n := float32(floatValue)
521+
numericValue = reflect.ValueOf(&n)
522+
case reflect.Float64:
523+
n := floatValue
524+
numericValue = reflect.ValueOf(&n)
525+
default:
526+
return reflect.Value{}, ErrUnknownFieldNumberType
527+
}
528+
529+
return numericValue, nil
530+
}
531+
532+
func handlePointer(val interface{}, t reflect.Type) (reflect.Value, error) {
533+
var concreteVal reflect.Value
534+
535+
switch cVal := val.(type) {
536+
case string:
537+
concreteVal = reflect.ValueOf(&cVal)
538+
case bool:
539+
concreteVal = reflect.ValueOf(&cVal)
540+
case complex64:
541+
concreteVal = reflect.ValueOf(&cVal)
542+
case complex128:
543+
concreteVal = reflect.ValueOf(&cVal)
544+
case uintptr:
545+
concreteVal = reflect.ValueOf(&cVal)
546+
default:
547+
return reflect.Value{}, ErrUnsupportedPtrType
548+
}
549+
550+
if t != concreteVal.Type() {
551+
return reflect.Value{}, ErrUnsupportedPtrType
552+
}
553+
554+
return concreteVal, nil
555+
}

0 commit comments

Comments
 (0)