Feature/omitempty (#35)

* Implemented a failing test demonstrating the intended behaviour of the omitempty annotation.

* Updated the failing test to ensure that unset field without the "omitempty" annotation are not inadvertently omitted.

* Working implementation of the "omitempty" annotation for fields that are of any type.

* Update the readme to include a brief description of how to use the `omitempty` in a attr field.

* Update the json example also using a uint for type variety.
This commit is contained in:
Aren Patel 2016-07-16 08:24:21 -07:00 committed by Sam Woodard
parent 3b09fe9cb9
commit de4994e265
3 changed files with 62 additions and 7 deletions

View File

@ -63,6 +63,7 @@ type Comment struct {
Id int `json:"id"` Id int `json:"id"`
PostId int `json:"post_id"` PostId int `json:"post_id"`
Body string `json:"body"` Body string `json:"body"`
Likes uint `json:"likes_count,omitempty"`
} }
``` ```
@ -127,6 +128,7 @@ type Comment struct {
Id int `jsonapi:"primary,comments"` Id int `jsonapi:"primary,comments"`
PostId int `jsonapi:"attr,post_id"` PostId int `jsonapi:"attr,post_id"`
Body string `jsonapi:"attr,body"` Body string `jsonapi:"attr,body"`
Likes uint `jsonapi:"attr,likes-count,omitempty"`
} }
``` ```
@ -149,14 +151,17 @@ types are shown in the examples, but not required.
#### `attr` #### `attr`
``` ```
`jsonapi:"attr,<key name in attributes hash>"` `jsonapi:"attr,<key name in attributes hash>,<optional: omitempty>"`
``` ```
These fields' values will end up in the `attributes`hash for a record. These fields' values will end up in the `attributes`hash for a record.
The first argument must be, `attr`, and the second should be the name The first argument must be, `attr`, and the second should be the name
for the key to display in the `attributes` hash for that record. The for the key to display in the `attributes` hash for that record. The optional
spec indicates that `attributes` key names should be dasherized for third argument is `omitempty` - if it is present the field will not be present
multiple word field names. in the `"attributes"` if the field's value is equivalent to the field types
empty value (ie if the `count` field is of type `int`, `omitempty` will omit the
field when `count` has a value of `0`). Lastly, the spec indicates that
`attributes` key names should be dasherized for multiple word field names.
#### `relation` #### `relation`

View File

@ -255,11 +255,16 @@ func visitModelNode(model interface{}, included *map[string]*Node, sideload bool
node.Attributes[args[1]] = tm.Unix() node.Attributes[args[1]] = tm.Unix()
} }
} else { } else {
strAttr, ok := fieldValue.Interface().(string) // Dealing with a fieldValue that is not a time
emptyValue := reflect.Zero(fieldValue.Type())
if ok && strAttr == "" && omitEmpty { // See if we need to omit this field
if omitEmpty && fieldValue.Interface() == emptyValue.Interface() {
continue continue
} else if ok { }
strAttr, ok := fieldValue.Interface().(string)
if ok {
node.Attributes[args[1]] = strAttr node.Attributes[args[1]] = strAttr
} else { } else {
node.Attributes[args[1]] = fieldValue.Interface() node.Attributes[args[1]] = fieldValue.Interface()

View File

@ -36,6 +36,51 @@ type Comment struct {
Body string `jsonapi:"attr,body"` Body string `jsonapi:"attr,body"`
} }
type Book struct {
ID int `jsonapi:"primary,books"`
Author string `jsonapi:"attr,author"`
ISBN string `jsonapi:"attr,isbn"`
Title string `jsonapi:"attr,title,omitempty"`
Pages *uint `jsonapi:"attr,pages,omitempty"`
PublishedAt time.Time
}
func TestOmitsEmptyAnnotation(t *testing.T) {
book := &Book{
Author: "aren55555",
PublishedAt: time.Now().AddDate(0, -1, 0),
}
out := bytes.NewBuffer(nil)
if err := MarshalOnePayload(out, book); err != nil {
t.Fatal(err)
}
var jsonData map[string]interface{}
if err := json.Unmarshal(out.Bytes(), &jsonData); err != nil {
t.Fatal(err)
}
attributes := jsonData["data"].(map[string]interface{})["attributes"].(map[string]interface{})
// Verify that the specifically omitted field were omitted
if val, exists := attributes["title"]; exists {
t.Fatalf("Was expecting the data.attributes.title key/value to have been omitted - it was not and had a value of %v", val)
}
if val, exists := attributes["pages"]; exists {
t.Fatalf("Was expecting the data.attributes.pages key/value to have been omitted - it was not and had a value of %v", val)
}
// Verify the implicity omitted fields were omitted
if val, exists := attributes["PublishedAt"]; exists {
t.Fatalf("Was expecting the data.attributes.PublishedAt key/value to have been implicity omitted - it was not and had a value of %v", val)
}
// Verify the unset fields were not omitted
if _, exists := attributes["isbn"]; !exists {
t.Fatal("Was expecting the data.attributes.isbn key/value to have NOT been omitted")
}
}
func TestHasPrimaryAnnotation(t *testing.T) { func TestHasPrimaryAnnotation(t *testing.T) {
testModel := &Blog{ testModel := &Blog{
ID: 5, ID: 5,