Skip to content

Commit 4309b1d

Browse files
committed
Support node id unmarshalling for custom types
1 parent d11604b commit 4309b1d

File tree

2 files changed

+128
-2
lines changed

2 files changed

+128
-2
lines changed

request.go

+22-2
Original file line numberDiff line numberDiff line change
@@ -542,9 +542,29 @@ func fullNode(n *Node, included *map[string]*Node) *Node {
542542
// assign will take the value specified and assign it to the field; if
543543
// field is expecting a ptr assign will assign a ptr.
544544
func assign(field, value reflect.Value) {
545-
if field.Kind() == reflect.Ptr {
545+
if value.Type().AssignableTo(field.Type()) {
546546
field.Set(value)
547+
return
548+
}
549+
550+
indirectValue := reflect.Indirect(value)
551+
if indirectValue.Type().AssignableTo(field.Type()) {
552+
field.Set(indirectValue)
553+
return
554+
}
555+
556+
// Conversion required.
557+
558+
if field.Kind() == reflect.Ptr {
559+
if value.Kind() == reflect.Ptr {
560+
field.Set(value.Convert(field.Type()))
561+
} else {
562+
// Because field is zero value, we cannot simply field.Elem().Set().
563+
v := reflect.New(field.Type().Elem())
564+
v.Elem().Set(value.Convert(field.Type().Elem()))
565+
field.Set(v)
566+
}
547567
} else {
548-
field.Set(reflect.Indirect(value))
568+
field.Set(reflect.Indirect(value).Convert(field.Type()))
549569
}
550570
}

request_test.go

+106
Original file line numberDiff line numberDiff line change
@@ -703,6 +703,112 @@ func TestManyPayload_withLinks(t *testing.T) {
703703
}
704704
}
705705

706+
func TestUnmarshalPayloadIDTypeOfString(t *testing.T) {
707+
t.Run("Unmarshal string to value type", func(t *testing.T) {
708+
data := map[string]interface{}{
709+
"data": map[string]interface{}{
710+
"type": "books",
711+
"id": "978-3-16-148410-0",
712+
"attributes": map[string]interface{}{
713+
"title": "Gesammelte Werke in deutscher Sprache",
714+
},
715+
},
716+
}
717+
b, err := json.Marshal(data)
718+
if err != nil {
719+
t.Fatalf("Unexpected error: %v", err)
720+
}
721+
722+
type (
723+
IBSN string
724+
725+
Book struct {
726+
ID IBSN `jsonapi:"primary,books"`
727+
Title string `jsonapi:"attr,title"`
728+
}
729+
)
730+
731+
book := &Book{}
732+
if err := UnmarshalPayload(bytes.NewReader(b), book); err != nil {
733+
t.Fatalf("Unexpected error: %v", err)
734+
}
735+
736+
expected := IBSN("978-3-16-148410-0")
737+
if book.ID != expected {
738+
t.Fatalf("Expected book id to be %v but got %v", expected, book.ID)
739+
}
740+
})
741+
742+
t.Run("Unmarshal string to ptr type", func(t *testing.T) {
743+
data := map[string]interface{}{
744+
"data": map[string]interface{}{
745+
"type": "books",
746+
"id": "978-3-16-148410-0",
747+
"attributes": map[string]interface{}{
748+
"title": "Gesammelte Werke in deutscher Sprache",
749+
},
750+
},
751+
}
752+
b, err := json.Marshal(data)
753+
if err != nil {
754+
t.Fatalf("Unexpected error: %v", err)
755+
}
756+
757+
type (
758+
IBSN string
759+
760+
Book struct {
761+
ID *IBSN `jsonapi:"primary,books"`
762+
Title string `jsonapi:"attr,title"`
763+
}
764+
)
765+
766+
book := &Book{}
767+
if err := UnmarshalPayload(bytes.NewReader(b), book); err != nil {
768+
t.Fatalf("Unexpected error: %v", err)
769+
}
770+
771+
expected := IBSN("978-3-16-148410-0")
772+
if !reflect.DeepEqual(book.ID, &expected) {
773+
t.Fatalf("Expected book id to be %v but got %v", &expected, book.ID)
774+
}
775+
})
776+
777+
t.Run("Unmarshal nil to ptr type", func(t *testing.T) {
778+
data := map[string]interface{}{
779+
"data": map[string]interface{}{
780+
"type": "books",
781+
"id": nil,
782+
"attributes": map[string]interface{}{
783+
"title": "Gesammelte Werke in deutscher Sprache",
784+
},
785+
},
786+
}
787+
b, err := json.Marshal(data)
788+
if err != nil {
789+
t.Fatalf("Unexpected error: %v", err)
790+
}
791+
792+
type (
793+
IBSN string
794+
795+
Book struct {
796+
ID *IBSN `jsonapi:"primary,books"`
797+
Title string `jsonapi:"attr,title"`
798+
}
799+
)
800+
801+
book := &Book{}
802+
if err := UnmarshalPayload(bytes.NewReader(b), book); err != nil {
803+
t.Fatalf("Unexpected error: %v", err)
804+
}
805+
806+
if book.ID != nil {
807+
t.Fatalf("Expected book id to be %v but got %v", nil, book.ID)
808+
}
809+
})
810+
}
811+
706812
func samplePayloadWithoutIncluded() map[string]interface{} {
707813
return map[string]interface{}{
708814
"data": map[string]interface{}{

0 commit comments

Comments
 (0)