-
Notifications
You must be signed in to change notification settings - Fork 7
/
uint64.go
151 lines (132 loc) · 2.94 KB
/
uint64.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
package nullable
import (
"context"
"database/sql/driver"
"encoding/json"
"strconv"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"gorm.io/gorm/schema"
)
// Uint64 SQL type that can retrieve NULL value
type Uint64 struct {
realValue uint64
isValid bool
}
// NewUint64 creates a new nullable 64-bit integer
func NewUint64(value *uint64) Uint64 {
if value == nil {
return Uint64{
realValue: 0,
isValid: false,
}
}
return Uint64{
realValue: *value,
isValid: true,
}
}
// Get either nil or 64-bit integer
func (n Uint64) Get() *uint64 {
if !n.isValid {
return nil
}
return &n.realValue
}
// Set either nil or 64-bit integer
func (n *Uint64) Set(value *uint64) {
n.isValid = (value != nil)
if n.isValid {
n.realValue = *value
} else {
n.realValue = 0
}
}
// MarshalJSON converts current value to JSON
func (n Uint64) MarshalJSON() ([]byte, error) {
return json.Marshal(n.Get())
}
// UnmarshalJSON writes JSON to this type
func (n *Uint64) UnmarshalJSON(data []byte) error {
dataString := string(data)
if len(dataString) == 0 || dataString == "null" {
n.isValid = false
n.realValue = 0
return nil
}
var parsed uint64
if err := json.Unmarshal(data, &parsed); err != nil {
return err
}
n.isValid = true
n.realValue = parsed
return nil
}
// Scan implements scanner interface
func (n *Uint64) Scan(value interface{}) error {
if value == nil {
n.realValue, n.isValid = 0, false
return nil
}
var scanned string
if err := convertAssign(&scanned, value); err != nil {
return err
}
radix := 10
if len(scanned) == 64 {
radix = 2
}
parsed, err := strconv.ParseUint(scanned, radix, 64)
if err != nil {
return err
}
n.realValue = parsed
n.isValid = true
return nil
}
// Value implements the driver Valuer interface.
func (n Uint64) Value() (driver.Value, error) {
if !n.isValid {
return nil, nil
}
return strconv.FormatUint(n.realValue, 10), nil
}
// GormValue implements the driver Valuer interface via GORM.
func (n Uint64) GormValue(ctx context.Context, db *gorm.DB) clause.Expr {
switch db.Dialector.Name() {
case "sqlite", "mysql":
// MySQL and SQLite are using Value() instead of GormValue()
value, err := n.Value()
if err != nil {
db.AddError(err)
return clause.Expr{}
}
return clause.Expr{SQL: "?", Vars: []interface{}{value}}
case "postgres":
if !n.isValid {
return clause.Expr{SQL: "?", Vars: []interface{}{nil}}
}
value := strconv.FormatUint(n.realValue, 2)
leadingZero := 64 - len(value)
for leadingZero > 0 {
value = "0" + value
leadingZero--
}
return clause.Expr{SQL: "?", Vars: []interface{}{value}}
}
return clause.Expr{}
}
// GormDataType gorm common data type
func (Uint64) GormDataType() string {
return "uint64_null"
}
// GormDBDataType gorm db data type
func (Uint64) GormDBDataType(db *gorm.DB, field *schema.Field) string {
switch db.Dialector.Name() {
case "sqlite", "mysql":
return "BIGINT UNSIGNED"
case "postgres":
return "bytea"
}
return ""
}