From 8117205a7549722353a70cfbc6046c4081f9c0c8 Mon Sep 17 00:00:00 2001 From: Jack Christensen Date: Tue, 3 Mar 2020 15:25:57 -0600 Subject: [PATCH] Range types Set method supports its own type, string, and nil Previously Set would always return an error when called on a range type. Now it will accept an instance of itself, a pointer to an instance of itself, a string, or nil. Strings are parsed with the same logic as DecodeText. --- daterange.go | 19 ++++++++++++- daterange_test.go | 66 ++++++++++++++++++++++++++++++++++++++++++++++ int4range.go | 19 ++++++++++++- int8range.go | 19 ++++++++++++- numrange.go | 19 ++++++++++++- tsrange.go | 19 ++++++++++++- tstzrange.go | 19 ++++++++++++- typed_range.go.erb | 19 ++++++++++++- 8 files changed, 192 insertions(+), 7 deletions(-) diff --git a/daterange.go b/daterange.go index 78e7b813..7b9af795 100644 --- a/daterange.go +++ b/daterange.go @@ -16,7 +16,24 @@ type Daterange struct { } func (dst *Daterange) Set(src interface{}) error { - return errors.Errorf("cannot convert %v to Daterange", src) + // untyped nil and typed nil interfaces are different + if src == nil { + *dst = Daterange{Status: Null} + return nil + } + + switch value := src.(type) { + case Daterange: + *dst = value + case *Daterange: + *dst = *value + case string: + return dst.DecodeText(nil, []byte(value)) + default: + return errors.Errorf("cannot convert %v to Daterange", src) + } + + return nil } func (dst Daterange) Get() interface{} { diff --git a/daterange_test.go b/daterange_test.go index 4118cffa..54d51e2d 100644 --- a/daterange_test.go +++ b/daterange_test.go @@ -65,3 +65,69 @@ func TestDaterangeNormalize(t *testing.T) { a.Upper.InfinityModifier == b.Upper.InfinityModifier }) } + +func TestDaterangeSet(t *testing.T) { + successfulTests := []struct { + source interface{} + result pgtype.Daterange + }{ + { + source: nil, + result: pgtype.Daterange{Status: pgtype.Null}, + }, + { + source: &pgtype.Daterange{ + Lower: pgtype.Date{Time: time.Date(1990, 12, 31, 0, 0, 0, 0, time.UTC), Status: pgtype.Present}, + Upper: pgtype.Date{Time: time.Date(2028, 1, 1, 0, 0, 0, 0, time.UTC), Status: pgtype.Present}, + LowerType: pgtype.Inclusive, + UpperType: pgtype.Exclusive, + Status: pgtype.Present, + }, + result: pgtype.Daterange{ + Lower: pgtype.Date{Time: time.Date(1990, 12, 31, 0, 0, 0, 0, time.UTC), Status: pgtype.Present}, + Upper: pgtype.Date{Time: time.Date(2028, 1, 1, 0, 0, 0, 0, time.UTC), Status: pgtype.Present}, + LowerType: pgtype.Inclusive, + UpperType: pgtype.Exclusive, + Status: pgtype.Present, + }, + }, + { + source: pgtype.Daterange{ + Lower: pgtype.Date{Time: time.Date(1990, 12, 31, 0, 0, 0, 0, time.UTC), Status: pgtype.Present}, + Upper: pgtype.Date{Time: time.Date(2028, 1, 1, 0, 0, 0, 0, time.UTC), Status: pgtype.Present}, + LowerType: pgtype.Inclusive, + UpperType: pgtype.Exclusive, + Status: pgtype.Present, + }, + result: pgtype.Daterange{ + Lower: pgtype.Date{Time: time.Date(1990, 12, 31, 0, 0, 0, 0, time.UTC), Status: pgtype.Present}, + Upper: pgtype.Date{Time: time.Date(2028, 1, 1, 0, 0, 0, 0, time.UTC), Status: pgtype.Present}, + LowerType: pgtype.Inclusive, + UpperType: pgtype.Exclusive, + Status: pgtype.Present, + }, + }, + { + source: "[1990-12-31,2028-01-01)", + result: pgtype.Daterange{ + Lower: pgtype.Date{Time: time.Date(1990, 12, 31, 0, 0, 0, 0, time.UTC), Status: pgtype.Present}, + Upper: pgtype.Date{Time: time.Date(2028, 1, 1, 0, 0, 0, 0, time.UTC), Status: pgtype.Present}, + LowerType: pgtype.Inclusive, + UpperType: pgtype.Exclusive, + Status: pgtype.Present, + }, + }, + } + + for i, tt := range successfulTests { + var r pgtype.Daterange + err := r.Set(tt.source) + if err != nil { + t.Errorf("%d: %v", i, err) + } + + if r != tt.result { + t.Errorf("%d: expected %v to convert to %v, but it was %v", i, tt.source, tt.result, r) + } + } +} diff --git a/int4range.go b/int4range.go index 6638e9c1..442f2501 100644 --- a/int4range.go +++ b/int4range.go @@ -16,7 +16,24 @@ type Int4range struct { } func (dst *Int4range) Set(src interface{}) error { - return errors.Errorf("cannot convert %v to Int4range", src) + // untyped nil and typed nil interfaces are different + if src == nil { + *dst = Int4range{Status: Null} + return nil + } + + switch value := src.(type) { + case Int4range: + *dst = value + case *Int4range: + *dst = *value + case string: + return dst.DecodeText(nil, []byte(value)) + default: + return errors.Errorf("cannot convert %v to Int4range", src) + } + + return nil } func (dst Int4range) Get() interface{} { diff --git a/int8range.go b/int8range.go index 88027974..92fcb136 100644 --- a/int8range.go +++ b/int8range.go @@ -16,7 +16,24 @@ type Int8range struct { } func (dst *Int8range) Set(src interface{}) error { - return errors.Errorf("cannot convert %v to Int8range", src) + // untyped nil and typed nil interfaces are different + if src == nil { + *dst = Int8range{Status: Null} + return nil + } + + switch value := src.(type) { + case Int8range: + *dst = value + case *Int8range: + *dst = *value + case string: + return dst.DecodeText(nil, []byte(value)) + default: + return errors.Errorf("cannot convert %v to Int8range", src) + } + + return nil } func (dst Int8range) Get() interface{} { diff --git a/numrange.go b/numrange.go index 64b7fbc3..40467686 100644 --- a/numrange.go +++ b/numrange.go @@ -16,7 +16,24 @@ type Numrange struct { } func (dst *Numrange) Set(src interface{}) error { - return errors.Errorf("cannot convert %v to Numrange", src) + // untyped nil and typed nil interfaces are different + if src == nil { + *dst = Numrange{Status: Null} + return nil + } + + switch value := src.(type) { + case Numrange: + *dst = value + case *Numrange: + *dst = *value + case string: + return dst.DecodeText(nil, []byte(value)) + default: + return errors.Errorf("cannot convert %v to Numrange", src) + } + + return nil } func (dst Numrange) Get() interface{} { diff --git a/tsrange.go b/tsrange.go index 68fa6d73..6ca12aed 100644 --- a/tsrange.go +++ b/tsrange.go @@ -16,7 +16,24 @@ type Tsrange struct { } func (dst *Tsrange) Set(src interface{}) error { - return errors.Errorf("cannot convert %v to Tsrange", src) + // untyped nil and typed nil interfaces are different + if src == nil { + *dst = Tsrange{Status: Null} + return nil + } + + switch value := src.(type) { + case Tsrange: + *dst = value + case *Tsrange: + *dst = *value + case string: + return dst.DecodeText(nil, []byte(value)) + default: + return errors.Errorf("cannot convert %v to Tsrange", src) + } + + return nil } func (dst Tsrange) Get() interface{} { diff --git a/tstzrange.go b/tstzrange.go index 8441275f..1b05c3ea 100644 --- a/tstzrange.go +++ b/tstzrange.go @@ -16,7 +16,24 @@ type Tstzrange struct { } func (dst *Tstzrange) Set(src interface{}) error { - return errors.Errorf("cannot convert %v to Tstzrange", src) + // untyped nil and typed nil interfaces are different + if src == nil { + *dst = Tstzrange{Status: Null} + return nil + } + + switch value := src.(type) { + case Tstzrange: + *dst = value + case *Tstzrange: + *dst = *value + case string: + return dst.DecodeText(nil, []byte(value)) + default: + return errors.Errorf("cannot convert %v to Tstzrange", src) + } + + return nil } func (dst Tstzrange) Get() interface{} { diff --git a/typed_range.go.erb b/typed_range.go.erb index 9846e5dd..e21b6cda 100644 --- a/typed_range.go.erb +++ b/typed_range.go.erb @@ -18,7 +18,24 @@ type <%= range_type %> struct { } func (dst *<%= range_type %>) Set(src interface{}) error { - return errors.Errorf("cannot convert %v to <%= range_type %>", src) + // untyped nil and typed nil interfaces are different + if src == nil { + *dst = <%= range_type %>{Status: Null} + return nil + } + + switch value := src.(type) { + case <%= range_type %>: + *dst = value + case *<%= range_type %>: + *dst = *value + case string: + return dst.DecodeText(nil, []byte(value)) + default: + return errors.Errorf("cannot convert %v to <%= range_type %>", src) + } + + return nil } func (dst <%= range_type %>) Get() interface{} {