Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Empty datetime will fail when returning results #3169

Merged
merged 9 commits into from
Apr 11, 2019
7 changes: 6 additions & 1 deletion query/outputnode.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,12 @@ func valToBytes(v types.Val) ([]byte, error) {
}
return []byte("false"), nil
case types.DateTimeID:
return v.Value.(time.Time).MarshalJSON()
// Return empty string instead of zero-time value string - issue#3166
t := v.Value.(time.Time)
if t.IsZero() {
return []byte(`""`), nil
}
return t.MarshalJSON()
case types.GeoID:
return geojson.Marshal(v.Value.(geom.T))
case types.UidID:
Expand Down
10 changes: 8 additions & 2 deletions types/conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -252,8 +252,14 @@ func Convert(from Val, toID TypeID) (Val, error) {
case DateTimeID:
{
var t time.Time
if err := t.UnmarshalBinary(data); err != nil {
return to, err
// When we use Convert(BinaryID, DateTimeID) to store values if the value is empty,
// the conversion yields a zero time value. Here we check if that's the case and skip
// marshaling and return the ztv. Then we can handle it better if we need to return it
// in a result.
if !bytes.Equal(data, []byte("")) {
if err := t.UnmarshalBinary(data); err != nil {
return to, err
}
}
// NOTE: when converting datetime values to anything else, we must
// check for zero-time value and return the zero value of the new type.
Expand Down
30 changes: 30 additions & 0 deletions types/conversion_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,36 @@ func TestSameConversionDateTime(t *testing.T) {
}
}

func TestConversionEmpty(t *testing.T) {
tests := []struct {
in, out Val
}{
{in: Val{Tid: BinaryID, Value: []byte{}},
out: Val{Tid: DateTimeID, Value: time.Time{}}},
{in: Val{Tid: BinaryID, Value: bs("")},
out: Val{Tid: DateTimeID, Value: time.Time{}}},
{in: Val{Tid: DateTimeID, Value: bs(time.Time{})},
out: Val{Tid: BinaryID, Value: []byte{}}},
{in: Val{Tid: StringID, Value: bs("")},
out: Val{Tid: DateTimeID, Value: time.Time{}}},
{in: Val{Tid: DateTimeID, Value: bs(time.Time{})},
out: Val{Tid: StringID, Value: ""}},
{in: Val{Tid: DefaultID, Value: bs("")},
out: Val{Tid: DateTimeID, Value: time.Time{}}},
{in: Val{Tid: DateTimeID, Value: bs(time.Time{})},
out: Val{Tid: DefaultID, Value: ""}},
{in: Val{Tid: DateTimeID, Value: bs("")},
out: Val{Tid: DateTimeID, Value: time.Time{}}},
{in: Val{Tid: DateTimeID, Value: []byte{}},
out: Val{Tid: DateTimeID, Value: time.Time{}}},
}
for _, tc := range tests {
out, err := Convert(tc.in, tc.out.Tid)
require.NoError(t, err)
require.EqualValues(t, tc.out, out)
}
}

func TestConvertToDefault(t *testing.T) {
tests := []struct {
in Val
Expand Down