forked from Mirrors/jsonapi
Merge pull request #6 from shwoodard/shwoodard-slemgrim-pull-99
Use jsonapi struct tags for nested attrs
This commit is contained in:
commit
417d4eb8fb
|
@ -165,14 +165,14 @@ type Company struct {
|
|||
}
|
||||
|
||||
type Team struct {
|
||||
Name string `json:"name"`
|
||||
Leader *Employee `json:"leader"`
|
||||
Members []Employee `json:"members"`
|
||||
Name string `jsonapi:"attr,name"`
|
||||
Leader *Employee `jsonapi:"attr,leader"`
|
||||
Members []Employee `jsonapi:"attr,members"`
|
||||
}
|
||||
|
||||
type Employee struct {
|
||||
Firstname string `json:"firstname"`
|
||||
Surname string `json:"surname"`
|
||||
Age int `json:"age"`
|
||||
HiredAt *time.Time `json:"hired-at,iso8601"`
|
||||
Firstname string `jsonapi:"attr,firstname"`
|
||||
Surname string `jsonapi:"attr,surname"`
|
||||
Age int `jsonapi:"attr,age"`
|
||||
HiredAt *time.Time `jsonapi:"attr,hired-at,iso8601"`
|
||||
}
|
||||
|
|
99
request.go
99
request.go
|
@ -13,7 +13,7 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
unsuportedStructTagMsg = "Unsupported jsonapi tag annotation, %s"
|
||||
unsupportedStructTagMsg = "Unsupported jsonapi tag annotation, %s"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -147,7 +147,7 @@ func unmarshalNode(data *Node, model reflect.Value, included *map[string]*Node)
|
|||
}()
|
||||
|
||||
modelValue := model.Elem()
|
||||
modelType := model.Type().Elem()
|
||||
modelType := modelValue.Type()
|
||||
|
||||
var er error
|
||||
|
||||
|
@ -217,39 +217,8 @@ func unmarshalNode(data *Node, model reflect.Value, included *map[string]*Node)
|
|||
|
||||
// Convert the numeric float to one of the supported ID numeric types
|
||||
// (int[8,16,32,64] or uint[8,16,32,64])
|
||||
var idValue reflect.Value
|
||||
switch kind {
|
||||
case reflect.Int:
|
||||
n := int(floatValue)
|
||||
idValue = reflect.ValueOf(&n)
|
||||
case reflect.Int8:
|
||||
n := int8(floatValue)
|
||||
idValue = reflect.ValueOf(&n)
|
||||
case reflect.Int16:
|
||||
n := int16(floatValue)
|
||||
idValue = reflect.ValueOf(&n)
|
||||
case reflect.Int32:
|
||||
n := int32(floatValue)
|
||||
idValue = reflect.ValueOf(&n)
|
||||
case reflect.Int64:
|
||||
n := int64(floatValue)
|
||||
idValue = reflect.ValueOf(&n)
|
||||
case reflect.Uint:
|
||||
n := uint(floatValue)
|
||||
idValue = reflect.ValueOf(&n)
|
||||
case reflect.Uint8:
|
||||
n := uint8(floatValue)
|
||||
idValue = reflect.ValueOf(&n)
|
||||
case reflect.Uint16:
|
||||
n := uint16(floatValue)
|
||||
idValue = reflect.ValueOf(&n)
|
||||
case reflect.Uint32:
|
||||
n := uint32(floatValue)
|
||||
idValue = reflect.ValueOf(&n)
|
||||
case reflect.Uint64:
|
||||
n := uint64(floatValue)
|
||||
idValue = reflect.ValueOf(&n)
|
||||
default:
|
||||
idValue, err := handleNumeric(floatValue, fieldType.Type, fieldValue)
|
||||
if err != nil {
|
||||
// We had a JSON float (numeric), but our field was not one of the
|
||||
// allowed numeric types
|
||||
er = ErrBadJSONAPIID
|
||||
|
@ -358,7 +327,7 @@ func unmarshalNode(data *Node, model reflect.Value, included *map[string]*Node)
|
|||
}
|
||||
|
||||
} else {
|
||||
er = fmt.Errorf(unsuportedStructTagMsg, annotation)
|
||||
er = fmt.Errorf(unsupportedStructTagMsg, annotation)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -395,33 +364,33 @@ func unmarshalAttribute(
|
|||
|
||||
// Handle field of type []string
|
||||
if fieldValue.Type() == reflect.TypeOf([]string{}) {
|
||||
value, err = handleStringSlice(attribute, args, fieldType, fieldValue)
|
||||
value, err = handleStringSlice(attribute)
|
||||
return
|
||||
}
|
||||
|
||||
// Handle field of type time.Time
|
||||
if fieldValue.Type() == reflect.TypeOf(time.Time{}) ||
|
||||
fieldValue.Type() == reflect.TypeOf(new(time.Time)) {
|
||||
value, err = handleTime(attribute, args, fieldType, fieldValue)
|
||||
value, err = handleTime(attribute, args, fieldValue)
|
||||
return
|
||||
}
|
||||
|
||||
// Handle field of type struct
|
||||
if fieldValue.Type().Kind() == reflect.Struct {
|
||||
value, err = handleStruct(attribute, args, fieldType, fieldValue)
|
||||
value, err = handleStruct(attribute, fieldValue)
|
||||
return
|
||||
}
|
||||
|
||||
// Handle field containing slice of structs
|
||||
if fieldValue.Type().Kind() == reflect.Slice &&
|
||||
reflect.TypeOf(fieldValue.Interface()).Elem().Kind() == reflect.Struct {
|
||||
value, err = handleStructSlice(attribute, args, fieldType, fieldValue)
|
||||
value, err = handleStructSlice(attribute, fieldValue)
|
||||
return
|
||||
}
|
||||
|
||||
// JSON value was a float (numeric)
|
||||
if value.Kind() == reflect.Float64 {
|
||||
value, err = handleNumeric(attribute, args, fieldType, fieldValue)
|
||||
value, err = handleNumeric(attribute, fieldType, fieldValue)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -440,11 +409,7 @@ func unmarshalAttribute(
|
|||
return
|
||||
}
|
||||
|
||||
func handleStringSlice(
|
||||
attribute interface{},
|
||||
args []string,
|
||||
fieldType reflect.Type,
|
||||
fieldValue reflect.Value) (reflect.Value, error) {
|
||||
func handleStringSlice(attribute interface{}) (reflect.Value, error) {
|
||||
v := reflect.ValueOf(attribute)
|
||||
values := make([]string, v.Len())
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
|
@ -454,11 +419,7 @@ func handleStringSlice(
|
|||
return reflect.ValueOf(values), nil
|
||||
}
|
||||
|
||||
func handleTime(
|
||||
attribute interface{},
|
||||
args []string,
|
||||
fieldType reflect.Type,
|
||||
fieldValue reflect.Value) (reflect.Value, error) {
|
||||
func handleTime(attribute interface{}, args []string, fieldValue reflect.Value) (reflect.Value, error) {
|
||||
var isIso8601 bool
|
||||
v := reflect.ValueOf(attribute)
|
||||
|
||||
|
@ -507,7 +468,6 @@ func handleTime(
|
|||
|
||||
func handleNumeric(
|
||||
attribute interface{},
|
||||
args []string,
|
||||
fieldType reflect.Type,
|
||||
fieldValue reflect.Value) (reflect.Value, error) {
|
||||
v := reflect.ValueOf(attribute)
|
||||
|
@ -584,12 +544,12 @@ func handlePointer(
|
|||
concreteVal = reflect.ValueOf(&cVal)
|
||||
case map[string]interface{}:
|
||||
var err error
|
||||
concreteVal, err = handleStruct(attribute, args, fieldType, fieldValue)
|
||||
concreteVal, err = handleStruct(attribute, fieldValue)
|
||||
if err != nil {
|
||||
return reflect.Value{}, newErrUnsupportedPtrType(
|
||||
reflect.ValueOf(attribute), fieldType, structField)
|
||||
}
|
||||
return concreteVal.Elem(), err
|
||||
return concreteVal, err
|
||||
default:
|
||||
return reflect.Value{}, newErrUnsupportedPtrType(
|
||||
reflect.ValueOf(attribute), fieldType, structField)
|
||||
|
@ -605,37 +565,42 @@ func handlePointer(
|
|||
|
||||
func handleStruct(
|
||||
attribute interface{},
|
||||
args []string,
|
||||
fieldType reflect.Type,
|
||||
fieldValue reflect.Value) (reflect.Value, error) {
|
||||
model := reflect.New(fieldValue.Type())
|
||||
|
||||
data, err := json.Marshal(attribute)
|
||||
if err != nil {
|
||||
return model, err
|
||||
return reflect.Value{}, err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(data, model.Interface())
|
||||
|
||||
if err != nil {
|
||||
return model, err
|
||||
node := new(Node)
|
||||
if err := json.Unmarshal(data, &node.Attributes); err != nil {
|
||||
return reflect.Value{}, err
|
||||
}
|
||||
|
||||
return model, err
|
||||
var model reflect.Value
|
||||
if fieldValue.Kind() == reflect.Ptr {
|
||||
model = reflect.New(fieldValue.Type().Elem())
|
||||
} else {
|
||||
model = reflect.New(fieldValue.Type())
|
||||
}
|
||||
|
||||
if err := unmarshalNode(node, model, nil); err != nil {
|
||||
return reflect.Value{}, err
|
||||
}
|
||||
|
||||
|
||||
return model, nil
|
||||
}
|
||||
|
||||
func handleStructSlice(
|
||||
attribute interface{},
|
||||
args []string,
|
||||
fieldType reflect.Type,
|
||||
fieldValue reflect.Value) (reflect.Value, error) {
|
||||
models := reflect.New(fieldValue.Type()).Elem()
|
||||
dataMap := reflect.ValueOf(attribute).Interface().([]interface{})
|
||||
for _, data := range dataMap {
|
||||
model := reflect.New(fieldValue.Type().Elem()).Elem()
|
||||
modelType := model.Type()
|
||||
|
||||
value, err := handleStruct(data, []string{}, modelType, model)
|
||||
value, err := handleStruct(data, model)
|
||||
|
||||
if err != nil {
|
||||
continue
|
||||
|
|
|
@ -1013,8 +1013,8 @@ func sampleSerializedEmbeddedTestModel() *Blog {
|
|||
|
||||
func TestUnmarshalNestedStructPtr(t *testing.T) {
|
||||
type Director struct {
|
||||
Firstname string `json:"firstname"`
|
||||
Surname string `json:"surname"`
|
||||
Firstname string `jsonapi:"attr,firstname"`
|
||||
Surname string `jsonapi:"attr,surname"`
|
||||
}
|
||||
type Movie struct {
|
||||
ID string `jsonapi:"primary,movies"`
|
||||
|
@ -1058,7 +1058,6 @@ func TestUnmarshalNestedStructPtr(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestUnmarshalNestedStruct(t *testing.T) {
|
||||
|
||||
boss := map[string]interface{}{
|
||||
"firstname": "Hubert",
|
||||
"surname": "Farnsworth",
|
||||
|
@ -1074,22 +1073,22 @@ func TestUnmarshalNestedStruct(t *testing.T) {
|
|||
"name": "Planet Express",
|
||||
"boss": boss,
|
||||
"founded-at": "2016-08-17T08:27:12Z",
|
||||
"teams": []Team{
|
||||
Team{
|
||||
Name: "Dev",
|
||||
Members: []Employee{
|
||||
Employee{Firstname: "Sean"},
|
||||
Employee{Firstname: "Iz"},
|
||||
"teams": []map[string]interface{}{
|
||||
map[string]interface{}{
|
||||
"name": "Dev",
|
||||
"members": []map[string]interface{}{
|
||||
map[string]interface{}{"firstname": "Sean"},
|
||||
map[string]interface{}{"firstname": "Iz"},
|
||||
},
|
||||
Leader: &Employee{Firstname: "Iz"},
|
||||
"leader": map[string]interface{}{"firstname": "Iz"},
|
||||
},
|
||||
Team{
|
||||
Name: "DxE",
|
||||
Members: []Employee{
|
||||
Employee{Firstname: "Akshay"},
|
||||
Employee{Firstname: "Peri"},
|
||||
map[string]interface{}{
|
||||
"name": "DxE",
|
||||
"members": []map[string]interface{}{
|
||||
map[string]interface{}{"firstname": "Akshay"},
|
||||
map[string]interface{}{"firstname": "Peri"},
|
||||
},
|
||||
Leader: &Employee{Firstname: "Peri"},
|
||||
"leader": map[string]interface{}{"firstname": "Peri"},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue