Skip to content

Commit 4c3896a

Browse files
Copilotshueybubbles
andcommitted
Add nullable civil types (NullDate, NullDateTime, NullTime)
Co-authored-by: shueybubbles <[email protected]>
1 parent c59984c commit 4c3896a

File tree

4 files changed

+712
-0
lines changed

4 files changed

+712
-0
lines changed

civil_null.go

Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
package mssql
2+
3+
import (
4+
"database/sql/driver"
5+
"encoding/json"
6+
"fmt"
7+
"time"
8+
9+
"github.com/golang-sql/civil"
10+
)
11+
12+
// NullDate represents a civil.Date that may be null.
13+
// NullDate implements the Scanner interface so it can be used as a scan destination,
14+
// similar to sql.NullString.
15+
type NullDate struct {
16+
Date civil.Date
17+
Valid bool // Valid is true if Date is not NULL
18+
}
19+
20+
// Scan implements the Scanner interface.
21+
func (n *NullDate) Scan(value interface{}) error {
22+
if value == nil {
23+
n.Date, n.Valid = civil.Date{}, false
24+
return nil
25+
}
26+
n.Valid = true
27+
switch v := value.(type) {
28+
case time.Time:
29+
n.Date = civil.DateOf(v)
30+
return nil
31+
default:
32+
n.Valid = false
33+
return fmt.Errorf("cannot scan %T into NullDate", value)
34+
}
35+
}
36+
37+
// Value implements the driver Valuer interface.
38+
func (n NullDate) Value() (driver.Value, error) {
39+
if !n.Valid {
40+
return nil, nil
41+
}
42+
return n.Date, nil
43+
}
44+
45+
// String returns the string representation of the date or "NULL".
46+
func (n NullDate) String() string {
47+
if !n.Valid {
48+
return "NULL"
49+
}
50+
return n.Date.String()
51+
}
52+
53+
// MarshalText implements the encoding.TextMarshaler interface.
54+
func (n NullDate) MarshalText() ([]byte, error) {
55+
if !n.Valid {
56+
return []byte("null"), nil
57+
}
58+
return n.Date.MarshalText()
59+
}
60+
61+
// UnmarshalJSON implements the json.Unmarshaler interface.
62+
func (n *NullDate) UnmarshalJSON(b []byte) error {
63+
if string(b) == "null" {
64+
n.Date, n.Valid = civil.Date{}, false
65+
return nil
66+
}
67+
err := json.Unmarshal(b, &n.Date)
68+
n.Valid = err == nil
69+
return err
70+
}
71+
72+
// MarshalJSON implements the json.Marshaler interface.
73+
func (n NullDate) MarshalJSON() ([]byte, error) {
74+
if !n.Valid {
75+
return []byte("null"), nil
76+
}
77+
return json.Marshal(n.Date)
78+
}
79+
80+
// NullDateTime represents a civil.DateTime that may be null.
81+
// NullDateTime implements the Scanner interface so it can be used as a scan destination,
82+
// similar to sql.NullString.
83+
type NullDateTime struct {
84+
DateTime civil.DateTime
85+
Valid bool // Valid is true if DateTime is not NULL
86+
}
87+
88+
// Scan implements the Scanner interface.
89+
func (n *NullDateTime) Scan(value interface{}) error {
90+
if value == nil {
91+
n.DateTime, n.Valid = civil.DateTime{}, false
92+
return nil
93+
}
94+
n.Valid = true
95+
switch v := value.(type) {
96+
case time.Time:
97+
n.DateTime = civil.DateTimeOf(v)
98+
return nil
99+
default:
100+
n.Valid = false
101+
return fmt.Errorf("cannot scan %T into NullDateTime", value)
102+
}
103+
}
104+
105+
// Value implements the driver Valuer interface.
106+
func (n NullDateTime) Value() (driver.Value, error) {
107+
if !n.Valid {
108+
return nil, nil
109+
}
110+
return n.DateTime, nil
111+
}
112+
113+
// String returns the string representation of the datetime or "NULL".
114+
func (n NullDateTime) String() string {
115+
if !n.Valid {
116+
return "NULL"
117+
}
118+
return n.DateTime.String()
119+
}
120+
121+
// MarshalText implements the encoding.TextMarshaler interface.
122+
func (n NullDateTime) MarshalText() ([]byte, error) {
123+
if !n.Valid {
124+
return []byte("null"), nil
125+
}
126+
return n.DateTime.MarshalText()
127+
}
128+
129+
// UnmarshalJSON implements the json.Unmarshaler interface.
130+
func (n *NullDateTime) UnmarshalJSON(b []byte) error {
131+
if string(b) == "null" {
132+
n.DateTime, n.Valid = civil.DateTime{}, false
133+
return nil
134+
}
135+
err := json.Unmarshal(b, &n.DateTime)
136+
n.Valid = err == nil
137+
return err
138+
}
139+
140+
// MarshalJSON implements the json.Marshaler interface.
141+
func (n NullDateTime) MarshalJSON() ([]byte, error) {
142+
if !n.Valid {
143+
return []byte("null"), nil
144+
}
145+
return json.Marshal(n.DateTime)
146+
}
147+
148+
// NullTime represents a civil.Time that may be null.
149+
// NullTime implements the Scanner interface so it can be used as a scan destination,
150+
// similar to sql.NullString.
151+
type NullTime struct {
152+
Time civil.Time
153+
Valid bool // Valid is true if Time is not NULL
154+
}
155+
156+
// Scan implements the Scanner interface.
157+
func (n *NullTime) Scan(value interface{}) error {
158+
if value == nil {
159+
n.Time, n.Valid = civil.Time{}, false
160+
return nil
161+
}
162+
n.Valid = true
163+
switch v := value.(type) {
164+
case time.Time:
165+
n.Time = civil.TimeOf(v)
166+
return nil
167+
default:
168+
n.Valid = false
169+
return fmt.Errorf("cannot scan %T into NullTime", value)
170+
}
171+
}
172+
173+
// Value implements the driver Valuer interface.
174+
func (n NullTime) Value() (driver.Value, error) {
175+
if !n.Valid {
176+
return nil, nil
177+
}
178+
return n.Time, nil
179+
}
180+
181+
// String returns the string representation of the time or "NULL".
182+
func (n NullTime) String() string {
183+
if !n.Valid {
184+
return "NULL"
185+
}
186+
return n.Time.String()
187+
}
188+
189+
// MarshalText implements the encoding.TextMarshaler interface.
190+
func (n NullTime) MarshalText() ([]byte, error) {
191+
if !n.Valid {
192+
return []byte("null"), nil
193+
}
194+
return n.Time.MarshalText()
195+
}
196+
197+
// UnmarshalJSON implements the json.Unmarshaler interface.
198+
func (n *NullTime) UnmarshalJSON(b []byte) error {
199+
if string(b) == "null" {
200+
n.Time, n.Valid = civil.Time{}, false
201+
return nil
202+
}
203+
err := json.Unmarshal(b, &n.Time)
204+
n.Valid = err == nil
205+
return err
206+
}
207+
208+
// MarshalJSON implements the json.Marshaler interface.
209+
func (n NullTime) MarshalJSON() ([]byte, error) {
210+
if !n.Valid {
211+
return []byte("null"), nil
212+
}
213+
return json.Marshal(n.Time)
214+
}

0 commit comments

Comments
 (0)