Fix all unmarshaljson funcs and all types

This commit is contained in:
Patrick O'brien 2016-11-11 01:00:05 +10:00
parent 1104869407
commit fed49d7096
32 changed files with 521 additions and 839 deletions

View file

@ -37,9 +37,6 @@ func BoolFromPtr(b *bool) Bool {
}
// UnmarshalJSON implements json.Unmarshaler.
// It supports number and null input.
// 0 will not be considered a null Bool.
// It also supports unmarshalling a sql.NullBool.
func (b *Bool) UnmarshalJSON(data []byte) error {
if bytes.Equal(data, NullBytes) {
b.Bool = false
@ -56,8 +53,6 @@ func (b *Bool) UnmarshalJSON(data []byte) error {
}
// UnmarshalText implements encoding.TextUnmarshaler.
// It will unmarshal to a null Bool if the input is a blank or not an integer.
// It will return an error if the input is not an integer, blank, or "null".
func (b *Bool) UnmarshalText(text []byte) error {
str := string(text)
switch str {
@ -77,7 +72,6 @@ func (b *Bool) UnmarshalText(text []byte) error {
}
// MarshalJSON implements json.Marshaler.
// It will encode null if this Bool is null.
func (b Bool) MarshalJSON() ([]byte, error) {
if !b.Valid {
return []byte("null"), nil
@ -89,7 +83,6 @@ func (b Bool) MarshalJSON() ([]byte, error) {
}
// MarshalText implements encoding.TextMarshaler.
// It will encode a blank string if this Bool is null.
func (b Bool) MarshalText() ([]byte, error) {
if !b.Valid {
return []byte{}, nil
@ -115,7 +108,6 @@ func (b Bool) Ptr() *bool {
}
// IsZero returns true for invalid Bools, for future omitempty support (Go 1.4?)
// A non-null Bool with a 0 value will not be considered zero.
func (b Bool) IsZero() bool {
return !b.Valid
}

View file

@ -6,9 +6,8 @@ import (
)
var (
boolJSON = []byte(`true`)
falseJSON = []byte(`false`)
nullBoolJSON = []byte(`{"Bool":true,"Valid":true}`)
boolJSON = []byte(`true`)
falseJSON = []byte(`false`)
)
func TestBoolFrom(t *testing.T) {
@ -37,12 +36,6 @@ func TestUnmarshalBool(t *testing.T) {
maybePanic(err)
assertBool(t, b, "bool json")
var nb Bool
err = json.Unmarshal(nullBoolJSON, &nb)
if err == nil {
panic("err should not be nil")
}
var null Bool
err = json.Unmarshal(nullJSON, &null)
maybePanic(err)

View file

@ -40,8 +40,6 @@ func BytesFromPtr(b *[]byte) Bytes {
}
// UnmarshalJSON implements json.Unmarshaler.
// If data is len 0 or nil, it will unmarshal to JSON null.
// If not, it will copy your data slice into Bytes.
func (b *Bytes) UnmarshalJSON(data []byte) error {
if bytes.Equal(data, NullBytes) {
b.Valid = false
@ -60,7 +58,6 @@ func (b *Bytes) UnmarshalJSON(data []byte) error {
}
// UnmarshalText implements encoding.TextUnmarshaler.
// It will unmarshal to nil if the text is nil or len 0.
func (b *Bytes) UnmarshalText(text []byte) error {
if text == nil || len(text) == 0 {
b.Bytes = nil
@ -74,7 +71,6 @@ func (b *Bytes) UnmarshalText(text []byte) error {
}
// MarshalJSON implements json.Marshaler.
// It will encode null if the Bytes is nil.
func (b Bytes) MarshalJSON() ([]byte, error) {
if len(b.Bytes) == 0 || b.Bytes == nil {
return []byte("null"), nil
@ -83,7 +79,6 @@ func (b Bytes) MarshalJSON() ([]byte, error) {
}
// MarshalText implements encoding.TextMarshaler.
// It will encode nil if the Bytes is invalid.
func (b Bytes) MarshalText() ([]byte, error) {
if !b.Valid {
return nil, nil

View file

@ -1,35 +1,25 @@
package null
import (
"bytes"
"database/sql/driver"
"encoding/json"
"fmt"
"reflect"
"strconv"
"gopkg.in/nullbio/null.v5/convert"
)
// NullFloat32 is a replica of sql.NullFloat64 for float32 types.
type NullFloat32 struct {
// Float32 is a nullable float32.
type Float32 struct {
Float32 float32
Valid bool
}
// Float32 is a nullable float32.
// It does not consider zero values to be null.
// It will decode to null, not zero, if null.
type Float32 struct {
NullFloat32
}
// NewFloat32 creates a new Float32
func NewFloat32(f float32, valid bool) Float32 {
return Float32{
NullFloat32: NullFloat32{
Float32: f,
Valid: valid,
},
Float32: f,
Valid: valid,
}
}
@ -47,33 +37,24 @@ func Float32FromPtr(f *float32) Float32 {
}
// UnmarshalJSON implements json.Unmarshaler.
// It supports number and null input.
// 0 will not be considered a null Float32.
// It also supports unmarshalling a sql.NullFloat32.
func (f *Float32) UnmarshalJSON(data []byte) error {
var err error
var v interface{}
if err = json.Unmarshal(data, &v); err != nil {
if bytes.Equal(data, NullBytes) {
f.Valid = false
f.Float32 = 0
return nil
}
var x float64
if err := json.Unmarshal(data, &x); err != nil {
return err
}
switch x := v.(type) {
case float64:
f.Float32 = float32(x)
case map[string]interface{}:
err = json.Unmarshal(data, &f.NullFloat32)
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())
}
f.Valid = err == nil
return err
f.Float32 = float32(x)
f.Valid = true
return nil
}
// UnmarshalText implements encoding.TextUnmarshaler.
// It will unmarshal to a null Float32 if the input is a blank or not an integer.
// It will return an error if the input is not an integer, blank, or "null".
func (f *Float32) UnmarshalText(text []byte) error {
str := string(text)
if str == "" || str == "null" {
@ -90,7 +71,6 @@ func (f *Float32) UnmarshalText(text []byte) error {
}
// MarshalJSON implements json.Marshaler.
// It will encode null if this Float32 is null.
func (f Float32) MarshalJSON() ([]byte, error) {
if !f.Valid {
return []byte("null"), nil
@ -99,7 +79,6 @@ func (f Float32) MarshalJSON() ([]byte, error) {
}
// MarshalText implements encoding.TextMarshaler.
// It will encode a blank string if this Float32 is null.
func (f Float32) MarshalText() ([]byte, error) {
if !f.Valid {
return []byte{}, nil
@ -122,25 +101,24 @@ func (f Float32) Ptr() *float32 {
}
// IsZero returns true for invalid Float32s, for future omitempty support (Go 1.4?)
// A non-null Float32 with a 0 value will not be considered zero.
func (f Float32) IsZero() bool {
return !f.Valid
}
// Scan implements the Scanner interface.
func (n *NullFloat32) Scan(value interface{}) error {
func (f *Float32) Scan(value interface{}) error {
if value == nil {
n.Float32, n.Valid = 0, false
f.Float32, f.Valid = 0, false
return nil
}
n.Valid = true
return convert.ConvertAssign(&n.Float32, value)
f.Valid = true
return convert.ConvertAssign(&f.Float32, value)
}
// Value implements the driver Valuer interface.
func (n NullFloat32) Value() (driver.Value, error) {
if !n.Valid {
func (f Float32) Value() (driver.Value, error) {
if !f.Valid {
return nil, nil
}
return float64(n.Float32), nil
return float64(f.Float32), nil
}

View file

@ -6,8 +6,7 @@ import (
)
var (
float32JSON = []byte(`1.2345`)
nullFloat32JSON = []byte(`{"Float32":1.2345,"Valid":true}`)
float32JSON = []byte(`1.2345`)
)
func TestFloat32From(t *testing.T) {
@ -36,11 +35,6 @@ func TestUnmarshalFloat32(t *testing.T) {
maybePanic(err)
assertFloat32(t, f, "float32 json")
var nf Float32
err = json.Unmarshal(nullFloat32JSON, &nf)
maybePanic(err)
assertFloat32(t, nf, "sq.NullFloat32 json")
var null Float32
err = json.Unmarshal(nullJSON, &null)
maybePanic(err)

View file

@ -1,27 +1,25 @@
package null
import (
"database/sql"
"bytes"
"database/sql/driver"
"encoding/json"
"fmt"
"reflect"
"strconv"
"github.com/nullbio/null/convert"
)
// Float64 is a nullable float64.
// It does not consider zero values to be null.
// It will decode to null, not zero, if null.
type Float64 struct {
sql.NullFloat64
Float64 float64
Valid bool
}
// NewFloat64 creates a new Float64
func NewFloat64(f float64, valid bool) Float64 {
return Float64{
NullFloat64: sql.NullFloat64{
Float64: f,
Valid: valid,
},
Float64: f,
Valid: valid,
}
}
@ -39,33 +37,22 @@ func Float64FromPtr(f *float64) Float64 {
}
// UnmarshalJSON implements json.Unmarshaler.
// It supports number and null input.
// 0 will not be considered a null Float64.
// It also supports unmarshalling a sql.NullFloat64.
func (f *Float64) UnmarshalJSON(data []byte) error {
var err error
var v interface{}
if err = json.Unmarshal(data, &v); err != nil {
return err
}
switch x := v.(type) {
case float64:
f.Float64 = float64(x)
case map[string]interface{}:
err = json.Unmarshal(data, &f.NullFloat64)
case nil:
if bytes.Equal(data, NullBytes) {
f.Float64 = 0
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
if err := json.Unmarshal(data, &f.Float64); err != nil {
return err
}
f.Valid = true
return nil
}
// UnmarshalText implements encoding.TextUnmarshaler.
// It will unmarshal to a null Float64 if the input is a blank or not an integer.
// It will return an error if the input is not an integer, blank, or "null".
func (f *Float64) UnmarshalText(text []byte) error {
str := string(text)
if str == "" || str == "null" {
@ -79,7 +66,6 @@ func (f *Float64) UnmarshalText(text []byte) error {
}
// MarshalJSON implements json.Marshaler.
// It will encode null if this Float64 is null.
func (f Float64) MarshalJSON() ([]byte, error) {
if !f.Valid {
return []byte("null"), nil
@ -88,7 +74,6 @@ func (f Float64) MarshalJSON() ([]byte, error) {
}
// MarshalText implements encoding.TextMarshaler.
// It will encode a blank string if this Float64 is null.
func (f Float64) MarshalText() ([]byte, error) {
if !f.Valid {
return []byte{}, nil
@ -111,7 +96,24 @@ func (f Float64) Ptr() *float64 {
}
// IsZero returns true for invalid Float64s, for future omitempty support (Go 1.4?)
// A non-null Float64 with a 0 value will not be considered zero.
func (f Float64) IsZero() bool {
return !f.Valid
}
// Scan implements the Scanner interface.
func (f *Float64) Scan(value interface{}) error {
if value == nil {
f.Float64, f.Valid = 0, false
return nil
}
f.Valid = true
return convert.ConvertAssign(&f.Float64, value)
}
// Value implements the driver Valuer interface.
func (f Float64) Value() (driver.Value, error) {
if !f.Valid {
return nil, nil
}
return f.Float64, nil
}

View file

@ -6,8 +6,7 @@ import (
)
var (
float64JSON = []byte(`1.2345`)
nullFloat64JSON = []byte(`{"Float64":1.2345,"Valid":true}`)
float64JSON = []byte(`1.2345`)
)
func TestFloat64From(t *testing.T) {
@ -36,11 +35,6 @@ func TestUnmarshalFloat64(t *testing.T) {
maybePanic(err)
assertFloat64(t, f, "float64 json")
var nf Float64
err = json.Unmarshal(nullFloat64JSON, &nf)
maybePanic(err)
assertFloat64(t, nf, "sq.NullFloat64 json")
var null Float64
err = json.Unmarshal(nullJSON, &null)
maybePanic(err)

71
int.go
View file

@ -1,35 +1,25 @@
package null
import (
"bytes"
"database/sql/driver"
"encoding/json"
"fmt"
"reflect"
"strconv"
"gopkg.in/nullbio/null.v5/convert"
)
// NullInt is a replica of sql.NullInt64 for int types.
type NullInt struct {
// Int is an nullable int.
type Int struct {
Int int
Valid bool
}
// Int is an nullable int.
// It does not consider zero values to be null.
// It will decode to null, not zero, if null.
type Int struct {
NullInt
}
// NewInt creates a new Int
func NewInt(i int, valid bool) Int {
return Int{
NullInt: NullInt{
Int: i,
Valid: valid,
},
Int: i,
Valid: valid,
}
}
@ -47,34 +37,24 @@ func IntFromPtr(i *int) Int {
}
// UnmarshalJSON implements json.Unmarshaler.
// It supports number and null input.
// 0 will not be considered a null Int.
// It also supports unmarshalling a sql.NullInt.
func (i *Int) UnmarshalJSON(data []byte) error {
var err error
var v interface{}
if err = json.Unmarshal(data, &v); err != nil {
if bytes.Equal(data, NullBytes) {
i.Valid = false
i.Int = 0
return nil
}
var x int64
if err := json.Unmarshal(data, &x); err != nil {
return err
}
switch v.(type) {
case float64:
// Unmarshal again, directly to int, to avoid intermediate float64
err = json.Unmarshal(data, &i.Int)
case map[string]interface{}:
err = json.Unmarshal(data, &i.NullInt)
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.Valid = err == nil
return err
i.Int = int(x)
i.Valid = true
return nil
}
// UnmarshalText implements encoding.TextUnmarshaler.
// It will unmarshal to a null Int if the input is a blank or not an integer.
// It will return an error if the input is not an integer, blank, or "null".
func (i *Int) UnmarshalText(text []byte) error {
str := string(text)
if str == "" || str == "null" {
@ -91,7 +71,6 @@ func (i *Int) UnmarshalText(text []byte) error {
}
// MarshalJSON implements json.Marshaler.
// It will encode null if this Int is null.
func (i Int) MarshalJSON() ([]byte, error) {
if !i.Valid {
return []byte("null"), nil
@ -100,7 +79,6 @@ func (i Int) MarshalJSON() ([]byte, error) {
}
// MarshalText implements encoding.TextMarshaler.
// It will encode a blank string if this Int is null.
func (i Int) MarshalText() ([]byte, error) {
if !i.Valid {
return []byte{}, nil
@ -123,25 +101,24 @@ func (i Int) Ptr() *int {
}
// IsZero returns true for invalid Ints, for future omitempty support (Go 1.4?)
// A non-null Int with a 0 value will not be considered zero.
func (i Int) IsZero() bool {
return !i.Valid
}
// Scan implements the Scanner interface.
func (n *NullInt) Scan(value interface{}) error {
func (i *Int) Scan(value interface{}) error {
if value == nil {
n.Int, n.Valid = 0, false
i.Int, i.Valid = 0, false
return nil
}
n.Valid = true
return convert.ConvertAssign(&n.Int, value)
i.Valid = true
return convert.ConvertAssign(&i.Int, value)
}
// Value implements the driver Valuer interface.
func (n NullInt) Value() (driver.Value, error) {
if !n.Valid {
func (i Int) Value() (driver.Value, error) {
if !i.Valid {
return nil, nil
}
return int64(n.Int), nil
return int64(i.Int), nil
}

View file

@ -1,35 +1,27 @@
package null
import (
"bytes"
"database/sql/driver"
"encoding/json"
"fmt"
"reflect"
"math"
"strconv"
"gopkg.in/nullbio/null.v5/convert"
)
// NullInt16 is a replica of sql.NullInt64 for int16 types.
type NullInt16 struct {
// Int16 is an nullable int16.
type Int16 struct {
Int16 int16
Valid bool
}
// Int16 is an nullable int16.
// It does not consider zero values to be null.
// It will decode to null, not zero, if null.
type Int16 struct {
NullInt16
}
// NewInt16 creates a new Int16
func NewInt16(i int16, valid bool) Int16 {
return Int16{
NullInt16: NullInt16{
Int16: i,
Valid: valid,
},
Int16: i,
Valid: valid,
}
}
@ -47,34 +39,28 @@ func Int16FromPtr(i *int16) Int16 {
}
// UnmarshalJSON implements json.Unmarshaler.
// It supports number and null input.
// 0 will not be considered a null Int16.
// It also supports unmarshalling a sql.NullInt16.
func (i *Int16) UnmarshalJSON(data []byte) error {
var err error
var v interface{}
if err = json.Unmarshal(data, &v); err != nil {
if bytes.Equal(data, NullBytes) {
i.Valid = false
i.Int16 = 0
return nil
}
var x int64
if err := json.Unmarshal(data, &x); err != nil {
return err
}
switch v.(type) {
case float64:
// Unmarshal again, directly to int16, to avoid intermediate float64
err = json.Unmarshal(data, &i.Int16)
case map[string]interface{}:
err = json.Unmarshal(data, &i.NullInt16)
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())
if x > math.MaxInt16 {
return fmt.Errorf("json: %d overflows max int16 value", x)
}
i.Valid = err == nil
return err
i.Int16 = int16(x)
i.Valid = true
return nil
}
// UnmarshalText implements encoding.TextUnmarshaler.
// It will unmarshal to a null Int16 if the input is a blank or not an integer.
// It will return an error if the input is not an integer, blank, or "null".
func (i *Int16) UnmarshalText(text []byte) error {
str := string(text)
if str == "" || str == "null" {
@ -91,7 +77,6 @@ func (i *Int16) UnmarshalText(text []byte) error {
}
// MarshalJSON implements json.Marshaler.
// It will encode null if this Int16 is null.
func (i Int16) MarshalJSON() ([]byte, error) {
if !i.Valid {
return []byte("null"), nil
@ -100,7 +85,6 @@ func (i Int16) MarshalJSON() ([]byte, error) {
}
// MarshalText implements encoding.TextMarshaler.
// It will encode a blank string if this Int16 is null.
func (i Int16) MarshalText() ([]byte, error) {
if !i.Valid {
return []byte{}, nil
@ -123,25 +107,24 @@ func (i Int16) Ptr() *int16 {
}
// IsZero returns true for invalid Int16's, for future omitempty support (Go 1.4?)
// A non-null Int16 with a 0 value will not be considered zero.
func (i Int16) IsZero() bool {
return !i.Valid
}
// Scan implements the Scanner interface.
func (n *NullInt16) Scan(value interface{}) error {
func (i *Int16) Scan(value interface{}) error {
if value == nil {
n.Int16, n.Valid = 0, false
i.Int16, i.Valid = 0, false
return nil
}
n.Valid = true
return convert.ConvertAssign(&n.Int16, value)
i.Valid = true
return convert.ConvertAssign(&i.Int16, value)
}
// Value implements the driver Valuer interface.
func (n NullInt16) Value() (driver.Value, error) {
if !n.Valid {
func (i Int16) Value() (driver.Value, error) {
if !i.Valid {
return nil, nil
}
return int64(n.Int16), nil
return int64(i.Int16), nil
}

View file

@ -2,14 +2,14 @@ package null
import (
"encoding/json"
"fmt"
"math"
"strconv"
"testing"
)
var (
int16JSON = []byte(`32766`)
nullInt16JSON = []byte(`{"Int16":32766,"Valid":true}`)
int16JSON = []byte(`32766`)
)
func TestInt16From(t *testing.T) {
@ -38,11 +38,6 @@ func TestUnmarshalInt16(t *testing.T) {
maybePanic(err)
assertInt16(t, i, "int16 json")
var ni Int16
err = json.Unmarshal(nullInt16JSON, &ni)
maybePanic(err)
assertInt16(t, ni, "sq.NullInt16 json")
var null Int16
err = json.Unmarshal(nullJSON, &null)
maybePanic(err)
@ -78,10 +73,11 @@ func TestUnmarshalInt16Overflow(t *testing.T) {
var i Int16
err := json.Unmarshal([]byte(strconv.FormatUint(uint64(int16Overflow), 10)), &i)
maybePanic(err)
fmt.Println(i)
// Attempt to overflow
int16Overflow++
err = json.Unmarshal([]byte(strconv.FormatUint(uint64(int16Overflow), 10)), &i)
fmt.Println(i)
if err == nil {
panic("err should be present; decoded value overflows int16")
}

View file

@ -1,35 +1,27 @@
package null
import (
"bytes"
"database/sql/driver"
"encoding/json"
"fmt"
"reflect"
"math"
"strconv"
"gopkg.in/nullbio/null.v5/convert"
)
// NullInt32 is a replica of sql.NullInt64 for int32 types.
type NullInt32 struct {
// Int32 is an nullable int32.
type Int32 struct {
Int32 int32
Valid bool
}
// Int32 is an nullable int32.
// It does not consider zero values to be null.
// It will decode to null, not zero, if null.
type Int32 struct {
NullInt32
}
// NewInt32 creates a new Int32
func NewInt32(i int32, valid bool) Int32 {
return Int32{
NullInt32: NullInt32{
Int32: i,
Valid: valid,
},
Int32: i,
Valid: valid,
}
}
@ -47,34 +39,28 @@ func Int32FromPtr(i *int32) Int32 {
}
// UnmarshalJSON implements json.Unmarshaler.
// It supports number and null input.
// 0 will not be considered a null Int32.
// It also supports unmarshalling a sql.NullInt32.
func (i *Int32) UnmarshalJSON(data []byte) error {
var err error
var v interface{}
if err = json.Unmarshal(data, &v); err != nil {
if bytes.Equal(data, NullBytes) {
i.Valid = false
i.Int32 = 0
return nil
}
var x int64
if err := json.Unmarshal(data, &x); err != nil {
return err
}
switch v.(type) {
case float64:
// Unmarshal again, directly to int32, to avoid intermediate float64
err = json.Unmarshal(data, &i.Int32)
case map[string]interface{}:
err = json.Unmarshal(data, &i.NullInt32)
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())
if x > math.MaxInt32 {
return fmt.Errorf("json: %d overflows max int32 value", x)
}
i.Valid = err == nil
return err
i.Int32 = int32(x)
i.Valid = true
return nil
}
// UnmarshalText implements encoding.TextUnmarshaler.
// It will unmarshal to a null Int32 if the input is a blank or not an integer.
// It will return an error if the input is not an integer, blank, or "null".
func (i *Int32) UnmarshalText(text []byte) error {
str := string(text)
if str == "" || str == "null" {
@ -91,7 +77,6 @@ func (i *Int32) UnmarshalText(text []byte) error {
}
// MarshalJSON implements json.Marshaler.
// It will encode null if this Int32 is null.
func (i Int32) MarshalJSON() ([]byte, error) {
if !i.Valid {
return []byte("null"), nil
@ -100,7 +85,6 @@ func (i Int32) MarshalJSON() ([]byte, error) {
}
// MarshalText implements encoding.TextMarshaler.
// It will encode a blank string if this Int32 is null.
func (i Int32) MarshalText() ([]byte, error) {
if !i.Valid {
return []byte{}, nil
@ -123,25 +107,24 @@ func (i Int32) Ptr() *int32 {
}
// IsZero returns true for invalid Int32's, for future omitempty support (Go 1.4?)
// A non-null Int32 with a 0 value will not be considered zero.
func (i Int32) IsZero() bool {
return !i.Valid
}
// Scan implements the Scanner interface.
func (n *NullInt32) Scan(value interface{}) error {
func (i *Int32) Scan(value interface{}) error {
if value == nil {
n.Int32, n.Valid = 0, false
i.Int32, i.Valid = 0, false
return nil
}
n.Valid = true
return convert.ConvertAssign(&n.Int32, value)
i.Valid = true
return convert.ConvertAssign(&i.Int32, value)
}
// Value implements the driver Valuer interface.
func (n NullInt32) Value() (driver.Value, error) {
if !n.Valid {
func (i Int32) Value() (driver.Value, error) {
if !i.Valid {
return nil, nil
}
return int64(n.Int32), nil
return int64(i.Int32), nil
}

View file

@ -8,8 +8,7 @@ import (
)
var (
int32JSON = []byte(`2147483646`)
nullInt32JSON = []byte(`{"Int32":2147483646,"Valid":true}`)
int32JSON = []byte(`2147483646`)
)
func TestInt32From(t *testing.T) {
@ -38,11 +37,6 @@ func TestUnmarshalInt32(t *testing.T) {
maybePanic(err)
assertInt32(t, i, "int32 json")
var ni Int32
err = json.Unmarshal(nullInt32JSON, &ni)
maybePanic(err)
assertInt32(t, ni, "sq.NullInt32 json")
var null Int32
err = json.Unmarshal(nullJSON, &null)
maybePanic(err)

View file

@ -1,27 +1,25 @@
package null
import (
"database/sql"
"bytes"
"database/sql/driver"
"encoding/json"
"fmt"
"reflect"
"strconv"
"github.com/nullbio/null/convert"
)
// Int64 is an nullable int64.
// It does not consider zero values to be null.
// It will decode to null, not zero, if null.
type Int64 struct {
sql.NullInt64
Int64 int64
Valid bool
}
// NewInt64 creates a new Int64
func NewInt64(i int64, valid bool) Int64 {
return Int64{
NullInt64: sql.NullInt64{
Int64: i,
Valid: valid,
},
Int64: i,
Valid: valid,
}
}
@ -39,34 +37,22 @@ func Int64FromPtr(i *int64) Int64 {
}
// UnmarshalJSON implements json.Unmarshaler.
// It supports number and null input.
// 0 will not be considered a null Int64.
// It also supports unmarshalling a sql.NullInt64.
func (i *Int64) UnmarshalJSON(data []byte) error {
var err error
var v interface{}
if err = json.Unmarshal(data, &v); err != nil {
if bytes.Equal(data, NullBytes) {
i.Valid = false
i.Int64 = 0
return nil
}
if err := json.Unmarshal(data, &i.Int64); err != nil {
return err
}
switch v.(type) {
case float64:
// Unmarshal again, directly to int64, to avoid intermediate float64
err = json.Unmarshal(data, &i.Int64)
case map[string]interface{}:
err = json.Unmarshal(data, &i.NullInt64)
case nil:
i.Valid = false
return nil
default:
err = fmt.Errorf("json: cannot unmarshal %v into Go value of type null.Int64", reflect.TypeOf(v).Name())
}
i.Valid = err == nil
return err
i.Valid = true
return nil
}
// UnmarshalText implements encoding.TextUnmarshaler.
// It will unmarshal to a null Int64 if the input is a blank or not an integer.
// It will return an error if the input is not an integer, blank, or "null".
func (i *Int64) UnmarshalText(text []byte) error {
str := string(text)
if str == "" || str == "null" {
@ -80,7 +66,6 @@ func (i *Int64) UnmarshalText(text []byte) error {
}
// MarshalJSON implements json.Marshaler.
// It will encode null if this Int64 is null.
func (i Int64) MarshalJSON() ([]byte, error) {
if !i.Valid {
return []byte("null"), nil
@ -89,7 +74,6 @@ func (i Int64) MarshalJSON() ([]byte, error) {
}
// MarshalText implements encoding.TextMarshaler.
// It will encode a blank string if this Int64 is null.
func (i Int64) MarshalText() ([]byte, error) {
if !i.Valid {
return []byte{}, nil
@ -112,7 +96,24 @@ func (i Int64) Ptr() *int64 {
}
// IsZero returns true for invalid Int64's, for future omitempty support (Go 1.4?)
// A non-null Int64 with a 0 value will not be considered zero.
func (i Int64) IsZero() bool {
return !i.Valid
}
// Scan implements the Scanner interface.
func (i *Int64) Scan(value interface{}) error {
if value == nil {
i.Int64, i.Valid = 0, false
return nil
}
i.Valid = true
return convert.ConvertAssign(&i.Int64, value)
}
// Value implements the driver Valuer interface.
func (i Int64) Value() (driver.Value, error) {
if !i.Valid {
return nil, nil
}
return i.Int64, nil
}

View file

@ -8,8 +8,7 @@ import (
)
var (
int64JSON = []byte(`9223372036854775806`)
nullInt64JSON = []byte(`{"Int64":9223372036854775806,"Valid":true}`)
int64JSON = []byte(`9223372036854775806`)
)
func TestInt64From(t *testing.T) {
@ -38,11 +37,6 @@ func TestUnmarshalInt64(t *testing.T) {
maybePanic(err)
assertInt64(t, i, "int64 json")
var ni Int64
err = json.Unmarshal(nullInt64JSON, &ni)
maybePanic(err)
assertInt64(t, ni, "sq.NullInt64 json")
var null Int64
err = json.Unmarshal(nullJSON, &null)
maybePanic(err)

73
int8.go
View file

@ -1,35 +1,27 @@
package null
import (
"bytes"
"database/sql/driver"
"encoding/json"
"fmt"
"reflect"
"math"
"strconv"
"gopkg.in/nullbio/null.v5/convert"
)
// NullInt8 is a replica of sql.NullInt64 for int8 types.
type NullInt8 struct {
// Int8 is an nullable int8.
type Int8 struct {
Int8 int8
Valid bool
}
// Int8 is an nullable int8.
// It does not consider zero values to be null.
// It will decode to null, not zero, if null.
type Int8 struct {
NullInt8
}
// NewInt8 creates a new Int8
func NewInt8(i int8, valid bool) Int8 {
return Int8{
NullInt8: NullInt8{
Int8: i,
Valid: valid,
},
Int8: i,
Valid: valid,
}
}
@ -47,34 +39,28 @@ func Int8FromPtr(i *int8) Int8 {
}
// UnmarshalJSON implements json.Unmarshaler.
// It supports number and null input.
// 0 will not be considered a null Int8.
// It also supports unmarshalling a sql.NullInt8.
func (i *Int8) UnmarshalJSON(data []byte) error {
var err error
var v interface{}
if err = json.Unmarshal(data, &v); err != nil {
if bytes.Equal(data, NullBytes) {
i.Valid = false
i.Int8 = 0
return nil
}
var x int64
if err := json.Unmarshal(data, &x); err != nil {
return err
}
switch v.(type) {
case float64:
// Unmarshal again, directly to int8, to avoid intermediate float64
err = json.Unmarshal(data, &i.Int8)
case map[string]interface{}:
err = json.Unmarshal(data, &i.NullInt8)
case nil:
i.Valid = false
return nil
default:
err = fmt.Errorf("json: cannot unmarshal %v into Go value of type null.Int8", reflect.TypeOf(v).Name())
if x > math.MaxInt8 {
return fmt.Errorf("json: %d overflows max int8 value", x)
}
i.Valid = err == nil
return err
i.Int8 = int8(x)
i.Valid = true
return nil
}
// UnmarshalText implements encoding.TextUnmarshaler.
// It will unmarshal to a null Int8 if the input is a blank or not an integer.
// It will return an error if the input is not an integer, blank, or "null".
func (i *Int8) UnmarshalText(text []byte) error {
str := string(text)
if str == "" || str == "null" {
@ -91,7 +77,6 @@ func (i *Int8) UnmarshalText(text []byte) error {
}
// MarshalJSON implements json.Marshaler.
// It will encode null if this Int8 is null.
func (i Int8) MarshalJSON() ([]byte, error) {
if !i.Valid {
return []byte("null"), nil
@ -100,7 +85,6 @@ func (i Int8) MarshalJSON() ([]byte, error) {
}
// MarshalText implements encoding.TextMarshaler.
// It will encode a blank string if this Int8 is null.
func (i Int8) MarshalText() ([]byte, error) {
if !i.Valid {
return []byte{}, nil
@ -123,25 +107,24 @@ func (i Int8) Ptr() *int8 {
}
// IsZero returns true for invalid Int8's, for future omitempty support (Go 1.4?)
// A non-null Int8 with a 0 value will not be considered zero.
func (i Int8) IsZero() bool {
return !i.Valid
}
// Scan implements the Scanner interface.
func (n *NullInt8) Scan(value interface{}) error {
func (i *Int8) Scan(value interface{}) error {
if value == nil {
n.Int8, n.Valid = 0, false
i.Int8, i.Valid = 0, false
return nil
}
n.Valid = true
return convert.ConvertAssign(&n.Int8, value)
i.Valid = true
return convert.ConvertAssign(&i.Int8, value)
}
// Value implements the driver Valuer interface.
func (n NullInt8) Value() (driver.Value, error) {
if !n.Valid {
func (i Int8) Value() (driver.Value, error) {
if !i.Valid {
return nil, nil
}
return int64(n.Int8), nil
return int64(i.Int8), nil
}

View file

@ -8,8 +8,7 @@ import (
)
var (
int8JSON = []byte(`126`)
nullInt8JSON = []byte(`{"Int8":126,"Valid":true}`)
int8JSON = []byte(`126`)
)
func TestInt8From(t *testing.T) {
@ -38,11 +37,6 @@ func TestUnmarshalInt8(t *testing.T) {
maybePanic(err)
assertInt8(t, i, "int8 json")
var ni Int8
err = json.Unmarshal(nullInt8JSON, &ni)
maybePanic(err)
assertInt8(t, ni, "sq.NullInt8 json")
var null Int8
err = json.Unmarshal(nullJSON, &null)
maybePanic(err)

View file

@ -6,8 +6,7 @@ import (
)
var (
intJSON = []byte(`12345`)
nullIntJSON = []byte(`{"Int":12345,"Valid":true}`)
intJSON = []byte(`12345`)
)
func TestIntFrom(t *testing.T) {
@ -36,11 +35,6 @@ func TestUnmarshalInt(t *testing.T) {
maybePanic(err)
assertInt(t, i, "int json")
var ni Int
err = json.Unmarshal(nullIntJSON, &ni)
maybePanic(err)
assertInt(t, ni, "sq.NullInt json")
var null Int
err = json.Unmarshal(nullJSON, &null)
maybePanic(err)

View file

@ -58,7 +58,6 @@ func (j JSON) Unmarshal(dest interface{}) error {
}
// UnmarshalJSON implements json.Unmarshaler.
// If not, it will copy your data slice into JSON.
func (j *JSON) UnmarshalJSON(data []byte) error {
if data == nil {
return fmt.Errorf("json: cannot unmarshal nil into Go value of type null.JSON")
@ -78,7 +77,6 @@ func (j *JSON) UnmarshalJSON(data []byte) error {
}
// UnmarshalText implements encoding.TextUnmarshaler.
// It will unmarshal to nil if the text is nil or len 0.
func (j *JSON) UnmarshalText(text []byte) error {
if text == nil || len(text) == 0 {
j.JSON = nil
@ -106,7 +104,6 @@ func (j *JSON) Marshal(obj interface{}) error {
}
// MarshalJSON implements json.Marshaler.
// It will encode null if the JSON is nil.
func (j JSON) MarshalJSON() ([]byte, error) {
if len(j.JSON) == 0 || j.JSON == nil {
return []byte("null"), nil
@ -115,7 +112,6 @@ func (j JSON) MarshalJSON() ([]byte, error) {
}
// MarshalText implements encoding.TextMarshaler.
// It will encode nil if the JSON is invalid.
func (j JSON) MarshalText() ([]byte, error) {
if !j.Valid {
return nil, nil

View file

@ -1,20 +1,17 @@
// Package null contains SQL types that consider zero input and null input as separate values,
// with convenient support for JSON and text marshaling.
// Types in this package will always encode to their null value if null.
// Use the zero subpackage if you want zero values and null to be treated the same.
package null
import (
"database/sql"
"bytes"
"database/sql/driver"
"encoding/json"
"fmt"
"reflect"
"github.com/nullbio/null/convert"
)
// String is a nullable string. It supports SQL and JSON serialization.
// It will marshal to null if null. Blank string input will be considered null.
type String struct {
sql.NullString
String string
Valid bool
}
// StringFrom creates a new String that will never be blank.
@ -33,39 +30,28 @@ func StringFromPtr(s *string) String {
// NewString creates a new String
func NewString(s string, valid bool) String {
return String{
NullString: sql.NullString{
String: s,
Valid: valid,
},
String: s,
Valid: valid,
}
}
// UnmarshalJSON implements json.Unmarshaler.
// It supports string and null input. Blank string input does not produce a null String.
// It also supports unmarshalling a sql.NullString.
func (s *String) UnmarshalJSON(data []byte) error {
var err error
var v interface{}
if err = json.Unmarshal(data, &v); err != nil {
return err
}
switch x := v.(type) {
case string:
s.String = x
case map[string]interface{}:
err = json.Unmarshal(data, &s.NullString)
case nil:
if bytes.Equal(data, NullBytes) {
s.String = ""
s.Valid = false
return nil
default:
err = fmt.Errorf("json: cannot unmarshal %v into Go value of type null.String", reflect.TypeOf(v).Name())
}
s.Valid = err == nil
return err
if err := json.Unmarshal(data, &s.String); err != nil {
return err
}
s.Valid = true
return nil
}
// MarshalJSON implements json.Marshaler.
// It will encode null if this String is null.
func (s String) MarshalJSON() ([]byte, error) {
if !s.Valid {
return []byte("null"), nil
@ -74,7 +60,6 @@ func (s String) MarshalJSON() ([]byte, error) {
}
// MarshalText implements encoding.TextMarshaler.
// It will encode a blank string when this String is null.
func (s String) MarshalText() ([]byte, error) {
if !s.Valid {
return []byte{}, nil
@ -83,7 +68,6 @@ func (s String) MarshalText() ([]byte, error) {
}
// UnmarshalText implements encoding.TextUnmarshaler.
// It will unmarshal to a null String if the input is a blank string.
func (s *String) UnmarshalText(text []byte) error {
s.String = string(text)
s.Valid = s.String != ""
@ -108,3 +92,21 @@ func (s String) Ptr() *string {
func (s String) IsZero() bool {
return !s.Valid
}
// Scan implements the Scanner interface.
func (s *String) Scan(value interface{}) error {
if value == nil {
s.String, s.Valid = "", false
return nil
}
s.Valid = true
return convert.ConvertAssign(&s.String, value)
}
// Value implements the driver Valuer interface.
func (s String) Value() (driver.Value, error) {
if !s.Valid {
return nil, nil
}
return s.String, nil
}

View file

@ -8,7 +8,6 @@ import (
var (
stringJSON = []byte(`"test"`)
blankStringJSON = []byte(`""`)
nullStringJSON = []byte(`{"String":"test","Valid":true}`)
nullJSON = []byte(`null`)
invalidJSON = []byte(`:)`)
@ -44,11 +43,6 @@ func TestUnmarshalString(t *testing.T) {
maybePanic(err)
assertStr(t, str, "string json")
var ns String
err = json.Unmarshal(nullStringJSON, &ns)
maybePanic(err)
assertStr(t, ns, "sql.NullString json")
var blank String
err = json.Unmarshal(blankStringJSON, &blank)
maybePanic(err)

88
time.go
View file

@ -1,44 +1,18 @@
package null
import (
"bytes"
"database/sql/driver"
"encoding/json"
"fmt"
"reflect"
"time"
)
// Time is a nullable time.Time. It supports SQL and JSON serialization.
// It will marshal to null if null.
type Time struct {
Time time.Time
Valid bool
}
// Scan implements the Scanner interface.
func (t *Time) Scan(value interface{}) error {
var err error
switch x := value.(type) {
case time.Time:
t.Time = x
case nil:
t.Valid = false
return nil
default:
err = fmt.Errorf("null: cannot scan type %T into null.Time: %v", value, value)
}
t.Valid = err == nil
return err
}
// Value implements the driver Valuer interface.
func (t Time) Value() (driver.Value, error) {
if !t.Valid {
return nil, nil
}
return t.Time, nil
}
// NewTime creates a new Time.
func NewTime(t time.Time, valid bool) Time {
return Time{
@ -61,7 +35,6 @@ func TimeFromPtr(t *time.Time) Time {
}
// MarshalJSON implements json.Marshaler.
// It will encode null if this time is null.
func (t Time) MarshalJSON() ([]byte, error) {
if !t.Valid {
return []byte("null"), nil
@ -70,36 +43,22 @@ func (t Time) MarshalJSON() ([]byte, error) {
}
// UnmarshalJSON implements json.Unmarshaler.
// It supports string, object (e.g. pq.NullTime and friends)
// and null input.
func (t *Time) UnmarshalJSON(data []byte) error {
var err error
var v interface{}
if err = json.Unmarshal(data, &v); err != nil {
return err
}
switch x := v.(type) {
case string:
err = t.Time.UnmarshalJSON(data)
case map[string]interface{}:
ti, tiOK := x["Time"].(string)
valid, validOK := x["Valid"].(bool)
if !tiOK || !validOK {
return fmt.Errorf(`json: unmarshalling object into Go value of type null.Time requires key "Time" to be of type string and key "Valid" to be of type bool; found %T and %T, respectively`, x["Time"], x["Valid"])
}
err = t.Time.UnmarshalText([]byte(ti))
t.Valid = valid
return err
case nil:
if bytes.Equal(data, NullBytes) {
t.Valid = false
t.Time = time.Time{}
return nil
default:
err = fmt.Errorf("json: cannot unmarshal %v into Go value of type null.Time", reflect.TypeOf(v).Name())
}
t.Valid = err == nil
return err
if err := t.Time.UnmarshalJSON(data); err != nil {
return err
}
t.Valid = true
return nil
}
// MarshalText implements encoding.TextMarshaler.
func (t Time) MarshalText() ([]byte, error) {
if !t.Valid {
return []byte("null"), nil
@ -107,6 +66,7 @@ func (t Time) MarshalText() ([]byte, error) {
return t.Time.MarshalText()
}
// UnmarshalText implements encoding.TextUnmarshaler.
func (t *Time) UnmarshalText(text []byte) error {
str := string(text)
if str == "" || str == "null" {
@ -133,3 +93,27 @@ func (t Time) Ptr() *time.Time {
}
return &t.Time
}
// Scan implements the Scanner interface.
func (t *Time) Scan(value interface{}) error {
var err error
switch x := value.(type) {
case time.Time:
t.Time = x
case nil:
t.Valid = false
return nil
default:
err = fmt.Errorf("null: cannot scan type %T into null.Time: %v", value, value)
}
t.Valid = err == nil
return err
}
// Value implements the driver Valuer interface.
func (t Time) Value() (driver.Value, error) {
if !t.Valid {
return nil, nil
}
return t.Time, nil
}

View file

@ -11,8 +11,6 @@ var (
timeJSON = []byte(`"` + timeString + `"`)
nullTimeJSON = []byte(`null`)
timeValue, _ = time.Parse(time.RFC3339, timeString)
timeObject = []byte(`{"Time":"2012-12-21T21:21:21Z","Valid":true}`)
nullObject = []byte(`{"Time":"0001-01-01T00:00:00Z","Valid":false}`)
badObject = []byte(`{"hello": "world"}`)
)
@ -27,20 +25,10 @@ func TestUnmarshalTimeJSON(t *testing.T) {
maybePanic(err)
assertNullTime(t, null, "null time json")
var fromObject Time
err = json.Unmarshal(timeObject, &fromObject)
maybePanic(err)
assertTime(t, fromObject, "time from object json")
var nullFromObj Time
err = json.Unmarshal(nullObject, &nullFromObj)
maybePanic(err)
assertNullTime(t, nullFromObj, "null from object json")
var invalid Time
err = invalid.UnmarshalJSON(invalidJSON)
if _, ok := err.(*json.SyntaxError); !ok {
t.Errorf("expected json.SyntaxError, not %T", err)
if _, ok := err.(*time.ParseError); !ok {
t.Errorf("expected json.ParseError, not %T", err)
}
assertNullTime(t, invalid, "invalid from object json")

111
uint.go
View file

@ -1,35 +1,25 @@
package null
import (
"bytes"
"database/sql/driver"
"encoding/json"
"fmt"
"reflect"
"strconv"
"gopkg.in/nullbio/null.v5/convert"
)
// NullUint is a replica of sql.NullInt64 for uint types.
type NullUint struct {
// Uint is an nullable uint.
type Uint struct {
Uint uint
Valid bool
}
// Uint is an nullable uint.
// It does not consider zero values to be null.
// It will decode to null, not zero, if null.
type Uint struct {
NullUint
}
// NewUint creates a new Uint
func NewUint(i uint, valid bool) Uint {
return Uint{
NullUint: NullUint{
Uint: i,
Valid: valid,
},
Uint: i,
Valid: valid,
}
}
@ -47,101 +37,88 @@ func UintFromPtr(i *uint) Uint {
}
// UnmarshalJSON implements json.Unmarshaler.
// It supports number and null input.
// 0 will not be considered a null Uint.
// It also supports unmarshalling a sql.NullUint.
func (i *Uint) UnmarshalJSON(data []byte) error {
var err error
var v interface{}
if err = json.Unmarshal(data, &v); err != nil {
func (u *Uint) UnmarshalJSON(data []byte) error {
if bytes.Equal(data, NullBytes) {
u.Valid = false
u.Uint = 0
return nil
}
var x uint64
if err := json.Unmarshal(data, &x); err != nil {
return err
}
switch v.(type) {
case float64:
// Unmarshal again, directly to uint, to avoid intermediate float64
err = json.Unmarshal(data, &i.Uint)
case map[string]interface{}:
err = json.Unmarshal(data, &i.NullUint)
case nil:
i.Valid = false
return nil
default:
err = fmt.Errorf("json: cannot unmarshal %v into Go value of type null.Uint", reflect.TypeOf(v).Name())
}
i.Valid = err == nil
return err
u.Uint = uint(x)
u.Valid = true
return nil
}
// UnmarshalText implements encoding.TextUnmarshaler.
// It will unmarshal to a null Uint if the input is a blank or not an integer.
// It will return an error if the input is not an integer, blank, or "null".
func (i *Uint) UnmarshalText(text []byte) error {
func (u *Uint) UnmarshalText(text []byte) error {
str := string(text)
if str == "" || str == "null" {
i.Valid = false
u.Valid = false
return nil
}
var err error
res, err := strconv.ParseUint(string(text), 10, 0)
i.Valid = err == nil
if i.Valid {
i.Uint = uint(res)
u.Valid = err == nil
if u.Valid {
u.Uint = uint(res)
}
return err
}
// MarshalJSON implements json.Marshaler.
// It will encode null if this Uint is null.
func (i Uint) MarshalJSON() ([]byte, error) {
if !i.Valid {
func (u Uint) MarshalJSON() ([]byte, error) {
if !u.Valid {
return []byte("null"), nil
}
return []byte(strconv.FormatUint(uint64(i.Uint), 10)), nil
return []byte(strconv.FormatUint(uint64(u.Uint), 10)), nil
}
// MarshalText implements encoding.TextMarshaler.
// It will encode a blank string if this Uint is null.
func (i Uint) MarshalText() ([]byte, error) {
if !i.Valid {
func (u Uint) MarshalText() ([]byte, error) {
if !u.Valid {
return []byte{}, nil
}
return []byte(strconv.FormatUint(uint64(i.Uint), 10)), nil
return []byte(strconv.FormatUint(uint64(u.Uint), 10)), nil
}
// SetValid changes this Uint's value and also sets it to be non-null.
func (i *Uint) SetValid(n uint) {
i.Uint = n
i.Valid = true
func (u *Uint) SetValid(n uint) {
u.Uint = n
u.Valid = true
}
// Ptr returns a pointer to this Uint's value, or a nil pointer if this Uint is null.
func (i Uint) Ptr() *uint {
if !i.Valid {
func (u Uint) Ptr() *uint {
if !u.Valid {
return nil
}
return &i.Uint
return &u.Uint
}
// IsZero returns true for invalid Uints, for future omitempty support (Go 1.4?)
// A non-null Uint with a 0 value will not be considered zero.
func (i Uint) IsZero() bool {
return !i.Valid
func (u Uint) IsZero() bool {
return !u.Valid
}
// Scan implements the Scanner interface.
func (n *NullUint) Scan(value interface{}) error {
func (u *Uint) Scan(value interface{}) error {
if value == nil {
n.Uint, n.Valid = 0, false
u.Uint, u.Valid = 0, false
return nil
}
n.Valid = true
return convert.ConvertAssign(&n.Uint, value)
u.Valid = true
return convert.ConvertAssign(&u.Uint, value)
}
// Value implements the driver Valuer interface.
func (n NullUint) Value() (driver.Value, error) {
if !n.Valid {
func (u Uint) Value() (driver.Value, error) {
if !u.Valid {
return nil, nil
}
return int64(n.Uint), nil
return int64(u.Uint), nil
}

113
uint16.go
View file

@ -1,35 +1,27 @@
package null
import (
"bytes"
"database/sql/driver"
"encoding/json"
"fmt"
"reflect"
"math"
"strconv"
"gopkg.in/nullbio/null.v5/convert"
)
// NullUint16 is a replica of sql.NullInt64 for uint16 types.
type NullUint16 struct {
// Uint16 is an nullable uint16.
type Uint16 struct {
Uint16 uint16
Valid bool
}
// Uint16 is an nullable uint16.
// It does not consider zero values to be null.
// It will decode to null, not zero, if null.
type Uint16 struct {
NullUint16
}
// NewUint16 creates a new Uint16
func NewUint16(i uint16, valid bool) Uint16 {
return Uint16{
NullUint16: NullUint16{
Uint16: i,
Valid: valid,
},
Uint16: i,
Valid: valid,
}
}
@ -47,101 +39,92 @@ func Uint16FromPtr(i *uint16) Uint16 {
}
// UnmarshalJSON implements json.Unmarshaler.
// It supports number and null input.
// 0 will not be considered a null Uint16.
// It also supports unmarshalling a sql.NullUint16.
func (i *Uint16) UnmarshalJSON(data []byte) error {
var err error
var v interface{}
if err = json.Unmarshal(data, &v); err != nil {
func (u *Uint16) UnmarshalJSON(data []byte) error {
if bytes.Equal(data, NullBytes) {
u.Valid = false
u.Uint16 = 0
return nil
}
var x uint64
if err := json.Unmarshal(data, &x); err != nil {
return err
}
switch v.(type) {
case float64:
// Unmarshal again, directly to uint16, to avoid intermediate float64
err = json.Unmarshal(data, &i.Uint16)
case map[string]interface{}:
err = json.Unmarshal(data, &i.NullUint16)
case nil:
i.Valid = false
return nil
default:
err = fmt.Errorf("json: cannot unmarshal %v into Go value of type null.Uint16", reflect.TypeOf(v).Name())
if x > math.MaxUint16 {
return fmt.Errorf("json: %d overflows max uint8 value", x)
}
i.Valid = err == nil
return err
u.Uint16 = uint16(x)
u.Valid = true
return nil
}
// UnmarshalText implements encoding.TextUnmarshaler.
// It will unmarshal to a null Uint16 if the input is a blank or not an integer.
// It will return an error if the input is not an integer, blank, or "null".
func (i *Uint16) UnmarshalText(text []byte) error {
func (u *Uint16) UnmarshalText(text []byte) error {
str := string(text)
if str == "" || str == "null" {
i.Valid = false
u.Valid = false
return nil
}
var err error
res, err := strconv.ParseUint(string(text), 10, 16)
i.Valid = err == nil
if i.Valid {
i.Uint16 = uint16(res)
u.Valid = err == nil
if u.Valid {
u.Uint16 = uint16(res)
}
return err
}
// MarshalJSON implements json.Marshaler.
// It will encode null if this Uint16 is null.
func (i Uint16) MarshalJSON() ([]byte, error) {
if !i.Valid {
func (u Uint16) MarshalJSON() ([]byte, error) {
if !u.Valid {
return []byte("null"), nil
}
return []byte(strconv.FormatUint(uint64(i.Uint16), 10)), nil
return []byte(strconv.FormatUint(uint64(u.Uint16), 10)), nil
}
// MarshalText implements encoding.TextMarshaler.
// It will encode a blank string if this Uint16 is null.
func (i Uint16) MarshalText() ([]byte, error) {
if !i.Valid {
func (u Uint16) MarshalText() ([]byte, error) {
if !u.Valid {
return []byte{}, nil
}
return []byte(strconv.FormatUint(uint64(i.Uint16), 10)), nil
return []byte(strconv.FormatUint(uint64(u.Uint16), 10)), nil
}
// SetValid changes this Uint16's value and also sets it to be non-null.
func (i *Uint16) SetValid(n uint16) {
i.Uint16 = n
i.Valid = true
func (u *Uint16) SetValid(n uint16) {
u.Uint16 = n
u.Valid = true
}
// Ptr returns a pointer to this Uint16's value, or a nil pointer if this Uint16 is null.
func (i Uint16) Ptr() *uint16 {
if !i.Valid {
func (u Uint16) Ptr() *uint16 {
if !u.Valid {
return nil
}
return &i.Uint16
return &u.Uint16
}
// IsZero returns true for invalid Uint16's, for future omitempty support (Go 1.4?)
// A non-null Uint16 with a 0 value will not be considered zero.
func (i Uint16) IsZero() bool {
return !i.Valid
func (u Uint16) IsZero() bool {
return !u.Valid
}
// Scan implements the Scanner interface.
func (n *NullUint16) Scan(value interface{}) error {
func (u *Uint16) Scan(value interface{}) error {
if value == nil {
n.Uint16, n.Valid = 0, false
u.Uint16, u.Valid = 0, false
return nil
}
n.Valid = true
return convert.ConvertAssign(&n.Uint16, value)
u.Valid = true
return convert.ConvertAssign(&u.Uint16, value)
}
// Value implements the driver Valuer interface.
func (n NullUint16) Value() (driver.Value, error) {
if !n.Valid {
func (u Uint16) Value() (driver.Value, error) {
if !u.Valid {
return nil, nil
}
return int64(n.Uint16), nil
return int64(u.Uint16), nil
}

View file

@ -8,8 +8,7 @@ import (
)
var (
uint16JSON = []byte(`65534`)
nullUint16JSON = []byte(`{"Uint16":65534,"Valid":true}`)
uint16JSON = []byte(`65534`)
)
func TestUint16From(t *testing.T) {
@ -38,11 +37,6 @@ func TestUnmarshalUint16(t *testing.T) {
maybePanic(err)
assertUint16(t, i, "uint16 json")
var ni Uint16
err = json.Unmarshal(nullUint16JSON, &ni)
maybePanic(err)
assertUint16(t, ni, "sq.NullUint16 json")
var null Uint16
err = json.Unmarshal(nullJSON, &null)
maybePanic(err)

113
uint32.go
View file

@ -1,35 +1,27 @@
package null
import (
"bytes"
"database/sql/driver"
"encoding/json"
"fmt"
"reflect"
"math"
"strconv"
"gopkg.in/nullbio/null.v5/convert"
)
// NullUint32 is a replica of sql.NullInt64 for uint32 types.
type NullUint32 struct {
// Uint32 is an nullable uint32.
type Uint32 struct {
Uint32 uint32
Valid bool
}
// Uint32 is an nullable uint32.
// It does not consider zero values to be null.
// It will decode to null, not zero, if null.
type Uint32 struct {
NullUint32
}
// NewUint32 creates a new Uint32
func NewUint32(i uint32, valid bool) Uint32 {
return Uint32{
NullUint32: NullUint32{
Uint32: i,
Valid: valid,
},
Uint32: i,
Valid: valid,
}
}
@ -47,101 +39,92 @@ func Uint32FromPtr(i *uint32) Uint32 {
}
// UnmarshalJSON implements json.Unmarshaler.
// It supports number and null input.
// 0 will not be considered a null Uint32.
// It also supports unmarshalling a sql.NullUint32.
func (i *Uint32) UnmarshalJSON(data []byte) error {
var err error
var v interface{}
if err = json.Unmarshal(data, &v); err != nil {
func (u *Uint32) UnmarshalJSON(data []byte) error {
if bytes.Equal(data, NullBytes) {
u.Valid = false
u.Uint32 = 0
return nil
}
var x uint64
if err := json.Unmarshal(data, &x); err != nil {
return err
}
switch v.(type) {
case float64:
// Unmarshal again, directly to uint32, to avoid intermediate float64
err = json.Unmarshal(data, &i.Uint32)
case map[string]interface{}:
err = json.Unmarshal(data, &i.NullUint32)
case nil:
i.Valid = false
return nil
default:
err = fmt.Errorf("json: cannot unmarshal %v into Go value of type null.Uint32", reflect.TypeOf(v).Name())
if x > math.MaxUint32 {
return fmt.Errorf("json: %d overflows max uint32 value", x)
}
i.Valid = err == nil
return err
u.Uint32 = uint32(x)
u.Valid = true
return nil
}
// UnmarshalText implements encoding.TextUnmarshaler.
// It will unmarshal to a null Uint32 if the input is a blank or not an integer.
// It will return an error if the input is not an integer, blank, or "null".
func (i *Uint32) UnmarshalText(text []byte) error {
func (u *Uint32) UnmarshalText(text []byte) error {
str := string(text)
if str == "" || str == "null" {
i.Valid = false
u.Valid = false
return nil
}
var err error
res, err := strconv.ParseUint(string(text), 10, 32)
i.Valid = err == nil
if i.Valid {
i.Uint32 = uint32(res)
u.Valid = err == nil
if u.Valid {
u.Uint32 = uint32(res)
}
return err
}
// MarshalJSON implements json.Marshaler.
// It will encode null if this Uint32 is null.
func (i Uint32) MarshalJSON() ([]byte, error) {
if !i.Valid {
func (u Uint32) MarshalJSON() ([]byte, error) {
if !u.Valid {
return []byte("null"), nil
}
return []byte(strconv.FormatUint(uint64(i.Uint32), 10)), nil
return []byte(strconv.FormatUint(uint64(u.Uint32), 10)), nil
}
// MarshalText implements encoding.TextMarshaler.
// It will encode a blank string if this Uint32 is null.
func (i Uint32) MarshalText() ([]byte, error) {
if !i.Valid {
func (u Uint32) MarshalText() ([]byte, error) {
if !u.Valid {
return []byte{}, nil
}
return []byte(strconv.FormatUint(uint64(i.Uint32), 10)), nil
return []byte(strconv.FormatUint(uint64(u.Uint32), 10)), nil
}
// SetValid changes this Uint32's value and also sets it to be non-null.
func (i *Uint32) SetValid(n uint32) {
i.Uint32 = n
i.Valid = true
func (u *Uint32) SetValid(n uint32) {
u.Uint32 = n
u.Valid = true
}
// Ptr returns a pointer to this Uint32's value, or a nil pointer if this Uint32 is null.
func (i Uint32) Ptr() *uint32 {
if !i.Valid {
func (u Uint32) Ptr() *uint32 {
if !u.Valid {
return nil
}
return &i.Uint32
return &u.Uint32
}
// IsZero returns true for invalid Uint32's, for future omitempty support (Go 1.4?)
// A non-null Uint32 with a 0 value will not be considered zero.
func (i Uint32) IsZero() bool {
return !i.Valid
func (u Uint32) IsZero() bool {
return !u.Valid
}
// Scan implements the Scanner interface.
func (n *NullUint32) Scan(value interface{}) error {
func (u *Uint32) Scan(value interface{}) error {
if value == nil {
n.Uint32, n.Valid = 0, false
u.Uint32, u.Valid = 0, false
return nil
}
n.Valid = true
return convert.ConvertAssign(&n.Uint32, value)
u.Valid = true
return convert.ConvertAssign(&u.Uint32, value)
}
// Value implements the driver Valuer interface.
func (n NullUint32) Value() (driver.Value, error) {
if !n.Valid {
func (u Uint32) Value() (driver.Value, error) {
if !u.Valid {
return nil, nil
}
return int64(n.Uint32), nil
return uint64(u.Uint32), nil
}

View file

@ -8,8 +8,7 @@ import (
)
var (
uint32JSON = []byte(`4294967294`)
nullUint32JSON = []byte(`{"Uint32":4294967294,"Valid":true}`)
uint32JSON = []byte(`4294967294`)
)
func TestUint32From(t *testing.T) {
@ -38,11 +37,6 @@ func TestUnmarshalUint32(t *testing.T) {
maybePanic(err)
assertUint32(t, i, "uint32 json")
var ni Uint32
err = json.Unmarshal(nullUint32JSON, &ni)
maybePanic(err)
assertUint32(t, ni, "sq.NullUint32 json")
var null Uint32
err = json.Unmarshal(nullJSON, &null)
maybePanic(err)

109
uint64.go
View file

@ -1,35 +1,25 @@
package null
import (
"bytes"
"database/sql/driver"
"encoding/json"
"fmt"
"reflect"
"strconv"
"gopkg.in/nullbio/null.v5/convert"
)
// NullUint64 is a replica of sql.NullInt64 for uint64 types.
type NullUint64 struct {
// Uint64 is an nullable uint64.
type Uint64 struct {
Uint64 uint64
Valid bool
}
// Uint64 is an nullable uint64.
// It does not consider zero values to be null.
// It will decode to null, not zero, if null.
type Uint64 struct {
NullUint64
}
// NewUint64 creates a new Uint64
func NewUint64(i uint64, valid bool) Uint64 {
return Uint64{
NullUint64: NullUint64{
Uint64: i,
Valid: valid,
},
Uint64: i,
Valid: valid,
}
}
@ -47,101 +37,86 @@ func Uint64FromPtr(i *uint64) Uint64 {
}
// UnmarshalJSON implements json.Unmarshaler.
// It supports number and null input.
// 0 will not be considered a null Uint64.
// It also supports unmarshalling a sql.NullUint64.
func (i *Uint64) UnmarshalJSON(data []byte) error {
var err error
var v interface{}
if err = json.Unmarshal(data, &v); err != nil {
func (u *Uint64) UnmarshalJSON(data []byte) error {
if bytes.Equal(data, NullBytes) {
u.Uint64 = 0
u.Valid = false
return nil
}
if err := json.Unmarshal(data, &u.Uint64); err != nil {
return err
}
switch v.(type) {
case float64:
// Unmarshal again, directly to uint64, to avoid intermediate float64
err = json.Unmarshal(data, &i.Uint64)
case map[string]interface{}:
err = json.Unmarshal(data, &i.NullUint64)
case nil:
i.Valid = false
return nil
default:
err = fmt.Errorf("json: cannot unmarshal %v into Go value of type null.Uint64", reflect.TypeOf(v).Name())
}
i.Valid = err == nil
return err
u.Valid = true
return nil
}
// UnmarshalText implements encoding.TextUnmarshaler.
// It will unmarshal to a null Uint64 if the input is a blank or not an integer.
// It will return an error if the input is not an integer, blank, or "null".
func (i *Uint64) UnmarshalText(text []byte) error {
func (u *Uint64) UnmarshalText(text []byte) error {
str := string(text)
if str == "" || str == "null" {
i.Valid = false
u.Valid = false
return nil
}
var err error
res, err := strconv.ParseUint(string(text), 10, 64)
i.Valid = err == nil
if i.Valid {
i.Uint64 = uint64(res)
u.Valid = err == nil
if u.Valid {
u.Uint64 = uint64(res)
}
return err
}
// MarshalJSON implements json.Marshaler.
// It will encode null if this Uint64 is null.
func (i Uint64) MarshalJSON() ([]byte, error) {
if !i.Valid {
func (u Uint64) MarshalJSON() ([]byte, error) {
if !u.Valid {
return []byte("null"), nil
}
return []byte(strconv.FormatUint(i.Uint64, 10)), nil
return []byte(strconv.FormatUint(u.Uint64, 10)), nil
}
// MarshalText implements encoding.TextMarshaler.
// It will encode a blank string if this Uint64 is null.
func (i Uint64) MarshalText() ([]byte, error) {
if !i.Valid {
func (u Uint64) MarshalText() ([]byte, error) {
if !u.Valid {
return []byte{}, nil
}
return []byte(strconv.FormatUint(i.Uint64, 10)), nil
return []byte(strconv.FormatUint(u.Uint64, 10)), nil
}
// SetValid changes this Uint64's value and also sets it to be non-null.
func (i *Uint64) SetValid(n uint64) {
i.Uint64 = n
i.Valid = true
func (u *Uint64) SetValid(n uint64) {
u.Uint64 = n
u.Valid = true
}
// Ptr returns a pointer to this Uint64's value, or a nil pointer if this Uint64 is null.
func (i Uint64) Ptr() *uint64 {
if !i.Valid {
func (u Uint64) Ptr() *uint64 {
if !u.Valid {
return nil
}
return &i.Uint64
return &u.Uint64
}
// IsZero returns true for invalid Uint64's, for future omitempty support (Go 1.4?)
// A non-null Uint64 with a 0 value will not be considered zero.
func (i Uint64) IsZero() bool {
return !i.Valid
func (u Uint64) IsZero() bool {
return !u.Valid
}
// Scan implements the Scanner interface.
func (n *NullUint64) Scan(value interface{}) error {
func (u *Uint64) Scan(value interface{}) error {
if value == nil {
n.Uint64, n.Valid = 0, false
u.Uint64, u.Valid = 0, false
return nil
}
n.Valid = true
return convert.ConvertAssign(&n.Uint64, value)
u.Valid = true
return convert.ConvertAssign(&u.Uint64, value)
}
// Value implements the driver Valuer interface.
func (n NullUint64) Value() (driver.Value, error) {
if !n.Valid {
func (u Uint64) Value() (driver.Value, error) {
if !u.Valid {
return nil, nil
}
return int64(n.Uint64), nil
return int64(u.Uint64), nil
}

View file

@ -6,8 +6,7 @@ import (
)
var (
uint64JSON = []byte(`18446744073709551614`)
nullUint64JSON = []byte(`{"Uint64":18446744073709551614,"Valid":true}`)
uint64JSON = []byte(`18446744073709551614`)
)
func TestUint64From(t *testing.T) {
@ -36,11 +35,6 @@ func TestUnmarshalUint64(t *testing.T) {
maybePanic(err)
assertUint64(t, i, "uint64 json")
var ni Uint64
err = json.Unmarshal(nullUint64JSON, &ni)
maybePanic(err)
assertUint64(t, ni, "sq.NullUint64 json")
var null Uint64
err = json.Unmarshal(nullJSON, &null)
maybePanic(err)

109
uint8.go
View file

@ -1,35 +1,27 @@
package null
import (
"bytes"
"database/sql/driver"
"encoding/json"
"fmt"
"reflect"
"math"
"strconv"
"gopkg.in/nullbio/null.v5/convert"
)
// NullUint8 is a replica of sql.NullInt64 for uint8 types.
type NullUint8 struct {
// Uint8 is an nullable uint8.
type Uint8 struct {
Uint8 uint8
Valid bool
}
// Uint8 is an nullable uint8.
// It does not consider zero values to be null.
// It will decode to null, not zero, if null.
type Uint8 struct {
NullUint8
}
// NewUint8 creates a new Uint8
func NewUint8(i uint8, valid bool) Uint8 {
return Uint8{
NullUint8: NullUint8{
Uint8: i,
Valid: valid,
},
Uint8: i,
Valid: valid,
}
}
@ -47,99 +39,90 @@ func Uint8FromPtr(i *uint8) Uint8 {
}
// UnmarshalJSON implements json.Unmarshaler.
// It supports number and null input.
// 0 will not be considered a null Uint8.
// It also supports unmarshalling a sql.NullUint8.
func (i *Uint8) UnmarshalJSON(data []byte) error {
var err error
var v interface{}
if err = json.Unmarshal(data, &v); err != nil {
func (u *Uint8) UnmarshalJSON(data []byte) error {
if bytes.Equal(data, NullBytes) {
u.Valid = false
u.Uint8 = 0
return nil
}
var x uint64
if err := json.Unmarshal(data, &x); err != nil {
return err
}
switch v.(type) {
case float64:
// Unmarshal again, directly to uint8, to avoid intermediate float64
err = json.Unmarshal(data, &i.Uint8)
case map[string]interface{}:
err = json.Unmarshal(data, &i.NullUint8)
case nil:
i.Valid = false
return nil
default:
err = fmt.Errorf("json: cannot unmarshal %v into Go value of type null.Uint8", reflect.TypeOf(v).Name())
if x > math.MaxUint8 {
return fmt.Errorf("json: %d overflows max uint8 value", x)
}
i.Valid = err == nil
return err
u.Uint8 = uint8(x)
u.Valid = true
return nil
}
// UnmarshalText implements encoding.TextUnmarshaler.
// It will unmarshal to a null Uint8 if the input is a blank or not an integer.
// It will return an error if the input is not an integer, blank, or "null".
func (i *Uint8) UnmarshalText(text []byte) error {
func (u *Uint8) UnmarshalText(text []byte) error {
str := string(text)
if str == "" || str == "null" {
i.Valid = false
u.Valid = false
return nil
}
var err error
res, err := strconv.ParseUint(string(text), 10, 8)
i.Valid = err == nil
if i.Valid {
i.Uint8 = uint8(res)
u.Valid = err == nil
if u.Valid {
u.Uint8 = uint8(res)
}
return err
}
// MarshalJSON implements json.Marshaler.
// It will encode null if this Uint8 is null.
func (i Uint8) MarshalJSON() ([]byte, error) {
if !i.Valid {
func (u Uint8) MarshalJSON() ([]byte, error) {
if !u.Valid {
return []byte("null"), nil
}
return []byte(strconv.FormatUint(uint64(i.Uint8), 10)), nil
return []byte(strconv.FormatUint(uint64(u.Uint8), 10)), nil
}
// MarshalText implements encoding.TextMarshaler.
// It will encode a blank string if this Uint8 is null.
func (i Uint8) MarshalText() ([]byte, error) {
if !i.Valid {
func (u Uint8) MarshalText() ([]byte, error) {
if !u.Valid {
return []byte{}, nil
}
return []byte(strconv.FormatUint(uint64(i.Uint8), 10)), nil
return []byte(strconv.FormatUint(uint64(u.Uint8), 10)), nil
}
// SetValid changes this Uint8's value and also sets it to be non-null.
func (i *Uint8) SetValid(n uint8) {
i.Uint8 = n
i.Valid = true
func (u *Uint8) SetValid(n uint8) {
u.Uint8 = n
u.Valid = true
}
// Ptr returns a pointer to this Uint8's value, or a nil pointer if this Uint8 is null.
func (i Uint8) Ptr() *uint8 {
if !i.Valid {
func (u Uint8) Ptr() *uint8 {
if !u.Valid {
return nil
}
return &i.Uint8
return &u.Uint8
}
// IsZero returns true for invalid Uint8's, for future omitempty support (Go 1.4?)
// A non-null Uint8 with a 0 value will not be considered zero.
func (i Uint8) IsZero() bool {
return !i.Valid
func (u Uint8) IsZero() bool {
return !u.Valid
}
// Scan implements the Scanner interface.
func (n *NullUint8) Scan(value interface{}) error {
func (u *Uint8) Scan(value interface{}) error {
if value == nil {
n.Uint8, n.Valid = 0, false
u.Uint8, u.Valid = 0, false
return nil
}
n.Valid = true
return convert.ConvertAssign(&n.Uint8, value)
u.Valid = true
return convert.ConvertAssign(&u.Uint8, value)
}
// Value implements the driver Valuer interface.
func (n NullUint8) Value() (driver.Value, error) {
func (n Uint8) Value() (driver.Value, error) {
if !n.Valid {
return nil, nil
}

View file

@ -8,8 +8,7 @@ import (
)
var (
uint8JSON = []byte(`254`)
nullUint8JSON = []byte(`{"Uint8":254,"Valid":true}`)
uint8JSON = []byte(`254`)
)
func TestUint8From(t *testing.T) {
@ -38,11 +37,6 @@ func TestUnmarshalUint8(t *testing.T) {
maybePanic(err)
assertUint8(t, i, "uint8 json")
var ni Uint8
err = json.Unmarshal(nullUint8JSON, &ni)
maybePanic(err)
assertUint8(t, ni, "sq.NullUint8 json")
var null Uint8
err = json.Unmarshal(nullJSON, &null)
maybePanic(err)

View file

@ -6,8 +6,7 @@ import (
)
var (
uintJSON = []byte(`12345`)
nullUintJSON = []byte(`{"Uint":12345,"Valid":true}`)
uintJSON = []byte(`12345`)
)
func TestUintFrom(t *testing.T) {
@ -36,11 +35,6 @@ func TestUnmarshalUint(t *testing.T) {
maybePanic(err)
assertUint(t, i, "uint json")
var ni Uint
err = json.Unmarshal(nullUintJSON, &ni)
maybePanic(err)
assertUint(t, ni, "sq.NullUint json")
var null Uint
err = json.Unmarshal(nullJSON, &null)
maybePanic(err)