Removed zero

Fix bool, bytes, json
This commit is contained in:
Patrick O'brien 2016-11-10 17:47:49 +10:00
parent b326f4655b
commit dc72f92a47
40 changed files with 105 additions and 5716 deletions

52
bool.go
View file

@ -1,27 +1,27 @@
package null
import (
"database/sql"
"bytes"
"database/sql/driver"
"encoding/json"
"errors"
"fmt"
"reflect"
"github.com/nullbio/null/convert"
)
// Bool is a nullable bool.
// It does not consider false values to be null.
// It will decode to null, not false, if null.
type Bool struct {
sql.NullBool
Bool bool
Valid bool
}
// NewBool creates a new Bool
func NewBool(b bool, valid bool) Bool {
return Bool{
NullBool: sql.NullBool{
Bool: b,
Valid: valid,
},
}
}
@ -43,26 +43,20 @@ func BoolFromPtr(b *bool) Bool {
// 0 will not be considered a null Bool.
// It also supports unmarshalling a sql.NullBool.
func (b *Bool) 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 bool:
b.Bool = x
case map[string]interface{}:
err = json.Unmarshal(data, &b.NullBool)
case nil:
if bytes.Equal(data, NullBytes) {
b.Bool = false
b.Valid = false
return nil
default:
err = fmt.Errorf("json: cannot unmarshal %v into Go value of type null.Bool", reflect.TypeOf(v).Name())
}
b.Valid = err == nil
if err := json.Unmarshal(data, &b.Bool); err != nil {
return err
}
b.Valid = true
return nil
}
// 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".
@ -127,3 +121,21 @@ func (b Bool) Ptr() *bool {
func (b Bool) IsZero() bool {
return !b.Valid
}
// Scan implements the Scanner interface.
func (b *Bool) Scan(value interface{}) error {
if value == nil {
b.Bool, b.Valid = false, false
return nil
}
b.Valid = true
return convert.ConvertAssign(&b.Bool, value)
}
// Value implements the driver Valuer interface.
func (b Bool) Value() (driver.Value, error) {
if !b.Valid {
return nil, nil
}
return b.Bool, nil
}

View file

@ -39,8 +39,9 @@ func TestUnmarshalBool(t *testing.T) {
var nb Bool
err = json.Unmarshal(nullBoolJSON, &nb)
maybePanic(err)
assertBool(t, nb, "sq.NullBool json")
if err == nil {
panic("err should not be nil")
}
var null Bool
err = json.Unmarshal(nullJSON, &null)

View file

@ -1,31 +1,27 @@
package null
import (
"bytes"
"database/sql/driver"
"encoding/json"
"gopkg.in/nullbio/null.v5/convert"
)
// NullBytes is a nullable byte slice.
type NullBytes struct {
Bytes []byte
Valid bool
}
// NullBytes is a global byte slice of JSON null
var NullBytes = []byte("null")
// Bytes is a nullable []byte.
// JSON marshals to zero if null.
// Considered null to SQL if zero.
type Bytes struct {
NullBytes
Bytes []byte
Valid bool
}
// NewBytes creates a new Bytes
func NewBytes(b []byte, valid bool) Bytes {
return Bytes{
NullBytes: NullBytes{
Bytes: b,
Valid: valid,
},
}
}
@ -47,14 +43,19 @@ func BytesFromPtr(b *[]byte) Bytes {
// 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 data == nil || len(data) == 0 {
b.Bytes = []byte("null")
} else {
b.Bytes = append(b.Bytes[0:0], data...)
if bytes.Equal(data, NullBytes) {
b.Valid = false
b.Bytes = nil
return nil
}
b.Valid = true
var s string
if err := json.Unmarshal(data, &s); err != nil {
return err
}
b.Bytes = []byte(s)
b.Valid = true
return nil
}
@ -110,19 +111,19 @@ func (b Bytes) IsZero() bool {
}
// Scan implements the Scanner interface.
func (n *NullBytes) Scan(value interface{}) error {
func (b *Bytes) Scan(value interface{}) error {
if value == nil {
n.Bytes, n.Valid = []byte{}, false
b.Bytes, b.Valid = []byte{}, false
return nil
}
n.Valid = true
return convert.ConvertAssign(&n.Bytes, value)
b.Valid = true
return convert.ConvertAssign(&b.Bytes, value)
}
// Value implements the driver Valuer interface.
func (n NullBytes) Value() (driver.Value, error) {
if !n.Valid {
func (b Bytes) Value() (driver.Value, error) {
if !b.Valid {
return nil, nil
}
return n.Bytes, nil
return b.Bytes, nil
}

View file

@ -11,7 +11,7 @@ var (
)
func TestBytesFrom(t *testing.T) {
i := BytesFrom([]byte(`"hello"`))
i := BytesFrom([]byte(`hello`))
assertBytes(t, i, "BytesFrom()")
zero := BytesFrom(nil)
@ -26,7 +26,7 @@ func TestBytesFrom(t *testing.T) {
}
func TestBytesFromPtr(t *testing.T) {
n := []byte(`"hello"`)
n := []byte(`hello`)
iptr := &n
i := BytesFromPtr(iptr)
assertBytes(t, i, "BytesFromPtr()")
@ -43,26 +43,23 @@ func TestUnmarshalBytes(t *testing.T) {
var ni Bytes
err = ni.UnmarshalJSON([]byte{})
if ni.Valid == false {
t.Errorf("expected Valid to be true, got false")
}
if !bytes.Equal(ni.Bytes, []byte("null")) {
t.Errorf("Expected Bytes to be nil slice, but was not: %#v %#v", ni.Bytes, []byte(`null`))
if err == nil {
t.Errorf("Expected error")
}
var null Bytes
err = null.UnmarshalJSON(nil)
if null.Valid == false {
t.Errorf("expected Valid to be true, got false")
err = null.UnmarshalJSON([]byte("null"))
if null.Valid == true {
t.Errorf("expected Valid to be false, got true")
}
if !bytes.Equal(null.Bytes, []byte(`null`)) {
t.Errorf("Expected Bytes to be []byte nil, but was not: %#v %#v", null.Bytes, []byte(`null`))
if null.Bytes != nil {
t.Errorf("Expected Bytes to be nil, but was not: %#v %#v", null.Bytes, []byte(`null`))
}
}
func TestTextUnmarshalBytes(t *testing.T) {
var i Bytes
err := i.UnmarshalText([]byte(`"hello"`))
err := i.UnmarshalText([]byte(`hello`))
maybePanic(err)
assertBytes(t, i, "UnmarshalText() []byte")
@ -132,15 +129,15 @@ func TestBytesIsZero(t *testing.T) {
func TestBytesSetValid(t *testing.T) {
change := NewBytes(nil, false)
assertNullBytes(t, change, "SetValid()")
change.SetValid([]byte(`"hello"`))
change.SetValid([]byte(`hello`))
assertBytes(t, change, "SetValid()")
}
func TestBytesScan(t *testing.T) {
var i Bytes
err := i.Scan(`"hello"`)
err := i.Scan(`hello`)
maybePanic(err)
assertBytes(t, i, "scanned []byte")
assertBytes(t, i, "Scan() []byte")
var null Bytes
err = null.Scan(nil)
@ -149,8 +146,8 @@ func TestBytesScan(t *testing.T) {
}
func assertBytes(t *testing.T, i Bytes, from string) {
if !bytes.Equal(i.Bytes, []byte(`"hello"`)) {
t.Errorf("bad %s []byte: %#v ≠ %#v\n", from, string(i.Bytes), string([]byte(`"hello"`)))
if !bytes.Equal(i.Bytes, []byte("hello")) {
t.Errorf("bad %s []byte: %v ≠ %v\n", from, string(i.Bytes), string([]byte(`hello`)))
}
if !i.Valid {
t.Error(from, "is invalid, but should be valid")

42
json.go
View file

@ -1,33 +1,26 @@
package null
import (
"bytes"
"database/sql/driver"
"encoding/json"
"errors"
"fmt"
"gopkg.in/nullbio/null.v5/convert"
)
// NullJSON is a nullable byte slice.
type NullJSON struct {
// JSON is a nullable []byte.
type JSON struct {
JSON []byte
Valid bool
}
// JSON is a nullable []byte.
// JSON marshals to zero if null.
// Considered null to SQL if zero.
type JSON struct {
NullJSON
}
// NewJSON creates a new JSON
func NewJSON(b []byte, valid bool) JSON {
return JSON{
NullJSON: NullJSON{
JSON: b,
Valid: valid,
},
}
}
@ -65,16 +58,21 @@ func (j JSON) Unmarshal(dest interface{}) error {
}
// 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 JSON.
func (j *JSON) UnmarshalJSON(data []byte) error {
if data == nil || len(data) == 0 {
if data == nil {
return fmt.Errorf("json: cannot unmarshal nil into Go value of type null.JSON")
}
if bytes.Equal(data, NullBytes) {
j.JSON = []byte("null")
} else {
j.JSON = append(j.JSON[0:0], data...)
j.Valid = false
return nil
}
j.Valid = true
j.JSON = make([]byte, len(data))
copy(j.JSON, data)
return nil
}
@ -145,19 +143,19 @@ func (j JSON) IsZero() bool {
}
// Scan implements the Scanner interface.
func (n *NullJSON) Scan(value interface{}) error {
func (j *JSON) Scan(value interface{}) error {
if value == nil {
n.JSON, n.Valid = []byte{}, false
j.JSON, j.Valid = []byte{}, false
return nil
}
n.Valid = true
return convert.ConvertAssign(&n.JSON, value)
j.Valid = true
return convert.ConvertAssign(&j.JSON, value)
}
// Value implements the driver Valuer interface.
func (n NullJSON) Value() (driver.Value, error) {
if !n.Valid {
func (j JSON) Value() (driver.Value, error) {
if !j.Valid {
return nil, nil
}
return n.JSON, nil
return j.JSON, nil
}

View file

@ -65,8 +65,8 @@ func TestMarshal(t *testing.T) {
if !bytes.Equal(i.JSON, []byte("null")) {
t.Errorf("Expected null, but got %s", string(i.JSON))
}
if i.Valid == false {
t.Error("Expected Valid true, got Valid false")
if i.Valid == true {
t.Error("Expected Valid false, got Valid true")
}
}
@ -114,8 +114,8 @@ func TestUnmarshalJSON(t *testing.T) {
if ni.Valid == false {
t.Errorf("expected Valid to be true, got false")
}
if !bytes.Equal(ni.JSON, []byte(`null`)) {
t.Errorf("Expected JSON to be null slice, but was not: %#v %#v", ni.JSON, []byte(nil))
if !bytes.Equal(ni.JSON, nil) {
t.Errorf("Expected JSON to be nil, but was not: %#v %#v", ni.JSON, []byte(nil))
}
var null JSON
@ -123,7 +123,7 @@ func TestUnmarshalJSON(t *testing.T) {
if ni.Valid == false {
t.Errorf("expected Valid to be true, got false")
}
if !bytes.Equal(null.JSON, []byte(`null`)) {
if !bytes.Equal(null.JSON, nil) {
t.Errorf("Expected JSON to be []byte nil, but was not: %#v %#v", null.JSON, []byte(nil))
}
}

View file

@ -1,121 +0,0 @@
package zero
import (
"database/sql"
"encoding/json"
"errors"
"fmt"
"reflect"
)
// Bool is a nullable bool. False input is considered null.
// JSON marshals to false if null.
// Considered null to SQL unmarshaled from a false value.
type Bool struct {
sql.NullBool
}
// NewBool creates a new Bool
func NewBool(b bool, valid bool) Bool {
return Bool{
NullBool: sql.NullBool{
Bool: b,
Valid: valid,
},
}
}
// BoolFrom creates a new Bool that will be null if false.
func BoolFrom(b bool) Bool {
return NewBool(b, b)
}
// BoolFromPtr creates a new Bool that be null if b is nil.
func BoolFromPtr(b *bool) Bool {
if b == nil {
return NewBool(false, false)
}
return NewBool(*b, true)
}
// UnmarshalJSON implements json.Unmarshaler.
// "false" will be considered a null Bool.
// It also supports unmarshalling a sql.NullBool.
func (b *Bool) 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 bool:
b.Bool = x
case map[string]interface{}:
err = json.Unmarshal(data, &b.NullBool)
case nil:
b.Valid = false
return nil
default:
err = fmt.Errorf("json: cannot unmarshal %v into Go value of type zero.Bool", reflect.TypeOf(v).Name())
}
b.Valid = (err == nil) && b.Bool
return err
}
// UnmarshalText implements encoding.TextUnmarshaler.
// It will unmarshal to a null Bool if the input is a false or not a bool.
// It will return an error if the input is not a float, blank, or "null".
func (b *Bool) UnmarshalText(text []byte) error {
str := string(text)
switch str {
case "", "null":
b.Valid = false
return nil
case "true":
b.Bool = true
case "false":
b.Bool = false
default:
b.Valid = false
return errors.New("invalid input:" + str)
}
b.Valid = b.Bool
return nil
}
// MarshalJSON implements json.Marshaler.
// It will encode null if this Bool is null.
func (b Bool) MarshalJSON() ([]byte, error) {
if !b.Valid || !b.Bool {
return []byte("false"), nil
}
return []byte("true"), nil
}
// MarshalText implements encoding.TextMarshaler.
// It will encode a zero if this Bool is null.
func (b Bool) MarshalText() ([]byte, error) {
if !b.Valid || !b.Bool {
return []byte("false"), nil
}
return []byte("true"), nil
}
// SetValid changes this Bool's value and also sets it to be non-null.
func (b *Bool) SetValid(v bool) {
b.Bool = v
b.Valid = true
}
// Ptr returns a poBooler to this Bool's value, or a nil poBooler if this Bool is null.
func (b Bool) Ptr() *bool {
if !b.Valid {
return nil
}
return &b.Bool
}
// IsZero returns true for null or zero Bools, for future omitempty support (Go 1.4?)
func (b Bool) IsZero() bool {
return !b.Valid || !b.Bool
}

View file

@ -1,187 +0,0 @@
package zero
import (
"encoding/json"
"testing"
)
var (
boolJSON = []byte(`true`)
falseJSON = []byte(`false`)
nullBoolJSON = []byte(`{"Bool":true,"Valid":true}`)
)
func TestBoolFrom(t *testing.T) {
b := BoolFrom(true)
assertBool(t, b, "BoolFrom()")
zero := BoolFrom(false)
if zero.Valid {
t.Error("BoolFrom(false)", "is valid, but should be invalid")
}
}
func TestBoolFromPtr(t *testing.T) {
v := true
bptr := &v
b := BoolFromPtr(bptr)
assertBool(t, b, "BoolFromPtr()")
null := BoolFromPtr(nil)
assertNullBool(t, null, "BoolFromPtr(nil)")
}
func TestUnmarshalBool(t *testing.T) {
var b Bool
err := json.Unmarshal(boolJSON, &b)
maybePanic(err)
assertBool(t, b, "float json")
var nb Bool
err = json.Unmarshal(nullBoolJSON, &nb)
maybePanic(err)
assertBool(t, nb, "sql.NullBool json")
var zero Bool
err = json.Unmarshal(falseJSON, &zero)
maybePanic(err)
assertNullBool(t, zero, "zero json")
var null Bool
err = json.Unmarshal(nullJSON, &null)
maybePanic(err)
assertNullBool(t, null, "null json")
var invalid Bool
err = invalid.UnmarshalJSON(invalidJSON)
if _, ok := err.(*json.SyntaxError); !ok {
t.Errorf("expected json.SyntaxError, not %T: %v", err, err)
}
assertNullBool(t, invalid, "invalid json")
var badType Bool
err = json.Unmarshal(intJSON, &badType)
if err == nil {
panic("err should not be nil")
}
assertNullBool(t, badType, "wrong type json")
}
func TestTextUnmarshalBool(t *testing.T) {
var b Bool
err := b.UnmarshalText(boolJSON)
maybePanic(err)
assertBool(t, b, "UnmarshalText() bool")
var zero Bool
err = zero.UnmarshalText(falseJSON)
maybePanic(err)
assertNullBool(t, zero, "UnmarshalText() zero bool")
var blank Bool
err = blank.UnmarshalText([]byte(""))
maybePanic(err)
assertNullBool(t, blank, "UnmarshalText() empty bool")
var null Bool
err = null.UnmarshalText(nullJSON)
maybePanic(err)
assertNullBool(t, null, `UnmarshalText() "null"`)
var invalid Bool
err = invalid.UnmarshalText(invalidJSON)
if err == nil {
panic("err should not be nil")
}
}
func TestMarshalBool(t *testing.T) {
b := BoolFrom(true)
data, err := json.Marshal(b)
maybePanic(err)
assertJSONEquals(t, data, "true", "non-empty json marshal")
// invalid values should be encoded as false
null := NewBool(false, false)
data, err = json.Marshal(null)
maybePanic(err)
assertJSONEquals(t, data, "false", "null json marshal")
}
func TestMarshalBoolText(t *testing.T) {
b := BoolFrom(true)
data, err := b.MarshalText()
maybePanic(err)
assertJSONEquals(t, data, "true", "non-empty text marshal")
// invalid values should be encoded as zero
null := NewBool(false, false)
data, err = null.MarshalText()
maybePanic(err)
assertJSONEquals(t, data, "false", "null text marshal")
}
func TestBoolPointer(t *testing.T) {
b := BoolFrom(true)
ptr := b.Ptr()
if *ptr != true {
t.Errorf("bad %s bool: %#v ≠ %v\n", "pointer", ptr, true)
}
null := NewBool(false, false)
ptr = null.Ptr()
if ptr != nil {
t.Errorf("bad %s bool: %#v ≠ %s\n", "nil pointer", ptr, "nil")
}
}
func TestBoolIsZero(t *testing.T) {
b := BoolFrom(true)
if b.IsZero() {
t.Errorf("IsZero() should be false")
}
null := NewBool(false, false)
if !null.IsZero() {
t.Errorf("IsZero() should be true")
}
zero := NewBool(false, true)
if !zero.IsZero() {
t.Errorf("IsZero() should be true")
}
}
func TestBoolSetValid(t *testing.T) {
change := NewBool(false, false)
assertNullBool(t, change, "SetValid()")
change.SetValid(true)
assertBool(t, change, "SetValid()")
}
func TestBoolScan(t *testing.T) {
var b Bool
err := b.Scan(true)
maybePanic(err)
assertBool(t, b, "scanned bool")
var null Bool
err = null.Scan(nil)
maybePanic(err)
assertNullBool(t, null, "scanned null")
}
func assertBool(t *testing.T, b Bool, from string) {
if b.Bool != true {
t.Errorf("bad %s bool: %d ≠ %v\n", from, b.Bool, true)
}
if !b.Valid {
t.Error(from, "is invalid, but should be valid")
}
}
func assertNullBool(t *testing.T, b Bool, from string) {
if b.Valid {
t.Error(from, "is valid, but should be invalid")
}
}

View file

@ -1,128 +0,0 @@
package zero
import (
"database/sql/driver"
"gopkg.in/nullbio/null.v5/convert"
)
// NullBytes is a nullable byte slice.
type NullBytes struct {
Bytes []byte
Valid bool
}
// Bytes is a nullable []byte.
// JSON marshals to zero if null.
// Considered null to SQL if zero.
type Bytes struct {
NullBytes
}
// NewBytes creates a new Bytes
func NewBytes(b []byte, valid bool) Bytes {
return Bytes{
NullBytes: NullBytes{
Bytes: b,
Valid: valid,
},
}
}
// BytesFrom creates a new Bytes that will be null if len zero.
func BytesFrom(b []byte) Bytes {
return NewBytes(b, len(b) != 0)
}
// BytesFromPtr creates a new Bytes that be null if len zero.
func BytesFromPtr(b *[]byte) Bytes {
if b == nil || len(*b) == 0 {
return NewBytes(nil, false)
}
n := NewBytes(*b, true)
return n
}
// 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 data == nil || len(data) == 0 {
b.Bytes = []byte("null")
b.Valid = false
} else {
b.Bytes = append(b.Bytes[0:0], data...)
b.Valid = true
}
return nil
}
// 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
b.Valid = false
} else {
b.Bytes = append(b.Bytes[0:0], text...)
b.Valid = true
}
return nil
}
// MarshalJSON implements json.Marshaler.
// It will encode null if the Bytes is nil.
func (b Bytes) MarshalJSON() ([]byte, error) {
if !b.Valid {
return []byte("null"), nil
}
return b.Bytes, nil
}
// 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
}
return b.Bytes, nil
}
// SetValid changes this Bytes's value and also sets it to be non-null.
func (b *Bytes) SetValid(n []byte) {
b.Bytes = n
b.Valid = true
}
// Ptr returns a pointer to this Bytes's value, or a nil pointer if this Bytes is null.
func (b Bytes) Ptr() *[]byte {
if !b.Valid {
return nil
}
return &b.Bytes
}
// IsZero returns true for null or zero Bytes's, for future omitempty support (Go 1.4?)
func (b Bytes) IsZero() bool {
return !b.Valid || b.Bytes == nil || len(b.Bytes) == 0
}
// Scan implements the Scanner interface.
func (n *NullBytes) Scan(value interface{}) error {
if value == nil {
n.Bytes, n.Valid = []byte{}, false
return nil
}
n.Valid = true
return convert.ConvertAssign(&n.Bytes, value)
}
// Value implements the driver Valuer interface.
func (n NullBytes) Value() (driver.Value, error) {
if !n.Valid {
return nil, nil
}
return n.Bytes, nil
}

View file

@ -1,169 +0,0 @@
package zero
import (
"bytes"
"encoding/json"
"testing"
)
var (
bytesJSON = []byte(`"hello"`)
)
func TestBytesFrom(t *testing.T) {
i := BytesFrom([]byte(`"hello"`))
assertBytes(t, i, "BytesFrom()")
zero := BytesFrom(nil)
if zero.Valid {
t.Error("BytesFrom(nil)", "is valid, but should be invalid")
}
zero = BytesFrom([]byte{})
if zero.Valid {
t.Error("BytesFrom([]byte{})", "is valid, but should be invalid")
}
}
func TestBytesFromPtr(t *testing.T) {
n := []byte(`"hello"`)
iptr := &n
i := BytesFromPtr(iptr)
assertBytes(t, i, "BytesFromPtr()")
null := BytesFromPtr(nil)
assertNullBytes(t, null, "BytesFromPtr(nil)")
}
func TestUnmarshalBytes(t *testing.T) {
var i Bytes
err := json.Unmarshal(bytesJSON, &i)
maybePanic(err)
assertBytes(t, i, "[]byte json")
var ni Bytes
err = ni.UnmarshalJSON([]byte{})
if ni.Valid == true {
t.Errorf("expected Valid to be false, got true")
}
if !bytes.Equal(ni.Bytes, []byte("null")) {
t.Errorf("Expected Bytes to be nil slice, but was not: %#v %#v", ni.Bytes, []byte(`null`))
}
var null Bytes
err = null.UnmarshalJSON(nil)
if null.Valid == true {
t.Errorf("expected Valid to be false, got true")
}
if !bytes.Equal(null.Bytes, []byte(`null`)) {
t.Errorf("Expected Bytes to be []byte nil, but was not: %#v %#v", null.Bytes, []byte(`null`))
}
}
func TestTextUnmarshalBytes(t *testing.T) {
var i Bytes
err := i.UnmarshalText([]byte(`"hello"`))
maybePanic(err)
assertBytes(t, i, "UnmarshalText() []byte")
var blank Bytes
err = blank.UnmarshalText([]byte(""))
maybePanic(err)
assertNullBytes(t, blank, "UnmarshalText() empty []byte")
}
func TestMarshalBytes(t *testing.T) {
i := BytesFrom([]byte(`"hello"`))
data, err := json.Marshal(i)
maybePanic(err)
assertJSONEquals(t, data, `"hello"`, "non-empty json marshal")
// invalid values should be encoded as null
null := NewBytes(nil, false)
data, err = json.Marshal(null)
maybePanic(err)
assertJSONEquals(t, data, "null", "null json marshal")
}
func TestMarshalBytesText(t *testing.T) {
i := BytesFrom([]byte(`"hello"`))
data, err := i.MarshalText()
maybePanic(err)
assertJSONEquals(t, data, `"hello"`, "non-empty text marshal")
// invalid values should be encoded as null
null := NewBytes(nil, false)
data, err = null.MarshalText()
maybePanic(err)
assertJSONEquals(t, data, "", "null text marshal")
}
func TestBytesPointer(t *testing.T) {
i := BytesFrom([]byte(`"hello"`))
ptr := i.Ptr()
if !bytes.Equal(*ptr, []byte(`"hello"`)) {
t.Errorf("bad %s []byte: %#v ≠ %s\n", "pointer", ptr, `"hello"`)
}
null := NewBytes(nil, false)
ptr = null.Ptr()
if ptr != nil {
t.Errorf("bad %s []byte: %#v ≠ %s\n", "nil pointer", ptr, "nil")
}
}
func TestBytesIsZero(t *testing.T) {
i := BytesFrom([]byte(`"hello"`))
if i.IsZero() {
t.Errorf("IsZero() should be false")
}
null := NewBytes(nil, false)
if !null.IsZero() {
t.Errorf("IsZero() should be true")
}
zero := NewBytes(nil, true)
if !zero.IsZero() {
t.Errorf("IsZero() should be true")
}
nz := NewBytes([]byte("thing"), true)
if nz.IsZero() {
t.Error("IsZero() should be false")
}
}
func TestBytesSetValid(t *testing.T) {
change := NewBytes(nil, false)
assertNullBytes(t, change, "SetValid()")
change.SetValid([]byte(`"hello"`))
assertBytes(t, change, "SetValid()")
}
func TestBytesScan(t *testing.T) {
var i Bytes
err := i.Scan(`"hello"`)
maybePanic(err)
assertBytes(t, i, "scanned []byte")
var null Bytes
err = null.Scan(nil)
maybePanic(err)
assertNullBytes(t, null, "scanned null")
}
func assertBytes(t *testing.T, i Bytes, from string) {
if !bytes.Equal(i.Bytes, []byte(`"hello"`)) {
t.Errorf("bad %s []byte: %#v ≠ %#v\n", from, string(i.Bytes), string([]byte(`"hello"`)))
}
if !i.Valid {
t.Error(from, "is invalid, but should be valid")
}
}
func assertNullBytes(t *testing.T, i Bytes, from string) {
if i.Valid {
t.Error(from, "is valid, but should be invalid")
}
}

View file

@ -1,144 +0,0 @@
package zero
import (
"database/sql/driver"
"encoding/json"
"fmt"
"reflect"
"strconv"
"gopkg.in/nullbio/null.v5/convert"
)
type NullFloat32 struct {
Float32 float32
Valid bool
}
// Float32 is a nullable float32. Zero input will be considered null.
// JSON marshals to zero if null.
// Considered null to SQL if zero.
type Float32 struct {
NullFloat32
}
// NewFloat32 creates a new Float32
func NewFloat32(f float32, valid bool) Float32 {
return Float32{
NullFloat32: NullFloat32{
Float32: f,
Valid: valid,
},
}
}
// Float32From creates a new Float32 that will be null if zero.
func Float32From(f float32) Float32 {
return NewFloat32(f, f != 0)
}
// Float32FromPtr creates a new Float32 that be null if f is nil.
func Float32FromPtr(f *float32) Float32 {
if f == nil {
return NewFloat32(0, false)
}
return NewFloat32(*f, true)
}
// UnmarshalJSON implements json.Unmarshaler.
// It supports number and null input.
// 0 will 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 {
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 zero.Float32", reflect.TypeOf(v).Name())
}
f.Valid = (err == nil) && (f.Float32 != 0)
return err
}
// UnmarshalText implements encoding.TextUnmarshaler.
// It will unmarshal to a null Float32 if the input is a blank, zero, or not a float.
// It will return an error if the input is not a float, blank, or "null".
func (f *Float32) UnmarshalText(text []byte) error {
str := string(text)
if str == "" || str == "null" {
f.Valid = false
return nil
}
var err error
res, err := strconv.ParseFloat(string(text), 32)
f.Float32 = float32(res)
f.Valid = (err == nil) && (f.Float32 != 0)
return err
}
// MarshalJSON implements json.Marshaler.
// It will encode null if this Float32 is null.
func (f Float32) MarshalJSON() ([]byte, error) {
n := f.Float32
if !f.Valid {
n = 0
}
return []byte(strconv.FormatFloat(float64(n), 'f', -1, 32)), nil
}
// MarshalText implements encoding.TextMarshaler.
// It will encode a zero if this Float32 is null.
func (f Float32) MarshalText() ([]byte, error) {
n := f.Float32
if !f.Valid {
n = 0
}
return []byte(strconv.FormatFloat(float64(n), 'f', -1, 32)), nil
}
// SetValid changes this Float32's value and also sets it to be non-null.
func (f *Float32) SetValid(v float32) {
f.Float32 = v
f.Valid = true
}
// Ptr returns a poFloater to this Float32's value, or a nil poFloater if this Float32 is null.
func (f Float32) Ptr() *float32 {
if !f.Valid {
return nil
}
return &f.Float32
}
// IsZero returns true for null or zero Float32's, for future omitempty support (Go 1.4?)
func (f Float32) IsZero() bool {
return !f.Valid || f.Float32 == 0
}
// Scan implements the Scanner interface.
func (n *NullFloat32) Scan(value interface{}) error {
if value == nil {
n.Float32, n.Valid = 0, false
return nil
}
n.Valid = true
return convert.ConvertAssign(&n.Float32, value)
}
// Value implements the driver Valuer interface.
func (n NullFloat32) Value() (driver.Value, error) {
if !n.Valid {
return nil, nil
}
return float64(n.Float32), nil
}

View file

@ -1,180 +0,0 @@
package zero
import (
"encoding/json"
"testing"
)
var (
float32JSON = []byte(`1.2345`)
nullFloat32JSON = []byte(`{"Float32":1.2345,"Valid":true}`)
)
func TestFloat32From(t *testing.T) {
f := Float32From(1.2345)
assertFloat32(t, f, "Float32From()")
zero := Float32From(0)
if zero.Valid {
t.Error("Float32From(0)", "is valid, but should be invalid")
}
}
func TestFloat32FromPtr(t *testing.T) {
n := float32(1.2345)
iptr := &n
f := Float32FromPtr(iptr)
assertFloat32(t, f, "Float32FromPtr()")
null := Float32FromPtr(nil)
assertNullFloat32(t, null, "Float32FromPtr(nil)")
}
func TestUnmarshalFloat32(t *testing.T) {
var f Float32
err := json.Unmarshal(float32JSON, &f)
maybePanic(err)
assertFloat32(t, f, "float json")
var nf Float32
err = json.Unmarshal(nullFloat32JSON, &nf)
maybePanic(err)
assertFloat32(t, nf, "sql.NullFloat32 json")
var zero Float32
err = json.Unmarshal(zeroJSON, &zero)
maybePanic(err)
assertNullFloat32(t, zero, "zero json")
var null Float32
err = json.Unmarshal(nullJSON, &null)
maybePanic(err)
assertNullFloat32(t, null, "null json")
var badType Float32
err = json.Unmarshal(boolJSON, &badType)
if err == nil {
panic("err should not be nil")
}
assertNullFloat32(t, badType, "wrong type json")
var invalid Float32
err = invalid.UnmarshalJSON(invalidJSON)
if _, ok := err.(*json.SyntaxError); !ok {
t.Errorf("expected json.SyntaxError, not %T", err)
}
assertNullFloat32(t, invalid, "invalid json")
}
func TestTextUnmarshalFloat32(t *testing.T) {
var f Float32
err := f.UnmarshalText([]byte("1.2345"))
maybePanic(err)
assertFloat32(t, f, "UnmarshalText() float")
var zero Float32
err = zero.UnmarshalText([]byte("0"))
maybePanic(err)
assertNullFloat32(t, zero, "UnmarshalText() zero float")
var blank Float32
err = blank.UnmarshalText([]byte(""))
maybePanic(err)
assertNullFloat32(t, blank, "UnmarshalText() empty float")
var null Float32
err = null.UnmarshalText([]byte("null"))
maybePanic(err)
assertNullFloat32(t, null, `UnmarshalText() "null"`)
}
func TestMarshalFloat32(t *testing.T) {
f := Float32From(1.2345)
data, err := json.Marshal(f)
maybePanic(err)
assertJSONEquals(t, data, "1.2345", "non-empty json marshal")
// invalid values should be encoded as 0
null := NewFloat32(0, false)
data, err = json.Marshal(null)
maybePanic(err)
assertJSONEquals(t, data, "0", "null json marshal")
}
func TestMarshalFloat32Text(t *testing.T) {
f := Float32From(1.2345)
data, err := f.MarshalText()
maybePanic(err)
assertJSONEquals(t, data, "1.2345", "non-empty text marshal")
// invalid values should be encoded as zero
null := NewFloat32(0, false)
data, err = null.MarshalText()
maybePanic(err)
assertJSONEquals(t, data, "0", "null text marshal")
}
func TestFloat32Pointer(t *testing.T) {
f := Float32From(1.2345)
ptr := f.Ptr()
if *ptr != 1.2345 {
t.Errorf("bad %s Float32: %#v ≠ %v\n", "pointer", ptr, 1.2345)
}
null := NewFloat32(0, false)
ptr = null.Ptr()
if ptr != nil {
t.Errorf("bad %s Float32: %#v ≠ %s\n", "nil pointer", ptr, "nil")
}
}
func TestFloat32IsZero(t *testing.T) {
f := Float32From(1.2345)
if f.IsZero() {
t.Errorf("IsZero() should be false")
}
null := NewFloat32(0, false)
if !null.IsZero() {
t.Errorf("IsZero() should be true")
}
zero := NewFloat32(0, true)
if !zero.IsZero() {
t.Errorf("IsZero() should be true")
}
}
func TestFloat32SetValid(t *testing.T) {
change := NewFloat32(0, false)
assertNullFloat32(t, change, "SetValid()")
change.SetValid(1.2345)
assertFloat32(t, change, "SetValid()")
}
func TestFloat32Scan(t *testing.T) {
var f Float32
err := f.Scan(1.2345)
maybePanic(err)
assertFloat32(t, f, "scanned float")
var null Float32
err = null.Scan(nil)
maybePanic(err)
assertNullFloat32(t, null, "scanned null")
}
func assertFloat32(t *testing.T, f Float32, from string) {
if f.Float32 != 1.2345 {
t.Errorf("bad %s float: %f ≠ %f\n", from, f.Float32, 1.2345)
}
if !f.Valid {
t.Error(from, "is invalid, but should be valid")
}
}
func assertNullFloat32(t *testing.T, f Float32, from string) {
if f.Valid {
t.Error(from, "is valid, but should be invalid")
}
}

View file

@ -1,118 +0,0 @@
package zero
import (
"database/sql"
"encoding/json"
"fmt"
"reflect"
"strconv"
)
// Float64 is a nullable float64. Zero input will be considered null.
// JSON marshals to zero if null.
// Considered null to SQL if zero.
type Float64 struct {
sql.NullFloat64
}
// NewFloat64 creates a new Float64
func NewFloat64(f float64, valid bool) Float64 {
return Float64{
NullFloat64: sql.NullFloat64{
Float64: f,
Valid: valid,
},
}
}
// Float64From creates a new Float64 that will be null if zero.
func Float64From(f float64) Float64 {
return NewFloat64(f, f != 0)
}
// Float64FromPtr creates a new Float64 that be null if f is nil.
func Float64FromPtr(f *float64) Float64 {
if f == nil {
return NewFloat64(0, false)
}
return NewFloat64(*f, true)
}
// UnmarshalJSON implements json.Unmarshaler.
// It supports number and null input.
// 0 will 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 = x
case map[string]interface{}:
err = json.Unmarshal(data, &f.NullFloat64)
case nil:
f.Valid = false
return nil
default:
err = fmt.Errorf("json: cannot unmarshal %v into Go value of type zero.Float64", reflect.TypeOf(v).Name())
}
f.Valid = (err == nil) && (f.Float64 != 0)
return err
}
// UnmarshalText implements encoding.TextUnmarshaler.
// It will unmarshal to a null Float64 if the input is a blank, zero, or not a float.
// It will return an error if the input is not a float, blank, or "null".
func (f *Float64) UnmarshalText(text []byte) error {
str := string(text)
if str == "" || str == "null" {
f.Valid = false
return nil
}
var err error
f.Float64, err = strconv.ParseFloat(string(text), 64)
f.Valid = (err == nil) && (f.Float64 != 0)
return err
}
// MarshalJSON implements json.Marshaler.
// It will encode null if this Float64 is null.
func (f Float64) MarshalJSON() ([]byte, error) {
n := f.Float64
if !f.Valid {
n = 0
}
return []byte(strconv.FormatFloat(n, 'f', -1, 64)), nil
}
// MarshalText implements encoding.TextMarshaler.
// It will encode a zero if this Float64 is null.
func (f Float64) MarshalText() ([]byte, error) {
n := f.Float64
if !f.Valid {
n = 0
}
return []byte(strconv.FormatFloat(n, 'f', -1, 64)), nil
}
// SetValid changes this Float64's value and also sets it to be non-null.
func (f *Float64) SetValid(v float64) {
f.Float64 = v
f.Valid = true
}
// Ptr returns a poFloater to this Float64's value, or a nil poFloater if this Float64 is null.
func (f Float64) Ptr() *float64 {
if !f.Valid {
return nil
}
return &f.Float64
}
// IsZero returns true for null or zero Float64's, for future omitempty support (Go 1.4?)
func (f Float64) IsZero() bool {
return !f.Valid || f.Float64 == 0
}

View file

@ -1,180 +0,0 @@
package zero
import (
"encoding/json"
"testing"
)
var (
floatJSON = []byte(`1.2345`)
nullFloat64JSON = []byte(`{"Float64":1.2345,"Valid":true}`)
)
func TestFloat64From(t *testing.T) {
f := Float64From(1.2345)
assertFloat64(t, f, "Float64From()")
zero := Float64From(0)
if zero.Valid {
t.Error("Float64From(0)", "is valid, but should be invalid")
}
}
func TestFloat64FromPtr(t *testing.T) {
n := float64(1.2345)
iptr := &n
f := Float64FromPtr(iptr)
assertFloat64(t, f, "Float64FromPtr()")
null := Float64FromPtr(nil)
assertNullFloat64(t, null, "Float64FromPtr(nil)")
}
func TestUnmarshalFloat64(t *testing.T) {
var f Float64
err := json.Unmarshal(floatJSON, &f)
maybePanic(err)
assertFloat64(t, f, "float json")
var nf Float64
err = json.Unmarshal(nullFloat64JSON, &nf)
maybePanic(err)
assertFloat64(t, nf, "sql.NullFloat64 json")
var zero Float64
err = json.Unmarshal(zeroJSON, &zero)
maybePanic(err)
assertNullFloat64(t, zero, "zero json")
var null Float64
err = json.Unmarshal(nullJSON, &null)
maybePanic(err)
assertNullFloat64(t, null, "null json")
var badType Float64
err = json.Unmarshal(boolJSON, &badType)
if err == nil {
panic("err should not be nil")
}
assertNullFloat64(t, badType, "wrong type json")
var invalid Float64
err = invalid.UnmarshalJSON(invalidJSON)
if _, ok := err.(*json.SyntaxError); !ok {
t.Errorf("expected json.SyntaxError, not %T", err)
}
assertNullFloat64(t, invalid, "invalid json")
}
func TestTextUnmarshalFloat64(t *testing.T) {
var f Float64
err := f.UnmarshalText([]byte("1.2345"))
maybePanic(err)
assertFloat64(t, f, "UnmarshalText() float")
var zero Float64
err = zero.UnmarshalText([]byte("0"))
maybePanic(err)
assertNullFloat64(t, zero, "UnmarshalText() zero float")
var blank Float64
err = blank.UnmarshalText([]byte(""))
maybePanic(err)
assertNullFloat64(t, blank, "UnmarshalText() empty float")
var null Float64
err = null.UnmarshalText([]byte("null"))
maybePanic(err)
assertNullFloat64(t, null, `UnmarshalText() "null"`)
}
func TestMarshalFloat64(t *testing.T) {
f := Float64From(1.2345)
data, err := json.Marshal(f)
maybePanic(err)
assertJSONEquals(t, data, "1.2345", "non-empty json marshal")
// invalid values should be encoded as 0
null := NewFloat64(0, false)
data, err = json.Marshal(null)
maybePanic(err)
assertJSONEquals(t, data, "0", "null json marshal")
}
func TestMarshalFloat64Text(t *testing.T) {
f := Float64From(1.2345)
data, err := f.MarshalText()
maybePanic(err)
assertJSONEquals(t, data, "1.2345", "non-empty text marshal")
// invalid values should be encoded as zero
null := NewFloat64(0, false)
data, err = null.MarshalText()
maybePanic(err)
assertJSONEquals(t, data, "0", "null text marshal")
}
func TestFloat64Pointer(t *testing.T) {
f := Float64From(1.2345)
ptr := f.Ptr()
if *ptr != 1.2345 {
t.Errorf("bad %s Float64: %#v ≠ %v\n", "pointer", ptr, 1.2345)
}
null := NewFloat64(0, false)
ptr = null.Ptr()
if ptr != nil {
t.Errorf("bad %s Float64: %#v ≠ %s\n", "nil pointer", ptr, "nil")
}
}
func TestFloat64IsZero(t *testing.T) {
f := Float64From(1.2345)
if f.IsZero() {
t.Errorf("IsZero() should be false")
}
null := NewFloat64(0, false)
if !null.IsZero() {
t.Errorf("IsZero() should be true")
}
zero := NewFloat64(0, true)
if !zero.IsZero() {
t.Errorf("IsZero() should be true")
}
}
func TestFloat64SetValid(t *testing.T) {
change := NewFloat64(0, false)
assertNullFloat64(t, change, "SetValid()")
change.SetValid(1.2345)
assertFloat64(t, change, "SetValid()")
}
func TestFloat64Scan(t *testing.T) {
var f Float64
err := f.Scan(1.2345)
maybePanic(err)
assertFloat64(t, f, "scanned float")
var null Float64
err = null.Scan(nil)
maybePanic(err)
assertNullFloat64(t, null, "scanned null")
}
func assertFloat64(t *testing.T, f Float64, from string) {
if f.Float64 != 1.2345 {
t.Errorf("bad %s float: %f ≠ %f\n", from, f.Float64, 1.2345)
}
if !f.Valid {
t.Error(from, "is invalid, but should be valid")
}
}
func assertNullFloat64(t *testing.T, f Float64, from string) {
if f.Valid {
t.Error(from, "is valid, but should be invalid")
}
}

View file

@ -1,146 +0,0 @@
package zero
import (
"database/sql/driver"
"encoding/json"
"fmt"
"reflect"
"strconv"
"gopkg.in/nullbio/null.v5/convert"
)
type NullInt struct {
Int int
Valid bool
}
// Int is a nullable int.
// JSON marshals to zero if null.
// Considered null to SQL if zero.
type Int struct {
NullInt
}
// NewInt creates a new Int
func NewInt(i int, valid bool) Int {
return Int{
NullInt: NullInt{
Int: i,
Valid: valid,
},
}
}
// IntFrom creates a new Int that will be null if zero.
func IntFrom(i int) Int {
return NewInt(i, i != 0)
}
// IntFromPtr creates a new Int that be null if i is nil.
func IntFromPtr(i *int) Int {
if i == nil {
return NewInt(0, false)
}
n := NewInt(*i, true)
return n
}
// UnmarshalJSON implements json.Unmarshaler.
// It supports number and null input.
// 0 will 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 {
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 zero.Int", reflect.TypeOf(v).Name())
}
i.Valid = (err == nil) && (i.Int != 0)
return err
}
// UnmarshalText implements encoding.TextUnmarshaler.
// It will unmarshal to a null Int if the input is a blank, zero, 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" {
i.Valid = false
return nil
}
var err error
res, err := strconv.ParseInt(string(text), 10, 0)
i.Int = int(res)
i.Valid = (err == nil) && (i.Int != 0)
return err
}
// MarshalJSON implements json.Marshaler.
// It will encode 0 if this Int is null.
func (i Int) MarshalJSON() ([]byte, error) {
n := i.Int
if !i.Valid {
n = 0
}
return []byte(strconv.FormatInt(int64(n), 10)), nil
}
// MarshalText implements encoding.TextMarshaler.
// It will encode a zero if this Int is null.
func (i Int) MarshalText() ([]byte, error) {
n := i.Int
if !i.Valid {
n = 0
}
return []byte(strconv.FormatInt(int64(n), 10)), nil
}
// SetValid changes this Int's value and also sets it to be non-null.
func (i *Int) SetValid(n int) {
i.Int = n
i.Valid = true
}
// Ptr returns a pointer to this Int's value, or a nil pointer if this Int is null.
func (i Int) Ptr() *int {
if !i.Valid {
return nil
}
return &i.Int
}
// IsZero returns true for null or zero Ints, for future omitempty support (Go 1.4?)
func (i Int) IsZero() bool {
return !i.Valid || i.Int == 0
}
// Scan implements the Scanner interface.
func (n *NullInt) Scan(value interface{}) error {
if value == nil {
n.Int, n.Valid = 0, false
return nil
}
n.Valid = true
return convert.ConvertAssign(&n.Int, value)
}
// Value implements the driver Valuer interface.
func (n NullInt) Value() (driver.Value, error) {
if !n.Valid {
return nil, nil
}
return int64(n.Int), nil
}

View file

@ -1,146 +0,0 @@
package zero
import (
"database/sql/driver"
"encoding/json"
"fmt"
"reflect"
"strconv"
"gopkg.in/nullbio/null.v5/convert"
)
type NullInt16 struct {
Int16 int16
Valid bool
}
// Int16 is a nullable int16.
// JSON marshals to zero if null.
// Considered null to SQL if zero.
type Int16 struct {
NullInt16
}
// NewInt16 creates a new Int16
func NewInt16(i int16, valid bool) Int16 {
return Int16{
NullInt16: NullInt16{
Int16: i,
Valid: valid,
},
}
}
// Int16From creates a new Int16 that will be null if zero.
func Int16From(i int16) Int16 {
return NewInt16(i, i != 0)
}
// Int16FromPtr creates a new Int16 that be null if i is nil.
func Int16FromPtr(i *int16) Int16 {
if i == nil {
return NewInt16(0, false)
}
n := NewInt16(*i, true)
return n
}
// UnmarshalJSON implements json.Unmarshaler.
// It supports number and null input.
// 0 will 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 {
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 zero.Int16", reflect.TypeOf(v).Name())
}
i.Valid = (err == nil) && (i.Int16 != 0)
return err
}
// UnmarshalText implements encoding.TextUnmarshaler.
// It will unmarshal to a null Int16 if the input is a blank, zero, 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" {
i.Valid = false
return nil
}
var err error
res, err := strconv.ParseInt(string(text), 10, 16)
i.Int16 = int16(res)
i.Valid = (err == nil) && (i.Int16 != 0)
return err
}
// MarshalJSON implements json.Marshaler.
// It will encode 0 if this Int16 is null.
func (i Int16) MarshalJSON() ([]byte, error) {
n := i.Int16
if !i.Valid {
n = 0
}
return []byte(strconv.FormatInt(int64(n), 10)), nil
}
// MarshalText implements encoding.TextMarshaler.
// It will encode a zero if this Int16 is null.
func (i Int16) MarshalText() ([]byte, error) {
n := i.Int16
if !i.Valid {
n = 0
}
return []byte(strconv.FormatInt(int64(n), 10)), nil
}
// SetValid changes this Int16's value and also sets it to be non-null.
func (i *Int16) SetValid(n int16) {
i.Int16 = n
i.Valid = true
}
// Ptr returns a pointer to this Int16's value, or a nil pointer if this Int16 is null.
func (i Int16) Ptr() *int16 {
if !i.Valid {
return nil
}
return &i.Int16
}
// IsZero returns true for null or zero Int16s, for future omitempty support (Go 1.4?)
func (i Int16) IsZero() bool {
return !i.Valid || i.Int16 == 0
}
// Scan implements the Scanner interface.
func (n *NullInt16) Scan(value interface{}) error {
if value == nil {
n.Int16, n.Valid = 0, false
return nil
}
n.Valid = true
return convert.ConvertAssign(&n.Int16, value)
}
// Value implements the driver Valuer interface.
func (n NullInt16) Value() (driver.Value, error) {
if !n.Valid {
return nil, nil
}
return int64(n.Int16), nil
}

View file

@ -1,207 +0,0 @@
package zero
import (
"encoding/json"
"math"
"strconv"
"testing"
)
var (
int16JSON = []byte(`32766`)
nullInt16JSON = []byte(`{"Int16":32766,"Valid":true}`)
zero16JSON = []byte(`0`)
)
func TestInt16From(t *testing.T) {
i := Int16From(32766)
assertInt16(t, i, "Int16From()")
zero := Int16From(0)
if zero.Valid {
t.Error("Int16From(0)", "is valid, but should be invalid")
}
}
func TestInt16FromPtr(t *testing.T) {
n := int16(32766)
iptr := &n
i := Int16FromPtr(iptr)
assertInt16(t, i, "Int16FromPtr()")
null := Int16FromPtr(nil)
assertNullInt16(t, null, "Int16FromPtr(nil)")
}
func TestUnmarshalInt16(t *testing.T) {
var i Int16
err := json.Unmarshal(int16JSON, &i)
maybePanic(err)
assertInt16(t, i, "int json")
var ni Int16
err = json.Unmarshal(nullInt16JSON, &ni)
maybePanic(err)
assertInt16(t, ni, "sql.NullInt16 json")
var zero Int16
err = json.Unmarshal(zero16JSON, &zero)
maybePanic(err)
assertNullInt16(t, zero, "zero json")
var null Int16
err = json.Unmarshal(nullJSON, &null)
maybePanic(err)
assertNullInt16(t, null, "null json")
var badType Int16
err = json.Unmarshal(boolJSON, &badType)
if err == nil {
panic("err should not be nil")
}
assertNullInt16(t, badType, "wrong type json")
var invalid Int16
err = invalid.UnmarshalJSON(invalidJSON)
if _, ok := err.(*json.SyntaxError); !ok {
t.Errorf("expected json.SyntaxError, not %T", err)
}
assertNullInt16(t, invalid, "invalid json")
}
func TestUnmarshalNonIntegerNumber16(t *testing.T) {
var i Int16
err := json.Unmarshal(floatJSON, &i)
if err == nil {
panic("err should be present; non-integer number coerced to int")
}
}
func TestUnmarshalInt16Overflow(t *testing.T) {
int64Overflow := uint64(math.MaxInt16)
// Max int64 should decode successfully
var i Int16
err := json.Unmarshal([]byte(strconv.FormatUint(int64Overflow, 10)), &i)
maybePanic(err)
// Attempt to overflow
int64Overflow++
err = json.Unmarshal([]byte(strconv.FormatUint(int64Overflow, 10)), &i)
if err == nil {
panic("err should be present; decoded value overflows int64")
}
}
func TestTextUnmarshalInt16(t *testing.T) {
var i Int16
err := i.UnmarshalText([]byte("32766"))
maybePanic(err)
assertInt16(t, i, "UnmarshalText() int")
var zero Int16
err = zero.UnmarshalText([]byte("0"))
maybePanic(err)
assertNullInt16(t, zero, "UnmarshalText() zero int")
var blank Int16
err = blank.UnmarshalText([]byte(""))
maybePanic(err)
assertNullInt16(t, blank, "UnmarshalText() empty int")
var null Int16
err = null.UnmarshalText([]byte("null"))
maybePanic(err)
assertNullInt16(t, null, `UnmarshalText() "null"`)
}
func TestMarshalInt16(t *testing.T) {
i := Int16From(32766)
data, err := json.Marshal(i)
maybePanic(err)
assertJSONEquals(t, data, "32766", "non-empty json marshal")
// invalid values should be encoded as 0
null := NewInt16(0, false)
data, err = json.Marshal(null)
maybePanic(err)
assertJSONEquals(t, data, "0", "null json marshal")
}
func TestMarshalInt16Text(t *testing.T) {
i := Int16From(32766)
data, err := i.MarshalText()
maybePanic(err)
assertJSONEquals(t, data, "32766", "non-empty text marshal")
// invalid values should be encoded as zero
null := NewInt16(0, false)
data, err = null.MarshalText()
maybePanic(err)
assertJSONEquals(t, data, "0", "null text marshal")
}
func TestInt16Pointer(t *testing.T) {
i := Int16From(32766)
ptr := i.Ptr()
if *ptr != 32766 {
t.Errorf("bad %s int: %#v ≠ %d\n", "pointer", ptr, 32766)
}
null := NewInt16(0, false)
ptr = null.Ptr()
if ptr != nil {
t.Errorf("bad %s int: %#v ≠ %s\n", "nil pointer", ptr, "nil")
}
}
func TestInt16IsZero(t *testing.T) {
i := Int16From(32766)
if i.IsZero() {
t.Errorf("IsZero() should be false")
}
null := NewInt16(0, false)
if !null.IsZero() {
t.Errorf("IsZero() should be true")
}
zero := NewInt16(0, true)
if !zero.IsZero() {
t.Errorf("IsZero() should be true")
}
}
func TestInt16Scan(t *testing.T) {
var i Int16
err := i.Scan(32766)
maybePanic(err)
assertInt16(t, i, "scanned int")
var null Int16
err = null.Scan(nil)
maybePanic(err)
assertNullInt16(t, null, "scanned null")
}
func TestInt16SetValid(t *testing.T) {
change := NewInt16(0, false)
assertNullInt16(t, change, "SetValid()")
change.SetValid(32766)
assertInt16(t, change, "SetValid()")
}
func assertInt16(t *testing.T, i Int16, from string) {
if i.Int16 != 32766 {
t.Errorf("bad %s int: %d ≠ %d\n", from, i.Int16, 32766)
}
if !i.Valid {
t.Error(from, "is invalid, but should be valid")
}
}
func assertNullInt16(t *testing.T, i Int16, from string) {
if i.Valid {
t.Error(from, "is valid, but should be invalid")
}
}

View file

@ -1,146 +0,0 @@
package zero
import (
"database/sql/driver"
"encoding/json"
"fmt"
"reflect"
"strconv"
"gopkg.in/nullbio/null.v5/convert"
)
type NullInt32 struct {
Int32 int32
Valid bool
}
// Int32 is a nullable int32.
// JSON marshals to zero if null.
// Considered null to SQL if zero.
type Int32 struct {
NullInt32
}
// NewInt32 creates a new Int32
func NewInt32(i int32, valid bool) Int32 {
return Int32{
NullInt32: NullInt32{
Int32: i,
Valid: valid,
},
}
}
// Int32From creates a new Int32 that will be null if zero.
func Int32From(i int32) Int32 {
return NewInt32(i, i != 0)
}
// Int32FromPtr creates a new Int32 that be null if i is nil.
func Int32FromPtr(i *int32) Int32 {
if i == nil {
return NewInt32(0, false)
}
n := NewInt32(*i, true)
return n
}
// UnmarshalJSON implements json.Unmarshaler.
// It supports number and null input.
// 0 will 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 {
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 zero.Int32", reflect.TypeOf(v).Name())
}
i.Valid = (err == nil) && (i.Int32 != 0)
return err
}
// UnmarshalText implements encoding.TextUnmarshaler.
// It will unmarshal to a null Int32 if the input is a blank, zero, 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" {
i.Valid = false
return nil
}
var err error
res, err := strconv.ParseInt(string(text), 10, 32)
i.Int32 = int32(res)
i.Valid = (err == nil) && (i.Int32 != 0)
return err
}
// MarshalJSON implements json.Marshaler.
// It will encode 0 if this Int32 is null.
func (i Int32) MarshalJSON() ([]byte, error) {
n := i.Int32
if !i.Valid {
n = 0
}
return []byte(strconv.FormatInt(int64(n), 10)), nil
}
// MarshalText implements encoding.TextMarshaler.
// It will encode a zero if this Int32 is null.
func (i Int32) MarshalText() ([]byte, error) {
n := i.Int32
if !i.Valid {
n = 0
}
return []byte(strconv.FormatInt(int64(n), 10)), nil
}
// SetValid changes this Int32's value and also sets it to be non-null.
func (i *Int32) SetValid(n int32) {
i.Int32 = n
i.Valid = true
}
// Ptr returns a pointer to this Int32's value, or a nil pointer if this Int32 is null.
func (i Int32) Ptr() *int32 {
if !i.Valid {
return nil
}
return &i.Int32
}
// IsZero returns true for null or zero Int32s, for future omitempty support (Go 1.4?)
func (i Int32) IsZero() bool {
return !i.Valid || i.Int32 == 0
}
// Scan implements the Scanner interface.
func (n *NullInt32) Scan(value interface{}) error {
if value == nil {
n.Int32, n.Valid = 0, false
return nil
}
n.Valid = true
return convert.ConvertAssign(&n.Int32, value)
}
// Value implements the driver Valuer interface.
func (n NullInt32) Value() (driver.Value, error) {
if !n.Valid {
return nil, nil
}
return int64(n.Int32), nil
}

View file

@ -1,207 +0,0 @@
package zero
import (
"encoding/json"
"math"
"strconv"
"testing"
)
var (
int32JSON = []byte(`2147483646`)
nullInt32JSON = []byte(`{"Int32":2147483646,"Valid":true}`)
zero32JSON = []byte(`0`)
)
func TestInt32From(t *testing.T) {
i := Int32From(2147483646)
assertInt32(t, i, "Int32From()")
zero := Int32From(0)
if zero.Valid {
t.Error("Int32From(0)", "is valid, but should be invalid")
}
}
func TestInt32FromPtr(t *testing.T) {
n := int32(2147483646)
iptr := &n
i := Int32FromPtr(iptr)
assertInt32(t, i, "Int32FromPtr()")
null := Int32FromPtr(nil)
assertNullInt32(t, null, "Int32FromPtr(nil)")
}
func TestUnmarshalInt32(t *testing.T) {
var i Int32
err := json.Unmarshal(int32JSON, &i)
maybePanic(err)
assertInt32(t, i, "int json")
var ni Int32
err = json.Unmarshal(nullInt32JSON, &ni)
maybePanic(err)
assertInt32(t, ni, "sql.NullInt32 json")
var zero Int32
err = json.Unmarshal(zero32JSON, &zero)
maybePanic(err)
assertNullInt32(t, zero, "zero json")
var null Int32
err = json.Unmarshal(nullJSON, &null)
maybePanic(err)
assertNullInt32(t, null, "null json")
var badType Int32
err = json.Unmarshal(boolJSON, &badType)
if err == nil {
panic("err should not be nil")
}
assertNullInt32(t, badType, "wrong type json")
var invalid Int32
err = invalid.UnmarshalJSON(invalidJSON)
if _, ok := err.(*json.SyntaxError); !ok {
t.Errorf("expected json.SyntaxError, not %T", err)
}
assertNullInt32(t, invalid, "invalid json")
}
func TestUnmarshalNonIntegerNumber32(t *testing.T) {
var i Int32
err := json.Unmarshal(floatJSON, &i)
if err == nil {
panic("err should be present; non-integer number coerced to int")
}
}
func TestUnmarshalInt32Overflow(t *testing.T) {
int64Overflow := uint64(math.MaxInt32)
// Max int64 should decode successfully
var i Int32
err := json.Unmarshal([]byte(strconv.FormatUint(int64Overflow, 10)), &i)
maybePanic(err)
// Attempt to overflow
int64Overflow++
err = json.Unmarshal([]byte(strconv.FormatUint(int64Overflow, 10)), &i)
if err == nil {
panic("err should be present; decoded value overflows int64")
}
}
func TestTextUnmarshalInt32(t *testing.T) {
var i Int32
err := i.UnmarshalText([]byte("2147483646"))
maybePanic(err)
assertInt32(t, i, "UnmarshalText() int")
var zero Int32
err = zero.UnmarshalText([]byte("0"))
maybePanic(err)
assertNullInt32(t, zero, "UnmarshalText() zero int")
var blank Int32
err = blank.UnmarshalText([]byte(""))
maybePanic(err)
assertNullInt32(t, blank, "UnmarshalText() empty int")
var null Int32
err = null.UnmarshalText([]byte("null"))
maybePanic(err)
assertNullInt32(t, null, `UnmarshalText() "null"`)
}
func TestMarshalInt32(t *testing.T) {
i := Int32From(2147483646)
data, err := json.Marshal(i)
maybePanic(err)
assertJSONEquals(t, data, "2147483646", "non-empty json marshal")
// invalid values should be encoded as 0
null := NewInt32(0, false)
data, err = json.Marshal(null)
maybePanic(err)
assertJSONEquals(t, data, "0", "null json marshal")
}
func TestMarshalInt32Text(t *testing.T) {
i := Int32From(2147483646)
data, err := i.MarshalText()
maybePanic(err)
assertJSONEquals(t, data, "2147483646", "non-empty text marshal")
// invalid values should be encoded as zero
null := NewInt32(0, false)
data, err = null.MarshalText()
maybePanic(err)
assertJSONEquals(t, data, "0", "null text marshal")
}
func TestInt32Pointer(t *testing.T) {
i := Int32From(2147483646)
ptr := i.Ptr()
if *ptr != 2147483646 {
t.Errorf("bad %s int: %#v ≠ %d\n", "pointer", ptr, 2147483646)
}
null := NewInt32(0, false)
ptr = null.Ptr()
if ptr != nil {
t.Errorf("bad %s int: %#v ≠ %s\n", "nil pointer", ptr, "nil")
}
}
func TestInt32IsZero(t *testing.T) {
i := Int32From(2147483646)
if i.IsZero() {
t.Errorf("IsZero() should be false")
}
null := NewInt32(0, false)
if !null.IsZero() {
t.Errorf("IsZero() should be true")
}
zero := NewInt32(0, true)
if !zero.IsZero() {
t.Errorf("IsZero() should be true")
}
}
func TestInt32Scan(t *testing.T) {
var i Int32
err := i.Scan(2147483646)
maybePanic(err)
assertInt32(t, i, "scanned int")
var null Int32
err = null.Scan(nil)
maybePanic(err)
assertNullInt32(t, null, "scanned null")
}
func TestInt32SetValid(t *testing.T) {
change := NewInt32(0, false)
assertNullInt32(t, change, "SetValid()")
change.SetValid(2147483646)
assertInt32(t, change, "SetValid()")
}
func assertInt32(t *testing.T, i Int32, from string) {
if i.Int32 != 2147483646 {
t.Errorf("bad %s int: %d ≠ %d\n", from, i.Int32, 2147483646)
}
if !i.Valid {
t.Error(from, "is invalid, but should be valid")
}
}
func assertNullInt32(t *testing.T, i Int32, from string) {
if i.Valid {
t.Error(from, "is valid, but should be invalid")
}
}

View file

@ -1,120 +0,0 @@
package zero
import (
"database/sql"
"encoding/json"
"fmt"
"reflect"
"strconv"
)
// Int64 is a nullable int64.
// JSON marshals to zero if null.
// Considered null to SQL if zero.
type Int64 struct {
sql.NullInt64
}
// NewInt64 creates a new Int64
func NewInt64(i int64, valid bool) Int64 {
return Int64{
NullInt64: sql.NullInt64{
Int64: i,
Valid: valid,
},
}
}
// Int64From creates a new Int64 that will be null if zero.
func Int64From(i int64) Int64 {
return NewInt64(i, i != 0)
}
// Int64FromPtr creates a new Int64 that be null if i is nil.
func Int64FromPtr(i *int64) Int64 {
if i == nil {
return NewInt64(0, false)
}
n := NewInt64(*i, true)
return n
}
// UnmarshalJSON implements json.Unmarshaler.
// It supports number and null input.
// 0 will 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 {
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 zero.Int64", reflect.TypeOf(v).Name())
}
i.Valid = (err == nil) && (i.Int64 != 0)
return err
}
// UnmarshalText implements encoding.TextUnmarshaler.
// It will unmarshal to a null Int64 if the input is a blank, zero, 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" {
i.Valid = false
return nil
}
var err error
i.Int64, err = strconv.ParseInt(string(text), 10, 64)
i.Valid = (err == nil) && (i.Int64 != 0)
return err
}
// MarshalJSON implements json.Marshaler.
// It will encode 0 if this Int64 is null.
func (i Int64) MarshalJSON() ([]byte, error) {
n := i.Int64
if !i.Valid {
n = 0
}
return []byte(strconv.FormatInt(n, 10)), nil
}
// MarshalText implements encoding.TextMarshaler.
// It will encode a zero if this Int64 is null.
func (i Int64) MarshalText() ([]byte, error) {
n := i.Int64
if !i.Valid {
n = 0
}
return []byte(strconv.FormatInt(n, 10)), nil
}
// SetValid changes this Int64's value and also sets it to be non-null.
func (i *Int64) SetValid(n int64) {
i.Int64 = n
i.Valid = true
}
// Ptr returns a pointer to this Int64's value, or a nil pointer if this Int64 is null.
func (i Int64) Ptr() *int64 {
if !i.Valid {
return nil
}
return &i.Int64
}
// IsZero returns true for null or zero Int64s, for future omitempty support (Go 1.4?)
func (i Int64) IsZero() bool {
return !i.Valid || i.Int64 == 0
}

View file

@ -1,207 +0,0 @@
package zero
import (
"encoding/json"
"math"
"strconv"
"testing"
)
var (
int64JSON = []byte(`9223372036854775806`)
nullInt64JSON = []byte(`{"Int64":9223372036854775806,"Valid":true}`)
zero64JSON = []byte(`0`)
)
func TestInt64From(t *testing.T) {
i := Int64From(9223372036854775806)
assertInt64(t, i, "Int64From()")
zero := Int64From(0)
if zero.Valid {
t.Error("Int64From(0)", "is valid, but should be invalid")
}
}
func TestInt64FromPtr(t *testing.T) {
n := int64(9223372036854775806)
iptr := &n
i := Int64FromPtr(iptr)
assertInt64(t, i, "Int64FromPtr()")
null := Int64FromPtr(nil)
assertNullInt64(t, null, "Int64FromPtr(nil)")
}
func TestUnmarshalInt64(t *testing.T) {
var i Int64
err := json.Unmarshal(int64JSON, &i)
maybePanic(err)
assertInt64(t, i, "int json")
var ni Int64
err = json.Unmarshal(nullInt64JSON, &ni)
maybePanic(err)
assertInt64(t, ni, "sql.NullInt64 json")
var zero Int64
err = json.Unmarshal(zero64JSON, &zero)
maybePanic(err)
assertNullInt64(t, zero, "zero json")
var null Int64
err = json.Unmarshal(nullJSON, &null)
maybePanic(err)
assertNullInt64(t, null, "null json")
var badType Int64
err = json.Unmarshal(boolJSON, &badType)
if err == nil {
panic("err should not be nil")
}
assertNullInt64(t, badType, "wrong type json")
var invalid Int64
err = invalid.UnmarshalJSON(invalidJSON)
if _, ok := err.(*json.SyntaxError); !ok {
t.Errorf("expected json.SyntaxError, not %T", err)
}
assertNullInt64(t, invalid, "invalid json")
}
func TestUnmarshalNonIntegerNumber64(t *testing.T) {
var i Int64
err := json.Unmarshal(floatJSON, &i)
if err == nil {
panic("err should be present; non-integer number coerced to int")
}
}
func TestUnmarshalInt64Overflow(t *testing.T) {
int64Overflow := uint64(math.MaxInt64)
// Max int64 should decode successfully
var i Int64
err := json.Unmarshal([]byte(strconv.FormatUint(int64Overflow, 10)), &i)
maybePanic(err)
// Attempt to overflow
int64Overflow++
err = json.Unmarshal([]byte(strconv.FormatUint(int64Overflow, 10)), &i)
if err == nil {
panic("err should be present; decoded value overflows int64")
}
}
func TestTextUnmarshalInt64(t *testing.T) {
var i Int64
err := i.UnmarshalText([]byte("9223372036854775806"))
maybePanic(err)
assertInt64(t, i, "UnmarshalText() int")
var zero Int64
err = zero.UnmarshalText([]byte("0"))
maybePanic(err)
assertNullInt64(t, zero, "UnmarshalText() zero int")
var blank Int64
err = blank.UnmarshalText([]byte(""))
maybePanic(err)
assertNullInt64(t, blank, "UnmarshalText() empty int")
var null Int64
err = null.UnmarshalText([]byte("null"))
maybePanic(err)
assertNullInt64(t, null, `UnmarshalText() "null"`)
}
func TestMarshalInt64(t *testing.T) {
i := Int64From(9223372036854775806)
data, err := json.Marshal(i)
maybePanic(err)
assertJSONEquals(t, data, "9223372036854775806", "non-empty json marshal")
// invalid values should be encoded as 0
null := NewInt64(0, false)
data, err = json.Marshal(null)
maybePanic(err)
assertJSONEquals(t, data, "0", "null json marshal")
}
func TestMarshalInt64Text(t *testing.T) {
i := Int64From(9223372036854775806)
data, err := i.MarshalText()
maybePanic(err)
assertJSONEquals(t, data, "9223372036854775806", "non-empty text marshal")
// invalid values should be encoded as zero
null := NewInt64(0, false)
data, err = null.MarshalText()
maybePanic(err)
assertJSONEquals(t, data, "0", "null text marshal")
}
func TestInt64Pointer(t *testing.T) {
i := Int64From(9223372036854775806)
ptr := i.Ptr()
if *ptr != 9223372036854775806 {
t.Errorf("bad %s int: %#v ≠ %d\n", "pointer", ptr, 9223372036854775806)
}
null := NewInt64(0, false)
ptr = null.Ptr()
if ptr != nil {
t.Errorf("bad %s int: %#v ≠ %s\n", "nil pointer", ptr, "nil")
}
}
func TestInt64IsZero(t *testing.T) {
i := Int64From(9223372036854775806)
if i.IsZero() {
t.Errorf("IsZero() should be false")
}
null := NewInt64(0, false)
if !null.IsZero() {
t.Errorf("IsZero() should be true")
}
zero := NewInt64(0, true)
if !zero.IsZero() {
t.Errorf("IsZero() should be true")
}
}
func TestInt64Scan(t *testing.T) {
var i Int64
err := i.Scan(9223372036854775806)
maybePanic(err)
assertInt64(t, i, "scanned int")
var null Int64
err = null.Scan(nil)
maybePanic(err)
assertNullInt64(t, null, "scanned null")
}
func TestInt64SetValid(t *testing.T) {
change := NewInt64(0, false)
assertNullInt64(t, change, "SetValid()")
change.SetValid(9223372036854775806)
assertInt64(t, change, "SetValid()")
}
func assertInt64(t *testing.T, i Int64, from string) {
if i.Int64 != 9223372036854775806 {
t.Errorf("bad %s int: %d ≠ %d\n", from, i.Int64, 9223372036854775806)
}
if !i.Valid {
t.Error(from, "is invalid, but should be valid")
}
}
func assertNullInt64(t *testing.T, i Int64, from string) {
if i.Valid {
t.Error(from, "is valid, but should be invalid")
}
}

View file

@ -1,146 +0,0 @@
package zero
import (
"database/sql/driver"
"encoding/json"
"fmt"
"reflect"
"strconv"
"gopkg.in/nullbio/null.v5/convert"
)
type NullInt8 struct {
Int8 int8
Valid bool
}
// Int8 is a nullable int8.
// JSON marshals to zero if null.
// Considered null to SQL if zero.
type Int8 struct {
NullInt8
}
// NewInt8 creates a new Int8
func NewInt8(i int8, valid bool) Int8 {
return Int8{
NullInt8: NullInt8{
Int8: i,
Valid: valid,
},
}
}
// Int8From creates a new Int8 that will be null if zero.
func Int8From(i int8) Int8 {
return NewInt8(i, i != 0)
}
// Int8FromPtr creates a new Int8 that be null if i is nil.
func Int8FromPtr(i *int8) Int8 {
if i == nil {
return NewInt8(0, false)
}
n := NewInt8(*i, true)
return n
}
// UnmarshalJSON implements json.Unmarshaler.
// It supports number and null input.
// 0 will 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 {
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 zero.Int8", reflect.TypeOf(v).Name())
}
i.Valid = (err == nil) && (i.Int8 != 0)
return err
}
// UnmarshalText implements encoding.TextUnmarshaler.
// It will unmarshal to a null Int8 if the input is a blank, zero, 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" {
i.Valid = false
return nil
}
var err error
res, err := strconv.ParseInt(string(text), 10, 8)
i.Int8 = int8(res)
i.Valid = (err == nil) && (i.Int8 != 0)
return err
}
// MarshalJSON implements json.Marshaler.
// It will encode 0 if this Int8 is null.
func (i Int8) MarshalJSON() ([]byte, error) {
n := i.Int8
if !i.Valid {
n = 0
}
return []byte(strconv.FormatInt(int64(n), 10)), nil
}
// MarshalText implements encoding.TextMarshaler.
// It will encode a zero if this Int8 is null.
func (i Int8) MarshalText() ([]byte, error) {
n := i.Int8
if !i.Valid {
n = 0
}
return []byte(strconv.FormatInt(int64(n), 10)), nil
}
// SetValid changes this Int8's value and also sets it to be non-null.
func (i *Int8) SetValid(n int8) {
i.Int8 = n
i.Valid = true
}
// Ptr returns a pointer to this Int8's value, or a nil pointer if this Int8 is null.
func (i Int8) Ptr() *int8 {
if !i.Valid {
return nil
}
return &i.Int8
}
// IsZero returns true for null or zero Int8s, for future omitempty support (Go 1.4?)
func (i Int8) IsZero() bool {
return !i.Valid || i.Int8 == 0
}
// Scan implements the Scanner interface.
func (n *NullInt8) Scan(value interface{}) error {
if value == nil {
n.Int8, n.Valid = 0, false
return nil
}
n.Valid = true
return convert.ConvertAssign(&n.Int8, value)
}
// Value implements the driver Valuer interface.
func (n NullInt8) Value() (driver.Value, error) {
if !n.Valid {
return nil, nil
}
return int64(n.Int8), nil
}

View file

@ -1,207 +0,0 @@
package zero
import (
"encoding/json"
"math"
"strconv"
"testing"
)
var (
int8JSON = []byte(`126`)
nullInt8JSON = []byte(`{"Int8":126,"Valid":true}`)
zero8JSON = []byte(`0`)
)
func TestInt8From(t *testing.T) {
i := Int8From(126)
assertInt8(t, i, "Int8From()")
zero := Int8From(0)
if zero.Valid {
t.Error("Int8From(0)", "is valid, but should be invalid")
}
}
func TestInt8FromPtr(t *testing.T) {
n := int8(126)
iptr := &n
i := Int8FromPtr(iptr)
assertInt8(t, i, "Int8FromPtr()")
null := Int8FromPtr(nil)
assertNullInt8(t, null, "Int8FromPtr(nil)")
}
func TestUnmarshalInt8(t *testing.T) {
var i Int8
err := json.Unmarshal(int8JSON, &i)
maybePanic(err)
assertInt8(t, i, "int json")
var ni Int8
err = json.Unmarshal(nullInt8JSON, &ni)
maybePanic(err)
assertInt8(t, ni, "sql.NullInt8 json")
var zero Int8
err = json.Unmarshal(zero8JSON, &zero)
maybePanic(err)
assertNullInt8(t, zero, "zero json")
var null Int8
err = json.Unmarshal(nullJSON, &null)
maybePanic(err)
assertNullInt8(t, null, "null json")
var badType Int8
err = json.Unmarshal(boolJSON, &badType)
if err == nil {
panic("err should not be nil")
}
assertNullInt8(t, badType, "wrong type json")
var invalid Int8
err = invalid.UnmarshalJSON(invalidJSON)
if _, ok := err.(*json.SyntaxError); !ok {
t.Errorf("expected json.SyntaxError, not %T", err)
}
assertNullInt8(t, invalid, "invalid json")
}
func TestUnmarshalNonIntegerNumber8(t *testing.T) {
var i Int8
err := json.Unmarshal(floatJSON, &i)
if err == nil {
panic("err should be present; non-integer number coerced to int")
}
}
func TestUnmarshalInt8Overflow(t *testing.T) {
int64Overflow := uint64(math.MaxInt8)
// Max int64 should decode successfully
var i Int8
err := json.Unmarshal([]byte(strconv.FormatUint(int64Overflow, 10)), &i)
maybePanic(err)
// Attempt to overflow
int64Overflow++
err = json.Unmarshal([]byte(strconv.FormatUint(int64Overflow, 10)), &i)
if err == nil {
panic("err should be present; decoded value overflows int64")
}
}
func TestTextUnmarshalInt8(t *testing.T) {
var i Int8
err := i.UnmarshalText([]byte("126"))
maybePanic(err)
assertInt8(t, i, "UnmarshalText() int")
var zero Int8
err = zero.UnmarshalText([]byte("0"))
maybePanic(err)
assertNullInt8(t, zero, "UnmarshalText() zero int")
var blank Int8
err = blank.UnmarshalText([]byte(""))
maybePanic(err)
assertNullInt8(t, blank, "UnmarshalText() empty int")
var null Int8
err = null.UnmarshalText([]byte("null"))
maybePanic(err)
assertNullInt8(t, null, `UnmarshalText() "null"`)
}
func TestMarshalInt8(t *testing.T) {
i := Int8From(126)
data, err := json.Marshal(i)
maybePanic(err)
assertJSONEquals(t, data, "126", "non-empty json marshal")
// invalid values should be encoded as 0
null := NewInt8(0, false)
data, err = json.Marshal(null)
maybePanic(err)
assertJSONEquals(t, data, "0", "null json marshal")
}
func TestMarshalInt8Text(t *testing.T) {
i := Int8From(126)
data, err := i.MarshalText()
maybePanic(err)
assertJSONEquals(t, data, "126", "non-empty text marshal")
// invalid values should be encoded as zero
null := NewInt8(0, false)
data, err = null.MarshalText()
maybePanic(err)
assertJSONEquals(t, data, "0", "null text marshal")
}
func TestInt8Pointer(t *testing.T) {
i := Int8From(126)
ptr := i.Ptr()
if *ptr != 126 {
t.Errorf("bad %s int: %#v ≠ %d\n", "pointer", ptr, 126)
}
null := NewInt8(0, false)
ptr = null.Ptr()
if ptr != nil {
t.Errorf("bad %s int: %#v ≠ %s\n", "nil pointer", ptr, "nil")
}
}
func TestInt8IsZero(t *testing.T) {
i := Int8From(126)
if i.IsZero() {
t.Errorf("IsZero() should be false")
}
null := NewInt8(0, false)
if !null.IsZero() {
t.Errorf("IsZero() should be true")
}
zero := NewInt8(0, true)
if !zero.IsZero() {
t.Errorf("IsZero() should be true")
}
}
func TestInt8Scan(t *testing.T) {
var i Int8
err := i.Scan(126)
maybePanic(err)
assertInt8(t, i, "scanned int")
var null Int8
err = null.Scan(nil)
maybePanic(err)
assertNullInt8(t, null, "scanned null")
}
func TestInt8SetValid(t *testing.T) {
change := NewInt8(0, false)
assertNullInt8(t, change, "SetValid()")
change.SetValid(126)
assertInt8(t, change, "SetValid()")
}
func assertInt8(t *testing.T, i Int8, from string) {
if i.Int8 != 126 {
t.Errorf("bad %s int: %d ≠ %d\n", from, i.Int8, 126)
}
if !i.Valid {
t.Error(from, "is invalid, but should be valid")
}
}
func assertNullInt8(t *testing.T, i Int8, from string) {
if i.Valid {
t.Error(from, "is valid, but should be invalid")
}
}

View file

@ -1,189 +0,0 @@
package zero
import (
"encoding/json"
"testing"
)
var (
intJSON = []byte(`12345`)
nullIntJSON = []byte(`{"Int":12345,"Valid":true}`)
zeroJSON = []byte(`0`)
)
func TestIntFrom(t *testing.T) {
i := IntFrom(12345)
assertInt(t, i, "IntFrom()")
zero := IntFrom(0)
if zero.Valid {
t.Error("IntFrom(0)", "is valid, but should be invalid")
}
}
func TestIntFromPtr(t *testing.T) {
n := int(12345)
iptr := &n
i := IntFromPtr(iptr)
assertInt(t, i, "IntFromPtr()")
null := IntFromPtr(nil)
assertNullInt(t, null, "IntFromPtr(nil)")
}
func TestUnmarshalInt(t *testing.T) {
var i Int
err := json.Unmarshal(intJSON, &i)
maybePanic(err)
assertInt(t, i, "int json")
var ni Int
err = json.Unmarshal(nullIntJSON, &ni)
maybePanic(err)
assertInt(t, ni, "sql.NullInt json")
var zero Int
err = json.Unmarshal(zeroJSON, &zero)
maybePanic(err)
assertNullInt(t, zero, "zero json")
var null Int
err = json.Unmarshal(nullJSON, &null)
maybePanic(err)
assertNullInt(t, null, "null json")
var badType Int
err = json.Unmarshal(boolJSON, &badType)
if err == nil {
panic("err should not be nil")
}
assertNullInt(t, badType, "wrong type json")
var invalid Int
err = invalid.UnmarshalJSON(invalidJSON)
if _, ok := err.(*json.SyntaxError); !ok {
t.Errorf("expected json.SyntaxError, not %T", err)
}
assertNullInt(t, invalid, "invalid json")
}
func TestUnmarshalNonIntegerNumber(t *testing.T) {
var i Int
err := json.Unmarshal(floatJSON, &i)
if err == nil {
panic("err should be present; non-integer number coerced to int")
}
}
func TestTextUnmarshalInt(t *testing.T) {
var i Int
err := i.UnmarshalText([]byte("12345"))
maybePanic(err)
assertInt(t, i, "UnmarshalText() int")
var zero Int
err = zero.UnmarshalText([]byte("0"))
maybePanic(err)
assertNullInt(t, zero, "UnmarshalText() zero int")
var blank Int
err = blank.UnmarshalText([]byte(""))
maybePanic(err)
assertNullInt(t, blank, "UnmarshalText() empty int")
var null Int
err = null.UnmarshalText([]byte("null"))
maybePanic(err)
assertNullInt(t, null, `UnmarshalText() "null"`)
}
func TestMarshalInt(t *testing.T) {
i := IntFrom(12345)
data, err := json.Marshal(i)
maybePanic(err)
assertJSONEquals(t, data, "12345", "non-empty json marshal")
// invalid values should be encoded as 0
null := NewInt(0, false)
data, err = json.Marshal(null)
maybePanic(err)
assertJSONEquals(t, data, "0", "null json marshal")
}
func TestMarshalIntText(t *testing.T) {
i := IntFrom(12345)
data, err := i.MarshalText()
maybePanic(err)
assertJSONEquals(t, data, "12345", "non-empty text marshal")
// invalid values should be encoded as zero
null := NewInt(0, false)
data, err = null.MarshalText()
maybePanic(err)
assertJSONEquals(t, data, "0", "null text marshal")
}
func TestIntPointer(t *testing.T) {
i := IntFrom(12345)
ptr := i.Ptr()
if *ptr != 12345 {
t.Errorf("bad %s int: %#v ≠ %d\n", "pointer", ptr, 12345)
}
null := NewInt(0, false)
ptr = null.Ptr()
if ptr != nil {
t.Errorf("bad %s int: %#v ≠ %s\n", "nil pointer", ptr, "nil")
}
}
func TestIntIsZero(t *testing.T) {
i := IntFrom(12345)
if i.IsZero() {
t.Errorf("IsZero() should be false")
}
null := NewInt(0, false)
if !null.IsZero() {
t.Errorf("IsZero() should be true")
}
zero := NewInt(0, true)
if !zero.IsZero() {
t.Errorf("IsZero() should be true")
}
}
func TestIntScan(t *testing.T) {
var i Int
err := i.Scan(12345)
maybePanic(err)
assertInt(t, i, "scanned int")
var null Int
err = null.Scan(nil)
maybePanic(err)
assertNullInt(t, null, "scanned null")
}
func TestIntSetValid(t *testing.T) {
change := NewInt(0, false)
assertNullInt(t, change, "SetValid()")
change.SetValid(12345)
assertInt(t, change, "SetValid()")
}
func assertInt(t *testing.T, i Int, from string) {
if i.Int != 12345 {
t.Errorf("bad %s int: %d ≠ %d\n", from, i.Int, 12345)
}
if !i.Valid {
t.Error(from, "is invalid, but should be valid")
}
}
func assertNullInt(t *testing.T, i Int, from string) {
if i.Valid {
t.Error(from, "is valid, but should be invalid")
}
}

View file

@ -1,128 +0,0 @@
package zero
import (
"database/sql/driver"
"gopkg.in/nullbio/null.v5/convert"
)
// NullJSON is a nullable byte slice.
type NullJSON struct {
JSON []byte
Valid bool
}
// JSON is a nullable []byte.
// JSON marshals to zero if null.
// Considered null to SQL if zero.
type JSON struct {
NullJSON
}
// NewJSON creates a new JSON
func NewJSON(b []byte, valid bool) JSON {
return JSON{
NullJSON: NullJSON{
JSON: b,
Valid: valid,
},
}
}
// JSONFrom creates a new JSON that will be null if len zero.
func JSONFrom(b []byte) JSON {
return NewJSON(b, len(b) != 0)
}
// JSONFromPtr creates a new JSON that be null if len zero.
func JSONFromPtr(b *[]byte) JSON {
if b == nil || len(*b) == 0 {
return NewJSON(nil, false)
}
n := NewJSON(*b, true)
return n
}
// 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 JSON.
func (j *JSON) UnmarshalJSON(data []byte) error {
if data == nil || len(data) == 0 {
j.JSON = []byte("null")
j.Valid = false
} else {
j.JSON = append(j.JSON[0:0], data...)
j.Valid = true
}
return nil
}
// 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
j.Valid = false
} else {
j.JSON = append(j.JSON[0:0], text...)
j.Valid = true
}
return nil
}
// MarshalJSON implements json.Marshaler.
// It will encode null if the JSON is nil.
func (j JSON) MarshalJSON() ([]byte, error) {
if !j.Valid {
return []byte("null"), nil
}
return j.JSON, nil
}
// 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
}
return j.JSON, nil
}
// SetValid changes this JSON's value and also sets it to be non-null.
func (j *JSON) SetValid(n []byte) {
j.JSON = n
j.Valid = true
}
// Ptr returns a pointer to this JSON's value, or a nil pointer if this JSON is null.
func (j JSON) Ptr() *[]byte {
if !j.Valid {
return nil
}
return &j.JSON
}
// IsZero returns true for null or zero JSON's, for future omitempty support (Go 1.4?)
func (j JSON) IsZero() bool {
return !j.Valid || j.JSON == nil || len(j.JSON) == 0
}
// Scan implements the Scanner interface.
func (n *NullJSON) Scan(value interface{}) error {
if value == nil {
n.JSON, n.Valid = []byte{}, false
return nil
}
n.Valid = true
return convert.ConvertAssign(&n.JSON, value)
}
// Value implements the driver Valuer interface.
func (n NullJSON) Value() (driver.Value, error) {
if !n.Valid {
return nil, nil
}
return n.JSON, nil
}

View file

@ -1,169 +0,0 @@
package zero
import (
"bytes"
"encoding/json"
"testing"
)
var (
jsonJSON = []byte(`"hello"`)
)
func TestJSONFrom(t *testing.T) {
i := JSONFrom([]byte(`"hello"`))
assertJSON(t, i, "JSONFrom()")
zero := JSONFrom(nil)
if zero.Valid {
t.Error("JSONFrom(nil)", "is valid, but should be invalid")
}
zero = JSONFrom([]byte{})
if zero.Valid {
t.Error("JSONFrom([]byte{})", "is valid, but should be invalid")
}
}
func TestJSONFromPtr(t *testing.T) {
n := []byte(`"hello"`)
iptr := &n
i := JSONFromPtr(iptr)
assertJSON(t, i, "JSONFromPtr()")
null := JSONFromPtr(nil)
assertNullJSON(t, null, "JSONFromPtr(nil)")
}
func TestUnmarshalJSON(t *testing.T) {
var i JSON
err := json.Unmarshal(bytesJSON, &i)
maybePanic(err)
assertJSON(t, i, "[]byte json")
var ni JSON
err = ni.UnmarshalJSON([]byte{})
if ni.Valid == true {
t.Errorf("expected Valid to be false, got true")
}
if !bytes.Equal(ni.JSON, []byte("null")) {
t.Errorf("Expected JSON to be nil slice, but was not: %#v %#v", ni.JSON, []byte(`null`))
}
var null JSON
err = null.UnmarshalJSON(nil)
if null.Valid == true {
t.Errorf("expected Valid to be false, got true")
}
if !bytes.Equal(null.JSON, []byte(`null`)) {
t.Errorf("Expected JSON to be []byte nil, but was not: %#v %#v", null.JSON, []byte(`null`))
}
}
func TestTextUnmarshalJSON(t *testing.T) {
var i JSON
err := i.UnmarshalText([]byte(`"hello"`))
maybePanic(err)
assertJSON(t, i, "UnmarshalText() []byte")
var blank JSON
err = blank.UnmarshalText([]byte(""))
maybePanic(err)
assertNullJSON(t, blank, "UnmarshalText() empty []byte")
}
func TestMarshalJSON(t *testing.T) {
i := JSONFrom([]byte(`"hello"`))
data, err := json.Marshal(i)
maybePanic(err)
assertJSONEquals(t, data, `"hello"`, "non-empty json marshal")
// invalid values should be encoded as null
null := NewJSON(nil, false)
data, err = json.Marshal(null)
maybePanic(err)
assertJSONEquals(t, data, "null", "null json marshal")
}
func TestMarshalJSONText(t *testing.T) {
i := JSONFrom([]byte(`"hello"`))
data, err := i.MarshalText()
maybePanic(err)
assertJSONEquals(t, data, `"hello"`, "non-empty text marshal")
// invalid values should be encoded as null
null := NewJSON(nil, false)
data, err = null.MarshalText()
maybePanic(err)
assertJSONEquals(t, data, "", "null text marshal")
}
func TestJSONPointer(t *testing.T) {
i := JSONFrom([]byte(`"hello"`))
ptr := i.Ptr()
if !bytes.Equal(*ptr, []byte(`"hello"`)) {
t.Errorf("bad %s []byte: %#v ≠ %s\n", "pointer", ptr, `"hello"`)
}
null := NewJSON(nil, false)
ptr = null.Ptr()
if ptr != nil {
t.Errorf("bad %s []byte: %#v ≠ %s\n", "nil pointer", ptr, "nil")
}
}
func TestJSONIsZero(t *testing.T) {
i := JSONFrom([]byte(`"hello"`))
if i.IsZero() {
t.Errorf("IsZero() should be false")
}
null := NewJSON(nil, false)
if !null.IsZero() {
t.Errorf("IsZero() should be true")
}
zero := NewJSON(nil, true)
if !zero.IsZero() {
t.Errorf("IsZero() should be true")
}
nz := NewJSON([]byte("thing"), true)
if nz.IsZero() {
t.Error("IsZero() should be false")
}
}
func TestJSONSetValid(t *testing.T) {
change := NewJSON(nil, false)
assertNullJSON(t, change, "SetValid()")
change.SetValid([]byte(`"hello"`))
assertJSON(t, change, "SetValid()")
}
func TestJSONScan(t *testing.T) {
var i JSON
err := i.Scan(`"hello"`)
maybePanic(err)
assertJSON(t, i, "scanned []byte")
var null JSON
err = null.Scan(nil)
maybePanic(err)
assertNullJSON(t, null, "scanned null")
}
func assertJSON(t *testing.T, i JSON, from string) {
if !bytes.Equal(i.JSON, []byte(`"hello"`)) {
t.Errorf("bad %s []byte: %#v ≠ %#v\n", from, string(i.JSON), string([]byte(`"hello"`)))
}
if !i.Valid {
t.Error(from, "is invalid, but should be valid")
}
}
func assertNullJSON(t *testing.T, i JSON, from string) {
if i.Valid {
t.Error(from, "is valid, but should be invalid")
}
}

View file

@ -1,103 +0,0 @@
// Package zero contains SQL types that consider zero input and null input to be equivalent
// with convenient support for JSON and text marshaling.
// Types in this package will JSON marshal to their zero value, even if null.
// Use the null parent package if you don't want this.
package zero
import (
"database/sql"
"encoding/json"
"fmt"
"reflect"
)
// String is a nullable string.
// JSON marshals to a blank string if null.
// Considered null to SQL if zero.
type String struct {
sql.NullString
}
// NewString creates a new String
func NewString(s string, valid bool) String {
return String{
NullString: sql.NullString{
String: s,
Valid: valid,
},
}
}
// StringFrom creates a new String that will be null if s is blank.
func StringFrom(s string) String {
return NewString(s, s != "")
}
// StringFromPtr creates a new String that be null if s is nil or blank.
// It will make s point to the String's value.
func StringFromPtr(s *string) String {
if s == nil {
return NewString("", false)
}
return NewString(*s, *s != "")
}
// UnmarshalJSON implements json.Unmarshaler.
// It supports string and null input. Blank string input produces 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:
s.Valid = false
return nil
default:
err = fmt.Errorf("json: cannot unmarshal %v into Go value of type zero.String", reflect.TypeOf(v).Name())
}
s.Valid = (err == nil) && (s.String != "")
return err
}
// 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
}
return []byte(s.String), nil
}
// 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 != ""
return nil
}
// SetValid changes this String's value and also sets it to be non-null.
func (s *String) SetValid(v string) {
s.String = v
s.Valid = true
}
// Ptr returns a pointer to this String's value, or a nil pointer if this String is null.
func (s String) Ptr() *string {
if !s.Valid {
return nil
}
return &s.String
}
// IsZero returns true for null or empty strings, for potential future omitempty support.
func (s String) IsZero() bool {
return !s.Valid || s.String == ""
}

View file

@ -1,189 +0,0 @@
package zero
import (
"encoding/json"
"testing"
)
var (
stringJSON = []byte(`"test"`)
blankStringJSON = []byte(`""`)
nullStringJSON = []byte(`{"String":"test","Valid":true}`)
nullJSON = []byte(`null`)
invalidJSON = []byte(`:)`)
)
type stringInStruct struct {
Test String `json:"test,omitempty"`
}
func TestStringFrom(t *testing.T) {
str := StringFrom("test")
assertStr(t, str, "StringFrom() string")
null := StringFrom("")
assertNullStr(t, null, "StringFrom() empty string")
}
func TestUnmarshalString(t *testing.T) {
var str String
err := json.Unmarshal(stringJSON, &str)
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)
assertNullStr(t, blank, "blank string json")
var null String
err = json.Unmarshal(nullJSON, &null)
maybePanic(err)
assertNullStr(t, null, "null json")
var badType String
err = json.Unmarshal(boolJSON, &badType)
if err == nil {
panic("err should not be nil")
}
assertNullStr(t, badType, "wrong type json")
var invalid String
err = invalid.UnmarshalJSON(invalidJSON)
if _, ok := err.(*json.SyntaxError); !ok {
t.Errorf("expected json.SyntaxError, not %T", err)
}
assertNullStr(t, invalid, "invalid json")
}
func TestTextUnmarshalString(t *testing.T) {
var str String
err := str.UnmarshalText([]byte("test"))
maybePanic(err)
assertStr(t, str, "UnmarshalText() string")
var null String
err = null.UnmarshalText([]byte(""))
maybePanic(err)
assertNullStr(t, null, "UnmarshalText() empty string")
}
func TestMarshalString(t *testing.T) {
str := StringFrom("test")
data, err := json.Marshal(str)
maybePanic(err)
assertJSONEquals(t, data, `"test"`, "non-empty json marshal")
// invalid values should be encoded as an empty string
null := StringFrom("")
data, err = json.Marshal(null)
maybePanic(err)
assertJSONEquals(t, data, `""`, "empty json marshal")
}
// Tests omitempty... broken until Go 1.4
// func TestMarshalStringInStruct(t *testing.T) {
// obj := stringInStruct{Test: StringFrom("")}
// data, err := json.Marshal(obj)
// maybePanic(err)
// assertJSONEquals(t, data, `{}`, "null string in struct")
// }
func TestStringPointer(t *testing.T) {
str := StringFrom("test")
ptr := str.Ptr()
if *ptr != "test" {
t.Errorf("bad %s string: %#v ≠ %s\n", "pointer", ptr, "test")
}
null := StringFrom("")
ptr = null.Ptr()
if ptr != nil {
t.Errorf("bad %s string: %#v ≠ %s\n", "nil pointer", ptr, "nil")
}
}
func TestStringFromPointer(t *testing.T) {
test := "test"
testptr := &test
str := StringFromPtr(testptr)
assertStr(t, str, "StringFromPtr()")
testptr = nil
null := StringFromPtr(testptr)
assertNullStr(t, null, "StringFromPtr()")
ptr := null.Ptr()
if ptr != nil {
t.Errorf("bad %s string: %#v ≠ %s\n", "nil pointer", ptr, "nil")
}
}
func TestStringIsZero(t *testing.T) {
str := StringFrom("test")
if str.IsZero() {
t.Errorf("IsZero() should be false")
}
null := StringFrom("")
if !null.IsZero() {
t.Errorf("IsZero() should be true")
}
empty := NewString("", true)
if !empty.IsZero() {
t.Errorf("IsZero() should be true")
}
}
func TestStringScan(t *testing.T) {
var str String
err := str.Scan("test")
maybePanic(err)
assertStr(t, str, "scanned string")
var null String
err = null.Scan(nil)
maybePanic(err)
assertNullStr(t, null, "scanned null")
}
func TestStringSetValid(t *testing.T) {
change := NewString("", false)
assertNullStr(t, change, "SetValid()")
change.SetValid("test")
assertStr(t, change, "SetValid()")
}
func maybePanic(err error) {
if err != nil {
panic(err)
}
}
func assertStr(t *testing.T, s String, from string) {
if s.String != "test" {
t.Errorf("bad %s string: %s ≠ %s\n", from, s.String, "test")
}
if !s.Valid {
t.Error(from, "is invalid, but should be valid")
}
}
func assertNullStr(t *testing.T, s String, from string) {
if s.Valid {
t.Error(from, "is valid, but should be invalid")
}
}
func assertJSONEquals(t *testing.T, data []byte, cmp string, from string) {
if string(data) != cmp {
t.Errorf("bad %s data: %s ≠ %s\n", from, data, cmp)
}
}

View file

@ -1,145 +0,0 @@
package zero
import (
"database/sql/driver"
"encoding/json"
"fmt"
"reflect"
"time"
)
// Time is a nullable time.Time.
// JSON marshals to the zero value for time.Time if null.
// Considered to be null to SQL if zero.
type Time struct {
Time time.Time
Valid bool
}
// Scan implements 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{
Time: t,
Valid: valid,
}
}
// TimeFrom creates a new Time that will
// be null if t is the zero value.
func TimeFrom(t time.Time) Time {
return NewTime(t, !t.IsZero())
}
// TimeFromPtr creates a new Time that will
// be null if t is nil or *t is the zero value.
func TimeFromPtr(t *time.Time) Time {
if t == nil {
return NewTime(time.Time{}, false)
}
return TimeFrom(*t)
}
// MarshalJSON implements json.Marshaler.
// It will encode the zero value of time.Time
// if this time is invalid.
func (t Time) MarshalJSON() ([]byte, error) {
if !t.Valid {
return (time.Time{}).MarshalJSON()
}
return t.Time.MarshalJSON()
}
// 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:
var ti time.Time
if err = ti.UnmarshalJSON(data); err != nil {
return err
}
*t = TimeFrom(ti)
return nil
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:
t.Valid = false
return nil
default:
return fmt.Errorf("json: cannot unmarshal %v into Go value of type null.Time", reflect.TypeOf(v).Name())
}
}
func (t Time) MarshalText() ([]byte, error) {
ti := t.Time
if !t.Valid {
ti = time.Time{}
}
return ti.MarshalText()
}
func (t *Time) UnmarshalText(text []byte) error {
str := string(text)
if str == "" || str == "null" {
t.Valid = false
return nil
}
if err := t.Time.UnmarshalText(text); err != nil {
return err
}
t.Valid = true
return nil
}
// SetValid changes this Time's value and
// sets it to be non-null.
func (t *Time) SetValid(v time.Time) {
t.Time = v
t.Valid = true
}
// Ptr returns a pointer to this Time's value,
// or a nil pointer if this Time is zero.
func (t Time) Ptr() *time.Time {
if !t.Valid {
return nil
}
return &t.Time
}

View file

@ -1,209 +0,0 @@
package zero
import (
"encoding/json"
"testing"
"time"
)
var (
timeString = "2012-12-21T21:21:21Z"
timeJSON = []byte(`"` + timeString + `"`)
zeroTimeStr = "0001-01-01T00:00:00Z"
zeroTimeJSON = []byte(`"0001-01-01T00:00:00Z"`)
blankTimeJSON = []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"}`)
)
func TestUnmarshalTimeJSON(t *testing.T) {
var ti Time
err := json.Unmarshal(timeObject, &ti)
maybePanic(err)
assertTime(t, ti, "UnmarshalJSON() json")
var blank Time
err = json.Unmarshal(blankTimeJSON, &blank)
maybePanic(err)
assertNullTime(t, blank, "blank time json")
var zero Time
err = json.Unmarshal(zeroTimeJSON, &zero)
maybePanic(err)
assertNullTime(t, zero, "zero time json")
var fromObject Time
err = json.Unmarshal(timeObject, &fromObject)
maybePanic(err)
assertTime(t, fromObject, "map time json")
var null Time
err = json.Unmarshal(nullObject, &null)
maybePanic(err)
assertNullTime(t, null, "map null time 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)
}
assertNullTime(t, invalid, "invalid from object json")
var bad Time
err = json.Unmarshal(badObject, &bad)
if err == nil {
t.Errorf("expected error: bad object")
}
assertNullTime(t, bad, "bad from object json")
var wrongType Time
err = json.Unmarshal(intJSON, &wrongType)
if err == nil {
t.Errorf("expected error: wrong type JSON")
}
assertNullTime(t, wrongType, "wrong type object json")
var wrongString Time
err = json.Unmarshal(stringJSON, &wrongString)
if err == nil {
t.Errorf("expected error: wrong string JSON")
}
assertNullTime(t, wrongString, "wrong string object json")
}
func TestMarshalTime(t *testing.T) {
ti := TimeFrom(timeValue)
data, err := json.Marshal(ti)
maybePanic(err)
assertJSONEquals(t, data, string(timeJSON), "non-empty json marshal")
null := TimeFromPtr(nil)
data, err = json.Marshal(null)
maybePanic(err)
assertJSONEquals(t, data, string(zeroTimeJSON), "empty json marshal")
}
func TestUnmarshalTimeText(t *testing.T) {
ti := TimeFrom(timeValue)
txt, err := ti.MarshalText()
maybePanic(err)
assertJSONEquals(t, txt, timeString, "marshal text")
var unmarshal Time
err = unmarshal.UnmarshalText(txt)
maybePanic(err)
assertTime(t, unmarshal, "unmarshal text")
var null Time
err = null.UnmarshalText(nullJSON)
maybePanic(err)
assertNullTime(t, null, "unmarshal null text")
txt, err = null.MarshalText()
maybePanic(err)
assertJSONEquals(t, txt, zeroTimeStr, "marshal null text")
var invalid Time
err = invalid.UnmarshalText([]byte("hello world"))
if err == nil {
t.Error("expected error")
}
assertNullTime(t, invalid, "bad string")
}
func TestTimeFrom(t *testing.T) {
ti := TimeFrom(timeValue)
assertTime(t, ti, "TimeFrom() time.Time")
var nt time.Time
null := TimeFrom(nt)
assertNullTime(t, null, "TimeFrom() empty time.Time")
}
func TestTimeFromPtr(t *testing.T) {
ti := TimeFromPtr(&timeValue)
assertTime(t, ti, "TimeFromPtr() time")
null := TimeFromPtr(nil)
assertNullTime(t, null, "TimeFromPtr(nil)")
}
func TestTimeSetValid(t *testing.T) {
var ti time.Time
change := TimeFrom(ti)
assertNullTime(t, change, "SetValid()")
change.SetValid(timeValue)
assertTime(t, change, "SetValid()")
}
func TestTimePointer(t *testing.T) {
ti := TimeFrom(timeValue)
ptr := ti.Ptr()
if *ptr != timeValue {
t.Errorf("bad %s time: %#v ≠ %v\n", "pointer", ptr, timeValue)
}
var nt time.Time
null := TimeFrom(nt)
ptr = null.Ptr()
if ptr != nil {
t.Errorf("bad %s time: %#v ≠ %s\n", "nil pointer", ptr, "nil")
}
}
func TestTimeScan(t *testing.T) {
var ti Time
err := ti.Scan(timeValue)
maybePanic(err)
assertTime(t, ti, "scanned time")
var null Time
err = null.Scan(nil)
maybePanic(err)
assertNullTime(t, null, "scanned null")
var wrong Time
err = wrong.Scan(int64(42))
if err == nil {
t.Error("expected error")
}
assertNullTime(t, wrong, "scanned wrong")
}
func TestTimeValue(t *testing.T) {
ti := TimeFrom(timeValue)
v, err := ti.Value()
maybePanic(err)
if ti.Time != timeValue {
t.Errorf("bad time.Time value: %v ≠ %v", ti.Time, timeValue)
}
var nt time.Time
zero := TimeFrom(nt)
v, err = zero.Value()
maybePanic(err)
if v != nil {
t.Errorf("bad %s time.Time value: %v ≠ %v", "zero", v, nil)
}
}
func assertTime(t *testing.T, ti Time, from string) {
if ti.Time != timeValue {
t.Errorf("bad %v time: %v ≠ %v\n", from, ti.Time, timeValue)
}
if !ti.Valid {
t.Error(from, "is invalid, but should be valid")
}
}
func assertNullTime(t *testing.T, ti Time, from string) {
if ti.Valid {
t.Error(from, "is valid, but should be invalid")
}
}

View file

@ -1,146 +0,0 @@
package zero
import (
"database/sql/driver"
"encoding/json"
"fmt"
"reflect"
"strconv"
"gopkg.in/nullbio/null.v5/convert"
)
type NullUint struct {
Uint uint
Valid bool
}
// Uint is a nullable uint.
// JSON marshals to zero if null.
// Considered null to SQL if zero.
type Uint struct {
NullUint
}
// NewUint creates a new Uint
func NewUint(i uint, valid bool) Uint {
return Uint{
NullUint: NullUint{
Uint: i,
Valid: valid,
},
}
}
// UintFrom creates a new Uint that will be null if zero.
func UintFrom(i uint) Uint {
return NewUint(i, i != 0)
}
// UintFromPtr creates a new Uint that be null if i is nil.
func UintFromPtr(i *uint) Uint {
if i == nil {
return NewUint(0, false)
}
n := NewUint(*i, true)
return n
}
// UnmarshalJSON implements json.Unmarshaler.
// It supports number and null input.
// 0 will 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 {
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 zero.Uint", reflect.TypeOf(v).Name())
}
i.Valid = (err == nil) && (i.Uint != 0)
return err
}
// UnmarshalText implements encoding.TextUnmarshaler.
// It will unmarshal to a null Uint if the input is a blank, zero, 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 {
str := string(text)
if str == "" || str == "null" {
i.Valid = false
return nil
}
var err error
res, err := strconv.ParseUint(string(text), 10, 0)
i.Uint = uint(res)
i.Valid = (err == nil) && (i.Uint != 0)
return err
}
// MarshalJSON implements json.Marshaler.
// It will encode 0 if this Uint is null.
func (i Uint) MarshalJSON() ([]byte, error) {
n := i.Uint
if !i.Valid {
n = 0
}
return []byte(strconv.FormatUint(uint64(n), 10)), nil
}
// MarshalText implements encoding.TextMarshaler.
// It will encode a zero if this Uint is null.
func (i Uint) MarshalText() ([]byte, error) {
n := i.Uint
if !i.Valid {
n = 0
}
return []byte(strconv.FormatUint(uint64(n), 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
}
// 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 {
return nil
}
return &i.Uint
}
// IsZero returns true for null or zero Uints, for future omitempty support (Go 1.4?)
func (i Uint) IsZero() bool {
return !i.Valid || i.Uint == 0
}
// Scan implements the Scanner interface.
func (n *NullUint) Scan(value interface{}) error {
if value == nil {
n.Uint, n.Valid = 0, false
return nil
}
n.Valid = true
return convert.ConvertAssign(&n.Uint, value)
}
// Value implements the driver Valuer interface.
func (n NullUint) Value() (driver.Value, error) {
if !n.Valid {
return nil, nil
}
return int64(n.Uint), nil
}

View file

@ -1,146 +0,0 @@
package zero
import (
"database/sql/driver"
"encoding/json"
"fmt"
"reflect"
"strconv"
"gopkg.in/nullbio/null.v5/convert"
)
type NullUint16 struct {
Uint16 uint16
Valid bool
}
// Uint16 is a nullable uint16.
// JSON marshals to zero if null.
// Considered null to SQL if zero.
type Uint16 struct {
NullUint16
}
// NewUint16 creates a new Uint16
func NewUint16(i uint16, valid bool) Uint16 {
return Uint16{
NullUint16: NullUint16{
Uint16: i,
Valid: valid,
},
}
}
// Uint16From creates a new Uint16 that will be null if zero.
func Uint16From(i uint16) Uint16 {
return NewUint16(i, i != 0)
}
// Uint16FromPtr creates a new Uint16 that be null if i is nil.
func Uint16FromPtr(i *uint16) Uint16 {
if i == nil {
return NewUint16(0, false)
}
n := NewUint16(*i, true)
return n
}
// UnmarshalJSON implements json.Unmarshaler.
// It supports number and null input.
// 0 will 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 {
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 zero.Uint16", reflect.TypeOf(v).Name())
}
i.Valid = (err == nil) && (i.Uint16 != 0)
return err
}
// UnmarshalText implements encoding.TextUnmarshaler.
// It will unmarshal to a null Uint16 if the input is a blank, zero, 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 {
str := string(text)
if str == "" || str == "null" {
i.Valid = false
return nil
}
var err error
res, err := strconv.ParseUint(string(text), 10, 16)
i.Uint16 = uint16(res)
i.Valid = (err == nil) && (i.Uint16 != 0)
return err
}
// MarshalJSON implements json.Marshaler.
// It will encode 0 if this Uint16 is null.
func (i Uint16) MarshalJSON() ([]byte, error) {
n := i.Uint16
if !i.Valid {
n = 0
}
return []byte(strconv.FormatUint(uint64(n), 10)), nil
}
// MarshalText implements encoding.TextMarshaler.
// It will encode a zero if this Uint16 is null.
func (i Uint16) MarshalText() ([]byte, error) {
n := i.Uint16
if !i.Valid {
n = 0
}
return []byte(strconv.FormatUint(uint64(n), 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
}
// 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 {
return nil
}
return &i.Uint16
}
// IsZero returns true for null or zero Uint16s, for future omitempty support (Go 1.4?)
func (i Uint16) IsZero() bool {
return !i.Valid || i.Uint16 == 0
}
// Scan implements the Scanner interface.
func (n *NullUint16) Scan(value interface{}) error {
if value == nil {
n.Uint16, n.Valid = 0, false
return nil
}
n.Valid = true
return convert.ConvertAssign(&n.Uint16, value)
}
// Value implements the driver Valuer interface.
func (n NullUint16) Value() (driver.Value, error) {
if !n.Valid {
return nil, nil
}
return int64(n.Uint16), nil
}

View file

@ -1,207 +0,0 @@
package zero
import (
"encoding/json"
"math"
"strconv"
"testing"
)
var (
uint16JSON = []byte(`65534`)
nullUint16JSON = []byte(`{"Uint16":65534,"Valid":true}`)
zeroU16JSON = []byte(`0`)
)
func TestUint16From(t *testing.T) {
i := Uint16From(65534)
assertUint16(t, i, "Uint16From()")
zero := Uint16From(0)
if zero.Valid {
t.Error("Uint16From(0)", "is valid, but should be invalid")
}
}
func TestUint16FromPtr(t *testing.T) {
n := uint16(65534)
iptr := &n
i := Uint16FromPtr(iptr)
assertUint16(t, i, "Uint16FromPtr()")
null := Uint16FromPtr(nil)
assertNullUint16(t, null, "Uint16FromPtr(nil)")
}
func TestUnmarshalUint16(t *testing.T) {
var i Uint16
err := json.Unmarshal(uint16JSON, &i)
maybePanic(err)
assertUint16(t, i, "int json")
var ni Uint16
err = json.Unmarshal(nullUint16JSON, &ni)
maybePanic(err)
assertUint16(t, ni, "sql.NullUint16 json")
var zero Uint16
err = json.Unmarshal(zeroU16JSON, &zero)
maybePanic(err)
assertNullUint16(t, zero, "zero json")
var null Uint16
err = json.Unmarshal(nullJSON, &null)
maybePanic(err)
assertNullUint16(t, null, "null json")
var badType Uint16
err = json.Unmarshal(boolJSON, &badType)
if err == nil {
panic("err should not be nil")
}
assertNullUint16(t, badType, "wrong type json")
var invalid Uint16
err = invalid.UnmarshalJSON(invalidJSON)
if _, ok := err.(*json.SyntaxError); !ok {
t.Errorf("expected json.SyntaxError, not %T", err)
}
assertNullUint16(t, invalid, "invalid json")
}
func TestUnmarshalNonIntegerNumberU16(t *testing.T) {
var i Uint16
err := json.Unmarshal(floatJSON, &i)
if err == nil {
panic("err should be present; non-integer number coerced to int")
}
}
func TestUnmarshalUint16Overflow(t *testing.T) {
int64Overflow := uint64(math.MaxUint16)
// Max int64 should decode successfully
var i Uint16
err := json.Unmarshal([]byte(strconv.FormatUint(int64Overflow, 10)), &i)
maybePanic(err)
// Attempt to overflow
int64Overflow++
err = json.Unmarshal([]byte(strconv.FormatUint(int64Overflow, 10)), &i)
if err == nil {
panic("err should be present; decoded value overflows int64")
}
}
func TestTextUnmarshalUint16(t *testing.T) {
var i Uint16
err := i.UnmarshalText([]byte("65534"))
maybePanic(err)
assertUint16(t, i, "UnmarshalText() int")
var zero Uint16
err = zero.UnmarshalText([]byte("0"))
maybePanic(err)
assertNullUint16(t, zero, "UnmarshalText() zero int")
var blank Uint16
err = blank.UnmarshalText([]byte(""))
maybePanic(err)
assertNullUint16(t, blank, "UnmarshalText() empty int")
var null Uint16
err = null.UnmarshalText([]byte("null"))
maybePanic(err)
assertNullUint16(t, null, `UnmarshalText() "null"`)
}
func TestMarshalUint16(t *testing.T) {
i := Uint16From(65534)
data, err := json.Marshal(i)
maybePanic(err)
assertJSONEquals(t, data, "65534", "non-empty json marshal")
// invalid values should be encoded as 0
null := NewUint16(0, false)
data, err = json.Marshal(null)
maybePanic(err)
assertJSONEquals(t, data, "0", "null json marshal")
}
func TestMarshalUint16Text(t *testing.T) {
i := Uint16From(65534)
data, err := i.MarshalText()
maybePanic(err)
assertJSONEquals(t, data, "65534", "non-empty text marshal")
// invalid values should be encoded as zero
null := NewUint16(0, false)
data, err = null.MarshalText()
maybePanic(err)
assertJSONEquals(t, data, "0", "null text marshal")
}
func TestUint16Pointer(t *testing.T) {
i := Uint16From(65534)
ptr := i.Ptr()
if *ptr != 65534 {
t.Errorf("bad %s int: %#v ≠ %d\n", "pointer", ptr, 65534)
}
null := NewUint16(0, false)
ptr = null.Ptr()
if ptr != nil {
t.Errorf("bad %s int: %#v ≠ %s\n", "nil pointer", ptr, "nil")
}
}
func TestUint16IsZero(t *testing.T) {
i := Uint16From(65534)
if i.IsZero() {
t.Errorf("IsZero() should be false")
}
null := NewUint16(0, false)
if !null.IsZero() {
t.Errorf("IsZero() should be true")
}
zero := NewUint16(0, true)
if !zero.IsZero() {
t.Errorf("IsZero() should be true")
}
}
func TestUint16Scan(t *testing.T) {
var i Uint16
err := i.Scan(65534)
maybePanic(err)
assertUint16(t, i, "scanned int")
var null Uint16
err = null.Scan(nil)
maybePanic(err)
assertNullUint16(t, null, "scanned null")
}
func TestUint16SetValid(t *testing.T) {
change := NewUint16(0, false)
assertNullUint16(t, change, "SetValid()")
change.SetValid(65534)
assertUint16(t, change, "SetValid()")
}
func assertUint16(t *testing.T, i Uint16, from string) {
if i.Uint16 != 65534 {
t.Errorf("bad %s int: %d ≠ %d\n", from, i.Uint16, 65534)
}
if !i.Valid {
t.Error(from, "is invalid, but should be valid")
}
}
func assertNullUint16(t *testing.T, i Uint16, from string) {
if i.Valid {
t.Error(from, "is valid, but should be invalid")
}
}

View file

@ -1,146 +0,0 @@
package zero
import (
"database/sql/driver"
"encoding/json"
"fmt"
"reflect"
"strconv"
"gopkg.in/nullbio/null.v5/convert"
)
type NullUint32 struct {
Uint32 uint32
Valid bool
}
// Uint32 is a nullable uint32.
// JSON marshals to zero if null.
// Considered null to SQL if zero.
type Uint32 struct {
NullUint32
}
// NewUint32 creates a new Uint32
func NewUint32(i uint32, valid bool) Uint32 {
return Uint32{
NullUint32: NullUint32{
Uint32: i,
Valid: valid,
},
}
}
// Uint32From creates a new Uint32 that will be null if zero.
func Uint32From(i uint32) Uint32 {
return NewUint32(i, i != 0)
}
// Uint32FromPtr creates a new Uint32 that be null if i is nil.
func Uint32FromPtr(i *uint32) Uint32 {
if i == nil {
return NewUint32(0, false)
}
n := NewUint32(*i, true)
return n
}
// UnmarshalJSON implements json.Unmarshaler.
// It supports number and null input.
// 0 will 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 {
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 zero.Uint32", reflect.TypeOf(v).Name())
}
i.Valid = (err == nil) && (i.Uint32 != 0)
return err
}
// UnmarshalText implements encoding.TextUnmarshaler.
// It will unmarshal to a null Uint32 if the input is a blank, zero, 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 {
str := string(text)
if str == "" || str == "null" {
i.Valid = false
return nil
}
var err error
res, err := strconv.ParseUint(string(text), 10, 32)
i.Uint32 = uint32(res)
i.Valid = (err == nil) && (i.Uint32 != 0)
return err
}
// MarshalJSON implements json.Marshaler.
// It will encode 0 if this Uint32 is null.
func (i Uint32) MarshalJSON() ([]byte, error) {
n := i.Uint32
if !i.Valid {
n = 0
}
return []byte(strconv.FormatUint(uint64(n), 10)), nil
}
// MarshalText implements encoding.TextMarshaler.
// It will encode a zero if this Uint32 is null.
func (i Uint32) MarshalText() ([]byte, error) {
n := i.Uint32
if !i.Valid {
n = 0
}
return []byte(strconv.FormatUint(uint64(n), 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
}
// 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 {
return nil
}
return &i.Uint32
}
// IsZero returns true for null or zero Uint32s, for future omitempty support (Go 1.4?)
func (i Uint32) IsZero() bool {
return !i.Valid || i.Uint32 == 0
}
// Scan implements the Scanner interface.
func (n *NullUint32) Scan(value interface{}) error {
if value == nil {
n.Uint32, n.Valid = 0, false
return nil
}
n.Valid = true
return convert.ConvertAssign(&n.Uint32, value)
}
// Value implements the driver Valuer interface.
func (n NullUint32) Value() (driver.Value, error) {
if !n.Valid {
return nil, nil
}
return int64(n.Uint32), nil
}

View file

@ -1,207 +0,0 @@
package zero
import (
"encoding/json"
"math"
"strconv"
"testing"
)
var (
uint32JSON = []byte(`4294967294`)
nullUint32JSON = []byte(`{"Uint32":4294967294,"Valid":true}`)
zeroU32JSON = []byte(`0`)
)
func TestUint32From(t *testing.T) {
i := Uint32From(4294967294)
assertUint32(t, i, "Uint32From()")
zero := Uint32From(0)
if zero.Valid {
t.Error("Uint32From(0)", "is valid, but should be invalid")
}
}
func TestUint32FromPtr(t *testing.T) {
n := uint32(4294967294)
iptr := &n
i := Uint32FromPtr(iptr)
assertUint32(t, i, "Uint32FromPtr()")
null := Uint32FromPtr(nil)
assertNullUint32(t, null, "Uint32FromPtr(nil)")
}
func TestUnmarshalUint32(t *testing.T) {
var i Uint32
err := json.Unmarshal(uint32JSON, &i)
maybePanic(err)
assertUint32(t, i, "int json")
var ni Uint32
err = json.Unmarshal(nullUint32JSON, &ni)
maybePanic(err)
assertUint32(t, ni, "sql.NullUint32 json")
var zero Uint32
err = json.Unmarshal(zeroU32JSON, &zero)
maybePanic(err)
assertNullUint32(t, zero, "zero json")
var null Uint32
err = json.Unmarshal(nullJSON, &null)
maybePanic(err)
assertNullUint32(t, null, "null json")
var badType Uint32
err = json.Unmarshal(boolJSON, &badType)
if err == nil {
panic("err should not be nil")
}
assertNullUint32(t, badType, "wrong type json")
var invalid Uint32
err = invalid.UnmarshalJSON(invalidJSON)
if _, ok := err.(*json.SyntaxError); !ok {
t.Errorf("expected json.SyntaxError, not %T", err)
}
assertNullUint32(t, invalid, "invalid json")
}
func TestUnmarshalNonIntegerNumberU32(t *testing.T) {
var i Uint32
err := json.Unmarshal(floatJSON, &i)
if err == nil {
panic("err should be present; non-integer number coerced to int")
}
}
func TestUnmarshalUint32Overflow(t *testing.T) {
int64Overflow := uint64(math.MaxUint32)
// Max int64 should decode successfully
var i Uint32
err := json.Unmarshal([]byte(strconv.FormatUint(int64Overflow, 10)), &i)
maybePanic(err)
// Attempt to overflow
int64Overflow++
err = json.Unmarshal([]byte(strconv.FormatUint(int64Overflow, 10)), &i)
if err == nil {
panic("err should be present; decoded value overflows int64")
}
}
func TestTextUnmarshalUint32(t *testing.T) {
var i Uint32
err := i.UnmarshalText([]byte("4294967294"))
maybePanic(err)
assertUint32(t, i, "UnmarshalText() int")
var zero Uint32
err = zero.UnmarshalText([]byte("0"))
maybePanic(err)
assertNullUint32(t, zero, "UnmarshalText() zero int")
var blank Uint32
err = blank.UnmarshalText([]byte(""))
maybePanic(err)
assertNullUint32(t, blank, "UnmarshalText() empty int")
var null Uint32
err = null.UnmarshalText([]byte("null"))
maybePanic(err)
assertNullUint32(t, null, `UnmarshalText() "null"`)
}
func TestMarshalUint32(t *testing.T) {
i := Uint32From(4294967294)
data, err := json.Marshal(i)
maybePanic(err)
assertJSONEquals(t, data, "4294967294", "non-empty json marshal")
// invalid values should be encoded as 0
null := NewUint32(0, false)
data, err = json.Marshal(null)
maybePanic(err)
assertJSONEquals(t, data, "0", "null json marshal")
}
func TestMarshalUint32Text(t *testing.T) {
i := Uint32From(4294967294)
data, err := i.MarshalText()
maybePanic(err)
assertJSONEquals(t, data, "4294967294", "non-empty text marshal")
// invalid values should be encoded as zero
null := NewUint32(0, false)
data, err = null.MarshalText()
maybePanic(err)
assertJSONEquals(t, data, "0", "null text marshal")
}
func TestUint32Pointer(t *testing.T) {
i := Uint32From(4294967294)
ptr := i.Ptr()
if *ptr != 4294967294 {
t.Errorf("bad %s int: %#v ≠ %d\n", "pointer", ptr, 4294967294)
}
null := NewUint32(0, false)
ptr = null.Ptr()
if ptr != nil {
t.Errorf("bad %s int: %#v ≠ %s\n", "nil pointer", ptr, "nil")
}
}
func TestUint32IsZero(t *testing.T) {
i := Uint32From(4294967294)
if i.IsZero() {
t.Errorf("IsZero() should be false")
}
null := NewUint32(0, false)
if !null.IsZero() {
t.Errorf("IsZero() should be true")
}
zero := NewUint32(0, true)
if !zero.IsZero() {
t.Errorf("IsZero() should be true")
}
}
func TestUint32Scan(t *testing.T) {
var i Uint32
err := i.Scan(4294967294)
maybePanic(err)
assertUint32(t, i, "scanned int")
var null Uint32
err = null.Scan(nil)
maybePanic(err)
assertNullUint32(t, null, "scanned null")
}
func TestUint32SetValid(t *testing.T) {
change := NewUint32(0, false)
assertNullUint32(t, change, "SetValid()")
change.SetValid(4294967294)
assertUint32(t, change, "SetValid()")
}
func assertUint32(t *testing.T, i Uint32, from string) {
if i.Uint32 != 4294967294 {
t.Errorf("bad %s int: %d ≠ %d\n", from, i.Uint32, 4294967294)
}
if !i.Valid {
t.Error(from, "is invalid, but should be valid")
}
}
func assertNullUint32(t *testing.T, i Uint32, from string) {
if i.Valid {
t.Error(from, "is valid, but should be invalid")
}
}

View file

@ -1,146 +0,0 @@
package zero
import (
"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 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,
},
}
}
// Uint64From creates a new Uint64 that will be null if zero.
func Uint64From(i uint64) Uint64 {
return NewUint64(i, i != 0)
}
// Uint64FromPtr creates a new Uint64 that be null if i is nil.
func Uint64FromPtr(i *uint64) Uint64 {
if i == nil {
return NewUint64(0, false)
}
n := NewUint64(*i, true)
return n
}
// UnmarshalJSON implements json.Unmarshaler.
// It supports number and null input.
// 0 will 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 {
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 zero.Uint64", reflect.TypeOf(v).Name())
}
i.Valid = (err == nil) && (i.Uint64 != 0)
return err
}
// UnmarshalText implements encoding.TextUnmarshaler.
// It will unmarshal to a null Uint64 if the input is a blank, zero, 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 {
str := string(text)
if str == "" || str == "null" {
i.Valid = false
return nil
}
var err error
i.Uint64, err = strconv.ParseUint(string(text), 10, 64)
i.Valid = (err == nil) && (i.Uint64 != 0)
return err
}
// MarshalJSON implements json.Marshaler.
// It will encode 0 if this Uint64 is null.
func (i Uint64) MarshalJSON() ([]byte, error) {
n := i.Uint64
if !i.Valid {
n = 0
}
return []byte(strconv.FormatUint(n, 10)), nil
}
// MarshalText implements encoding.TextMarshaler.
// It will encode a zero if this Uint64 is null.
func (i Uint64) MarshalText() ([]byte, error) {
n := i.Uint64
if !i.Valid {
n = 0
}
return []byte(strconv.FormatUint(n, 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
}
// 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 {
return nil
}
return &i.Uint64
}
// IsZero returns true for null or zero Uint64s, for future omitempty support (Go 1.4?)
func (i Uint64) IsZero() bool {
return !i.Valid || i.Uint64 == 0
}
// Scan implements the Scanner interface.
func (n *NullUint64) Scan(value interface{}) error {
if value == nil {
n.Uint64, n.Valid = 0, false
return nil
}
n.Valid = true
return convert.ConvertAssign(&n.Uint64, value)
}
// Value implements the driver Valuer interface.
func (n NullUint64) Value() (driver.Value, error) {
if !n.Valid {
return nil, nil
}
return int64(n.Uint64), nil
}

View file

@ -1,189 +0,0 @@
package zero
import (
"encoding/json"
"testing"
)
var (
uint64JSON = []byte(`18446744073709551614`)
nullUint64JSON = []byte(`{"Uint64":18446744073709551614,"Valid":true}`)
zeroU64JSON = []byte(`0`)
)
func TestUint64From(t *testing.T) {
i := Uint64From(18446744073709551614)
assertUint64(t, i, "Uint64From()")
zero := Uint64From(0)
if zero.Valid {
t.Error("Uint64From(0)", "is valid, but should be invalid")
}
}
func TestUint64FromPtr(t *testing.T) {
n := uint64(18446744073709551614)
iptr := &n
i := Uint64FromPtr(iptr)
assertUint64(t, i, "Uint64FromPtr()")
null := Uint64FromPtr(nil)
assertNullUint64(t, null, "Uint64FromPtr(nil)")
}
func TestUnmarshalUint64(t *testing.T) {
var i Uint64
err := json.Unmarshal(uint64JSON, &i)
maybePanic(err)
assertUint64(t, i, "int json")
var ni Uint64
err = json.Unmarshal(nullUint64JSON, &ni)
maybePanic(err)
assertUint64(t, ni, "sql.NullUint64 json")
var zero Uint64
err = json.Unmarshal(zeroU64JSON, &zero)
maybePanic(err)
assertNullUint64(t, zero, "zero json")
var null Uint64
err = json.Unmarshal(nullJSON, &null)
maybePanic(err)
assertNullUint64(t, null, "null json")
var badType Uint64
err = json.Unmarshal(boolJSON, &badType)
if err == nil {
panic("err should not be nil")
}
assertNullUint64(t, badType, "wrong type json")
var invalid Uint64
err = invalid.UnmarshalJSON(invalidJSON)
if _, ok := err.(*json.SyntaxError); !ok {
t.Errorf("expected json.SyntaxError, not %T", err)
}
assertNullUint64(t, invalid, "invalid json")
}
func TestUnmarshalNonIntegerNumberU64(t *testing.T) {
var i Uint64
err := json.Unmarshal(floatJSON, &i)
if err == nil {
panic("err should be present; non-integer number coerced to int")
}
}
func TestTextUnmarshalUint64(t *testing.T) {
var i Uint64
err := i.UnmarshalText([]byte("18446744073709551614"))
maybePanic(err)
assertUint64(t, i, "UnmarshalText() int")
var zero Uint64
err = zero.UnmarshalText([]byte("0"))
maybePanic(err)
assertNullUint64(t, zero, "UnmarshalText() zero int")
var blank Uint64
err = blank.UnmarshalText([]byte(""))
maybePanic(err)
assertNullUint64(t, blank, "UnmarshalText() empty int")
var null Uint64
err = null.UnmarshalText([]byte("null"))
maybePanic(err)
assertNullUint64(t, null, `UnmarshalText() "null"`)
}
func TestMarshalUint64(t *testing.T) {
i := Uint64From(18446744073709551614)
data, err := json.Marshal(i)
maybePanic(err)
assertJSONEquals(t, data, "18446744073709551614", "non-empty json marshal")
// invalid values should be encoded as 0
null := NewUint64(0, false)
data, err = json.Marshal(null)
maybePanic(err)
assertJSONEquals(t, data, "0", "null json marshal")
}
func TestMarshalUint64Text(t *testing.T) {
i := Uint64From(18446744073709551614)
data, err := i.MarshalText()
maybePanic(err)
assertJSONEquals(t, data, "18446744073709551614", "non-empty text marshal")
// invalid values should be encoded as zero
null := NewUint64(0, false)
data, err = null.MarshalText()
maybePanic(err)
assertJSONEquals(t, data, "0", "null text marshal")
}
func TestUint64Pointer(t *testing.T) {
i := Uint64From(18446744073709551614)
ptr := i.Ptr()
if *ptr != 18446744073709551614 {
t.Errorf("bad %s int: %#v ≠ %d\n", "pointer", ptr, uint64(18446744073709551614))
}
null := NewUint64(0, false)
ptr = null.Ptr()
if ptr != nil {
t.Errorf("bad %s int: %#v ≠ %s\n", "nil pointer", ptr, "nil")
}
}
func TestUint64IsZero(t *testing.T) {
i := Uint64From(18446744073709551614)
if i.IsZero() {
t.Errorf("IsZero() should be false")
}
null := NewUint64(0, false)
if !null.IsZero() {
t.Errorf("IsZero() should be true")
}
zero := NewUint64(0, true)
if !zero.IsZero() {
t.Errorf("IsZero() should be true")
}
}
func TestUint64Scan(t *testing.T) {
var i Uint64
err := i.Scan(uint64(18446744073709551614))
maybePanic(err)
assertUint64(t, i, "scanned int")
var null Uint64
err = null.Scan(nil)
maybePanic(err)
assertNullUint64(t, null, "scanned null")
}
func TestUint64SetValid(t *testing.T) {
change := NewUint64(0, false)
assertNullUint64(t, change, "SetValid()")
change.SetValid(18446744073709551614)
assertUint64(t, change, "SetValid()")
}
func assertUint64(t *testing.T, i Uint64, from string) {
if i.Uint64 != 18446744073709551614 {
t.Errorf("bad %s int: %d ≠ %d\n", from, i.Uint64, uint64(18446744073709551614))
}
if !i.Valid {
t.Error(from, "is invalid, but should be valid")
}
}
func assertNullUint64(t *testing.T, i Uint64, from string) {
if i.Valid {
t.Error(from, "is valid, but should be invalid")
}
}

View file

@ -1,146 +0,0 @@
package zero
import (
"database/sql/driver"
"encoding/json"
"fmt"
"reflect"
"strconv"
"gopkg.in/nullbio/null.v5/convert"
)
type NullUint8 struct {
Uint8 uint8
Valid bool
}
// Uint8 is a nullable uint8.
// JSON marshals to zero if null.
// Considered null to SQL if zero.
type Uint8 struct {
NullUint8
}
// NewUint8 creates a new Uint8
func NewUint8(i uint8, valid bool) Uint8 {
return Uint8{
NullUint8: NullUint8{
Uint8: i,
Valid: valid,
},
}
}
// Uint8From creates a new Uint8 that will be null if zero.
func Uint8From(i uint8) Uint8 {
return NewUint8(i, i != 0)
}
// Uint8FromPtr creates a new Uint8 that be null if i is nil.
func Uint8FromPtr(i *uint8) Uint8 {
if i == nil {
return NewUint8(0, false)
}
n := NewUint8(*i, true)
return n
}
// UnmarshalJSON implements json.Unmarshaler.
// It supports number and null input.
// 0 will 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 {
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 zero.Uint8", reflect.TypeOf(v).Name())
}
i.Valid = (err == nil) && (i.Uint8 != 0)
return err
}
// UnmarshalText implements encoding.TextUnmarshaler.
// It will unmarshal to a null Uint8 if the input is a blank, zero, 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 {
str := string(text)
if str == "" || str == "null" {
i.Valid = false
return nil
}
var err error
res, err := strconv.ParseUint(string(text), 10, 8)
i.Uint8 = uint8(res)
i.Valid = (err == nil) && (i.Uint8 != 0)
return err
}
// MarshalJSON implements json.Marshaler.
// It will encode 0 if this Uint8 is null.
func (i Uint8) MarshalJSON() ([]byte, error) {
n := i.Uint8
if !i.Valid {
n = 0
}
return []byte(strconv.FormatUint(uint64(n), 10)), nil
}
// MarshalText implements encoding.TextMarshaler.
// It will encode a zero if this Uint8 is null.
func (i Uint8) MarshalText() ([]byte, error) {
n := i.Uint8
if !i.Valid {
n = 0
}
return []byte(strconv.FormatUint(uint64(n), 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
}
// 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 {
return nil
}
return &i.Uint8
}
// IsZero returns true for null or zero Uint8s, for future omitempty support (Go 1.4?)
func (i Uint8) IsZero() bool {
return !i.Valid || i.Uint8 == 0
}
// Scan implements the Scanner interface.
func (n *NullUint8) Scan(value interface{}) error {
if value == nil {
n.Uint8, n.Valid = 0, false
return nil
}
n.Valid = true
return convert.ConvertAssign(&n.Uint8, value)
}
// Value implements the driver Valuer interface.
func (n NullUint8) Value() (driver.Value, error) {
if !n.Valid {
return nil, nil
}
return int64(n.Uint8), nil
}

View file

@ -1,207 +0,0 @@
package zero
import (
"encoding/json"
"math"
"strconv"
"testing"
)
var (
uint8JSON = []byte(`254`)
nullUint8JSON = []byte(`{"Uint8":254,"Valid":true}`)
zeroU8JSON = []byte(`0`)
)
func TestUint8From(t *testing.T) {
i := Uint8From(254)
assertUint8(t, i, "Uint8From()")
zero := Uint8From(0)
if zero.Valid {
t.Error("Uint8From(0)", "is valid, but should be invalid")
}
}
func TestUint8FromPtr(t *testing.T) {
n := uint8(254)
iptr := &n
i := Uint8FromPtr(iptr)
assertUint8(t, i, "Uint8FromPtr()")
null := Uint8FromPtr(nil)
assertNullUint8(t, null, "Uint8FromPtr(nil)")
}
func TestUnmarshalUint8(t *testing.T) {
var i Uint8
err := json.Unmarshal(uint8JSON, &i)
maybePanic(err)
assertUint8(t, i, "int json")
var ni Uint8
err = json.Unmarshal(nullUint8JSON, &ni)
maybePanic(err)
assertUint8(t, ni, "sql.NullUint8 json")
var zero Uint8
err = json.Unmarshal(zeroU8JSON, &zero)
maybePanic(err)
assertNullUint8(t, zero, "zero json")
var null Uint8
err = json.Unmarshal(nullJSON, &null)
maybePanic(err)
assertNullUint8(t, null, "null json")
var badType Uint8
err = json.Unmarshal(boolJSON, &badType)
if err == nil {
panic("err should not be nil")
}
assertNullUint8(t, badType, "wrong type json")
var invalid Uint8
err = invalid.UnmarshalJSON(invalidJSON)
if _, ok := err.(*json.SyntaxError); !ok {
t.Errorf("expected json.SyntaxError, not %T", err)
}
assertNullUint8(t, invalid, "invalid json")
}
func TestUnmarshalNonIntegerNumberU8(t *testing.T) {
var i Uint8
err := json.Unmarshal(floatJSON, &i)
if err == nil {
panic("err should be present; non-integer number coerced to int")
}
}
func TestUnmarshalUint8Overflow(t *testing.T) {
int64Overflow := uint64(math.MaxUint8)
// Max int64 should decode successfully
var i Uint8
err := json.Unmarshal([]byte(strconv.FormatUint(int64Overflow, 10)), &i)
maybePanic(err)
// Attempt to overflow
int64Overflow++
err = json.Unmarshal([]byte(strconv.FormatUint(int64Overflow, 10)), &i)
if err == nil {
panic("err should be present; decoded value overflows int64")
}
}
func TestTextUnmarshalUint8(t *testing.T) {
var i Uint8
err := i.UnmarshalText([]byte("254"))
maybePanic(err)
assertUint8(t, i, "UnmarshalText() int")
var zero Uint8
err = zero.UnmarshalText([]byte("0"))
maybePanic(err)
assertNullUint8(t, zero, "UnmarshalText() zero int")
var blank Uint8
err = blank.UnmarshalText([]byte(""))
maybePanic(err)
assertNullUint8(t, blank, "UnmarshalText() empty int")
var null Uint8
err = null.UnmarshalText([]byte("null"))
maybePanic(err)
assertNullUint8(t, null, `UnmarshalText() "null"`)
}
func TestMarshalUint8(t *testing.T) {
i := Uint8From(254)
data, err := json.Marshal(i)
maybePanic(err)
assertJSONEquals(t, data, "254", "non-empty json marshal")
// invalid values should be encoded as 0
null := NewUint8(0, false)
data, err = json.Marshal(null)
maybePanic(err)
assertJSONEquals(t, data, "0", "null json marshal")
}
func TestMarshalUint8Text(t *testing.T) {
i := Uint8From(254)
data, err := i.MarshalText()
maybePanic(err)
assertJSONEquals(t, data, "254", "non-empty text marshal")
// invalid values should be encoded as zero
null := NewUint8(0, false)
data, err = null.MarshalText()
maybePanic(err)
assertJSONEquals(t, data, "0", "null text marshal")
}
func TestUint8Pointer(t *testing.T) {
i := Uint8From(254)
ptr := i.Ptr()
if *ptr != 254 {
t.Errorf("bad %s int: %#v ≠ %d\n", "pointer", ptr, 254)
}
null := NewUint8(0, false)
ptr = null.Ptr()
if ptr != nil {
t.Errorf("bad %s int: %#v ≠ %s\n", "nil pointer", ptr, "nil")
}
}
func TestUint8IsZero(t *testing.T) {
i := Uint8From(254)
if i.IsZero() {
t.Errorf("IsZero() should be false")
}
null := NewUint8(0, false)
if !null.IsZero() {
t.Errorf("IsZero() should be true")
}
zero := NewUint8(0, true)
if !zero.IsZero() {
t.Errorf("IsZero() should be true")
}
}
func TestUint8Scan(t *testing.T) {
var i Uint8
err := i.Scan(254)
maybePanic(err)
assertUint8(t, i, "scanned int")
var null Uint8
err = null.Scan(nil)
maybePanic(err)
assertNullUint8(t, null, "scanned null")
}
func TestUint8SetValid(t *testing.T) {
change := NewUint8(0, false)
assertNullUint8(t, change, "SetValid()")
change.SetValid(254)
assertUint8(t, change, "SetValid()")
}
func assertUint8(t *testing.T, i Uint8, from string) {
if i.Uint8 != 254 {
t.Errorf("bad %s int: %d ≠ %d\n", from, i.Uint8, 254)
}
if !i.Valid {
t.Error(from, "is invalid, but should be valid")
}
}
func assertNullUint8(t *testing.T, i Uint8, from string) {
if i.Valid {
t.Error(from, "is valid, but should be invalid")
}
}

View file

@ -1,189 +0,0 @@
package zero
import (
"encoding/json"
"testing"
)
var (
uintJSON = []byte(`12345`)
nullUintJSON = []byte(`{"Uint":12345,"Valid":true}`)
zeroUJSON = []byte(`0`)
)
func TestUintFrom(t *testing.T) {
i := UintFrom(12345)
assertUint(t, i, "UintFrom()")
zero := UintFrom(0)
if zero.Valid {
t.Error("UintFrom(0)", "is valid, but should be invalid")
}
}
func TestUintFromPtr(t *testing.T) {
n := uint(12345)
iptr := &n
i := UintFromPtr(iptr)
assertUint(t, i, "UintFromPtr()")
null := UintFromPtr(nil)
assertNullUint(t, null, "UintFromPtr(nil)")
}
func TestUnmarshalUint(t *testing.T) {
var i Uint
err := json.Unmarshal(uintJSON, &i)
maybePanic(err)
assertUint(t, i, "uint json")
var ni Uint
err = json.Unmarshal(nullUintJSON, &ni)
maybePanic(err)
assertUint(t, ni, "sql.NullUint json")
var zero Uint
err = json.Unmarshal(zeroUJSON, &zero)
maybePanic(err)
assertNullUint(t, zero, "zero json")
var null Uint
err = json.Unmarshal(nullJSON, &null)
maybePanic(err)
assertNullUint(t, null, "null json")
var badType Uint
err = json.Unmarshal(boolJSON, &badType)
if err == nil {
panic("err should not be nil")
}
assertNullUint(t, badType, "wrong type json")
var invalid Uint
err = invalid.UnmarshalJSON(invalidJSON)
if _, ok := err.(*json.SyntaxError); !ok {
t.Errorf("expected json.SyntaxError, not %T", err)
}
assertNullUint(t, invalid, "invalid json")
}
func TestUnmarshalNonUintegerNumber(t *testing.T) {
var i Uint
err := json.Unmarshal(floatJSON, &i)
if err == nil {
panic("err should be present; non-uinteger number coerced to uint")
}
}
func TestTextUnmarshalUint(t *testing.T) {
var i Uint
err := i.UnmarshalText([]byte("12345"))
maybePanic(err)
assertUint(t, i, "UnmarshalText() uint")
var zero Uint
err = zero.UnmarshalText([]byte("0"))
maybePanic(err)
assertNullUint(t, zero, "UnmarshalText() zero uint")
var blank Uint
err = blank.UnmarshalText([]byte(""))
maybePanic(err)
assertNullUint(t, blank, "UnmarshalText() empty uint")
var null Uint
err = null.UnmarshalText([]byte("null"))
maybePanic(err)
assertNullUint(t, null, `UnmarshalText() "null"`)
}
func TestMarshalUint(t *testing.T) {
i := UintFrom(12345)
data, err := json.Marshal(i)
maybePanic(err)
assertJSONEquals(t, data, "12345", "non-empty json marshal")
// invalid values should be encoded as 0
null := NewUint(0, false)
data, err = json.Marshal(null)
maybePanic(err)
assertJSONEquals(t, data, "0", "null json marshal")
}
func TestMarshalUintText(t *testing.T) {
i := UintFrom(12345)
data, err := i.MarshalText()
maybePanic(err)
assertJSONEquals(t, data, "12345", "non-empty text marshal")
// invalid values should be encoded as zero
null := NewUint(0, false)
data, err = null.MarshalText()
maybePanic(err)
assertJSONEquals(t, data, "0", "null text marshal")
}
func TestUintPouinter(t *testing.T) {
i := UintFrom(12345)
ptr := i.Ptr()
if *ptr != 12345 {
t.Errorf("bad %s uint: %#v ≠ %d\n", "pouinter", ptr, 12345)
}
null := NewUint(0, false)
ptr = null.Ptr()
if ptr != nil {
t.Errorf("bad %s uint: %#v ≠ %s\n", "nil pouinter", ptr, "nil")
}
}
func TestUintIsZero(t *testing.T) {
i := UintFrom(12345)
if i.IsZero() {
t.Errorf("IsZero() should be false")
}
null := NewUint(0, false)
if !null.IsZero() {
t.Errorf("IsZero() should be true")
}
zero := NewUint(0, true)
if !zero.IsZero() {
t.Errorf("IsZero() should be true")
}
}
func TestUintScan(t *testing.T) {
var i Uint
err := i.Scan(12345)
maybePanic(err)
assertUint(t, i, "scanned uint")
var null Uint
err = null.Scan(nil)
maybePanic(err)
assertNullUint(t, null, "scanned null")
}
func TestUintSetValid(t *testing.T) {
change := NewUint(0, false)
assertNullUint(t, change, "SetValid()")
change.SetValid(12345)
assertUint(t, change, "SetValid()")
}
func assertUint(t *testing.T, i Uint, from string) {
if i.Uint != 12345 {
t.Errorf("bad %s uint: %d ≠ %d\n", from, i.Uint, 12345)
}
if !i.Valid {
t.Error(from, "is invalid, but should be valid")
}
}
func assertNullUint(t *testing.T, i Uint, from string) {
if i.Valid {
t.Error(from, "is valid, but should be invalid")
}
}