Removed zero
Fix bool, bytes, json
This commit is contained in:
parent
b326f4655b
commit
dc72f92a47
40 changed files with 105 additions and 5716 deletions
58
bool.go
58
bool.go
|
@ -1,27 +1,27 @@
|
||||||
package null
|
package null
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"bytes"
|
||||||
|
"database/sql/driver"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"reflect"
|
"github.com/nullbio/null/convert"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Bool is a nullable bool.
|
// Bool is a nullable bool.
|
||||||
// It does not consider false values to be null.
|
// It does not consider false values to be null.
|
||||||
// It will decode to null, not false, if null.
|
// It will decode to null, not false, if null.
|
||||||
type Bool struct {
|
type Bool struct {
|
||||||
sql.NullBool
|
Bool bool
|
||||||
|
Valid bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBool creates a new Bool
|
// NewBool creates a new Bool
|
||||||
func NewBool(b bool, valid bool) Bool {
|
func NewBool(b bool, valid bool) Bool {
|
||||||
return Bool{
|
return Bool{
|
||||||
NullBool: sql.NullBool{
|
Bool: b,
|
||||||
Bool: b,
|
Valid: valid,
|
||||||
Valid: valid,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,24 +43,18 @@ func BoolFromPtr(b *bool) Bool {
|
||||||
// 0 will not be considered a null Bool.
|
// 0 will not be considered a null Bool.
|
||||||
// It also supports unmarshalling a sql.NullBool.
|
// It also supports unmarshalling a sql.NullBool.
|
||||||
func (b *Bool) UnmarshalJSON(data []byte) error {
|
func (b *Bool) UnmarshalJSON(data []byte) error {
|
||||||
var err error
|
if bytes.Equal(data, NullBytes) {
|
||||||
var v interface{}
|
b.Bool = false
|
||||||
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
|
b.Valid = false
|
||||||
return nil
|
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
|
|
||||||
return err
|
if err := json.Unmarshal(data, &b.Bool); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
b.Valid = true
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalText implements encoding.TextUnmarshaler.
|
// UnmarshalText implements encoding.TextUnmarshaler.
|
||||||
|
@ -127,3 +121,21 @@ func (b Bool) Ptr() *bool {
|
||||||
func (b Bool) IsZero() bool {
|
func (b Bool) IsZero() bool {
|
||||||
return !b.Valid
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -39,8 +39,9 @@ func TestUnmarshalBool(t *testing.T) {
|
||||||
|
|
||||||
var nb Bool
|
var nb Bool
|
||||||
err = json.Unmarshal(nullBoolJSON, &nb)
|
err = json.Unmarshal(nullBoolJSON, &nb)
|
||||||
maybePanic(err)
|
if err == nil {
|
||||||
assertBool(t, nb, "sq.NullBool json")
|
panic("err should not be nil")
|
||||||
|
}
|
||||||
|
|
||||||
var null Bool
|
var null Bool
|
||||||
err = json.Unmarshal(nullJSON, &null)
|
err = json.Unmarshal(nullJSON, &null)
|
||||||
|
|
49
bytes.go
49
bytes.go
|
@ -1,31 +1,27 @@
|
||||||
package null
|
package null
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"database/sql/driver"
|
"database/sql/driver"
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
"gopkg.in/nullbio/null.v5/convert"
|
"gopkg.in/nullbio/null.v5/convert"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NullBytes is a nullable byte slice.
|
// NullBytes is a global byte slice of JSON null
|
||||||
type NullBytes struct {
|
var NullBytes = []byte("null")
|
||||||
Bytes []byte
|
|
||||||
Valid bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bytes is a nullable []byte.
|
// Bytes is a nullable []byte.
|
||||||
// JSON marshals to zero if null.
|
|
||||||
// Considered null to SQL if zero.
|
|
||||||
type Bytes struct {
|
type Bytes struct {
|
||||||
NullBytes
|
Bytes []byte
|
||||||
|
Valid bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBytes creates a new Bytes
|
// NewBytes creates a new Bytes
|
||||||
func NewBytes(b []byte, valid bool) Bytes {
|
func NewBytes(b []byte, valid bool) Bytes {
|
||||||
return Bytes{
|
return Bytes{
|
||||||
NullBytes: NullBytes{
|
Bytes: b,
|
||||||
Bytes: b,
|
Valid: valid,
|
||||||
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 data is len 0 or nil, it will unmarshal to JSON null.
|
||||||
// If not, it will copy your data slice into Bytes.
|
// If not, it will copy your data slice into Bytes.
|
||||||
func (b *Bytes) UnmarshalJSON(data []byte) error {
|
func (b *Bytes) UnmarshalJSON(data []byte) error {
|
||||||
if data == nil || len(data) == 0 {
|
if bytes.Equal(data, NullBytes) {
|
||||||
b.Bytes = []byte("null")
|
b.Valid = false
|
||||||
} else {
|
b.Bytes = nil
|
||||||
b.Bytes = append(b.Bytes[0:0], data...)
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,19 +111,19 @@ func (b Bytes) IsZero() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scan implements the Scanner interface.
|
// Scan implements the Scanner interface.
|
||||||
func (n *NullBytes) Scan(value interface{}) error {
|
func (b *Bytes) Scan(value interface{}) error {
|
||||||
if value == nil {
|
if value == nil {
|
||||||
n.Bytes, n.Valid = []byte{}, false
|
b.Bytes, b.Valid = []byte{}, false
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
n.Valid = true
|
b.Valid = true
|
||||||
return convert.ConvertAssign(&n.Bytes, value)
|
return convert.ConvertAssign(&b.Bytes, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Value implements the driver Valuer interface.
|
// Value implements the driver Valuer interface.
|
||||||
func (n NullBytes) Value() (driver.Value, error) {
|
func (b Bytes) Value() (driver.Value, error) {
|
||||||
if !n.Valid {
|
if !b.Valid {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
return n.Bytes, nil
|
return b.Bytes, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestBytesFrom(t *testing.T) {
|
func TestBytesFrom(t *testing.T) {
|
||||||
i := BytesFrom([]byte(`"hello"`))
|
i := BytesFrom([]byte(`hello`))
|
||||||
assertBytes(t, i, "BytesFrom()")
|
assertBytes(t, i, "BytesFrom()")
|
||||||
|
|
||||||
zero := BytesFrom(nil)
|
zero := BytesFrom(nil)
|
||||||
|
@ -26,7 +26,7 @@ func TestBytesFrom(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBytesFromPtr(t *testing.T) {
|
func TestBytesFromPtr(t *testing.T) {
|
||||||
n := []byte(`"hello"`)
|
n := []byte(`hello`)
|
||||||
iptr := &n
|
iptr := &n
|
||||||
i := BytesFromPtr(iptr)
|
i := BytesFromPtr(iptr)
|
||||||
assertBytes(t, i, "BytesFromPtr()")
|
assertBytes(t, i, "BytesFromPtr()")
|
||||||
|
@ -43,26 +43,23 @@ func TestUnmarshalBytes(t *testing.T) {
|
||||||
|
|
||||||
var ni Bytes
|
var ni Bytes
|
||||||
err = ni.UnmarshalJSON([]byte{})
|
err = ni.UnmarshalJSON([]byte{})
|
||||||
if ni.Valid == false {
|
if err == nil {
|
||||||
t.Errorf("expected Valid to be true, got false")
|
t.Errorf("Expected error")
|
||||||
}
|
|
||||||
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
|
var null Bytes
|
||||||
err = null.UnmarshalJSON(nil)
|
err = null.UnmarshalJSON([]byte("null"))
|
||||||
if null.Valid == false {
|
if null.Valid == true {
|
||||||
t.Errorf("expected Valid to be true, got false")
|
t.Errorf("expected Valid to be false, got true")
|
||||||
}
|
}
|
||||||
if !bytes.Equal(null.Bytes, []byte(`null`)) {
|
if null.Bytes != nil {
|
||||||
t.Errorf("Expected Bytes to be []byte nil, but was not: %#v %#v", null.Bytes, []byte(`null`))
|
t.Errorf("Expected Bytes to be nil, but was not: %#v %#v", null.Bytes, []byte(`null`))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTextUnmarshalBytes(t *testing.T) {
|
func TestTextUnmarshalBytes(t *testing.T) {
|
||||||
var i Bytes
|
var i Bytes
|
||||||
err := i.UnmarshalText([]byte(`"hello"`))
|
err := i.UnmarshalText([]byte(`hello`))
|
||||||
maybePanic(err)
|
maybePanic(err)
|
||||||
assertBytes(t, i, "UnmarshalText() []byte")
|
assertBytes(t, i, "UnmarshalText() []byte")
|
||||||
|
|
||||||
|
@ -132,15 +129,15 @@ func TestBytesIsZero(t *testing.T) {
|
||||||
func TestBytesSetValid(t *testing.T) {
|
func TestBytesSetValid(t *testing.T) {
|
||||||
change := NewBytes(nil, false)
|
change := NewBytes(nil, false)
|
||||||
assertNullBytes(t, change, "SetValid()")
|
assertNullBytes(t, change, "SetValid()")
|
||||||
change.SetValid([]byte(`"hello"`))
|
change.SetValid([]byte(`hello`))
|
||||||
assertBytes(t, change, "SetValid()")
|
assertBytes(t, change, "SetValid()")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBytesScan(t *testing.T) {
|
func TestBytesScan(t *testing.T) {
|
||||||
var i Bytes
|
var i Bytes
|
||||||
err := i.Scan(`"hello"`)
|
err := i.Scan(`hello`)
|
||||||
maybePanic(err)
|
maybePanic(err)
|
||||||
assertBytes(t, i, "scanned []byte")
|
assertBytes(t, i, "Scan() []byte")
|
||||||
|
|
||||||
var null Bytes
|
var null Bytes
|
||||||
err = null.Scan(nil)
|
err = null.Scan(nil)
|
||||||
|
@ -149,8 +146,8 @@ func TestBytesScan(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func assertBytes(t *testing.T, i Bytes, from string) {
|
func assertBytes(t *testing.T, i Bytes, from string) {
|
||||||
if !bytes.Equal(i.Bytes, []byte(`"hello"`)) {
|
if !bytes.Equal(i.Bytes, []byte("hello")) {
|
||||||
t.Errorf("bad %s []byte: %#v ≠ %#v\n", from, string(i.Bytes), string([]byte(`"hello"`)))
|
t.Errorf("bad %s []byte: %v ≠ %v\n", from, string(i.Bytes), string([]byte(`hello`)))
|
||||||
}
|
}
|
||||||
if !i.Valid {
|
if !i.Valid {
|
||||||
t.Error(from, "is invalid, but should be valid")
|
t.Error(from, "is invalid, but should be valid")
|
||||||
|
|
46
json.go
46
json.go
|
@ -1,33 +1,26 @@
|
||||||
package null
|
package null
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"database/sql/driver"
|
"database/sql/driver"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"gopkg.in/nullbio/null.v5/convert"
|
"gopkg.in/nullbio/null.v5/convert"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NullJSON is a nullable byte slice.
|
// JSON is a nullable []byte.
|
||||||
type NullJSON struct {
|
type JSON struct {
|
||||||
JSON []byte
|
JSON []byte
|
||||||
Valid bool
|
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
|
// NewJSON creates a new JSON
|
||||||
func NewJSON(b []byte, valid bool) JSON {
|
func NewJSON(b []byte, valid bool) JSON {
|
||||||
return JSON{
|
return JSON{
|
||||||
NullJSON: NullJSON{
|
JSON: b,
|
||||||
JSON: b,
|
Valid: valid,
|
||||||
Valid: valid,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,16 +58,21 @@ func (j JSON) Unmarshal(dest interface{}) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalJSON implements json.Unmarshaler.
|
// 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.
|
// If not, it will copy your data slice into JSON.
|
||||||
func (j *JSON) UnmarshalJSON(data []byte) error {
|
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")
|
j.JSON = []byte("null")
|
||||||
} else {
|
j.Valid = false
|
||||||
j.JSON = append(j.JSON[0:0], data...)
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
j.Valid = true
|
j.Valid = true
|
||||||
|
j.JSON = make([]byte, len(data))
|
||||||
|
copy(j.JSON, data)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -145,19 +143,19 @@ func (j JSON) IsZero() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scan implements the Scanner interface.
|
// Scan implements the Scanner interface.
|
||||||
func (n *NullJSON) Scan(value interface{}) error {
|
func (j *JSON) Scan(value interface{}) error {
|
||||||
if value == nil {
|
if value == nil {
|
||||||
n.JSON, n.Valid = []byte{}, false
|
j.JSON, j.Valid = []byte{}, false
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
n.Valid = true
|
j.Valid = true
|
||||||
return convert.ConvertAssign(&n.JSON, value)
|
return convert.ConvertAssign(&j.JSON, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Value implements the driver Valuer interface.
|
// Value implements the driver Valuer interface.
|
||||||
func (n NullJSON) Value() (driver.Value, error) {
|
func (j JSON) Value() (driver.Value, error) {
|
||||||
if !n.Valid {
|
if !j.Valid {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
return n.JSON, nil
|
return j.JSON, nil
|
||||||
}
|
}
|
||||||
|
|
10
json_test.go
10
json_test.go
|
@ -65,8 +65,8 @@ func TestMarshal(t *testing.T) {
|
||||||
if !bytes.Equal(i.JSON, []byte("null")) {
|
if !bytes.Equal(i.JSON, []byte("null")) {
|
||||||
t.Errorf("Expected null, but got %s", string(i.JSON))
|
t.Errorf("Expected null, but got %s", string(i.JSON))
|
||||||
}
|
}
|
||||||
if i.Valid == false {
|
if i.Valid == true {
|
||||||
t.Error("Expected Valid true, got Valid false")
|
t.Error("Expected Valid false, got Valid true")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,8 +114,8 @@ func TestUnmarshalJSON(t *testing.T) {
|
||||||
if ni.Valid == false {
|
if ni.Valid == false {
|
||||||
t.Errorf("expected Valid to be true, got false")
|
t.Errorf("expected Valid to be true, got false")
|
||||||
}
|
}
|
||||||
if !bytes.Equal(ni.JSON, []byte(`null`)) {
|
if !bytes.Equal(ni.JSON, nil) {
|
||||||
t.Errorf("Expected JSON to be null slice, but was not: %#v %#v", ni.JSON, []byte(nil))
|
t.Errorf("Expected JSON to be nil, but was not: %#v %#v", ni.JSON, []byte(nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
var null JSON
|
var null JSON
|
||||||
|
@ -123,7 +123,7 @@ func TestUnmarshalJSON(t *testing.T) {
|
||||||
if ni.Valid == false {
|
if ni.Valid == false {
|
||||||
t.Errorf("expected Valid to be true, got 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))
|
t.Errorf("Expected JSON to be []byte nil, but was not: %#v %#v", null.JSON, []byte(nil))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
121
zero/bool.go
121
zero/bool.go
|
@ -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
|
|
||||||
}
|
|
|
@ -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")
|
|
||||||
}
|
|
||||||
}
|
|
128
zero/bytes.go
128
zero/bytes.go
|
@ -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
|
|
||||||
}
|
|
|
@ -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")
|
|
||||||
}
|
|
||||||
}
|
|
144
zero/float32.go
144
zero/float32.go
|
@ -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
|
|
||||||
}
|
|
|
@ -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")
|
|
||||||
}
|
|
||||||
}
|
|
118
zero/float64.go
118
zero/float64.go
|
@ -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
|
|
||||||
}
|
|
|
@ -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")
|
|
||||||
}
|
|
||||||
}
|
|
146
zero/int.go
146
zero/int.go
|
@ -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
|
|
||||||
}
|
|
146
zero/int16.go
146
zero/int16.go
|
@ -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
|
|
||||||
}
|
|
|
@ -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")
|
|
||||||
}
|
|
||||||
}
|
|
146
zero/int32.go
146
zero/int32.go
|
@ -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
|
|
||||||
}
|
|
|
@ -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")
|
|
||||||
}
|
|
||||||
}
|
|
120
zero/int64.go
120
zero/int64.go
|
@ -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
|
|
||||||
}
|
|
|
@ -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")
|
|
||||||
}
|
|
||||||
}
|
|
146
zero/int8.go
146
zero/int8.go
|
@ -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
|
|
||||||
}
|
|
|
@ -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")
|
|
||||||
}
|
|
||||||
}
|
|
189
zero/int_test.go
189
zero/int_test.go
|
@ -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")
|
|
||||||
}
|
|
||||||
}
|
|
128
zero/json.go
128
zero/json.go
|
@ -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
|
|
||||||
}
|
|
|
@ -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")
|
|
||||||
}
|
|
||||||
}
|
|
103
zero/string.go
103
zero/string.go
|
@ -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 == ""
|
|
||||||
}
|
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
145
zero/time.go
145
zero/time.go
|
@ -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
|
|
||||||
}
|
|
|
@ -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")
|
|
||||||
}
|
|
||||||
}
|
|
146
zero/uint.go
146
zero/uint.go
|
@ -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
|
|
||||||
}
|
|
146
zero/uint16.go
146
zero/uint16.go
|
@ -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
|
|
||||||
}
|
|
|
@ -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")
|
|
||||||
}
|
|
||||||
}
|
|
146
zero/uint32.go
146
zero/uint32.go
|
@ -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
|
|
||||||
}
|
|
|
@ -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")
|
|
||||||
}
|
|
||||||
}
|
|
146
zero/uint64.go
146
zero/uint64.go
|
@ -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
|
|
||||||
}
|
|
|
@ -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")
|
|
||||||
}
|
|
||||||
}
|
|
146
zero/uint8.go
146
zero/uint8.go
|
@ -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
|
|
||||||
}
|
|
|
@ -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")
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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")
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue