diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..97c25f2 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,7 @@ +# Contribute + +Report bugs on GitHub and discuss your ideas and feature requests before you open a pull request. Pull requests must pass the test suite and add new tests for each new feature. Bugs should be validated by tests. The Go code must be formatted by gofmt. + +## Execute tests + +To execute the tests, you need to have all supported databases installed (for integration tests). The tests can then be executed by running the *run_tests* script or by executing the steps inside manually. All tests must be passed before a pull request can be opened. New code must be tested to keep the test coverage above 80% at least. diff --git a/README.md b/README.md index 6aa7281..1d21f7d 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,11 @@ go get github.com/emvicom/null ## Usage +Here is a short example demonstrating the string type. The other types (int64, float64 and bool) work in the same way. + ``` +package main + import ( "encoding/json" "database/sql" @@ -36,16 +40,21 @@ type NullableString struct { } func main() { - str := NullableString{null.String{sql.NullString{String: "nullable string", Valid: true}}} + str := null.NewString("nullable string", true) + // or long version: str := NullableString{null.String{sql.NullString{String: "nullable string", Valid: true}}} data, _ := json.Marshal(str) fmt.Println(string(data)) // -> {"value": "nullable"} - str.Valid = false + str.SetNil() // use str.SetValid("value") to set a value again data, _ = json.Marshal(str) fmt.Println(string(data)) // -> {"value": null} } ``` +## Contribute + +[See CONTRIBUTING.md](CONTRIBUTING.md) + ## License MIT diff --git a/bool.go b/bool.go index 49b76a6..fc5be3b 100644 --- a/bool.go +++ b/bool.go @@ -10,6 +10,12 @@ type Bool struct { sql.NullBool } +// Returns a new nullable Bool object. +// This is equivalent to `null.Bool{sql.NullBool{Bool: b, Valid: valid}}`. +func NewBool(b, valid bool) Bool { + return Bool{sql.NullBool{Bool: b, Valid: valid}} +} + func (this Bool) MarshalJSON() ([]byte, error) { if this.Valid { return json.Marshal(this.Bool) @@ -34,3 +40,15 @@ func (this *Bool) UnmarshalJSON(data []byte) error { return nil } + +// Sets the value and valid to true. +func (this *Bool) SetValid(b bool) { + this.Bool = b + this.Valid = true +} + +// Sets the value to default and valid to false. +func (this *Bool) SetNil() { + this.Bool = false + this.Valid = false +} diff --git a/bool_test.go b/bool_test.go index d3b55ec..b4e1241 100644 --- a/bool_test.go +++ b/bool_test.go @@ -10,6 +10,14 @@ type testBool struct { Value Bool `json:"value"` } +func TestNewBool(t *testing.T) { + value := NewBool(true, true) + + if !value.Bool || !value.Valid { + t.Fatal("New Bool must have value and be valid") + } +} + func TestMarshalBool(t *testing.T) { value := Bool{sql.NullBool{Bool: true, Valid: true}} @@ -46,3 +54,18 @@ func TestUnmarshalBool(t *testing.T) { t.Fatal("Unmarshalled null bool must be invalid") } } + +func TestGettersSettersBool(t *testing.T) { + value := NewBool(true, true) + value.SetNil() + + if value.Bool || value.Valid { + t.Fatal("Bool must be nil") + } + + value.SetValid(true) + + if !value.Bool || !value.Valid { + t.Fatal("Bool must be valid") + } +} diff --git a/float64.go b/float64.go index f4c8e55..70d2157 100644 --- a/float64.go +++ b/float64.go @@ -10,6 +10,12 @@ type Float64 struct { sql.NullFloat64 } +// Returns a new nullable Float64 object. +// This is equivalent to `null.Float64{sql.NullFloat64{Float64: f, Valid: valid}}`. +func NewFloat64(f float64, valid bool) Float64 { + return Float64{sql.NullFloat64{Float64: f, Valid: valid}} +} + func (this Float64) MarshalJSON() ([]byte, error) { if this.Valid { return json.Marshal(this.Float64) @@ -34,3 +40,15 @@ func (this *Float64) UnmarshalJSON(data []byte) error { return nil } + +// Sets the value and valid to true. +func (this *Float64) SetValid(f float64) { + this.Float64 = f + this.Valid = true +} + +// Sets the value to default and valid to false. +func (this *Float64) SetNil() { + this.Float64 = 0 + this.Valid = false +} diff --git a/float64_test.go b/float64_test.go index 1b516c7..4388e74 100644 --- a/float64_test.go +++ b/float64_test.go @@ -10,6 +10,14 @@ type testFloat64 struct { Value Float64 `json:"value"` } +func TestNewFloat64(t *testing.T) { + value := NewFloat64(123.45, true) + + if value.Float64 != 123.45 || !value.Valid { + t.Fatal("New Float64 must have value and be valid") + } +} + func TestMarshalFloat64(t *testing.T) { value := Float64{sql.NullFloat64{Float64: 123.45, Valid: true}} @@ -46,3 +54,18 @@ func TestUnmarshalFloat64(t *testing.T) { t.Fatal("Unmarshalled null float64 must be invalid") } } + +func TestGettersSettersFloat64(t *testing.T) { + value := NewFloat64(123.45, true) + value.SetNil() + + if value.Float64 != 0 || value.Valid { + t.Fatal("Float64 must be nil") + } + + value.SetValid(123.45) + + if value.Float64 != 123.45 || !value.Valid { + t.Fatal("Float64 must be valid") + } +} diff --git a/int64.go b/int64.go index 88056f4..f8e13fe 100644 --- a/int64.go +++ b/int64.go @@ -10,6 +10,12 @@ type Int64 struct { sql.NullInt64 } +// Returns a new nullable Int64 object. +// This is equivalent to `null.Int64{sql.NullInt64{Int64: i, Valid: valid}}`. +func NewInt64(i int64, valid bool) Int64 { + return Int64{sql.NullInt64{Int64: i, Valid: valid}} +} + func (this Int64) MarshalJSON() ([]byte, error) { if this.Valid { return json.Marshal(this.Int64) @@ -34,3 +40,15 @@ func (this *Int64) UnmarshalJSON(data []byte) error { return nil } + +// Sets the value and valid to true. +func (this *Int64) SetValid(i int64) { + this.Int64 = i + this.Valid = true +} + +// Sets the value to default and valid to false. +func (this *Int64) SetNil() { + this.Int64 = 0 + this.Valid = false +} diff --git a/int64_test.go b/int64_test.go index 349514b..bae9ad4 100644 --- a/int64_test.go +++ b/int64_test.go @@ -10,6 +10,14 @@ type testInt64 struct { Value Int64 `json:"value"` } +func TestNewInt64(t *testing.T) { + value := NewInt64(123, true) + + if value.Int64 != 123 || !value.Valid { + t.Fatal("New Int64 must have value and be valid") + } +} + func TestMarshalInt64(t *testing.T) { value := Int64{sql.NullInt64{Int64: 123, Valid: true}} @@ -46,3 +54,18 @@ func TestUnmarshalInt64(t *testing.T) { t.Fatal("Unmarshalled null int64 must be invalid") } } + +func TestGettersSettersInt64(t *testing.T) { + value := NewInt64(123, true) + value.SetNil() + + if value.Int64 != 0 || value.Valid { + t.Fatal("Int64 must be nil") + } + + value.SetValid(123) + + if value.Int64 != 123 || !value.Valid { + t.Fatal("Int64 must be valid") + } +} diff --git a/string.go b/string.go index 6a50c22..05117d8 100644 --- a/string.go +++ b/string.go @@ -10,6 +10,12 @@ type String struct { sql.NullString } +// Returns a new nullable String object. +// This is equivalent to `null.String{sql.NullString{String: s, Valid: valid}}`. +func NewString(s string, valid bool) String { + return String{sql.NullString{String: s, Valid: valid}} +} + func (this String) MarshalJSON() ([]byte, error) { if this.Valid { return json.Marshal(this.String) @@ -34,3 +40,15 @@ func (this *String) UnmarshalJSON(data []byte) error { return nil } + +// Sets the value and valid to true. +func (this *String) SetValid(s string) { + this.String = s + this.Valid = true +} + +// Sets the value to default and valid to false. +func (this *String) SetNil() { + this.String = "" + this.Valid = false +} diff --git a/string_test.go b/string_test.go index dd9de1c..228de2f 100644 --- a/string_test.go +++ b/string_test.go @@ -10,6 +10,14 @@ type testString struct { Value String `json:"value"` } +func TestNewString(t *testing.T) { + value := NewString("test", true) + + if value.String != "test" || !value.Valid { + t.Fatal("New String must have value and be valid") + } +} + func TestMarshalString(t *testing.T) { value := String{sql.NullString{String: "test", Valid: true}} @@ -46,3 +54,18 @@ func TestUnmarshalString(t *testing.T) { t.Fatal("Unmarshalled null string must be invalid") } } + +func TestGettersSettersString(t *testing.T) { + value := NewString("test", true) + value.SetNil() + + if value.String != "" || value.Valid { + t.Fatal("String must be nil") + } + + value.SetValid("test") + + if value.String != "test" || !value.Valid { + t.Fatal("String must be valid") + } +}