aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoryenlin.lai <yenlin.lai@cobinhood.com>2019-03-25 17:02:55 +0800
committeryenlinlai <38415072+yenlinlai@users.noreply.github.com>2019-03-29 10:50:26 +0800
commit05ad7315b3c581519964b7762074e00de3c4ceac (patch)
tree1c950703241e33a1e29abd93cd7defa39db43719
parente0229cc82c9fd950c86d599f78b42c5384c46e6a (diff)
downloaddexon-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.go35
-rw-r--r--errors.go40
2 files changed, 65 insertions, 10 deletions
diff --git a/decimal.go b/decimal.go
index 2b884d6..0f5079c 100644
--- a/decimal.go
+++ b/decimal.go
@@ -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)
+}