From bb4d09f5b4612c774fe7bbe457c57eb7f9b7ccc0 Mon Sep 17 00:00:00 2001 From: Brandon Croft Date: Wed, 15 Nov 2023 10:49:51 -0700 Subject: [PATCH] Fix omitted model value for polyrelation fields --- request_test.go | 31 +++++++++++++++++++++++++++++++ response.go | 7 ++++++- response_test.go | 12 ++++++++++++ 3 files changed, 49 insertions(+), 1 deletion(-) diff --git a/request_test.go b/request_test.go index 5a1b24a..7eb9bda 100644 --- a/request_test.go +++ b/request_test.go @@ -734,6 +734,37 @@ func Test_UnmarshalPayload_polymorphicRelations_no_choice(t *testing.T) { } } +func Test_UnmarshalPayload_polymorphicRelations_omitted(t *testing.T) { + type pointerToOne struct { + ID string `jsonapi:"primary,blogs"` + Title string `jsonapi:"attr,title"` + Hero *OneOfMedia `jsonapi:"polyrelation,hero-media"` + } + + in := bytes.NewReader([]byte(`{ + "data": { + "type": "blogs", + "id": "3", + "attributes": { + "title": "Hello, World" + } + } + }`)) + out := new(pointerToOne) + + if err := UnmarshalPayload(in, out); err != nil { + t.Fatal(err) + } + + if out.Title != "Hello, World" { + t.Errorf("expected Title %q but got %q", "Hello, World", out.Title) + } + + if out.Hero != nil { + t.Fatalf("expected Hero to be nil, but got %+v", out.Hero) + } +} + func Test_choiceStructMapping(t *testing.T) { cases := []struct { val reflect.Type diff --git a/response.go b/response.go index e23dd9c..602b16b 100644 --- a/response.go +++ b/response.go @@ -417,8 +417,13 @@ func visitModelNode(model interface{}, included *map[string]*Node, if choiceValue.IsNil() { fieldValue = reflect.ValueOf(nil) } - structValue := choiceValue.Elem() + + // Short circuit if field is omitted from model + if !structValue.IsValid() { + break + } + if found, err := selectChoiceTypeStructField(structValue); err == nil { fieldValue = found } diff --git a/response_test.go b/response_test.go index da10dee..599d999 100644 --- a/response_test.go +++ b/response_test.go @@ -167,6 +167,18 @@ func TestMarshalPayloadWithHasOneNilPolyrelation(t *testing.T) { } } +func TestMarshalPayloadWithHasOneOmittedPolyrelation(t *testing.T) { + blog := &BlogPostWithPoly{ + ID: "1", + Title: "Hello, World", + } + + out := bytes.NewBuffer(nil) + if err := MarshalPayload(out, blog); err != nil { + t.Fatalf("expected no error but got %s", err) + } +} + func TestMarshalPayloadWithHasOneNilRelation(t *testing.T) { blog := &Blog{ ID: 1,