Skip to content

Commit 1dc4f04

Browse files
authored
Merge pull request #27 from notchairmk/notchairmk/fix-parsing-deprecated-relation
fix: handle deprecating relation for polyrelation
2 parents 042320d + 9e3a973 commit 1dc4f04

File tree

2 files changed

+75
-0
lines changed

2 files changed

+75
-0
lines changed

request.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,9 +309,33 @@ func unmarshalNode(data *Node, model reflect.Value, included *map[string]*Node)
309309

310310
modelValue := model.Elem()
311311
modelType := modelValue.Type()
312+
polyrelationFields := map[string]reflect.Type{}
312313

313314
var er error
314315

316+
// preprocess the model to find polyrelation fields
317+
for i := 0; i < modelValue.NumField(); i++ {
318+
fieldValue := modelValue.Field(i)
319+
fieldType := modelType.Field(i)
320+
321+
args, err := getStructTags(fieldType)
322+
if err != nil {
323+
er = err
324+
break
325+
}
326+
327+
if len(args) < 2 {
328+
continue
329+
}
330+
331+
annotation := args[0]
332+
name := args[1]
333+
334+
if annotation == annotationPolyRelation {
335+
polyrelationFields[name] = fieldValue.Type()
336+
}
337+
}
338+
315339
for i := 0; i < modelValue.NumField(); i++ {
316340
fieldValue := modelValue.Field(i)
317341
fieldType := modelType.Field(i)
@@ -474,6 +498,13 @@ func unmarshalNode(data *Node, model reflect.Value, included *map[string]*Node)
474498
continue
475499
}
476500

501+
// If the field is also a polyrelation field, then prefer the polyrelation.
502+
// Otherwise stop processing this node.
503+
// This is to allow relation and polyrelation fields to coexist, supporting deprecation for consumers
504+
if pFieldType, ok := polyrelationFields[args[1]]; ok && fieldValue.Type() != pFieldType {
505+
continue
506+
}
507+
477508
// This will hold either the value of the choice type model or the actual
478509
// model, depending on annotation
479510
m := reflect.New(fieldValue.Type().Elem())

request_test.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -847,6 +847,50 @@ func Test_UnmarshalPayload_polymorphicRelations_omitted(t *testing.T) {
847847
}
848848
}
849849

850+
func Test_UnmarshalPayload_polymorphicRelations_deprecatedRelation(t *testing.T) {
851+
type withDeprecatedRelation struct {
852+
ID string `jsonapi:"primary,blogs"`
853+
Title string `jsonapi:"attr,title"`
854+
Media *OneOfMedia `jsonapi:"polyrelation,media"`
855+
Image *Image `jsonapi:"relation,media"` // Deprecated
856+
}
857+
858+
in := bytes.NewReader([]byte(`{
859+
"data": [{
860+
"type": "blogs",
861+
"id": "3",
862+
"attributes": {
863+
"title": "Hello, World"
864+
},
865+
"relationships": {
866+
"media": {
867+
"data": {
868+
"type": "videos",
869+
"id": "123"
870+
}
871+
}
872+
}
873+
}]
874+
}`))
875+
876+
model := reflect.TypeOf(new(withDeprecatedRelation))
877+
878+
out, err := UnmarshalManyPayload(in, model)
879+
if err != nil {
880+
t.Fatal(err)
881+
}
882+
883+
result := out[0].(*withDeprecatedRelation)
884+
885+
if result.Title != "Hello, World" {
886+
t.Errorf("expected Title %q but got %q", "Hello, World", result.Title)
887+
}
888+
889+
if result.Media.Video.ID != "123" {
890+
t.Fatalf("expected Video to be \"123\", but got %+v", result.Media.Video)
891+
}
892+
}
893+
850894
func Test_choiceStructMapping(t *testing.T) {
851895
cases := []struct {
852896
val reflect.Type

0 commit comments

Comments
 (0)