-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add NullableRelationship support #23
base: main
Are you sure you want to change the base?
Conversation
http://jsonapi.org/format/#document-resource-object-relationships http://jsonapi.org/format/#document-resource-object-linkage Relationships can have a data node set to null (e.g. to disassociate the relationship) The NullableRelationship type allows this data to be marshalled/unmarshalled Supports slice and regular reference types
RFC3339Time NullableAttr[time.Time] `jsonapi:"attr,rfc3339_time,rfc3339,omitempty"` | ||
ISO8601Time NullableAttr[time.Time] `jsonapi:"attr,iso8601_time,iso8601,omitempty"` | ||
Bool NullableAttr[bool] `jsonapi:"attr,bool,omitempty"` | ||
NullableComment NullableRelationship[*Comment] `jsonapi:"relation,nullable_comment,omitempty"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the intended usage.
By setting the NullableRelationship to an explicit value it will serialize that value, by setting the NullableRelationship to an explicit null will serialize a null value which is intended to clear the relationship.
// unwind that here | ||
if strings.HasPrefix(fieldType.Type.Name(), "NullableRelationship[") { | ||
if m.Kind() == reflect.Ptr { | ||
m = reflect.New(fieldValue.Type().Elem().Elem()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the grossest part of the code. It feels wrong to "just unwrap one more pointer" but it does work as expected.
}, | ||
}, | ||
{ | ||
desc: "nullable_comment_not_null", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we were to want to support de-serializing slice types we would implement tests for that here.
As it's not included in the PR those sorts of tests are omitted here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry this took a while for me to get to @joekarl. I left some comments for review.
t.Set(value.(T)) | ||
} | ||
|
||
// IsNull indicate whether the field was sent, and had a value of `null` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: s/indicate/indicates/
@@ -471,20 +491,29 @@ func unmarshalNode(data *Node, model reflect.Value, included *map[string]*Node) | |||
so unmarshal and set fieldValue only if data obj is not null | |||
*/ | |||
if relationship.Data == nil { | |||
|
|||
// Explicit null supplied for the field value | |||
// If a nullable relationship we set the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👀
// this indicates disassociating the relationship | ||
isExplicitNull = true | ||
} else if relationshipDecodeErr != nil { | ||
fmt.Printf("decode err %v\n", relationshipDecodeErr) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want to swallow this error?
fieldValue.Set(m) | ||
if strings.HasPrefix(fieldType.Type.Name(), "NullableRelationship[") { | ||
fieldValue.Set(reflect.MakeMapWithSize(fieldValue.Type(), 1)) | ||
fieldValue.SetMapIndex(reflect.ValueOf(true), m) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
|
||
// Explicit null supplied for the field value | ||
// If a nullable relationship we set the | ||
if isExplicitNull && strings.HasPrefix(fieldType.Type.Name(), "NullableRelationship[") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be enough to simply check isExplicitNull
? It looks like the only way it can be true here is if we have a NullableRelationship
.
@@ -331,7 +331,7 @@ func visitModelNode(model interface{}, included *map[string]*Node, | |||
node.Attributes = make(map[string]interface{}) | |||
} | |||
|
|||
// Handle Nullable[T] | |||
// Handle NullableAttr[T] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🙇
http://jsonapi.org/format/#document-resource-object-relationships
http://jsonapi.org/format/#document-resource-object-linkage
Relationships can have a data node set to null (e.g. to disassociate the relationship)
The NullableRelationship type allows this data to be serialized/de-serialized. When serialized, a NullableRelationship with an explicit null will serialize to the appropriate "null" type. Either '"data": null' or '[]'.
Supports slice and regular reference types for serialization, and regular reference types for de-serialization.
The reason to not support slices for de-serialization is we need to decide how to handle the zero type for a NullableRelationship[[]*...] slice. Since we aren't using this and can emulate the nulling behavior by omitting omit-empty we decided to ignore this case for now.