Skip to content

Commit 9620fb7

Browse files
authored
Add Spanner support for Encode and Decode (#395)
1 parent e1e92bf commit 9620fb7

2 files changed

Lines changed: 199 additions & 0 deletions

File tree

decimal.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1923,6 +1923,16 @@ func (d *Decimal) GobDecode(data []byte) error {
19231923
return d.UnmarshalBinary(data)
19241924
}
19251925

1926+
// DecodeSpanner decodes a Spanner value into a Decimal
1927+
func (d *Decimal) DecodeSpanner(val interface{}) error {
1928+
return d.Scan(val)
1929+
}
1930+
1931+
// EncodeSpanner encodes a Decimal into a Spanner value
1932+
func (d Decimal) EncodeSpanner() (interface{}, error) {
1933+
return d.String(), nil
1934+
}
1935+
19261936
// StringScaled first scales the decimal then calls .String() on it.
19271937
//
19281938
// Deprecated: buggy and unintuitive. Use StringFixed instead.
@@ -2164,6 +2174,32 @@ func (d NullDecimal) MarshalText() (text []byte, err error) {
21642174
return d.Decimal.MarshalText()
21652175
}
21662176

2177+
// DecodeSpanner decodes a Spanner value into a Decimal
2178+
func (d *NullDecimal) DecodeSpanner(value interface{}) error {
2179+
switch t := value.(type) {
2180+
case nil:
2181+
d.Valid = false
2182+
return nil
2183+
case *string:
2184+
if t == nil {
2185+
d.Valid = false
2186+
return nil
2187+
}
2188+
value = *t
2189+
}
2190+
d.Valid = true
2191+
2192+
return d.Decimal.Scan(value)
2193+
}
2194+
2195+
// EncodeSpanner encodes a Decimal into a Spanner value
2196+
func (d NullDecimal) EncodeSpanner() (interface{}, error) {
2197+
if !d.Valid {
2198+
return nil, nil
2199+
}
2200+
return d.Decimal.String(), nil
2201+
}
2202+
21672203
// Trig functions
21682204

21692205
// Atan returns the arctangent, in radians, of x.

decimal_test.go

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2505,6 +2505,77 @@ func TestDecimal_Value(t *testing.T) {
25052505
}
25062506
}
25072507

2508+
func decodeSpannerHelper(t *testing.T, dbval interface{}, expected Decimal) {
2509+
t.Helper()
2510+
2511+
a := Decimal{}
2512+
if err := a.DecodeSpanner(dbval); err != nil {
2513+
// DecodeSpanner failed... no need to test result value
2514+
t.Errorf("a.DecodeSpanner(%v) failed with message: %s", dbval, err)
2515+
} else if !a.Equal(expected) {
2516+
// DecodeSpanner succeeded... test resulting values
2517+
t.Errorf("%s does not equal to %s", a, expected)
2518+
}
2519+
}
2520+
2521+
type spannerDecoder interface {
2522+
DecodeSpanner(input interface{}) error
2523+
}
2524+
2525+
func TestDecimal_DecodeSpanner(t *testing.T) {
2526+
// test the DecodeSpanner method that implements spanner.Decoder interface
2527+
if _, ok := interface{}(new(Decimal)).(spannerDecoder); !ok {
2528+
t.Error("Decimal does not implement spanner.Decoder")
2529+
}
2530+
2531+
dbvalue := 54.33
2532+
expected := NewFromFloat(dbvalue)
2533+
decodeSpannerHelper(t, dbvalue, expected)
2534+
2535+
// also test uint64
2536+
dbvalueUint64 := uint64(2)
2537+
expected = New(2, 0)
2538+
decodeSpannerHelper(t, dbvalueUint64, expected)
2539+
2540+
// ensure we can handle the return of either []byte or string
2541+
valueStr := "535.666"
2542+
dbvalueStr := []byte(valueStr)
2543+
expected, err := NewFromString(valueStr)
2544+
if err != nil {
2545+
t.Fatal(err)
2546+
}
2547+
decodeSpannerHelper(t, dbvalueStr, expected)
2548+
decodeSpannerHelper(t, valueStr, expected)
2549+
2550+
type foo struct{}
2551+
a := Decimal{}
2552+
err = a.DecodeSpanner(foo{})
2553+
if err == nil {
2554+
t.Errorf("a.DecodeSpanner(Foo{}) should have thrown an error but did not")
2555+
}
2556+
}
2557+
2558+
type spannerEncoder interface {
2559+
EncodeSpanner() (interface{}, error)
2560+
}
2561+
2562+
func TestDecimal_EncodeSpanner(t *testing.T) {
2563+
// Make sure this does implement the spanner.Encoder interface
2564+
if _, ok := interface{}(Decimal{}).(spannerEncoder); !ok {
2565+
t.Error("Decimal does not implement spanner.Encoder")
2566+
}
2567+
2568+
// check that normal case is handled appropriately
2569+
a := New(1234, -2)
2570+
expected := "12.34"
2571+
value, err := a.Value()
2572+
if err != nil {
2573+
t.Errorf("Decimal(12.34).Value() failed with message: %s", err)
2574+
} else if got := value.(string); got != expected {
2575+
t.Errorf("%s does not equal to %s", a, expected)
2576+
}
2577+
}
2578+
25082579
// old tests after this line
25092580

25102581
func TestDecimal_Scale(t *testing.T) {
@@ -3301,6 +3372,98 @@ func TestNullDecimal_Value(t *testing.T) {
33013372
}
33023373
}
33033374

3375+
func TestNullDecimal_DecodeSpanner(t *testing.T) {
3376+
// test the DecodeSpanner method that implements the
3377+
// spanner.Decoder interface
3378+
if _, ok := interface{}(new(NullDecimal)).(spannerDecoder); !ok {
3379+
t.Error("NullDecimal does not implement spanner.Decoder")
3380+
}
3381+
3382+
// Make sure handles nil value
3383+
a := NullDecimal{}
3384+
var dbvaluePtr interface{}
3385+
err := a.DecodeSpanner(dbvaluePtr)
3386+
if err != nil {
3387+
// DecodeSpanner failed... no need to test result value
3388+
t.Errorf("a.DecodeSpanner(nil) failed with message: %s", err)
3389+
} else {
3390+
if a.Valid {
3391+
t.Errorf("%s is not null", a.Decimal)
3392+
}
3393+
}
3394+
3395+
// Make sure handles nil *string
3396+
dbvaluePtr = (*string)(nil)
3397+
if err := a.DecodeSpanner(dbvaluePtr); err != nil {
3398+
// DecodeSpanner failed... no need to test result value
3399+
t.Errorf("a.DecodeSpanner((*string)(nil)) failed with message: %s", err)
3400+
} else {
3401+
if a.Valid {
3402+
t.Errorf("%s is not null", a.Decimal)
3403+
}
3404+
}
3405+
3406+
valueStr := "535.666"
3407+
expected, err := NewFromString(valueStr)
3408+
if err != nil {
3409+
t.Fatal(err)
3410+
}
3411+
3412+
// Handle string
3413+
err = a.DecodeSpanner(valueStr)
3414+
if err != nil {
3415+
// DecodeSpanner failed... no need to test result value
3416+
t.Errorf("a.DecodeSpanner('535.666') failed with message: %s", err)
3417+
} else {
3418+
// DecodeSpanner succeeded... test resulting values
3419+
if !a.Valid {
3420+
t.Errorf("%s is null", a.Decimal)
3421+
} else if !a.Decimal.Equals(expected) {
3422+
t.Errorf("%v does not equal %v", a, expected)
3423+
}
3424+
}
3425+
3426+
// handle *string
3427+
err = a.DecodeSpanner(&valueStr)
3428+
if err != nil {
3429+
// DecodeSpanner failed... no need to test result value
3430+
t.Errorf("a.DecodeSpanner('535.666') failed with message: %s", err)
3431+
} else {
3432+
// DecodeSpanner succeeded... test resulting values
3433+
if !a.Valid {
3434+
t.Errorf("%s is null", a.Decimal)
3435+
} else if !a.Decimal.Equals(expected) {
3436+
t.Errorf("%v does not equal %v", a, expected)
3437+
}
3438+
}
3439+
}
3440+
3441+
func TestNullDecimal_EncodeSpanner(t *testing.T) {
3442+
// Make sure this does implement the spanner.Encoder interface
3443+
var nullDecimal NullDecimal
3444+
if _, ok := interface{}(nullDecimal).(spannerEncoder); !ok {
3445+
t.Error("NullDecimal does not implement spanner.Encoder")
3446+
}
3447+
3448+
// check that null is handled appropriately
3449+
value, err := nullDecimal.EncodeSpanner()
3450+
if err != nil {
3451+
t.Errorf("NullDecimal{}.Valid() failed with message: %s", err)
3452+
} else if value != nil {
3453+
t.Errorf("%v is not nil", value)
3454+
}
3455+
3456+
// check that normal case is handled appropriately
3457+
a := NullDecimal{Decimal: New(1234, -2), Valid: true}
3458+
expected := "12.34"
3459+
value, err = a.EncodeSpanner()
3460+
if err != nil {
3461+
t.Errorf("NullDecimal(12.34).EncodeSpanner() failed with message: %s", err)
3462+
} else if value.(string) != expected {
3463+
t.Errorf("%v does not equal %v", a, expected)
3464+
}
3465+
}
3466+
33043467
func TestBinary(t *testing.T) {
33053468
for _, y := range testTable {
33063469
x := y.float

0 commit comments

Comments
 (0)