2015-07-06 16:40:43 -04:00
|
|
|
package jsonapi
|
|
|
|
|
|
|
|
import (
|
2015-09-17 18:55:53 -04:00
|
|
|
"bytes"
|
2015-07-08 12:34:37 -04:00
|
|
|
"encoding/json"
|
2015-07-06 16:40:43 -04:00
|
|
|
"errors"
|
2015-07-07 18:46:20 -04:00
|
|
|
"fmt"
|
2015-07-08 12:34:37 -04:00
|
|
|
"io"
|
2015-07-06 16:40:43 -04:00
|
|
|
"reflect"
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
2016-07-22 21:34:38 -04:00
|
|
|
const (
|
|
|
|
unsuportedStructTagMsg = "Unsupported jsonapi tag annotation, %s"
|
|
|
|
)
|
2016-01-05 16:13:24 -05:00
|
|
|
|
|
|
|
var (
|
2016-07-22 21:34:38 -04:00
|
|
|
// ErrInvalidTime is returned when a struct has a time.Time type field, but
|
|
|
|
// the JSON value was not a unix timestamp integer.
|
|
|
|
ErrInvalidTime = errors.New("Only numbers can be parsed as dates, unix timestamps")
|
2016-09-22 16:58:07 -04:00
|
|
|
// ErrInvalidISO8601 is returned when a struct has a time.Time type field and includes
|
|
|
|
// "iso8601" in the tag spec, but the JSON value was not an ISO8601 timestamp string.
|
|
|
|
ErrInvalidISO8601 = errors.New("Only strings can be parsed as dates, ISO8601 timestamps")
|
2016-07-22 21:34:38 -04:00
|
|
|
// ErrUnknownFieldNumberType is returned when the JSON value was a float
|
|
|
|
// (numeric) but the Struct field was a non numeric type (i.e. not int, uint,
|
|
|
|
// float, etc)
|
2016-01-12 13:00:18 -05:00
|
|
|
ErrUnknownFieldNumberType = errors.New("The struct field was not of a known number type")
|
2016-07-22 21:34:38 -04:00
|
|
|
// ErrUnsupportedPtrType is returned when the Struct field was a pointer but
|
|
|
|
// the JSON value was of a different type
|
|
|
|
ErrUnsupportedPtrType = errors.New("Pointer type in struct is not supported")
|
2016-01-05 16:13:24 -05:00
|
|
|
)
|
|
|
|
|
2016-07-22 21:34:38 -04:00
|
|
|
// UnmarshalPayload converts an io into a struct instance using jsonapi tags on
|
|
|
|
// struct fields. This method supports single request payloads only, at the
|
|
|
|
// moment. Bulk creates and updates are not supported yet.
|
2015-07-13 12:48:26 -04:00
|
|
|
//
|
2015-07-13 14:23:03 -04:00
|
|
|
// Will Unmarshal embedded and sideloaded payloads. The latter is only possible if the
|
|
|
|
// object graph is complete. That is, in the "relationships" data there are type and id,
|
|
|
|
// keys that correspond to records in the "included" array.
|
|
|
|
//
|
2015-07-13 12:48:26 -04:00
|
|
|
// For example you could pass it, in, req.Body and, model, a BlogPost
|
|
|
|
// struct instance to populate in an http handler,
|
|
|
|
//
|
2015-07-13 18:04:21 -04:00
|
|
|
// func CreateBlog(w http.ResponseWriter, r *http.Request) {
|
|
|
|
// blog := new(Blog)
|
2015-07-13 12:48:26 -04:00
|
|
|
//
|
2015-07-13 18:04:21 -04:00
|
|
|
// if err := jsonapi.UnmarshalPayload(r.Body, blog); err != nil {
|
|
|
|
// http.Error(w, err.Error(), 500)
|
|
|
|
// return
|
|
|
|
// }
|
2015-07-13 12:48:26 -04:00
|
|
|
//
|
2015-07-13 18:04:21 -04:00
|
|
|
// // ...do stuff with your blog...
|
2015-07-13 12:48:26 -04:00
|
|
|
//
|
2015-07-13 18:04:21 -04:00
|
|
|
// w.WriteHeader(201)
|
|
|
|
// w.Header().Set("Content-Type", "application/vnd.api+json")
|
2015-07-13 12:48:26 -04:00
|
|
|
//
|
2015-07-13 18:04:21 -04:00
|
|
|
// if err := jsonapi.MarshalOnePayload(w, blog); err != nil {
|
|
|
|
// http.Error(w, err.Error(), 500)
|
|
|
|
// }
|
|
|
|
// }
|
2015-07-13 12:48:26 -04:00
|
|
|
//
|
|
|
|
//
|
2016-07-22 21:31:33 -04:00
|
|
|
// Visit https://github.com/google/jsonapi#create for more info.
|
2015-07-13 12:48:26 -04:00
|
|
|
//
|
2015-07-13 14:23:03 -04:00
|
|
|
// model interface{} should be a pointer to a struct.
|
2015-07-10 12:07:12 -04:00
|
|
|
func UnmarshalPayload(in io.Reader, model interface{}) error {
|
|
|
|
payload := new(OnePayload)
|
2015-07-08 12:34:37 -04:00
|
|
|
|
|
|
|
if err := json.NewDecoder(in).Decode(payload); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2015-07-10 14:41:54 -04:00
|
|
|
if payload.Included != nil {
|
|
|
|
includedMap := make(map[string]*Node)
|
|
|
|
for _, included := range payload.Included {
|
2016-07-05 21:32:15 -04:00
|
|
|
key := fmt.Sprintf("%s,%s", included.Type, included.ID)
|
2015-07-10 14:41:54 -04:00
|
|
|
includedMap[key] = included
|
|
|
|
}
|
|
|
|
|
|
|
|
return unmarshalNode(payload.Data, reflect.ValueOf(model), &includedMap)
|
|
|
|
}
|
2016-07-22 21:34:38 -04:00
|
|
|
return unmarshalNode(payload.Data, reflect.ValueOf(model), nil)
|
2015-07-07 18:46:20 -04:00
|
|
|
}
|
2015-07-06 16:40:43 -04:00
|
|
|
|
2015-10-27 12:29:56 -04:00
|
|
|
func UnmarshalManyPayload(in io.Reader, t reflect.Type) ([]interface{}, error) {
|
|
|
|
payload := new(ManyPayload)
|
|
|
|
|
|
|
|
if err := json.NewDecoder(in).Decode(payload); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if payload.Included != nil {
|
|
|
|
includedMap := make(map[string]*Node)
|
|
|
|
for _, included := range payload.Included {
|
2016-07-05 21:32:15 -04:00
|
|
|
key := fmt.Sprintf("%s,%s", included.Type, included.ID)
|
2015-10-27 12:29:56 -04:00
|
|
|
includedMap[key] = included
|
|
|
|
}
|
|
|
|
|
|
|
|
var models []interface{}
|
|
|
|
for _, data := range payload.Data {
|
2015-10-28 13:08:50 -04:00
|
|
|
model := reflect.New(t.Elem())
|
|
|
|
err := unmarshalNode(data, model, &includedMap)
|
2015-10-27 12:29:56 -04:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
models = append(models, model.Interface())
|
|
|
|
}
|
|
|
|
|
|
|
|
return models, nil
|
2016-07-22 21:34:38 -04:00
|
|
|
}
|
2015-10-27 12:29:56 -04:00
|
|
|
|
2016-07-22 21:34:38 -04:00
|
|
|
var models []interface{}
|
2015-10-27 12:29:56 -04:00
|
|
|
|
2016-07-22 21:34:38 -04:00
|
|
|
for _, data := range payload.Data {
|
|
|
|
model := reflect.New(t.Elem())
|
|
|
|
err := unmarshalNode(data, model, nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
models = append(models, model.Interface())
|
2015-10-27 12:29:56 -04:00
|
|
|
}
|
|
|
|
|
2016-07-22 21:34:38 -04:00
|
|
|
return models, nil
|
2015-10-27 12:29:56 -04:00
|
|
|
}
|
|
|
|
|
2015-08-29 13:29:58 -04:00
|
|
|
func unmarshalNode(data *Node, model reflect.Value, included *map[string]*Node) (err error) {
|
|
|
|
defer func() {
|
|
|
|
if r := recover(); r != nil {
|
|
|
|
err = fmt.Errorf("data is not a jsonapi representation of '%v'", model.Type())
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
2015-07-07 18:46:20 -04:00
|
|
|
modelValue := model.Elem()
|
|
|
|
modelType := model.Type().Elem()
|
2015-07-06 16:40:43 -04:00
|
|
|
|
|
|
|
var er error
|
2015-07-06 16:41:38 -04:00
|
|
|
|
2016-01-05 16:13:24 -05:00
|
|
|
for i := 0; i < modelValue.NumField(); i++ {
|
2015-07-07 18:46:20 -04:00
|
|
|
fieldType := modelType.Field(i)
|
2015-07-20 19:10:52 -04:00
|
|
|
tag := fieldType.Tag.Get("jsonapi")
|
|
|
|
if tag == "" {
|
2016-01-05 16:13:24 -05:00
|
|
|
continue
|
2015-07-20 19:10:52 -04:00
|
|
|
}
|
2015-07-06 16:40:43 -04:00
|
|
|
|
2015-07-20 19:10:52 -04:00
|
|
|
fieldValue := modelValue.Field(i)
|
2015-07-06 16:40:43 -04:00
|
|
|
|
|
|
|
args := strings.Split(tag, ",")
|
|
|
|
|
2015-09-10 18:55:51 -04:00
|
|
|
if len(args) < 1 {
|
2016-01-05 16:13:24 -05:00
|
|
|
er = ErrBadJSONAPIStructTag
|
|
|
|
break
|
2015-07-08 14:49:36 -04:00
|
|
|
}
|
|
|
|
|
2015-09-10 18:55:51 -04:00
|
|
|
annotation := args[0]
|
2015-07-06 16:40:43 -04:00
|
|
|
|
2016-07-22 21:34:38 -04:00
|
|
|
if (annotation == clientIDAnnotation && len(args) != 1) ||
|
|
|
|
(annotation != clientIDAnnotation && len(args) < 2) {
|
2016-01-05 16:13:24 -05:00
|
|
|
er = ErrBadJSONAPIStructTag
|
|
|
|
break
|
2015-09-10 18:55:51 -04:00
|
|
|
}
|
2015-07-06 16:40:43 -04:00
|
|
|
|
2015-09-10 18:55:51 -04:00
|
|
|
if annotation == "primary" {
|
2016-07-05 21:32:15 -04:00
|
|
|
if data.ID == "" {
|
2016-01-05 16:13:24 -05:00
|
|
|
continue
|
2015-09-10 18:55:51 -04:00
|
|
|
}
|
2015-07-06 16:40:43 -04:00
|
|
|
|
2015-09-10 18:55:51 -04:00
|
|
|
if data.Type != args[1] {
|
2016-04-08 20:34:02 -04:00
|
|
|
er = fmt.Errorf("Trying to Unmarshal an object of type %#v, but %#v does not match", data.Type, args[1])
|
2016-01-05 16:13:24 -05:00
|
|
|
break
|
2015-09-10 18:55:51 -04:00
|
|
|
}
|
2015-07-09 15:27:03 -04:00
|
|
|
|
2015-09-10 18:55:51 -04:00
|
|
|
if fieldValue.Kind() == reflect.String {
|
2016-07-05 21:32:15 -04:00
|
|
|
fieldValue.Set(reflect.ValueOf(data.ID))
|
2015-09-10 18:55:51 -04:00
|
|
|
} else if fieldValue.Kind() == reflect.Int {
|
2016-07-05 21:32:15 -04:00
|
|
|
id, err := strconv.Atoi(data.ID)
|
2015-09-10 18:55:51 -04:00
|
|
|
if err != nil {
|
|
|
|
er = err
|
2016-01-05 16:13:24 -05:00
|
|
|
break
|
2015-07-10 11:20:49 -04:00
|
|
|
}
|
2015-09-10 18:55:51 -04:00
|
|
|
fieldValue.SetInt(int64(id))
|
|
|
|
} else {
|
2016-01-05 16:13:24 -05:00
|
|
|
er = ErrBadJSONAPIID
|
|
|
|
break
|
2015-09-10 18:55:51 -04:00
|
|
|
}
|
2016-07-22 21:34:38 -04:00
|
|
|
} else if annotation == clientIDAnnotation {
|
2016-07-05 21:32:15 -04:00
|
|
|
if data.ClientID == "" {
|
2016-01-05 16:13:24 -05:00
|
|
|
continue
|
2015-09-10 18:55:51 -04:00
|
|
|
}
|
2015-07-09 15:27:03 -04:00
|
|
|
|
2016-07-05 21:32:15 -04:00
|
|
|
fieldValue.Set(reflect.ValueOf(data.ClientID))
|
2015-09-10 18:55:51 -04:00
|
|
|
} else if annotation == "attr" {
|
|
|
|
attributes := data.Attributes
|
2016-01-05 16:13:24 -05:00
|
|
|
if attributes == nil || len(data.Attributes) == 0 {
|
|
|
|
continue
|
2015-09-10 18:55:51 -04:00
|
|
|
}
|
2015-07-06 16:40:43 -04:00
|
|
|
|
2016-09-22 16:58:07 -04:00
|
|
|
var iso8601 bool
|
|
|
|
|
|
|
|
if len(args) > 2 {
|
|
|
|
for _, arg := range args[2:] {
|
|
|
|
if arg == "iso8601" {
|
|
|
|
iso8601 = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-10 18:55:51 -04:00
|
|
|
val := attributes[args[1]]
|
2015-07-09 15:27:03 -04:00
|
|
|
|
2016-01-05 16:13:24 -05:00
|
|
|
// continue if the attribute was not included in the request
|
2015-09-10 18:55:51 -04:00
|
|
|
if val == nil {
|
2016-01-05 16:13:24 -05:00
|
|
|
continue
|
2015-09-10 18:55:51 -04:00
|
|
|
}
|
2015-07-07 18:46:20 -04:00
|
|
|
|
2015-09-10 18:55:51 -04:00
|
|
|
v := reflect.ValueOf(val)
|
2015-07-06 16:40:43 -04:00
|
|
|
|
2016-07-22 21:34:38 -04:00
|
|
|
// Handle field of type time.Time
|
2015-09-10 18:55:51 -04:00
|
|
|
if fieldValue.Type() == reflect.TypeOf(time.Time{}) {
|
2016-09-22 16:58:07 -04:00
|
|
|
if iso8601 {
|
|
|
|
var tm string
|
|
|
|
if v.Kind() == reflect.String {
|
|
|
|
tm = v.Interface().(string)
|
|
|
|
} else {
|
|
|
|
er = ErrInvalidISO8601
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
t, err := time.Parse(iso8601TimeFormat, tm)
|
|
|
|
if err != nil {
|
|
|
|
er = ErrInvalidISO8601
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
fieldValue.Set(reflect.ValueOf(t))
|
|
|
|
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2015-09-10 18:55:51 -04:00
|
|
|
var at int64
|
2015-07-06 17:35:17 -04:00
|
|
|
|
2015-09-10 18:55:51 -04:00
|
|
|
if v.Kind() == reflect.Float64 {
|
|
|
|
at = int64(v.Interface().(float64))
|
|
|
|
} else if v.Kind() == reflect.Int {
|
|
|
|
at = v.Int()
|
|
|
|
} else {
|
2016-01-05 16:13:24 -05:00
|
|
|
er = ErrInvalidTime
|
|
|
|
break
|
2015-07-10 11:20:49 -04:00
|
|
|
}
|
2015-07-06 16:40:43 -04:00
|
|
|
|
2015-09-10 18:55:51 -04:00
|
|
|
t := time.Unix(at, 0)
|
2015-07-07 18:46:20 -04:00
|
|
|
|
2015-09-10 18:55:51 -04:00
|
|
|
fieldValue.Set(reflect.ValueOf(t))
|
|
|
|
|
2016-01-05 16:13:24 -05:00
|
|
|
continue
|
2015-09-10 18:55:51 -04:00
|
|
|
}
|
2015-07-07 18:46:20 -04:00
|
|
|
|
2015-10-28 13:08:50 -04:00
|
|
|
if fieldValue.Type() == reflect.TypeOf([]string(nil)) {
|
|
|
|
values := make([]string, v.Len())
|
|
|
|
for i := 0; i < v.Len(); i++ {
|
|
|
|
values[i] = v.Index(i).Interface().(string)
|
|
|
|
}
|
|
|
|
|
|
|
|
fieldValue.Set(reflect.ValueOf(values))
|
|
|
|
|
2016-01-05 16:13:24 -05:00
|
|
|
continue
|
2015-10-28 13:08:50 -04:00
|
|
|
}
|
|
|
|
|
2015-10-13 12:10:10 -04:00
|
|
|
if fieldValue.Type() == reflect.TypeOf(new(time.Time)) {
|
2016-09-22 16:58:07 -04:00
|
|
|
if iso8601 {
|
|
|
|
var tm string
|
|
|
|
if v.Kind() == reflect.String {
|
|
|
|
tm = v.Interface().(string)
|
|
|
|
} else {
|
|
|
|
er = ErrInvalidISO8601
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
v, err := time.Parse(iso8601TimeFormat, tm)
|
|
|
|
if err != nil {
|
|
|
|
er = ErrInvalidISO8601
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
t := &v
|
|
|
|
|
|
|
|
fieldValue.Set(reflect.ValueOf(t))
|
|
|
|
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2015-10-13 12:10:10 -04:00
|
|
|
var at int64
|
|
|
|
|
|
|
|
if v.Kind() == reflect.Float64 {
|
|
|
|
at = int64(v.Interface().(float64))
|
|
|
|
} else if v.Kind() == reflect.Int {
|
|
|
|
at = v.Int()
|
|
|
|
} else {
|
2016-01-05 16:13:24 -05:00
|
|
|
er = ErrInvalidTime
|
|
|
|
break
|
2015-10-13 12:10:10 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
v := time.Unix(at, 0)
|
|
|
|
t := &v
|
|
|
|
|
|
|
|
fieldValue.Set(reflect.ValueOf(t))
|
|
|
|
|
2016-01-05 16:13:24 -05:00
|
|
|
continue
|
2015-10-13 12:10:10 -04:00
|
|
|
}
|
|
|
|
|
2016-07-22 21:34:38 -04:00
|
|
|
// JSON value was a float (numeric)
|
2016-01-12 13:00:18 -05:00
|
|
|
if v.Kind() == reflect.Float64 {
|
|
|
|
floatValue := v.Interface().(float64)
|
|
|
|
|
|
|
|
// The field may or may not be a pointer to a numeric; the kind var
|
|
|
|
// will not contain a pointer type
|
|
|
|
var kind reflect.Kind
|
|
|
|
if fieldValue.Kind() == reflect.Ptr {
|
|
|
|
kind = fieldType.Type.Elem().Kind()
|
|
|
|
} else {
|
|
|
|
kind = fieldType.Type.Kind()
|
|
|
|
}
|
|
|
|
|
|
|
|
var numericValue reflect.Value
|
|
|
|
|
|
|
|
switch kind {
|
|
|
|
case reflect.Int:
|
|
|
|
n := int(floatValue)
|
|
|
|
numericValue = reflect.ValueOf(&n)
|
|
|
|
case reflect.Int8:
|
|
|
|
n := int8(floatValue)
|
|
|
|
numericValue = reflect.ValueOf(&n)
|
|
|
|
case reflect.Int16:
|
|
|
|
n := int16(floatValue)
|
|
|
|
numericValue = reflect.ValueOf(&n)
|
|
|
|
case reflect.Int32:
|
|
|
|
n := int32(floatValue)
|
|
|
|
numericValue = reflect.ValueOf(&n)
|
|
|
|
case reflect.Int64:
|
|
|
|
n := int64(floatValue)
|
|
|
|
numericValue = reflect.ValueOf(&n)
|
|
|
|
case reflect.Uint:
|
|
|
|
n := uint(floatValue)
|
|
|
|
numericValue = reflect.ValueOf(&n)
|
|
|
|
case reflect.Uint8:
|
|
|
|
n := uint8(floatValue)
|
|
|
|
numericValue = reflect.ValueOf(&n)
|
|
|
|
case reflect.Uint16:
|
|
|
|
n := uint16(floatValue)
|
|
|
|
numericValue = reflect.ValueOf(&n)
|
|
|
|
case reflect.Uint32:
|
|
|
|
n := uint32(floatValue)
|
|
|
|
numericValue = reflect.ValueOf(&n)
|
|
|
|
case reflect.Uint64:
|
|
|
|
n := uint64(floatValue)
|
|
|
|
numericValue = reflect.ValueOf(&n)
|
|
|
|
case reflect.Float32:
|
|
|
|
n := float32(floatValue)
|
|
|
|
numericValue = reflect.ValueOf(&n)
|
|
|
|
case reflect.Float64:
|
|
|
|
n := float64(floatValue)
|
|
|
|
numericValue = reflect.ValueOf(&n)
|
|
|
|
default:
|
2016-07-22 21:34:38 -04:00
|
|
|
// We had a JSON float (numeric), but our field was a non numeric
|
|
|
|
// type
|
2016-01-12 13:00:18 -05:00
|
|
|
er = ErrUnknownFieldNumberType
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
if fieldValue.Kind() == reflect.Ptr {
|
|
|
|
fieldValue.Set(numericValue)
|
|
|
|
} else {
|
|
|
|
fieldValue.Set(reflect.Indirect(numericValue))
|
|
|
|
}
|
|
|
|
|
|
|
|
continue
|
2015-09-10 18:55:51 -04:00
|
|
|
}
|
2016-07-22 21:34:38 -04:00
|
|
|
|
|
|
|
// Field was a Pointer type
|
|
|
|
if fieldValue.Kind() == reflect.Ptr {
|
|
|
|
var concreteVal reflect.Value
|
|
|
|
|
|
|
|
switch cVal := val.(type) {
|
|
|
|
case string:
|
|
|
|
concreteVal = reflect.ValueOf(&cVal)
|
|
|
|
case bool:
|
|
|
|
concreteVal = reflect.ValueOf(&cVal)
|
|
|
|
case complex64:
|
|
|
|
concreteVal = reflect.ValueOf(&cVal)
|
|
|
|
case complex128:
|
|
|
|
concreteVal = reflect.ValueOf(&cVal)
|
|
|
|
case uintptr:
|
|
|
|
concreteVal = reflect.ValueOf(&cVal)
|
|
|
|
default:
|
|
|
|
er = ErrUnsupportedPtrType
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
if fieldValue.Type() != concreteVal.Type() {
|
|
|
|
// TODO: use fmt.Errorf so that you can have a more informative
|
|
|
|
// message that reports the attempted type that was not supported.
|
|
|
|
er = ErrUnsupportedPtrType
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
fieldValue.Set(concreteVal)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2016-01-12 13:00:18 -05:00
|
|
|
fieldValue.Set(reflect.ValueOf(val))
|
2016-07-22 21:34:38 -04:00
|
|
|
|
2015-09-10 18:55:51 -04:00
|
|
|
} else if annotation == "relation" {
|
|
|
|
isSlice := fieldValue.Type().Kind() == reflect.Slice
|
2015-07-07 18:46:20 -04:00
|
|
|
|
2015-09-10 18:55:51 -04:00
|
|
|
if data.Relationships == nil || data.Relationships[args[1]] == nil {
|
2016-01-05 16:13:24 -05:00
|
|
|
continue
|
2015-09-10 18:55:51 -04:00
|
|
|
}
|
2015-07-07 18:46:20 -04:00
|
|
|
|
2015-09-10 18:55:51 -04:00
|
|
|
if isSlice {
|
2015-09-17 18:55:53 -04:00
|
|
|
relationship := new(RelationshipManyNode)
|
|
|
|
|
|
|
|
buf := bytes.NewBuffer(nil)
|
|
|
|
|
|
|
|
json.NewEncoder(buf).Encode(data.Relationships[args[1]])
|
|
|
|
json.NewDecoder(buf).Decode(relationship)
|
|
|
|
|
|
|
|
data := relationship.Data
|
2015-09-10 18:55:51 -04:00
|
|
|
models := reflect.New(fieldValue.Type()).Elem()
|
2015-07-10 11:30:59 -04:00
|
|
|
|
2015-09-17 18:55:53 -04:00
|
|
|
for _, n := range data {
|
2015-09-10 18:55:51 -04:00
|
|
|
m := reflect.New(fieldValue.Type().Elem().Elem())
|
2015-07-07 18:46:20 -04:00
|
|
|
|
2016-07-22 21:34:38 -04:00
|
|
|
if err := unmarshalNode(
|
|
|
|
fullNode(n, included),
|
|
|
|
m,
|
|
|
|
included,
|
|
|
|
); err != nil {
|
2015-07-07 18:46:20 -04:00
|
|
|
er = err
|
2016-01-05 16:13:24 -05:00
|
|
|
break
|
2015-07-07 18:46:20 -04:00
|
|
|
}
|
|
|
|
|
2015-09-10 18:55:51 -04:00
|
|
|
models = reflect.Append(models, m)
|
2015-07-07 18:46:20 -04:00
|
|
|
}
|
|
|
|
|
2015-09-10 18:55:51 -04:00
|
|
|
fieldValue.Set(models)
|
2015-07-07 18:46:20 -04:00
|
|
|
} else {
|
2015-09-17 18:55:53 -04:00
|
|
|
relationship := new(RelationshipOneNode)
|
|
|
|
|
|
|
|
buf := bytes.NewBuffer(nil)
|
|
|
|
|
2016-07-22 21:34:38 -04:00
|
|
|
json.NewEncoder(buf).Encode(
|
|
|
|
data.Relationships[args[1]],
|
|
|
|
)
|
2015-09-17 18:55:53 -04:00
|
|
|
json.NewDecoder(buf).Decode(relationship)
|
|
|
|
|
2015-09-10 18:55:51 -04:00
|
|
|
m := reflect.New(fieldValue.Type().Elem())
|
2015-09-17 18:55:53 -04:00
|
|
|
|
2016-07-22 21:34:38 -04:00
|
|
|
if err := unmarshalNode(
|
|
|
|
fullNode(relationship.Data, included),
|
|
|
|
m,
|
|
|
|
included,
|
|
|
|
); err != nil {
|
2015-09-10 18:55:51 -04:00
|
|
|
er = err
|
2016-01-05 16:13:24 -05:00
|
|
|
break
|
2015-09-10 18:55:51 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
fieldValue.Set(m)
|
2015-07-06 16:40:43 -04:00
|
|
|
}
|
2015-09-10 18:55:51 -04:00
|
|
|
|
|
|
|
} else {
|
2016-01-05 16:13:24 -05:00
|
|
|
er = fmt.Errorf(unsuportedStructTagMsg, annotation)
|
2015-07-06 16:40:43 -04:00
|
|
|
}
|
2016-01-05 16:13:24 -05:00
|
|
|
}
|
2015-07-06 16:40:43 -04:00
|
|
|
|
|
|
|
if er != nil {
|
|
|
|
return er
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2015-07-07 18:46:20 -04:00
|
|
|
|
2015-09-17 18:55:53 -04:00
|
|
|
func fullNode(n *Node, included *map[string]*Node) *Node {
|
2016-07-05 21:32:15 -04:00
|
|
|
includedKey := fmt.Sprintf("%s,%s", n.Type, n.ID)
|
2015-07-07 18:46:20 -04:00
|
|
|
|
2015-09-17 18:55:53 -04:00
|
|
|
if included != nil && (*included)[includedKey] != nil {
|
|
|
|
return (*included)[includedKey]
|
2015-07-07 18:46:20 -04:00
|
|
|
}
|
|
|
|
|
2015-09-17 18:55:53 -04:00
|
|
|
return n
|
2015-07-07 18:46:20 -04:00
|
|
|
}
|