mirror of
https://github.com/shopspring/decimal.git
synced 2024-11-22 20:40:48 +01:00
Added JSON support for NullDecimal (#62)
* Corrected NullDecimal comment Saying that NullDecimal is immutable is just incorrect, and we don't need to duplicate the description of properties of a Decimal type here. * Added UnmarshalJSON and MarshalJSON support for NullDecimal * Added tests for JSON operations on NullDecimal * Fixed mistakes in tests
This commit is contained in:
parent
aed1bfe463
commit
ad668bb369
2 changed files with 112 additions and 2 deletions
22
decimal.go
22
decimal.go
|
@ -928,8 +928,8 @@ func unquoteIfQuoted(value interface{}) (string, error) {
|
|||
return string(bytes), nil
|
||||
}
|
||||
|
||||
// NullDecimal represents a fixed-point decimal. It is immutable.
|
||||
// number = value * 10 ^ exp
|
||||
// NullDecimal represents a nullable decimal with compatibility for
|
||||
// scanning null values from the database.
|
||||
type NullDecimal struct {
|
||||
Decimal Decimal
|
||||
Valid bool
|
||||
|
@ -952,3 +952,21 @@ func (d NullDecimal) Value() (driver.Value, error) {
|
|||
}
|
||||
return d.Decimal.Value()
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the json.Unmarshaler interface.
|
||||
func (d *NullDecimal) UnmarshalJSON(decimalBytes []byte) error {
|
||||
if string(decimalBytes) == "null" {
|
||||
d.Valid = false
|
||||
return nil
|
||||
}
|
||||
d.Valid = true
|
||||
return d.Decimal.UnmarshalJSON(decimalBytes)
|
||||
}
|
||||
|
||||
// MarshalJSON implements the json.Marshaler interface.
|
||||
func (d NullDecimal) MarshalJSON() ([]byte, error) {
|
||||
if !d.Valid {
|
||||
return []byte("null"), nil
|
||||
}
|
||||
return d.Decimal.MarshalJSON()
|
||||
}
|
||||
|
|
|
@ -332,6 +332,98 @@ func TestBadJSON(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestNullDecimalJSON(t *testing.T) {
|
||||
for _, s := range testTable {
|
||||
var doc struct {
|
||||
Amount NullDecimal `json:"amount"`
|
||||
}
|
||||
docStr := `{"amount":"` + s + `"}`
|
||||
docStrNumber := `{"amount":` + s + `}`
|
||||
err := json.Unmarshal([]byte(docStr), &doc)
|
||||
if err != nil {
|
||||
t.Errorf("error unmarshaling %s: %v", docStr, err)
|
||||
} else {
|
||||
if !doc.Amount.Valid {
|
||||
t.Errorf("expected %s to be valid (not NULL), got Valid = false", s)
|
||||
}
|
||||
if doc.Amount.Decimal.String() != s {
|
||||
t.Errorf("expected %s, got %s (%s, %d)",
|
||||
s, doc.Amount.Decimal.String(),
|
||||
doc.Amount.Decimal.value.String(), doc.Amount.Decimal.exp)
|
||||
}
|
||||
}
|
||||
|
||||
out, err := json.Marshal(&doc)
|
||||
if err != nil {
|
||||
t.Errorf("error marshaling %+v: %v", doc, err)
|
||||
} else if string(out) != docStr {
|
||||
t.Errorf("expected %s, got %s", docStr, string(out))
|
||||
}
|
||||
|
||||
// make sure unquoted marshalling works too
|
||||
MarshalJSONWithoutQuotes = true
|
||||
out, err = json.Marshal(&doc)
|
||||
if err != nil {
|
||||
t.Errorf("error marshaling %+v: %v", doc, err)
|
||||
} else if string(out) != docStrNumber {
|
||||
t.Errorf("expected %s, got %s", docStrNumber, string(out))
|
||||
}
|
||||
MarshalJSONWithoutQuotes = false
|
||||
}
|
||||
|
||||
var doc struct {
|
||||
Amount NullDecimal `json:"amount"`
|
||||
}
|
||||
docStr := `{"amount": null}`
|
||||
err := json.Unmarshal([]byte(docStr), &doc)
|
||||
if err != nil {
|
||||
t.Errorf("error unmarshaling %s: %v", docStr, err)
|
||||
} else if doc.Amount.Valid {
|
||||
t.Errorf("expected null value to have Valid = false, got Valid = true and Decimal = %s (%s, %d)",
|
||||
doc.Amount.Decimal.String(),
|
||||
doc.Amount.Decimal.value.String(), doc.Amount.Decimal.exp)
|
||||
}
|
||||
|
||||
expected := `{"amount":null}`
|
||||
out, err := json.Marshal(&doc)
|
||||
if err != nil {
|
||||
t.Errorf("error marshaling %+v: %v", doc, err)
|
||||
} else if string(out) != expected {
|
||||
t.Errorf("expected %s, got %s", expected, string(out))
|
||||
}
|
||||
|
||||
// make sure unquoted marshalling works too
|
||||
MarshalJSONWithoutQuotes = true
|
||||
expectedUnquoted := `{"amount":null}`
|
||||
out, err = json.Marshal(&doc)
|
||||
if err != nil {
|
||||
t.Errorf("error marshaling %+v: %v", doc, err)
|
||||
} else if string(out) != expectedUnquoted {
|
||||
t.Errorf("expected %s, got %s", expectedUnquoted, string(out))
|
||||
}
|
||||
MarshalJSONWithoutQuotes = false
|
||||
}
|
||||
|
||||
func TestNullDecimalBadJSON(t *testing.T) {
|
||||
for _, testCase := range []string{
|
||||
"]o_o[",
|
||||
"{",
|
||||
`{"amount":""`,
|
||||
`{"amount":""}`,
|
||||
`{"amount":"nope"}`,
|
||||
`{"amount":nope}`,
|
||||
`0.333`,
|
||||
} {
|
||||
var doc struct {
|
||||
Amount NullDecimal `json:"amount"`
|
||||
}
|
||||
err := json.Unmarshal([]byte(testCase), &doc)
|
||||
if err == nil {
|
||||
t.Errorf("expected error, got %+v", doc)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestXML(t *testing.T) {
|
||||
for _, s := range testTable {
|
||||
var doc struct {
|
||||
|
|
Loading…
Reference in a new issue