Skip to content

Commit

Permalink
Merge pull request #27 from notchairmk/notchairmk/fix-parsing-depreca…
Browse files Browse the repository at this point in the history
…ted-relation

fix: handle deprecating relation for polyrelation
  • Loading branch information
brandonc authored Jan 7, 2025
2 parents 042320d + 9e3a973 commit 1dc4f04
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 0 deletions.
31 changes: 31 additions & 0 deletions request.go
Original file line number Diff line number Diff line change
Expand Up @@ -309,9 +309,33 @@ func unmarshalNode(data *Node, model reflect.Value, included *map[string]*Node)

modelValue := model.Elem()
modelType := modelValue.Type()
polyrelationFields := map[string]reflect.Type{}

var er error

// preprocess the model to find polyrelation fields
for i := 0; i < modelValue.NumField(); i++ {
fieldValue := modelValue.Field(i)
fieldType := modelType.Field(i)

args, err := getStructTags(fieldType)
if err != nil {
er = err
break
}

if len(args) < 2 {
continue
}

annotation := args[0]
name := args[1]

if annotation == annotationPolyRelation {
polyrelationFields[name] = fieldValue.Type()
}
}

for i := 0; i < modelValue.NumField(); i++ {
fieldValue := modelValue.Field(i)
fieldType := modelType.Field(i)
Expand Down Expand Up @@ -474,6 +498,13 @@ func unmarshalNode(data *Node, model reflect.Value, included *map[string]*Node)
continue
}

// If the field is also a polyrelation field, then prefer the polyrelation.
// Otherwise stop processing this node.
// This is to allow relation and polyrelation fields to coexist, supporting deprecation for consumers
if pFieldType, ok := polyrelationFields[args[1]]; ok && fieldValue.Type() != pFieldType {
continue
}

// This will hold either the value of the choice type model or the actual
// model, depending on annotation
m := reflect.New(fieldValue.Type().Elem())
Expand Down
44 changes: 44 additions & 0 deletions request_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -847,6 +847,50 @@ func Test_UnmarshalPayload_polymorphicRelations_omitted(t *testing.T) {
}
}

func Test_UnmarshalPayload_polymorphicRelations_deprecatedRelation(t *testing.T) {
type withDeprecatedRelation struct {
ID string `jsonapi:"primary,blogs"`
Title string `jsonapi:"attr,title"`
Media *OneOfMedia `jsonapi:"polyrelation,media"`
Image *Image `jsonapi:"relation,media"` // Deprecated
}

in := bytes.NewReader([]byte(`{
"data": [{
"type": "blogs",
"id": "3",
"attributes": {
"title": "Hello, World"
},
"relationships": {
"media": {
"data": {
"type": "videos",
"id": "123"
}
}
}
}]
}`))

model := reflect.TypeOf(new(withDeprecatedRelation))

out, err := UnmarshalManyPayload(in, model)
if err != nil {
t.Fatal(err)
}

result := out[0].(*withDeprecatedRelation)

if result.Title != "Hello, World" {
t.Errorf("expected Title %q but got %q", "Hello, World", result.Title)
}

if result.Media.Video.ID != "123" {
t.Fatalf("expected Video to be \"123\", but got %+v", result.Media.Video)
}
}

func Test_choiceStructMapping(t *testing.T) {
cases := []struct {
val reflect.Type
Expand Down

0 comments on commit 1dc4f04

Please sign in to comment.