Skip to content

Commit

Permalink
Added new nullable Time type.
Browse files Browse the repository at this point in the history
  • Loading branch information
Kugelschieber committed Mar 18, 2019
1 parent ea30b80 commit 1be41c1
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 12 deletions.
5 changes: 2 additions & 3 deletions bool.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,9 @@ func (b *Bool) UnmarshalJSON(data []byte) error {
}

if value != nil {
b.Valid = true
b.Bool = *value
b.SetValid(*value)
} else {
b.Valid = false
b.SetNil()
}

return nil
Expand Down
5 changes: 2 additions & 3 deletions float64.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,9 @@ func (f *Float64) UnmarshalJSON(data []byte) error {
}

if value != nil {
f.Valid = true
f.Float64 = *value
f.SetValid(*value)
} else {
f.Valid = false
f.SetNil()
}

return nil
Expand Down
5 changes: 2 additions & 3 deletions int64.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,9 @@ func (i *Int64) UnmarshalJSON(data []byte) error {
}

if value != nil {
i.Valid = true
i.Int64 = *value
i.SetValid(*value)
} else {
i.Valid = false
i.SetNil()
}

return nil
Expand Down
5 changes: 2 additions & 3 deletions string.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,9 @@ func (s *String) UnmarshalJSON(data []byte) error {
}

if value != nil {
s.Valid = true
s.String = *value
s.SetValid(*value)
} else {
s.Valid = false
s.SetNil()
}

return nil
Expand Down
56 changes: 56 additions & 0 deletions time.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package null

import (
"encoding/json"
"time"
)

// Time is a nullable time.Time, that supports parsing to/from JSON.
type Time struct {
time.Time
Valid bool
}

// NewTime returns a new nullable time.Time object.
// This is equivalent to `null.Time{Time: t, Valid: valid}`.
func NewTime(t time.Time, valid bool) Time {
return Time{Time: t, Valid: valid}
}

// MarshalJSON implements the encoding json interface.
func (t Time) MarshalJSON() ([]byte, error) {
if t.Valid {
return json.Marshal(t.Time)
}

return json.Marshal(nil)
}

// UnmarshalJSON implements the encoding json interface.
func (t *Time) UnmarshalJSON(data []byte) error {
var value time.Time

if err := json.Unmarshal(data, &value); err != nil {
return err
}

if !value.IsZero() {
t.SetValid(value)
} else {
t.SetNil()
}

return nil
}

// SetValid sets the value and valid to true.
func (t *Time) SetValid(value time.Time) {
t.Time = value
t.Valid = true
}

// SetNil sets the value to default and valid to false.
func (t *Time) SetNil() {
t.Time = time.Time{}
t.Valid = false
}
77 changes: 77 additions & 0 deletions time_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package null

import (
"encoding/json"
"testing"
"time"
)

type testTime struct {
Value Time `json:"value"`
}

func TestNewTime(t *testing.T) {
value := NewTime(time.Now(), true)

if value.Time.Equal(time.Time{}) || !value.Valid {
t.Fatal("New Time must have value and be valid")
}
}

func TestMarshalTime(t *testing.T) {
now := time.Now()
nowStrBytes, _ := json.Marshal(now)
nowStr := string(nowStrBytes)
value := Time{Time: now, Valid: true}

if data, err := json.Marshal(value); err != nil || string(data) != nowStr {
t.Fatalf("Time must be marshalled to value, but was %v %v", err, string(data))
}

value.Valid = false

if data, err := json.Marshal(value); err != nil || string(data) != "null" {
t.Fatalf("Time must be marshalled to null, but was %v %v", err, string(data))
}
}

func TestUnmarshalTime(t *testing.T) {
now := time.Now()
nowStrBytes, _ := json.Marshal(now)
nowStr := string(nowStrBytes)
str := `{"value": `+nowStr+`}`
var value testTime

if err := json.Unmarshal([]byte(str), &value); err != nil {
t.Fatalf("Time must be unmarshalled to value, but was %v", err)
}

if !value.Value.Valid || !value.Value.Time.Equal(now) {
t.Fatalf("Unmarshalled null Time must be valid, but was %v", value.Value)
}

str = `{"value": null}`

if err := json.Unmarshal([]byte(str), &value); err != nil {
t.Fatalf("Time must be unmarshalled to null, but was %v", err)
}

if value.Value.Valid {
t.Fatal("Unmarshalled null Time must be invalid")
}
}

func TestGettersSettersTime(t *testing.T) {
value := NewTime(time.Now(), true)
value.SetNil()

if !value.Time.Equal(time.Time{}) || value.Valid {
t.Fatal("Time must be nil")
}

value.SetValid(time.Now())

if value.Time.Equal(time.Time{}) || !value.Valid {
t.Fatal("Time must be valid")
}
}

0 comments on commit 1be41c1

Please sign in to comment.