Skip to content

Commit

Permalink
Unify KeyString and Validate datatype functions as Parse
Browse files Browse the repository at this point in the history
  • Loading branch information
bandreghetti committed Oct 5, 2020
1 parent 2ef6027 commit 6f9d2a9
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 63 deletions.
95 changes: 35 additions & 60 deletions assets/dataType.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,31 @@ type DataType struct {
AcceptedFormats []string `json:"acceptedFormats"`
Description string `json:"description,omitempty"`

KeyString func(interface{}) (string, error) `json:"-"`
Validate func(interface{}) (interface{}, error) `json:"-"`
Parse func(interface{}) (string, interface{}, error) `json:"-"`

KeyString func(interface{}) (string, error) `json:"-"` // DEPRECATED. Use Parse instead.
Validate func(interface{}) (interface{}, error) `json:"-"` // DEPRECATED. Use Parse instead.
}

// CustomDataTypes allows cc developer to inject custom primitive data types
func CustomDataTypes(m map[string]DataType) error {
for k, v := range m {
if v.KeyString == nil || v.Validate == nil {
return errors.NewCCError("invalid custom data type", 500)
if v.Parse == nil {
// These function signatures are deprecated and this is here for backwards compatibility only.
if v.KeyString == nil || v.Validate == nil {
return errors.NewCCError("invalid custom data type", 500)
}
v.Parse = func(d interface{}) (key string, ret interface{}, err error) {
key, err = v.KeyString(d)
if err != nil {
return
}

ret, err = v.Validate(d)
return
}
}

dataTypeMap[k] = v
}
return nil
Expand All @@ -42,110 +57,70 @@ func DataTypeMap() map[string]DataType {
var dataTypeMap = map[string]DataType{
"string": {
AcceptedFormats: []string{"string"},
KeyString: func(data interface{}) (string, error) {
dataVal, ok := data.(string)
if !ok {
return "", errors.NewCCError("asset property should be a string", 400)
}

return dataVal, nil
},

Validate: func(data interface{}) (interface{}, error) {
Parse: func(data interface{}) (string, interface{}, error) {
parsedData, ok := data.(string)
if !ok {
return nil, errors.NewCCError("property must be a string", 400)
return parsedData, nil, errors.NewCCError("property must be a string", 400)
}
return parsedData, nil
return parsedData, parsedData, nil
},
},
"number": {
AcceptedFormats: []string{"number"},
KeyString: func(data interface{}) (string, error) {
Parse: func(data interface{}) (string, interface{}, error) {
dataVal, ok := data.(float64)
if !ok {
propValStr, okStr := data.(string)
if !okStr {
return "", errors.NewCCError("asset property should be a number", 400)
return "", nil, errors.NewCCError("asset property should be a number", 400)
}
var err error
dataVal, err = strconv.ParseFloat(propValStr, 64)
if err != nil {
return "", errors.WrapErrorWithStatus(err, fmt.Sprintf("asset property should be a number"), 400)
return "", nil, errors.WrapErrorWithStatus(err, fmt.Sprintf("asset property should be a number"), 400)
}
}

// Float IEEE 754 hexadecimal representation
return strconv.FormatUint(math.Float64bits(dataVal), 16), nil
},

Validate: func(data interface{}) (interface{}, error) {
parsedData, ok := data.(float64)
if !ok {
return nil, errors.NewCCError("property must be a number", 400)
}

return parsedData, nil
return strconv.FormatUint(math.Float64bits(dataVal), 16), dataVal, nil
},
},
"boolean": {
AcceptedFormats: []string{"boolean"},
KeyString: func(data interface{}) (string, error) {
Parse: func(data interface{}) (string, interface{}, error) {
dataVal, ok := data.(bool)
if !ok {
dataValStr, okStr := data.(string)
if !okStr {
return "", errors.NewCCError("asset property should be a boolean", 400)
return "", nil, errors.NewCCError("asset property should be a boolean", 400)
}
if dataValStr != "true" && dataValStr != "false" {
return "", errors.NewCCError("asset property should be a boolean", 400)
return "", nil, errors.NewCCError("asset property should be a boolean", 400)
}
if dataValStr == "true" {
dataVal = true
}
}

if dataVal {
return "t", nil
}
return "f", nil
},

Validate: func(data interface{}) (interface{}, error) {
parsedData, ok := data.(bool)
if !ok {
return nil, errors.NewCCError("property must be a boolean", 400)
return "t", dataVal, nil
}

return parsedData, nil
return "f", dataVal, nil
},
},
"datetime": {
AcceptedFormats: []string{"string"},
KeyString: func(data interface{}) (string, error) {
Parse: func(data interface{}) (string, interface{}, error) {
dataVal, ok := data.(string)
if !ok {
return "", errors.NewCCError("asset property should be a RFC3339 string", 400)
return "", nil, errors.NewCCError("asset property should be a RFC3339 string", 400)
}
dataTime, err := time.Parse(time.RFC3339, dataVal)
if err != nil {
return "", errors.WrapErrorWithStatus(err, "invalid asset property RFC3339 format", 400)
}

return dataTime.Format(time.RFC3339), nil
},

Validate: func(data interface{}) (interface{}, error) {
dataVal, ok := data.(string)
if !ok {
return nil, errors.NewCCError("asset property must be an RFC3339 string", 400)
}
parsedData, err := time.Parse(time.RFC3339, dataVal)
if err != nil {
return nil, errors.WrapErrorWithStatus(err, "invalid asset property RFC3339 format", 400)
return "", nil, errors.WrapErrorWithStatus(err, "invalid asset property RFC3339 format", 400)
}

return parsedData, nil
return dataTime.Format(time.RFC3339), dataTime, nil
},
},
}
2 changes: 1 addition & 1 deletion assets/generateKey.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ func GenerateKey(asset map[string]interface{}) (string, errors.ICCError) {
dataType, dataTypeExists := dataTypeMap[dataTypeName]
if dataTypeExists {
// If key is a primitive data type, append its String value to seed
seed, err := dataType.KeyString(propInterface)
seed, _, err := dataType.Parse(propInterface)
if err != nil {
return "", errors.WrapError(err, fmt.Sprintf("failed to generate key for asset property '%s'", prop.Label))
}
Expand Down
2 changes: 1 addition & 1 deletion assets/validateProp.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func validateProp(prop interface{}, propDef AssetProp) (interface{}, error) {
// Validate data types
dataType, dataTypeExists := dataTypeMap[dataTypeName]
if dataTypeExists { // if data type is a primary data type
parsedProp, err = dataType.Validate(prop)
_, parsedProp, err = dataType.Parse(prop)
if err != nil {
return nil, errors.WrapError(err, fmt.Sprintf("invalid '%s' (%s) asset property", propDef.Tag, propDef.Label))
}
Expand Down
2 changes: 1 addition & 1 deletion transactions/getArgs.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ func validateTxArg(argType string, arg interface{}) (interface{}, errors.ICCErro
dataTypeMap := assets.DataTypeMap()
dataType, dataTypeExists := dataTypeMap[argType]
if dataTypeExists { // if argument is a primitive data type
argAsInterface, err = dataType.Validate(arg)
_, argAsInterface, err = dataType.Parse(arg)
if err != nil {
return nil, errors.WrapError(err, "invalid argument format")
}
Expand Down

0 comments on commit 6f9d2a9

Please sign in to comment.