From 8629ed71e98863641b4e7e698de84072f43a8e14 Mon Sep 17 00:00:00 2001 From: CrushedPixel Date: Wed, 28 Mar 2018 15:04:52 +0200 Subject: [PATCH 1/2] Add support for attributes of custom defined types --- models_test.go | 15 +++++++++++++++ request.go | 32 +++++++++++++++++++++++++++++--- request_test.go | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+), 3 deletions(-) diff --git a/models_test.go b/models_test.go index a53dd61..5159295 100644 --- a/models_test.go +++ b/models_test.go @@ -155,3 +155,18 @@ func (bc *BadComment) JSONAPILinks() *Links { "self": []string{"invalid", "should error"}, } } + +type CustomIntType int +type CustomFloatType float64 +type CustomStringType string + +type CustomAttributeTypes struct { + ID string `jsonapi:"primary,customtypes"` + + Int CustomIntType `jsonapi:"attr,int"` + IntPtr *CustomIntType `jsonapi:"attr,intptr"` + IntPtrNull *CustomIntType `jsonapi:"attr,intptrnull"` + + Float CustomFloatType `jsonapi:"attr,float"` + String CustomStringType `jsonapi:"attr,string"` +} diff --git a/request.go b/request.go index fe29706..f0dc291 100644 --- a/request.go +++ b/request.go @@ -449,7 +449,7 @@ func unmarshalNode(data *Node, model reflect.Value, included *map[string]*Node) if fieldValue.Kind() != v.Kind() { return ErrInvalidType } - fieldValue.Set(reflect.ValueOf(val)) + assignValue(fieldValue, reflect.ValueOf(val)) } else if annotation == annotationRelation { isSlice := fieldValue.Type().Kind() == reflect.Slice @@ -542,9 +542,35 @@ func fullNode(n *Node, included *map[string]*Node) *Node { // assign will take the value specified and assign it to the field; if // field is expecting a ptr assign will assign a ptr. func assign(field, value reflect.Value) { + value = reflect.Indirect(value) + if field.Kind() == reflect.Ptr { - field.Set(value) + // initialize pointer so it's value + // can be set by assignValue + field.Set(reflect.New(field.Type().Elem())) + assignValue(field.Elem(), value) } else { - field.Set(reflect.Indirect(value)) + assignValue(field, value) + } +} + +// assign assigns the specified value to the field, +// expecting both values not to be pointer types. +func assignValue(field, value reflect.Value) { + switch field.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, + reflect.Int32, reflect.Int64: + field.SetInt(value.Int()) + case reflect.Uint, reflect.Uint8, reflect.Uint16, + reflect.Uint32, reflect.Uint64, reflect.Uintptr: + field.SetUint(value.Uint()) + case reflect.Float32, reflect.Float64: + field.SetFloat(value.Float()) + case reflect.String: + field.SetString(value.String()) + case reflect.Bool: + field.SetBool(value.Bool()) + default: + field.Set(value) } } diff --git a/request_test.go b/request_test.go index 2206449..31e73f7 100644 --- a/request_test.go +++ b/request_test.go @@ -703,6 +703,54 @@ func TestManyPayload_withLinks(t *testing.T) { } } +func TestUnmarshalCustomTypeAttributes(t *testing.T) { + customInt := CustomIntType(5) + customFloat := CustomFloatType(1.5) + customString := CustomStringType("Test") + + data := map[string]interface{}{ + "data": map[string]interface{}{ + "type": "customtypes", + "id": "1", + "attributes": map[string]interface{}{ + "int": customInt, + "intptr": &customInt, + "intptrnull": nil, + + "float": customFloat, + "string": customString, + }, + }, + } + payload, err := payload(data) + if err != nil { + t.Fatal(err) + } + + // Parse JSON API payload + customAttributeTypes := new(CustomAttributeTypes) + if err := UnmarshalPayload(bytes.NewReader(payload), customAttributeTypes); err != nil { + t.Fatal(err) + } + + if expected, actual := customInt, customAttributeTypes.Int; expected != actual { + t.Fatalf("Was expecting custom int to be `%s`, got `%s`", expected, actual) + } + if expected, actual := customInt, *customAttributeTypes.IntPtr; expected != actual { + t.Fatalf("Was expecting custom int pointer to be `%s`, got `%s`", expected, actual) + } + if customAttributeTypes.IntPtrNull != nil { + t.Fatalf("Was expecting custom int pointer to be , got `%s`", customAttributeTypes.IntPtrNull) + } + + if expected, actual := customFloat, customAttributeTypes.Float; expected != actual { + t.Fatalf("Was expecting custom float to be `%s`, got `%s`", expected, actual) + } + if expected, actual := customString, customAttributeTypes.String; expected != actual { + t.Fatalf("Was expecting custom string to be `%s`, got `%s`", expected, actual) + } +} + func samplePayloadWithoutIncluded() map[string]interface{} { return map[string]interface{}{ "data": map[string]interface{}{ From ed520b3a37447a090eb36826364df8e06f3601d7 Mon Sep 17 00:00:00 2001 From: CrushedPixel Date: Wed, 28 Mar 2018 15:14:32 +0200 Subject: [PATCH 2/2] Fixed format types --- request_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/request_test.go b/request_test.go index 31e73f7..f7ab2b9 100644 --- a/request_test.go +++ b/request_test.go @@ -734,17 +734,17 @@ func TestUnmarshalCustomTypeAttributes(t *testing.T) { } if expected, actual := customInt, customAttributeTypes.Int; expected != actual { - t.Fatalf("Was expecting custom int to be `%s`, got `%s`", expected, actual) + t.Fatalf("Was expecting custom int to be `%d`, got `%d`", expected, actual) } if expected, actual := customInt, *customAttributeTypes.IntPtr; expected != actual { - t.Fatalf("Was expecting custom int pointer to be `%s`, got `%s`", expected, actual) + t.Fatalf("Was expecting custom int pointer to be `%d`, got `%d`", expected, actual) } if customAttributeTypes.IntPtrNull != nil { - t.Fatalf("Was expecting custom int pointer to be , got `%s`", customAttributeTypes.IntPtrNull) + t.Fatalf("Was expecting custom int pointer to be , got `%d`", customAttributeTypes.IntPtrNull) } if expected, actual := customFloat, customAttributeTypes.Float; expected != actual { - t.Fatalf("Was expecting custom float to be `%s`, got `%s`", expected, actual) + t.Fatalf("Was expecting custom float to be `%f`, got `%f`", expected, actual) } if expected, actual := customString, customAttributeTypes.String; expected != actual { t.Fatalf("Was expecting custom string to be `%s`, got `%s`", expected, actual)