basic handling of many relationship

This commit is contained in:
Sam Woodard 2015-07-05 10:59:35 -07:00
parent 0aa225cfcc
commit b321aa831e
2 changed files with 108 additions and 20 deletions

View File

@ -24,15 +24,28 @@ type JsonApiResponse struct {
}
func CreateJsonApiResponse(model interface{}) (*JsonApiResponse, error) {
rootNode := new(JsonApiNode)
jsonApiResponse := &JsonApiResponse{Data: rootNode}
rootNode, included, err := visitModelNode(model)
if err != nil {
return nil, err
}
primaryKeyType := reflect.TypeOf(model)
resp := &JsonApiResponse{Data: rootNode}
resp.Included = included
// TODO make Included unique
return resp, nil
}
func visitModelNode(model interface{}) (*JsonApiNode, []*JsonApiNode, error) {
node := new(JsonApiNode)
var err error
included := make([]*JsonApiNode, 0)
primaryKeyType.FieldByNameFunc(func(name string) bool {
field, found := primaryKeyType.FieldByName(name)
modelType := reflect.TypeOf(model)
modelType.FieldByNameFunc(func(name string) bool {
field, found := modelType.FieldByName(name)
if found {
fieldValue := reflect.ValueOf(model).FieldByName(name)
@ -43,24 +56,50 @@ func CreateJsonApiResponse(model interface{}) (*JsonApiResponse, error) {
if annotation == "primary" {
if len(args) >= 2 {
rootNode.Id = fmt.Sprintf("%v", fieldValue.Interface())
rootNode.Type = args[1]
node.Id = fmt.Sprintf("%v", fieldValue.Interface())
node.Type = args[1]
} else {
err = errors.New("'type' as second argument required for 'primary'")
}
} else if annotation == "attr" {
if rootNode.Attributes == nil {
rootNode.Attributes = make(map[string]interface{})
if node.Attributes == nil {
node.Attributes = make(map[string]interface{})
}
if len(args) >= 2 {
rootNode.Attributes[args[1]] = fieldValue.Interface()
node.Attributes[args[1]] = fieldValue.Interface()
} else {
err = errors.New("'type' as second argument required for 'primary'")
}
} else if annotation == "relation" {
if node.Relationships == nil {
node.Relationships = make(map[string]interface{})
}
if fieldValue.Type().Kind() == reflect.Slice {
relationship, err := visitModelNodeRelationships(args[1], fieldValue)
if err == nil {
shallowNodes := make([]*JsonApiNode, 0)
for k, v := range relationship {
for _, node := range v {
included = append(included, node)
shallowNode := *node
shallowNode.Attributes = nil
shallowNodes = append(shallowNodes, &shallowNode)
}
node.Relationships[k] = shallowNodes
}
} else {
err = err
}
} else {
}
} else {
err = errors.New("Unsupported jsonapi tag annotation")
err = errors.New(fmt.Sprintf("Unsupported jsonapi tag annotation, %s", annotation))
}
}
}
@ -69,10 +108,28 @@ func CreateJsonApiResponse(model interface{}) (*JsonApiResponse, error) {
})
if err != nil {
return nil, err
return nil, nil, err
}
return jsonApiResponse, nil
return node, included, nil
}
func visitModelNodeRelationships(relationName string, models reflect.Value) (map[string][]*JsonApiNode, error) {
relationship := make(map[string][]*JsonApiNode)
nodes := make([]*JsonApiNode, 0)
for i := 0; i < models.Len(); i++ {
node, _, err := visitModelNode(models.Index(i).Interface())
if err != nil {
return nil, err
}
nodes = append(nodes, node)
}
relationship[relationName] = nodes
return relationship, nil
}
func handleField(field reflect.StructField) {

View File

@ -1,26 +1,56 @@
package jsonapi
import "testing"
import (
"bytes"
"encoding/json"
"fmt"
"testing"
)
type Post struct {
Id int `jsonapi:"primary,posts"`
Title string `jsonapi:"attr,title"`
Body string `jsonapi:"attr,body"`
}
type Blog struct {
Id int `json:"id" jsonapi:"primary,blogs"`
Title string `json:"title" jsonapi:"attr,title"`
Id int `jsonapi:"primary,blogs"`
Title string `jsonapi:"attr,title"`
Posts []Post `jsonapi:"relation,posts"`
}
func TestHasPrimaryAnnotation(t *testing.T) {
testModel := Blog{
Id: 5,
Title: "Title 1",
Posts: []Post{
Post{
Id: 1,
Title: "Foo",
Body: "Bar",
},
Post{
Id: 2,
Title: "Fuubar",
Body: "Bas",
},
},
}
resp, err := CreateJsonApiResponse(testModel)
response := resp.Data
if err != nil {
t.Fatal(err)
}
if response.Type != "blogs" {
t.Fatalf("type should have been blogs")
out := bytes.NewBuffer(nil)
json.NewEncoder(out).Encode(resp)
fmt.Printf("%s\n", out.Bytes())
response := resp.Data
if response.Type != "Blogs" {
t.Fatalf("type should have been Blogs")
}
if response.Id != "5" {
@ -35,11 +65,12 @@ func TestSupportsAttributes(t *testing.T) {
}
resp, err := CreateJsonApiResponse(testModel)
response := resp.Data
if err != nil {
t.Fatal(err)
}
response := resp.Data
if response.Attributes == nil || len(response.Attributes) != 1 {
t.Fatalf("Expected 1 Attributes")
}