Update field data behavior (#5489)

* Update Get and getPrimitive to correctly handle nil and error values

* Return empty slice on zero length decode result
This commit is contained in:
Calvin Leung Huang 2018-10-15 10:36:13 -07:00 committed by GitHub
parent 8db6aabee1
commit 334e43a646
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -63,8 +63,10 @@ func (d *FieldData) Get(k string) interface{} {
panic(fmt.Sprintf("field %s not in the schema", k)) panic(fmt.Sprintf("field %s not in the schema", k))
} }
// If the value can't be decoded, use the zero or default value for the field
// type
value, ok := d.GetOk(k) value, ok := d.GetOk(k)
if !ok { if !ok || value == nil {
value = schema.DefaultOrZero() value = schema.DefaultOrZero()
} }
@ -96,8 +98,10 @@ func (d *FieldData) GetFirst(k ...string) (interface{}, bool) {
return nil, false return nil, false
} }
// GetOk gets the value for the given field. The second return value // GetOk gets the value for the given field. The second return value will be
// will be false if the key is invalid or the key is not set at all. // false if the key is invalid or the key is not set at all. If the field k is
// set and the decoded value is nil, the default or zero value
// will be returned instead.
func (d *FieldData) GetOk(k string) (interface{}, bool) { func (d *FieldData) GetOk(k string) (interface{}, bool) {
schema, ok := d.Schema[k] schema, ok := d.Schema[k]
if !ok { if !ok {
@ -147,49 +151,49 @@ func (d *FieldData) getPrimitive(k string, schema *FieldSchema) (interface{}, bo
case TypeBool: case TypeBool:
var result bool var result bool
if err := mapstructure.WeakDecode(raw, &result); err != nil { if err := mapstructure.WeakDecode(raw, &result); err != nil {
return nil, true, err return nil, false, err
} }
return result, true, nil return result, true, nil
case TypeInt: case TypeInt:
var result int var result int
if err := mapstructure.WeakDecode(raw, &result); err != nil { if err := mapstructure.WeakDecode(raw, &result); err != nil {
return nil, true, err return nil, false, err
} }
return result, true, nil return result, true, nil
case TypeString: case TypeString:
var result string var result string
if err := mapstructure.WeakDecode(raw, &result); err != nil { if err := mapstructure.WeakDecode(raw, &result); err != nil {
return nil, true, err return nil, false, err
} }
return result, true, nil return result, true, nil
case TypeLowerCaseString: case TypeLowerCaseString:
var result string var result string
if err := mapstructure.WeakDecode(raw, &result); err != nil { if err := mapstructure.WeakDecode(raw, &result); err != nil {
return nil, true, err return nil, false, err
} }
return strings.ToLower(result), true, nil return strings.ToLower(result), true, nil
case TypeNameString: case TypeNameString:
var result string var result string
if err := mapstructure.WeakDecode(raw, &result); err != nil { if err := mapstructure.WeakDecode(raw, &result); err != nil {
return nil, true, err return nil, false, err
} }
matched, err := regexp.MatchString("^\\w(([\\w-.]+)?\\w)?$", result) matched, err := regexp.MatchString("^\\w(([\\w-.]+)?\\w)?$", result)
if err != nil { if err != nil {
return nil, true, err return nil, false, err
} }
if !matched { if !matched {
return nil, true, errors.New("field does not match the formatting rules") return nil, false, errors.New("field does not match the formatting rules")
} }
return result, true, nil return result, true, nil
case TypeMap: case TypeMap:
var result map[string]interface{} var result map[string]interface{}
if err := mapstructure.WeakDecode(raw, &result); err != nil { if err := mapstructure.WeakDecode(raw, &result); err != nil {
return nil, true, err return nil, false, err
} }
return result, true, nil return result, true, nil
@ -217,20 +221,20 @@ func (d *FieldData) getPrimitive(k string, schema *FieldSchema) (interface{}, bo
case string: case string:
dur, err := parseutil.ParseDurationSecond(inp) dur, err := parseutil.ParseDurationSecond(inp)
if err != nil { if err != nil {
return nil, true, err return nil, false, err
} }
result = int(dur.Seconds()) result = int(dur.Seconds())
case json.Number: case json.Number:
valInt64, err := inp.Int64() valInt64, err := inp.Int64()
if err != nil { if err != nil {
return nil, true, err return nil, false, err
} }
result = int(valInt64) result = int(valInt64)
default: default:
return nil, false, fmt.Errorf("invalid input '%v'", raw) return nil, false, fmt.Errorf("invalid input '%v'", raw)
} }
if result < 0 { if result < 0 {
return nil, true, fmt.Errorf("cannot provide negative value '%d'", result) return nil, false, fmt.Errorf("cannot provide negative value '%d'", result)
} }
return result, true, nil return result, true, nil
@ -243,24 +247,33 @@ func (d *FieldData) getPrimitive(k string, schema *FieldSchema) (interface{}, bo
} }
decoder, err := mapstructure.NewDecoder(config) decoder, err := mapstructure.NewDecoder(config)
if err != nil { if err != nil {
return nil, true, err return nil, false, err
} }
if err := decoder.Decode(raw); err != nil { if err := decoder.Decode(raw); err != nil {
return nil, true, err return nil, false, err
}
if len(result) == 0 {
return make([]int, 0), true, nil
} }
return result, true, nil return result, true, nil
case TypeSlice: case TypeSlice:
var result []interface{} var result []interface{}
if err := mapstructure.WeakDecode(raw, &result); err != nil { if err := mapstructure.WeakDecode(raw, &result); err != nil {
return nil, true, err return nil, false, err
}
if len(result) == 0 {
return make([]interface{}, 0), true, nil
} }
return result, true, nil return result, true, nil
case TypeStringSlice: case TypeStringSlice:
var result []string var result []string
if err := mapstructure.WeakDecode(raw, &result); err != nil { if err := mapstructure.WeakDecode(raw, &result); err != nil {
return nil, true, err return nil, false, err
}
if len(result) == 0 {
return make([]string, 0), true, nil
} }
return strutil.TrimStrings(result), true, nil return strutil.TrimStrings(result), true, nil
@ -281,7 +294,7 @@ func (d *FieldData) getPrimitive(k string, schema *FieldSchema) (interface{}, bo
// If map parse fails, parse as a string list of = delimited pairs // If map parse fails, parse as a string list of = delimited pairs
var listResult []string var listResult []string
if err := mapstructure.WeakDecode(raw, &listResult); err != nil { if err := mapstructure.WeakDecode(raw, &listResult); err != nil {
return nil, true, err return nil, false, err
} }
result := make(map[string]string, len(listResult)) result := make(map[string]string, len(listResult))
@ -350,7 +363,7 @@ func (d *FieldData) getPrimitive(k string, schema *FieldSchema) (interface{}, bo
if err := mapstructure.WeakDecode(raw, &resultMap); err == nil { if err := mapstructure.WeakDecode(raw, &resultMap); err == nil {
result, err = toHeader(resultMap) result, err = toHeader(resultMap)
if err != nil { if err != nil {
return nil, true, err return nil, false, err
} }
return result, true, nil return result, true, nil
} }
@ -364,11 +377,11 @@ func (d *FieldData) getPrimitive(k string, schema *FieldSchema) (interface{}, bo
headerBytes = []byte(headerStr) headerBytes = []byte(headerStr)
} }
if err := json.NewDecoder(bytes.NewReader(headerBytes)).Decode(&resultMap); err != nil { if err := json.NewDecoder(bytes.NewReader(headerBytes)).Decode(&resultMap); err != nil {
return nil, true, err return nil, false, err
} }
result, err = toHeader(resultMap) result, err = toHeader(resultMap)
if err != nil { if err != nil {
return nil, true, err return nil, false, err
} }
return result, true, nil return result, true, nil
} }
@ -379,17 +392,17 @@ func (d *FieldData) getPrimitive(k string, schema *FieldSchema) (interface{}, bo
for _, keyPairIfc := range keyPairs { for _, keyPairIfc := range keyPairs {
keyPair, ok := keyPairIfc.(string) keyPair, ok := keyPairIfc.(string)
if !ok { if !ok {
return nil, true, fmt.Errorf("invalid key pair %q", keyPair) return nil, false, fmt.Errorf("invalid key pair %q", keyPair)
} }
keyPairSlice := strings.SplitN(keyPair, ":", 2) keyPairSlice := strings.SplitN(keyPair, ":", 2)
if len(keyPairSlice) != 2 || keyPairSlice[0] == "" { if len(keyPairSlice) != 2 || keyPairSlice[0] == "" {
return nil, true, fmt.Errorf("invalid key pair %q", keyPair) return nil, false, fmt.Errorf("invalid key pair %q", keyPair)
} }
result.Add(keyPairSlice[0], keyPairSlice[1]) result.Add(keyPairSlice[0], keyPairSlice[1])
} }
return result, true, nil return result, true, nil
} }
return nil, true, fmt.Errorf("%s not provided an expected format", raw) return nil, false, fmt.Errorf("%s not provided an expected format", raw)
default: default:
panic(fmt.Sprintf("Unknown type: %s", schema.Type)) panic(fmt.Sprintf("Unknown type: %s", schema.Type))