Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dave/support string to int float from json #6

Open
wants to merge 17 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 32 additions & 5 deletions float32.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import (
"bytes"
"database/sql/driver"
"encoding/json"
"fmt"
"math"
"reflect"
"strconv"

"github.com/volatiletech/null/convert"
Expand Down Expand Up @@ -44,14 +47,38 @@ func (f *Float32) UnmarshalJSON(data []byte) error {
return nil
}

var x float64
if err := json.Unmarshal(data, &x); err != nil {
var err error
var v interface{}
if err = json.Unmarshal(data, &v); err != nil {
return err
}

f.Float32 = float32(x)
f.Valid = true
return nil
var r float64
switch x := v.(type) {
case float64:
r = v.(float64)
case string:
str := string(x)
if len(str) == 0 {
f.Valid = false
return nil
}

r, err = strconv.ParseFloat(str, 32)
case nil:
f.Valid = false
return nil
default:
err = fmt.Errorf("json: cannot unmarshal %v into Go value of type null.Float32", reflect.TypeOf(v).Name())
}

if r > math.MaxFloat32 {
return fmt.Errorf("json: %f overflows max float32 value", r)
}

f.Float32 = float32(r)
f.Valid = (err == nil) && (f.Float32 != 0)
return err
}

// UnmarshalText implements encoding.TextUnmarshaler.
Expand Down
13 changes: 12 additions & 1 deletion float32_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import (
)

var (
float32JSON = []byte(`1.2345`)
float32JSON = []byte(`1.2345`)
float32StringJSON = []byte(`"1.2345"`)
)

func TestFloat32From(t *testing.T) {
Expand Down Expand Up @@ -35,11 +36,21 @@ func TestUnmarshalFloat32(t *testing.T) {
maybePanic(err)
assertFloat32(t, f, "float32 json")

var sf Float32
err = json.Unmarshal(float32StringJSON, &sf)
maybePanic(err)
assertFloat32(t, sf, "float32 string json")

var null Float32
err = json.Unmarshal(nullJSON, &null)
maybePanic(err)
assertNullFloat32(t, null, "null json")

var bf Float32
err = json.Unmarshal(blankStringJSON, &bf)
maybePanic(err)
assertNullFloat32(t, bf, "blank json string")

var badType Float32
err = json.Unmarshal(boolJSON, &badType)
if err == nil {
Expand Down
28 changes: 23 additions & 5 deletions float64.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"bytes"
"database/sql/driver"
"encoding/json"
"fmt"
"reflect"
"strconv"

"github.com/volatiletech/null/convert"
Expand Down Expand Up @@ -43,13 +45,29 @@ func (f *Float64) UnmarshalJSON(data []byte) error {
f.Valid = false
return nil
}

if err := json.Unmarshal(data, &f.Float64); err != nil {
var err error
var v interface{}
if err = json.Unmarshal(data, &v); err != nil {
return err
}

f.Valid = true
return nil
switch x := v.(type) {
case float64:
f.Float64 = float64(x)
case string:
str := string(x)
if len(str) == 0 {
f.Valid = false
return nil
}
f.Float64, err = strconv.ParseFloat(str, 64)
case nil:
f.Valid = false
return nil
default:
err = fmt.Errorf("json: cannot unmarshal %v into Go value of type null.Float64", reflect.TypeOf(v).Name())
}
f.Valid = err == nil
return err
}

// UnmarshalText implements encoding.TextUnmarshaler.
Expand Down
13 changes: 12 additions & 1 deletion float64_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import (
)

var (
float64JSON = []byte(`1.2345`)
float64JSON = []byte(`1.2345`)
float64StringJSON = []byte(`"1.2345"`)
)

func TestFloat64From(t *testing.T) {
Expand Down Expand Up @@ -35,11 +36,21 @@ func TestUnmarshalFloat64(t *testing.T) {
maybePanic(err)
assertFloat64(t, f, "float64 json")

var sf Float64
err = json.Unmarshal(float64StringJSON, &sf)
maybePanic(err)
assertFloat64(t, sf, "float64 string json")

var null Float64
err = json.Unmarshal(nullJSON, &null)
maybePanic(err)
assertNullFloat64(t, null, "null json")

var bf Float64
err = json.Unmarshal(blankStringJSON, &bf)
maybePanic(err)
assertNullFloat64(t, bf, "blank json string")

var badType Float64
err = json.Unmarshal(boolJSON, &badType)
if err == nil {
Expand Down
29 changes: 24 additions & 5 deletions int.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import (
"bytes"
"database/sql/driver"
"encoding/json"
"fmt"
"math"
"reflect"
"strconv"

"github.com/volatiletech/null/convert"
Expand Down Expand Up @@ -45,14 +47,31 @@ func (i *Int) UnmarshalJSON(data []byte) error {
return nil
}

var x int64
if err := json.Unmarshal(data, &x); err != nil {
var err error
var v interface{}
if err = json.Unmarshal(data, &v); err != nil {
return err
}
switch x := v.(type) {
case float64:
// Unmarshal again, directly to int, to avoid intermediate float64
err = json.Unmarshal(data, &i.Int)
case string:
str := string(x)
if len(str) == 0 {
i.Valid = false
return nil
}
i.Int, err = strconv.Atoi(str)
case nil:
i.Valid = false
return nil
default:
err = fmt.Errorf("json: cannot unmarshal %v into Go value of type null.Int", reflect.TypeOf(v).Name())
}

i.Int = int(x)
i.Valid = true
return nil
i.Valid = (err == nil) && (i.Int != 0)
return err
}

// UnmarshalText implements encoding.TextUnmarshaler.
Expand Down
36 changes: 29 additions & 7 deletions int16.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"encoding/json"
"fmt"
"math"
"reflect"
"strconv"

"github.com/volatiletech/null/convert"
Expand Down Expand Up @@ -46,18 +47,39 @@ func (i *Int16) UnmarshalJSON(data []byte) error {
return nil
}

var x int64
if err := json.Unmarshal(data, &x); err != nil {
var err error
var v interface{}
if err = json.Unmarshal(data, &v); err != nil {
return err
}

if x > math.MaxInt16 {
return fmt.Errorf("json: %d overflows max int16 value", x)
var r int64
switch x := v.(type) {
case float64:
// Unmarshal again, directly to int64, to avoid intermediate float64
err = json.Unmarshal(data, &r)
case string:
str := string(x)
if len(str) == 0 {
i.Valid = false
return nil
}

r, err = strconv.ParseInt(str, 10, 16)
case nil:
i.Valid = false
return nil
default:
err = fmt.Errorf("json: cannot unmarshal %v into Go value of type null.Int16", reflect.TypeOf(v).Name())
}

i.Int16 = int16(x)
i.Valid = true
return nil
if r > math.MaxInt16 {
return fmt.Errorf("json: %d overflows max int16 value", r)
}

i.Int16 = int16(r)
i.Valid = (err == nil) && (i.Int16 != 0)
return err
}

// UnmarshalText implements encoding.TextUnmarshaler.
Expand Down
13 changes: 12 additions & 1 deletion int16_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import (
)

var (
int16JSON = []byte(`32766`)
int16JSON = []byte(`32766`)
int16StringJSON = []byte(`"32766"`)
)

func TestInt16From(t *testing.T) {
Expand Down Expand Up @@ -37,11 +38,21 @@ func TestUnmarshalInt16(t *testing.T) {
maybePanic(err)
assertInt16(t, i, "int16 json")

var si Int16
err = json.Unmarshal(int16StringJSON, &si)
maybePanic(err)
assertInt16(t, si, "int16 string json")

var null Int16
err = json.Unmarshal(nullJSON, &null)
maybePanic(err)
assertNullInt16(t, null, "null json")

var bi Int16
err = json.Unmarshal(blankStringJSON, &bi)
maybePanic(err)
assertNullInt16(t, bi, "blank json string")

var badType Int16
err = json.Unmarshal(boolJSON, &badType)
if err == nil {
Expand Down
36 changes: 29 additions & 7 deletions int32.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"encoding/json"
"fmt"
"math"
"reflect"
"strconv"

"github.com/volatiletech/null/convert"
Expand Down Expand Up @@ -47,18 +48,39 @@ func (i *Int32) UnmarshalJSON(data []byte) error {
return nil
}

var x int64
if err := json.Unmarshal(data, &x); err != nil {
var err error
var v interface{}
if err = json.Unmarshal(data, &v); err != nil {
return err
}

if x > math.MaxInt32 {
return fmt.Errorf("json: %d overflows max int32 value", x)
var r int64
switch x := v.(type) {
case float64:
// Unmarshal again, directly to uint64, to avoid intermediate float64
err = json.Unmarshal(data, &r)
case string:
str := string(x)
if len(str) == 0 {
i.Valid = false
return nil
}

r, err = strconv.ParseInt(str, 10, 32)
case nil:
i.Valid = false
return nil
default:
err = fmt.Errorf("json: cannot unmarshal %v into Go value of type null.Int32", reflect.TypeOf(v).Name())
}

i.Int32 = int32(x)
i.Valid = true
return nil
if r > math.MaxInt32 {
return fmt.Errorf("json: %d overflows max int32 value", r)
}

i.Int32 = int32(r)
i.Valid = (err == nil) && (i.Int32 != 0)
return err
}

// UnmarshalText implements encoding.TextUnmarshaler.
Expand Down
13 changes: 12 additions & 1 deletion int32_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import (
)

var (
int32JSON = []byte(`2147483646`)
int32JSON = []byte(`2147483646`)
int32StringJSON = []byte(`"2147483646"`)
)

func TestInt32From(t *testing.T) {
Expand Down Expand Up @@ -37,11 +38,21 @@ func TestUnmarshalInt32(t *testing.T) {
maybePanic(err)
assertInt32(t, i, "int32 json")

var si Int32
err = json.Unmarshal(int32StringJSON, &si)
maybePanic(err)
assertInt32(t, si, "int32 string json")

var null Int32
err = json.Unmarshal(nullJSON, &null)
maybePanic(err)
assertNullInt32(t, null, "null json")

var bi Int32
err = json.Unmarshal(blankStringJSON, &bi)
maybePanic(err)
assertNullInt32(t, bi, "blank json string")

var badType Int32
err = json.Unmarshal(boolJSON, &badType)
if err == nil {
Expand Down
Loading