diff options
author | yenlin.lai <yenlin.lai@cobinhood.com> | 2019-03-25 17:02:55 +0800 |
---|---|---|
committer | yenlinlai <38415072+yenlinlai@users.noreply.github.com> | 2019-03-29 10:50:26 +0800 |
commit | 05ad7315b3c581519964b7762074e00de3c4ceac (patch) | |
tree | 1c950703241e33a1e29abd93cd7defa39db43719 | |
parent | e0229cc82c9fd950c86d599f78b42c5384c46e6a (diff) | |
download | dexon-decimal-05ad7315b3c581519964b7762074e00de3c4ceac.tar.gz dexon-decimal-05ad7315b3c581519964b7762074e00de3c4ceac.tar.zst dexon-decimal-05ad7315b3c581519964b7762074e00de3c4ceac.zip |
error: properly wrap errors into error types
Let the caller has the ability to identify basic cause of error
without the need of hard-coded string contains/prefix/suffix.
-rw-r--r-- | decimal.go | 35 | ||||
-rw-r--r-- | errors.go | 40 |
2 files changed, 65 insertions, 10 deletions
@@ -116,9 +116,13 @@ func NewFromString(value string) (Decimal, error) { expInt, err := strconv.ParseInt(value[eIndex+1:], 10, 32) if err != nil { if e, ok := err.(*strconv.NumError); ok && e.Err == strconv.ErrRange { - return Decimal{}, fmt.Errorf("can't convert %s to decimal: fractional part too long", value) + return Decimal{}, &ErrorExponentLimit{value: value} + } + return Decimal{}, &ErrorInvalidFormat{ + reason: fmt.Sprintf( + "can't convert %s to decimal: exponent is not numeric", + value), } - return Decimal{}, fmt.Errorf("can't convert %s to decimal: exponent is not numeric", value) } value = value[:eIndex] exp = expInt @@ -139,18 +143,26 @@ func NewFromString(value string) (Decimal, error) { expInt := -len(decimalPart) exp += int64(expInt) } else { - return Decimal{}, fmt.Errorf("can't convert %s to decimal: too many .s", value) + return Decimal{}, &ErrorInvalidFormat{ + reason: fmt.Sprintf( + "can't convert %s to decimal: too many .s", + value), + } } dValue := new(big.Int) _, ok := dValue.SetString(intString, 10) if !ok { - return Decimal{}, fmt.Errorf("can't convert %s to decimal", value) + return Decimal{}, &ErrorInvalidFormat{ + reason: fmt.Sprintf("can't convert %s to decimal", value), + } } if exp < math.MinInt32 || exp > math.MaxInt32 { // NOTE(vadim): I doubt a string could realistically be this long - return Decimal{}, fmt.Errorf("can't convert %s to decimal: fractional part too long", originalInput) + return Decimal{}, &ErrorExponentLimit{ + value: originalInput, + } } return Decimal{ @@ -931,13 +943,13 @@ func (d *Decimal) UnmarshalJSON(decimalBytes []byte) error { str, err := unquoteIfQuoted(decimalBytes) if err != nil { - return fmt.Errorf("Error decoding string '%s': %s", decimalBytes, err) + return err } decimal, err := NewFromString(str) *d = decimal if err != nil { - return fmt.Errorf("Error decoding string '%s': %s", str, err) + return err } return nil } @@ -1025,7 +1037,7 @@ func (d *Decimal) UnmarshalText(text []byte) error { dec, err := NewFromString(str) *d = dec if err != nil { - return fmt.Errorf("Error decoding string '%s': %s", str, err) + return err } return nil @@ -1171,8 +1183,11 @@ func unquoteIfQuoted(value interface{}) (string, error) { case []byte: bytes = v default: - return "", fmt.Errorf("Could not convert value '%+v' to byte array of type '%T'", - value, value) + return "", &ErrorInvalidType{ + reason: fmt.Sprintf( + "Could not convert value '%+v' to byte array of type '%T'", + value, value), + } } // If the amount is quoted, strip the quotes diff --git a/errors.go b/errors.go new file mode 100644 index 0000000..4734614 --- /dev/null +++ b/errors.go @@ -0,0 +1,40 @@ +package decimal + +import "fmt" + +// ErrorExponentLimit is returned when the decimal exponent exceed int32 range. +type ErrorExponentLimit struct { + value string +} + +// Error implements error interface. +func (e *ErrorExponentLimit) Error() string { + return fmt.Sprintf("can't convert %s to decimal: fractional part too long", e.value) +} + +// ErrorInvalidFormat is returned when the input string is not valid integer. +type ErrorInvalidFormat struct { + reason string +} + +// Error implements error interface. +func (e *ErrorInvalidFormat) Error() string { + return e.reason +} + +// ErrorInvalidType is returned when the value passed into sql.Scanner is not +// with expected type. (valid types: int64, float64, []byte, string) +type ErrorInvalidType struct { + reason string +} + +// Error implements error interface. +func (e *ErrorInvalidType) Error() string { + return e.reason +} + +func assertErrorInterface() { + var _ error = (*ErrorExponentLimit)(nil) + var _ error = (*ErrorInvalidFormat)(nil) + var _ error = (*ErrorInvalidType)(nil) +} |