1 package pgtype_test
2
3 import (
4 "database/sql/driver"
5 "fmt"
6 "reflect"
7 "testing"
8 "time"
9
10 "github.com/jackc/pgtype"
11 "github.com/jackc/pgtype/testutil"
12 )
13
14 type customDate struct {
15 t time.Time
16 }
17
18 func (d customDate) Value() (driver.Value, error) {
19 return d.t.Format("2006-01-02"), nil
20 }
21
22 func (d *customDate) Scan(src interface{}) (err error) {
23 if src == nil {
24 d.t = time.Time{}
25 return nil
26 }
27
28 switch v := src.(type) {
29 case int64:
30 d.t = time.Unix(v, 0).UTC()
31 case float64:
32 d.t = time.Unix(int64(v), 0).UTC()
33 case string:
34 d.t, err = time.Parse("2006-01-02", v)
35 case []byte:
36 d.t, err = time.Parse("2006-01-02", string(v))
37 case time.Time:
38 d.t = v
39 default:
40 err = fmt.Errorf("failed to scan type '%T' into date", src)
41 }
42 return err
43 }
44
45 func TestDateTranscode(t *testing.T) {
46 testutil.TestSuccessfulTranscodeEqFunc(t, "date", []interface{}{
47 &pgtype.Date{Time: time.Date(1900, 1, 1, 0, 0, 0, 0, time.UTC), Status: pgtype.Present},
48 &pgtype.Date{Time: time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC), Status: pgtype.Present},
49 &pgtype.Date{Time: time.Date(1999, 12, 31, 0, 0, 0, 0, time.UTC), Status: pgtype.Present},
50 &pgtype.Date{Time: time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), Status: pgtype.Present},
51 &pgtype.Date{Time: time.Date(2000, 1, 2, 0, 0, 0, 0, time.UTC), Status: pgtype.Present},
52 &pgtype.Date{Time: time.Date(2200, 1, 1, 0, 0, 0, 0, time.UTC), Status: pgtype.Present},
53 &pgtype.Date{Status: pgtype.Null},
54 &pgtype.Date{Status: pgtype.Present, InfinityModifier: pgtype.Infinity},
55 &pgtype.Date{Status: pgtype.Present, InfinityModifier: -pgtype.Infinity},
56 }, func(a, b interface{}) bool {
57 at := a.(pgtype.Date)
58 bt := b.(pgtype.Date)
59
60 return at.Time.Equal(bt.Time) && at.Status == bt.Status && at.InfinityModifier == bt.InfinityModifier
61 })
62 }
63
64 func TestDateSet(t *testing.T) {
65 type _time time.Time
66
67 successfulTests := []struct {
68 source interface{}
69 result pgtype.Date
70 }{
71 {source: time.Date(1900, 1, 1, 0, 0, 0, 0, time.UTC), result: pgtype.Date{Time: time.Date(1900, 1, 1, 0, 0, 0, 0, time.UTC), Status: pgtype.Present}},
72 {source: time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC), result: pgtype.Date{Time: time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC), Status: pgtype.Present}},
73 {source: time.Date(1999, 12, 31, 0, 0, 0, 0, time.UTC), result: pgtype.Date{Time: time.Date(1999, 12, 31, 0, 0, 0, 0, time.UTC), Status: pgtype.Present}},
74 {source: time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), result: pgtype.Date{Time: time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), Status: pgtype.Present}},
75 {source: time.Date(2000, 1, 2, 0, 0, 0, 0, time.UTC), result: pgtype.Date{Time: time.Date(2000, 1, 2, 0, 0, 0, 0, time.UTC), Status: pgtype.Present}},
76 {source: time.Date(2200, 1, 1, 0, 0, 0, 0, time.UTC), result: pgtype.Date{Time: time.Date(2200, 1, 1, 0, 0, 0, 0, time.UTC), Status: pgtype.Present}},
77 {source: _time(time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC)), result: pgtype.Date{Time: time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC), Status: pgtype.Present}},
78 {source: "1999-12-31", result: pgtype.Date{Time: time.Date(1999, 12, 31, 0, 0, 0, 0, time.UTC), Status: pgtype.Present}},
79 {source: "0001-01-01 BC", result: pgtype.Date{Time: time.Date(0000, 01, 01, 0, 0, 0, 0, time.UTC), Status: pgtype.Present}},
80 {source: customDate{t: time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC)}, result: pgtype.Date{Time: time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC), Status: pgtype.Present}},
81 }
82
83 for i, tt := range successfulTests {
84 var d pgtype.Date
85 err := d.Set(tt.source)
86 if err != nil {
87 t.Errorf("%d: %v", i, err)
88 }
89
90 if d != tt.result {
91 t.Errorf("%d: expected %v to convert to %v, but it was %v", i, tt.source, tt.result, d)
92 }
93 }
94 }
95
96 func TestDateAssignTo(t *testing.T) {
97 var tim time.Time
98 var ptim *time.Time
99
100 simpleTests := []struct {
101 src pgtype.Date
102 dst interface{}
103 expected interface{}
104 }{
105 {src: pgtype.Date{Time: time.Date(2015, 1, 1, 0, 0, 0, 0, time.Local), Status: pgtype.Present}, dst: &tim, expected: time.Date(2015, 1, 1, 0, 0, 0, 0, time.Local)},
106 {src: pgtype.Date{Time: time.Date(2015, 1, 1, 0, 0, 0, 0, time.Local), Status: pgtype.Present}, dst: &customDate{}, expected: customDate{t: time.Date(2015, 1, 1, 0, 0, 0, 0, time.Local)}},
107 {src: pgtype.Date{Time: time.Time{}, Status: pgtype.Null}, dst: &ptim, expected: ((*time.Time)(nil))},
108 }
109
110 for i, tt := range simpleTests {
111 err := tt.src.AssignTo(tt.dst)
112 if err != nil {
113 t.Errorf("%d: %v", i, err)
114 }
115
116 if dst := reflect.ValueOf(tt.dst).Elem().Interface(); dst != tt.expected {
117 t.Errorf("%d: expected %v to assign %v, but result was %v", i, tt.src, tt.expected, dst)
118 }
119 }
120
121 pointerAllocTests := []struct {
122 src pgtype.Date
123 dst interface{}
124 expected interface{}
125 }{
126 {src: pgtype.Date{Time: time.Date(2015, 1, 1, 0, 0, 0, 0, time.Local), Status: pgtype.Present}, dst: &ptim, expected: time.Date(2015, 1, 1, 0, 0, 0, 0, time.Local)},
127 }
128
129 for i, tt := range pointerAllocTests {
130 err := tt.src.AssignTo(tt.dst)
131 if err != nil {
132 t.Errorf("%d: %v", i, err)
133 }
134
135 if dst := reflect.ValueOf(tt.dst).Elem().Elem().Interface(); dst != tt.expected {
136 t.Errorf("%d: expected %v to assign %v, but result was %v", i, tt.src, tt.expected, dst)
137 }
138 }
139
140 errorTests := []struct {
141 src pgtype.Date
142 dst interface{}
143 }{
144 {src: pgtype.Date{Time: time.Date(2015, 1, 1, 0, 0, 0, 0, time.Local), InfinityModifier: pgtype.Infinity, Status: pgtype.Present}, dst: &tim},
145 {src: pgtype.Date{Time: time.Date(2015, 1, 1, 0, 0, 0, 0, time.Local), InfinityModifier: pgtype.NegativeInfinity, Status: pgtype.Present}, dst: &tim},
146 {src: pgtype.Date{Time: time.Date(2015, 1, 1, 0, 0, 0, 0, time.Local), Status: pgtype.Null}, dst: &tim},
147 }
148
149 for i, tt := range errorTests {
150 err := tt.src.AssignTo(tt.dst)
151 if err == nil {
152 t.Errorf("%d: expected error but none was returned (%v -> %v)", i, tt.src, tt.dst)
153 }
154 }
155 }
156
157 func TestDateMarshalJSON(t *testing.T) {
158 successfulTests := []struct {
159 source pgtype.Date
160 result string
161 }{
162 {source: pgtype.Date{Status: pgtype.Null}, result: "null"},
163 {source: pgtype.Date{Time: time.Date(2012, 3, 29, 0, 0, 0, 0, time.UTC), Status: pgtype.Present}, result: "\"2012-03-29\""},
164 {source: pgtype.Date{Time: time.Date(2012, 3, 29, 10, 5, 45, 0, time.FixedZone("", -6*60*60)), Status: pgtype.Present}, result: "\"2012-03-29\""},
165 {source: pgtype.Date{Time: time.Date(2012, 3, 29, 10, 5, 45, 555*1000*1000, time.FixedZone("", -6*60*60)), Status: pgtype.Present}, result: "\"2012-03-29\""},
166 {source: pgtype.Date{InfinityModifier: pgtype.Infinity, Status: pgtype.Present}, result: "\"infinity\""},
167 {source: pgtype.Date{InfinityModifier: pgtype.NegativeInfinity, Status: pgtype.Present}, result: "\"-infinity\""},
168 }
169 for i, tt := range successfulTests {
170 r, err := tt.source.MarshalJSON()
171 if err != nil {
172 t.Errorf("%d: %v", i, err)
173 }
174
175 if string(r) != tt.result {
176 t.Errorf("%d: expected %v to convert to %v, but it was %v", i, tt.source, tt.result, string(r))
177 }
178 }
179 }
180
181 func TestDateUnmarshalJSON(t *testing.T) {
182 successfulTests := []struct {
183 source string
184 result pgtype.Date
185 }{
186 {source: "null", result: pgtype.Date{Status: pgtype.Null}},
187 {source: "\"2012-03-29\"", result: pgtype.Date{Time: time.Date(2012, 3, 29, 0, 0, 0, 0, time.UTC), Status: pgtype.Present}},
188 {source: "\"2012-03-29\"", result: pgtype.Date{Time: time.Date(2012, 3, 29, 10, 5, 45, 0, time.FixedZone("", -6*60*60)), Status: pgtype.Present}},
189 {source: "\"2012-03-29\"", result: pgtype.Date{Time: time.Date(2012, 3, 29, 10, 5, 45, 555*1000*1000, time.FixedZone("", -6*60*60)), Status: pgtype.Present}},
190 {source: "\"infinity\"", result: pgtype.Date{InfinityModifier: pgtype.Infinity, Status: pgtype.Present}},
191 {source: "\"-infinity\"", result: pgtype.Date{InfinityModifier: pgtype.NegativeInfinity, Status: pgtype.Present}},
192 }
193 for i, tt := range successfulTests {
194 var r pgtype.Date
195 err := r.UnmarshalJSON([]byte(tt.source))
196 if err != nil {
197 t.Errorf("%d: %v", i, err)
198 }
199
200 if r.Time.Year() != tt.result.Time.Year() || r.Time.Month() != tt.result.Time.Month() || r.Time.Day() != tt.result.Time.Day() || r.Status != tt.result.Status || r.InfinityModifier != tt.result.InfinityModifier {
201 t.Errorf("%d: expected %v to convert to %v, but it was %v", i, tt.source, tt.result, r)
202 }
203 }
204 }
205
View as plain text