Skip to content

Commit 36d34cf

Browse files
feat: add nullable civil types for date/time parameters
Adds NullDate, NullDateTime, and NullTime types that wrap civil.Date, civil.DateTime, and civil.Time with nullable semantics. - Implements Scanner and Valuer interfaces for database operations - Supports TVP (Table Value Parameters) with null handling - Supports OUT parameters Closes #289
1 parent 95e5e8a commit 36d34cf

File tree

5 files changed

+462
-0
lines changed

5 files changed

+462
-0
lines changed

civil_null.go

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
//go:build go1.9
2+
// +build go1.9
3+
4+
package mssql
5+
6+
import (
7+
"database/sql/driver"
8+
"fmt"
9+
"time"
10+
11+
"github.com/golang-sql/civil"
12+
)
13+
14+
// NullDate represents a civil.Date that may be null.
15+
// NullDate implements the Scanner interface so it can be used as a scan destination.
16+
type NullDate struct {
17+
Date civil.Date
18+
Valid bool
19+
}
20+
21+
// Scan implements the Scanner interface.
22+
func (n *NullDate) Scan(value interface{}) error {
23+
if value == nil {
24+
n.Date, n.Valid = civil.Date{}, false
25+
return nil
26+
}
27+
n.Valid = true
28+
switch v := value.(type) {
29+
case time.Time:
30+
n.Date = civil.DateOf(v)
31+
return nil
32+
default:
33+
n.Valid = false
34+
return fmt.Errorf("cannot scan %T into NullDate", value)
35+
}
36+
}
37+
38+
// Value implements the driver Valuer interface.
39+
func (n NullDate) Value() (driver.Value, error) {
40+
if !n.Valid {
41+
return nil, nil
42+
}
43+
return n.Date, nil
44+
}
45+
46+
// NullDateTime represents a civil.DateTime that may be null.
47+
// NullDateTime implements the Scanner interface so it can be used as a scan destination.
48+
type NullDateTime struct {
49+
DateTime civil.DateTime
50+
Valid bool
51+
}
52+
53+
// Scan implements the Scanner interface.
54+
func (n *NullDateTime) Scan(value interface{}) error {
55+
if value == nil {
56+
n.DateTime, n.Valid = civil.DateTime{}, false
57+
return nil
58+
}
59+
n.Valid = true
60+
switch v := value.(type) {
61+
case time.Time:
62+
n.DateTime = civil.DateTimeOf(v)
63+
return nil
64+
default:
65+
n.Valid = false
66+
return fmt.Errorf("cannot scan %T into NullDateTime", value)
67+
}
68+
}
69+
70+
// Value implements the driver Valuer interface.
71+
func (n NullDateTime) Value() (driver.Value, error) {
72+
if !n.Valid {
73+
return nil, nil
74+
}
75+
return n.DateTime, nil
76+
}
77+
78+
// NullTime represents a civil.Time that may be null.
79+
// NullTime implements the Scanner interface so it can be used as a scan destination.
80+
type NullTime struct {
81+
Time civil.Time
82+
Valid bool
83+
}
84+
85+
// Scan implements the Scanner interface.
86+
func (n *NullTime) Scan(value interface{}) error {
87+
if value == nil {
88+
n.Time, n.Valid = civil.Time{}, false
89+
return nil
90+
}
91+
n.Valid = true
92+
switch v := value.(type) {
93+
case time.Time:
94+
n.Time = civil.TimeOf(v)
95+
return nil
96+
default:
97+
n.Valid = false
98+
return fmt.Errorf("cannot scan %T into NullTime", value)
99+
}
100+
}
101+
102+
// Value implements the driver Valuer interface.
103+
func (n NullTime) Value() (driver.Value, error) {
104+
if !n.Valid {
105+
return nil, nil
106+
}
107+
return n.Time, nil
108+
}

0 commit comments

Comments
 (0)