1
|
|
|
package postgres |
2
|
|
|
|
3
|
|
|
import ( |
4
|
|
|
"database/sql/driver" |
5
|
|
|
"encoding/binary" |
6
|
|
|
"errors" |
7
|
|
|
"fmt" |
8
|
|
|
"strconv" |
9
|
|
|
|
10
|
|
|
"github.com/jackc/pgio" |
11
|
|
|
"github.com/jackc/pgtype" |
12
|
|
|
) |
13
|
|
|
|
14
|
|
|
// pguint64 represents a PostgreSQL uint64 type |
15
|
|
|
type pguint64 struct { |
16
|
|
|
Uint uint64 |
17
|
|
|
Status pgtype.Status |
18
|
|
|
} |
19
|
|
|
|
20
|
|
|
// Set sets the pguint64 value from various input types |
21
|
|
|
func (p *pguint64) Set(src interface{}) error { |
22
|
|
|
switch value := src.(type) { |
23
|
|
|
case int64: |
24
|
|
|
if value < 0 { |
25
|
|
|
return fmt.Errorf("%d is less than minimum value for pguint64", value) |
26
|
|
|
} |
27
|
|
|
*p = pguint64{Uint: uint64(value), Status: pgtype.Present} |
28
|
|
|
case int32: |
29
|
|
|
if value < 0 { |
30
|
|
|
return fmt.Errorf("%d is less than minimum value for pguint64", value) |
31
|
|
|
} |
32
|
|
|
*p = pguint64{Uint: uint64(value), Status: pgtype.Present} |
33
|
|
|
case uint32: |
34
|
|
|
*p = pguint64{Uint: uint64(value), Status: pgtype.Present} |
35
|
|
|
case uint64: |
36
|
|
|
*p = pguint64{Uint: value, Status: pgtype.Present} |
37
|
|
|
default: |
38
|
|
|
return fmt.Errorf("cannot convert %v to pguint64", value) |
39
|
|
|
} |
40
|
|
|
|
41
|
|
|
return nil |
42
|
|
|
} |
43
|
|
|
|
44
|
|
|
// Get returns the underlying value |
45
|
|
|
func (p pguint64) Get() interface{} { |
46
|
|
|
switch p.Status { |
47
|
|
|
case pgtype.Present: |
48
|
|
|
return p.Uint |
49
|
|
|
case pgtype.Null: |
50
|
|
|
return nil |
51
|
|
|
default: |
52
|
|
|
return p.Status |
53
|
|
|
} |
54
|
|
|
} |
55
|
|
|
|
56
|
|
|
// AssignTo assigns the value to the destination |
57
|
|
|
func (p *pguint64) AssignTo(dst interface{}) error { |
58
|
|
|
switch v := dst.(type) { |
59
|
|
|
case *uint64: |
60
|
|
|
if p.Status == pgtype.Present { |
61
|
|
|
*v = p.Uint |
62
|
|
|
} else { |
63
|
|
|
return fmt.Errorf("cannot assign %v into %T", p, dst) |
64
|
|
|
} |
65
|
|
|
case **uint64: |
66
|
|
|
if p.Status == pgtype.Present { |
67
|
|
|
n := p.Uint |
68
|
|
|
*v = &n |
69
|
|
|
} else { |
70
|
|
|
*v = nil |
71
|
|
|
} |
72
|
|
|
} |
73
|
|
|
|
74
|
|
|
return nil |
75
|
|
|
} |
76
|
|
|
|
77
|
|
|
// DecodeText decodes text format |
78
|
|
|
func (p *pguint64) DecodeText(ci *pgtype.ConnInfo, src []byte) error { |
79
|
|
|
if src == nil { |
80
|
|
|
*p = pguint64{Status: pgtype.Null} |
81
|
|
|
return nil |
82
|
|
|
} |
83
|
|
|
|
84
|
|
|
n, err := strconv.ParseUint(string(src), 10, 64) |
85
|
|
|
if err != nil { |
86
|
|
|
return err |
87
|
|
|
} |
88
|
|
|
|
89
|
|
|
*p = pguint64{Uint: n, Status: pgtype.Present} |
90
|
|
|
return nil |
91
|
|
|
} |
92
|
|
|
|
93
|
|
|
// DecodeBinary decodes binary format |
94
|
|
|
func (p *pguint64) DecodeBinary(ci *pgtype.ConnInfo, src []byte) error { |
95
|
|
|
if src == nil { |
96
|
|
|
*p = pguint64{Status: pgtype.Null} |
97
|
|
|
return nil |
98
|
|
|
} |
99
|
|
|
|
100
|
|
|
if len(src) != 4 { |
101
|
|
|
return fmt.Errorf("invalid length: %v", len(src)) |
102
|
|
|
} |
103
|
|
|
|
104
|
|
|
n := binary.BigEndian.Uint64(src) |
105
|
|
|
*p = pguint64{Uint: n, Status: pgtype.Present} |
106
|
|
|
return nil |
107
|
|
|
} |
108
|
|
|
|
109
|
|
|
// EncodeText encodes to text format |
110
|
|
|
func (p pguint64) EncodeText(ci *pgtype.ConnInfo, buf []byte) ([]byte, error) { |
111
|
|
|
switch p.Status { |
112
|
|
|
case pgtype.Null: |
113
|
|
|
return nil, nil |
114
|
|
|
case pgtype.Undefined: |
115
|
|
|
return nil, errors.New("encode text status undefined status") |
116
|
|
|
} |
117
|
|
|
|
118
|
|
|
return append(buf, strconv.FormatUint(p.Uint, 10)...), nil |
119
|
|
|
} |
120
|
|
|
|
121
|
|
|
// EncodeBinary encodes to binary format |
122
|
|
|
func (p pguint64) EncodeBinary(ci *pgtype.ConnInfo, buf []byte) ([]byte, error) { |
123
|
|
|
switch p.Status { |
124
|
|
|
case pgtype.Null: |
125
|
|
|
return nil, nil |
126
|
|
|
case pgtype.Undefined: |
127
|
|
|
return nil, errors.New("encode text status undefined status") |
128
|
|
|
} |
129
|
|
|
|
130
|
|
|
return pgio.AppendUint64(buf, p.Uint), nil |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
// Scan implements the database/sql Scanner interface |
134
|
|
|
func (p *pguint64) Scan(src interface{}) error { |
135
|
|
|
if src == nil { |
136
|
|
|
*p = pguint64{Status: pgtype.Null} |
137
|
|
|
return nil |
138
|
|
|
} |
139
|
|
|
|
140
|
|
|
switch src := src.(type) { |
141
|
|
|
case uint32: |
142
|
|
|
*p = pguint64{Uint: uint64(src), Status: pgtype.Present} |
143
|
|
|
return nil |
144
|
|
|
case int64: |
145
|
|
|
*p = pguint64{Uint: uint64(src), Status: pgtype.Present} |
146
|
|
|
return nil |
147
|
|
|
case uint64: |
148
|
|
|
*p = pguint64{Uint: src, Status: pgtype.Present} |
149
|
|
|
return nil |
150
|
|
|
case string: |
151
|
|
|
return p.DecodeText(nil, []byte(src)) |
152
|
|
|
case []byte: |
153
|
|
|
srcCopy := make([]byte, len(src)) |
154
|
|
|
copy(srcCopy, src) |
155
|
|
|
return p.DecodeText(nil, srcCopy) |
156
|
|
|
} |
157
|
|
|
|
158
|
|
|
return fmt.Errorf("cannot scan %T", src) |
159
|
|
|
} |
160
|
|
|
|
161
|
|
|
// Value implements the database/sql/driver Valuer interface |
162
|
|
|
func (p pguint64) Value() (driver.Value, error) { |
163
|
|
|
switch p.Status { |
164
|
|
|
case pgtype.Present: |
165
|
|
|
return int64(p.Uint), nil |
166
|
|
|
case pgtype.Null: |
167
|
|
|
return nil, nil |
168
|
|
|
default: |
169
|
|
|
return nil, errors.New("encode text status undefined status") |
170
|
|
|
} |
171
|
|
|
} |
172
|
|
|
|