forked from Mirrors/jsonapi
Merge pull request #5 from Slemgrim/refactor-ptr-error
Refactor ptr error and cleanup
This commit is contained in:
commit
8b7e0bc2c0
104
request.go
104
request.go
|
@ -29,22 +29,33 @@ var (
|
||||||
ErrUnknownFieldNumberType = errors.New("The struct field was not of a known number type")
|
ErrUnknownFieldNumberType = errors.New("The struct field was not of a known number type")
|
||||||
// ErrInvalidType is returned when the given type is incompatible with the expected type.
|
// ErrInvalidType is returned when the given type is incompatible with the expected type.
|
||||||
ErrInvalidType = errors.New("Invalid type provided") // I wish we used punctuation.
|
ErrInvalidType = errors.New("Invalid type provided") // I wish we used punctuation.
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ErrUnsupportedPtrType is returned when the Struct field was a pointer but
|
// ErrUnsupportedPtrType is returned when the Struct field was a pointer but
|
||||||
// the JSON value was of a different type
|
// the JSON value was of a different type
|
||||||
func ErrUnsupportedPtrType(rf reflect.Value, t reflect.Type, structField reflect.StructField) error {
|
type ErrUnsupportedPtrType struct {
|
||||||
typeName := t.Elem().Name()
|
rf reflect.Value
|
||||||
kind := t.Elem().Kind()
|
t reflect.Type
|
||||||
|
structField reflect.StructField
|
||||||
|
}
|
||||||
|
|
||||||
|
func (eupt ErrUnsupportedPtrType) Error() string {
|
||||||
|
typeName := eupt.t.Elem().Name()
|
||||||
|
kind := eupt.t.Elem().Kind()
|
||||||
if kind.String() != "" && kind.String() != typeName {
|
if kind.String() != "" && kind.String() != typeName {
|
||||||
typeName = fmt.Sprintf("%s (%s)", typeName, kind.String())
|
typeName = fmt.Sprintf("%s (%s)", typeName, kind.String())
|
||||||
}
|
}
|
||||||
return fmt.Errorf(
|
return fmt.Sprintf(
|
||||||
"jsonapi: Can't unmarshal %+v (%s) to struct field `%s`, which is a pointer to `%s`",
|
"jsonapi: Can't unmarshal %+v (%s) to struct field `%s`, which is a pointer to `%s`",
|
||||||
rf, rf.Type().Kind(), structField.Name, typeName,
|
eupt.rf, eupt.rf.Type().Kind(), eupt.structField.Name, typeName,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newErrUnsupportedPtrType(rf reflect.Value, t reflect.Type, structField reflect.StructField) error {
|
||||||
|
return ErrUnsupportedPtrType{rf, t, structField}
|
||||||
|
}
|
||||||
|
|
||||||
// UnmarshalPayload converts an io into a struct instance using jsonapi tags on
|
// UnmarshalPayload converts an io into a struct instance using jsonapi tags on
|
||||||
// struct fields. This method supports single request payloads only, at the
|
// struct fields. This method supports single request payloads only, at the
|
||||||
// moment. Bulk creates and updates are not supported yet.
|
// moment. Bulk creates and updates are not supported yet.
|
||||||
|
@ -129,7 +140,6 @@ func UnmarshalManyPayload(in io.Reader, t reflect.Type) ([]interface{}, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func unmarshalNode(data *Node, model reflect.Value, included *map[string]*Node) (err error) {
|
func unmarshalNode(data *Node, model reflect.Value, included *map[string]*Node) (err error) {
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
err = fmt.Errorf("data is not a jsonapi representation of '%v'", model.Type())
|
err = fmt.Errorf("data is not a jsonapi representation of '%v'", model.Type())
|
||||||
|
@ -375,8 +385,11 @@ func assign(field, value reflect.Value) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func unmarshalAttribute(attribute interface{}, args []string, structField reflect.StructField, fieldValue reflect.Value) (value reflect.Value, err error) {
|
func unmarshalAttribute(
|
||||||
|
attribute interface{},
|
||||||
|
args []string,
|
||||||
|
structField reflect.StructField,
|
||||||
|
fieldValue reflect.Value) (value reflect.Value, err error) {
|
||||||
value = reflect.ValueOf(attribute)
|
value = reflect.ValueOf(attribute)
|
||||||
fieldType := structField.Type
|
fieldType := structField.Type
|
||||||
|
|
||||||
|
@ -387,7 +400,8 @@ func unmarshalAttribute(attribute interface{}, args []string, structField reflec
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle field of type time.Time
|
// Handle field of type time.Time
|
||||||
if fieldValue.Type() == reflect.TypeOf(time.Time{}) || fieldValue.Type() == reflect.TypeOf(new(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, fieldType, fieldValue)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -399,7 +413,8 @@ func unmarshalAttribute(attribute interface{}, args []string, structField reflec
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle field containing slice of structs
|
// Handle field containing slice of structs
|
||||||
if fieldValue.Type().Kind() == reflect.Slice && reflect.TypeOf(fieldValue.Interface()).Elem().Kind() == reflect.Struct {
|
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, args, fieldType, fieldValue)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -425,7 +440,11 @@ func unmarshalAttribute(attribute interface{}, args []string, structField reflec
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleStringSlice(attribute interface{}, args []string, fieldType reflect.Type, fieldValue reflect.Value) (reflect.Value, error) {
|
func handleStringSlice(
|
||||||
|
attribute interface{},
|
||||||
|
args []string,
|
||||||
|
fieldType reflect.Type,
|
||||||
|
fieldValue reflect.Value) (reflect.Value, error) {
|
||||||
v := reflect.ValueOf(attribute)
|
v := reflect.ValueOf(attribute)
|
||||||
values := make([]string, v.Len())
|
values := make([]string, v.Len())
|
||||||
for i := 0; i < v.Len(); i++ {
|
for i := 0; i < v.Len(); i++ {
|
||||||
|
@ -435,8 +454,11 @@ func handleStringSlice(attribute interface{}, args []string, fieldType reflect.T
|
||||||
return reflect.ValueOf(values), nil
|
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,
|
||||||
|
fieldType reflect.Type,
|
||||||
|
fieldValue reflect.Value) (reflect.Value, error) {
|
||||||
var isIso8601 bool
|
var isIso8601 bool
|
||||||
v := reflect.ValueOf(attribute)
|
v := reflect.ValueOf(attribute)
|
||||||
|
|
||||||
|
@ -483,7 +505,11 @@ func handleTime(attribute interface{}, args []string, fieldType reflect.Type, fi
|
||||||
return reflect.ValueOf(t), nil
|
return reflect.ValueOf(t), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleNumeric(attribute interface{}, args []string, fieldType reflect.Type, fieldValue reflect.Value) (reflect.Value, error) {
|
func handleNumeric(
|
||||||
|
attribute interface{},
|
||||||
|
args []string,
|
||||||
|
fieldType reflect.Type,
|
||||||
|
fieldValue reflect.Value) (reflect.Value, error) {
|
||||||
v := reflect.ValueOf(attribute)
|
v := reflect.ValueOf(attribute)
|
||||||
floatValue := v.Interface().(float64)
|
floatValue := v.Interface().(float64)
|
||||||
|
|
||||||
|
@ -540,7 +566,12 @@ func handleNumeric(attribute interface{}, args []string, fieldType reflect.Type,
|
||||||
return numericValue, nil
|
return numericValue, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func handlePointer(attribute interface{}, args []string, fieldType reflect.Type, fieldValue reflect.Value, structField reflect.StructField) (reflect.Value, error) {
|
func handlePointer(
|
||||||
|
attribute interface{},
|
||||||
|
args []string,
|
||||||
|
fieldType reflect.Type,
|
||||||
|
fieldValue reflect.Value,
|
||||||
|
structField reflect.StructField) (reflect.Value, error) {
|
||||||
t := fieldValue.Type()
|
t := fieldValue.Type()
|
||||||
var concreteVal reflect.Value
|
var concreteVal reflect.Value
|
||||||
|
|
||||||
|
@ -549,50 +580,55 @@ func handlePointer(attribute interface{}, args []string, fieldType reflect.Type,
|
||||||
concreteVal = reflect.ValueOf(&cVal)
|
concreteVal = reflect.ValueOf(&cVal)
|
||||||
case bool:
|
case bool:
|
||||||
concreteVal = reflect.ValueOf(&cVal)
|
concreteVal = reflect.ValueOf(&cVal)
|
||||||
case complex64:
|
case complex64, complex128, uintptr:
|
||||||
concreteVal = reflect.ValueOf(&cVal)
|
|
||||||
case complex128:
|
|
||||||
concreteVal = reflect.ValueOf(&cVal)
|
|
||||||
case uintptr:
|
|
||||||
concreteVal = reflect.ValueOf(&cVal)
|
concreteVal = reflect.ValueOf(&cVal)
|
||||||
case map[string]interface{}:
|
case map[string]interface{}:
|
||||||
var err error
|
var err error
|
||||||
concreteVal, err = handleStruct(attribute, args, fieldType, fieldValue)
|
concreteVal, err = handleStruct(attribute, args, fieldType, fieldValue)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return reflect.Value{}, ErrUnsupportedPtrType(reflect.ValueOf(attribute), fieldType, structField)
|
return reflect.Value{}, newErrUnsupportedPtrType(
|
||||||
|
reflect.ValueOf(attribute), fieldType, structField)
|
||||||
}
|
}
|
||||||
return concreteVal.Elem(), err
|
return concreteVal.Elem(), err
|
||||||
default:
|
default:
|
||||||
return reflect.Value{}, ErrUnsupportedPtrType(reflect.ValueOf(attribute), fieldType, structField)
|
return reflect.Value{}, newErrUnsupportedPtrType(
|
||||||
|
reflect.ValueOf(attribute), fieldType, structField)
|
||||||
}
|
}
|
||||||
|
|
||||||
if t != concreteVal.Type() {
|
if t != concreteVal.Type() {
|
||||||
return reflect.Value{}, ErrUnsupportedPtrType(reflect.ValueOf(attribute), fieldType, structField)
|
return reflect.Value{}, newErrUnsupportedPtrType(
|
||||||
|
reflect.ValueOf(attribute), fieldType, structField)
|
||||||
}
|
}
|
||||||
|
|
||||||
return concreteVal, nil
|
return concreteVal, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleStruct(attribute interface{}, args []string, fieldType reflect.Type, fieldValue reflect.Value) (reflect.Value, error) {
|
func handleStruct(
|
||||||
|
attribute interface{},
|
||||||
|
args []string,
|
||||||
|
fieldType reflect.Type,
|
||||||
|
fieldValue reflect.Value) (reflect.Value, error) {
|
||||||
model := reflect.New(fieldValue.Type())
|
model := reflect.New(fieldValue.Type())
|
||||||
|
|
||||||
var er error
|
data, err := json.Marshal(attribute)
|
||||||
|
if err != nil {
|
||||||
data, er := json.Marshal(attribute)
|
return model, err
|
||||||
if er != nil {
|
|
||||||
return model, er
|
|
||||||
}
|
}
|
||||||
|
|
||||||
er = json.Unmarshal(data, model.Interface())
|
err = json.Unmarshal(data, model.Interface())
|
||||||
|
|
||||||
if er != nil {
|
if err != nil {
|
||||||
return model, er
|
return model, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return model, er
|
return model, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleStructSlice(attribute interface{}, args []string, fieldType reflect.Type, fieldValue reflect.Value) (reflect.Value, error) {
|
func handleStructSlice(
|
||||||
|
attribute interface{},
|
||||||
|
args []string,
|
||||||
|
fieldType reflect.Type,
|
||||||
|
fieldValue reflect.Value) (reflect.Value, error) {
|
||||||
models := reflect.New(fieldValue.Type()).Elem()
|
models := reflect.New(fieldValue.Type()).Elem()
|
||||||
dataMap := reflect.ValueOf(attribute).Interface().([]interface{})
|
dataMap := reflect.ValueOf(attribute).Interface().([]interface{})
|
||||||
for _, data := range dataMap {
|
for _, data := range dataMap {
|
||||||
|
|
|
@ -136,6 +136,9 @@ func TestUnmarshalToStructWithPointerAttr_BadType_bool(t *testing.T) {
|
||||||
if err.Error() != expectedErrorMessage {
|
if err.Error() != expectedErrorMessage {
|
||||||
t.Fatalf("Unexpected error message: %s", err.Error())
|
t.Fatalf("Unexpected error message: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
if _, ok := err.(ErrUnsupportedPtrType); !ok {
|
||||||
|
t.Fatalf("Unexpected error type: %s", reflect.TypeOf(err))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUnmarshalToStructWithPointerAttr_BadType_MapPtr(t *testing.T) {
|
func TestUnmarshalToStructWithPointerAttr_BadType_MapPtr(t *testing.T) {
|
||||||
|
@ -153,6 +156,9 @@ func TestUnmarshalToStructWithPointerAttr_BadType_MapPtr(t *testing.T) {
|
||||||
if err.Error() != expectedErrorMessage {
|
if err.Error() != expectedErrorMessage {
|
||||||
t.Fatalf("Unexpected error message: %s", err.Error())
|
t.Fatalf("Unexpected error message: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
if _, ok := err.(ErrUnsupportedPtrType); !ok {
|
||||||
|
t.Fatalf("Unexpected error type: %s", reflect.TypeOf(err))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUnmarshalToStructWithPointerAttr_BadType_Struct(t *testing.T) {
|
func TestUnmarshalToStructWithPointerAttr_BadType_Struct(t *testing.T) {
|
||||||
|
@ -171,6 +177,9 @@ func TestUnmarshalToStructWithPointerAttr_BadType_Struct(t *testing.T) {
|
||||||
if err.Error() != expectedErrorMessage {
|
if err.Error() != expectedErrorMessage {
|
||||||
t.Fatalf("Unexpected error message: %s", err.Error())
|
t.Fatalf("Unexpected error message: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
if _, ok := err.(ErrUnsupportedPtrType); !ok {
|
||||||
|
t.Fatalf("Unexpected error type: %s", reflect.TypeOf(err))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUnmarshalToStructWithPointerAttr_BadType_IntSlice(t *testing.T) {
|
func TestUnmarshalToStructWithPointerAttr_BadType_IntSlice(t *testing.T) {
|
||||||
|
@ -189,6 +198,9 @@ func TestUnmarshalToStructWithPointerAttr_BadType_IntSlice(t *testing.T) {
|
||||||
if err.Error() != expectedErrorMessage {
|
if err.Error() != expectedErrorMessage {
|
||||||
t.Fatalf("Unexpected error message: %s", err.Error())
|
t.Fatalf("Unexpected error message: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
if _, ok := err.(ErrUnsupportedPtrType); !ok {
|
||||||
|
t.Fatalf("Unexpected error type: %s", reflect.TypeOf(err))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestStringPointerField(t *testing.T) {
|
func TestStringPointerField(t *testing.T) {
|
||||||
|
|
Loading…
Reference in New Issue