Skip to content

Commit

Permalink
feat: add nullable.Time
Browse files Browse the repository at this point in the history
  • Loading branch information
kernle32dll committed Feb 9, 2020
1 parent ecb7d6b commit 4d2cbb1
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 0 deletions.
31 changes: 31 additions & 0 deletions time.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package nullable

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

// Time represents a time that may be null or not
// present in json at all.
type Time struct {
Present bool // Present is true if key is present in json
Valid bool // Valid is true if value is not null and valid time
Value time.Time
}

// UnmarshalJSON implements json.Marshaler interface.
func (t *Time) UnmarshalJSON(data []byte) error {
t.Present = true

if bytes.Equal(data, null) {
return nil
}

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

t.Valid = true
return nil
}
68 changes: 68 additions & 0 deletions time_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package nullable

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

var referenceDate = time.Date(1991, 5, 23, 1, 2, 3, 4, time.UTC)

func TestTime_UnmarshalJSON(t *testing.T) {
tests := []struct {
name string
buf *bytes.Buffer
expect Time
expectErr error
}{
{
name: "null value",
buf: bytes.NewBufferString(`{"value":null}`),
expect: Time{
Present: true,
},
expectErr: nil,
},
{
name: "valid value",
buf: bytes.NewBufferString(`{"value":"` + referenceDate.Format(time.RFC3339Nano) + `"}`),
expect: Time{
Present: true,
Valid: true,
Value: referenceDate,
},
expectErr: nil,
},
{
name: "empty",
buf: bytes.NewBufferString(`{}`),
expect: Time{},
expectErr: nil,
},
{
name: "unmarshallable",
buf: bytes.NewBufferString(`{"value":42}`),
expect: Time{
Present: true,
},
expectErr: &time.ParseError{},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
str := struct {
Value Time `json:"value"`
}{}

if err := json.Unmarshal(tt.buf.Bytes(), &str); !typeMatch(tt.expectErr, err) {
t.Fatalf("unexpected unmarshaling error: %s", err)
}

got := str.Value
if got.Present != tt.expect.Present || got.Valid != tt.expect.Valid || got.Value != tt.expect.Value {
t.Errorf("expected value to be %#v got %#v", tt.expect, got)
}
})
}
}

0 comments on commit 4d2cbb1

Please sign in to comment.