-
Notifications
You must be signed in to change notification settings - Fork 1
/
nullablecurrency.go
190 lines (168 loc) · 5.13 KB
/
nullablecurrency.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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
package money
import (
"database/sql/driver"
"encoding/json"
"fmt"
)
// NullableCurrency holds a 3 character ISO 4217 alphabetic code,
// or an empty string as valid value representing NULL in SQL databases.
// NullableCurrency implements the database/sql.Scanner and database/sql/driver.Valuer interfaces,
// and will treat an empty NullableCurrency string as SQL NULL value.
// The main difference between Currency and NullableCurrency is:
// Currency("").Valid() == false
// NullableCurrency("").Valid() == true
type NullableCurrency string
// IsNull returns true if the NullableCurrency is null.
// IsNull implements the nullable.Nullable interface.
func (n NullableCurrency) IsNull() bool {
return n == CurrencyNull
}
// IsNotNull returns true if the NullableCurrency is not null.
func (n NullableCurrency) IsNotNull() bool {
return n != CurrencyNull
}
// Set sets an ID for this NullableCurrency
func (n *NullableCurrency) Set(currency Currency) {
*n = NullableCurrency(currency)
}
// SetNull sets the NullableCurrency to null
func (n *NullableCurrency) SetNull() {
*n = CurrencyNull
}
// Get returns the non nullable Currency value
// or panics if the NullableCurrency is null.
// Note: check with IsNull before using Get!
func (n NullableCurrency) Get() Currency {
if n.IsNull() {
panic("NULL money.Currency")
}
return Currency(n)
}
// GetOr returns the Currency if n valid and not null,
// or else the passed defaultVal is returned.
func (n NullableCurrency) GetOr(defaultVal Currency) Currency {
if !n.ValidAndNotNull() {
return defaultVal
}
return Currency(n)
}
// StringOr returns the NullableCurrency as string
// or the passed defaultString if the NullableCurrency is null.
func (n NullableCurrency) StringOr(defaultString string) string {
if n.IsNull() {
return defaultString
}
return string(n)
}
// Valid returns true if c is an empty string, or a valid 3 character ISO 4217 alphabetic code.
func (n NullableCurrency) Valid() bool {
return n == CurrencyNull || Currency(n).Valid()
}
// ValidAndNotNull returns if the currency is valid and not Null.
func (n NullableCurrency) ValidAndNotNull() bool {
return Currency(n).Valid()
}
// Valid returns true if c is nil, an empty string, or a valid 3 character ISO 4217 alphabetic code.
// Safe to call on a nil pointer.
func (n *NullableCurrency) ValidPtr() bool {
if n == nil || *n == CurrencyNull {
return true
}
return Currency(*n).Valid()
}
// Normalized normalizes a currency string
func (n NullableCurrency) Normalized() (NullableCurrency, error) {
if n == CurrencyNull {
return n, nil
}
norm, err := Currency(n).Normalized()
return NullableCurrency(norm), err
}
// NormalizedOrNull returns a normalized currency or CurrencyNull
// if there was an error while normalizing.
func (n NullableCurrency) NormalizedOrNull() NullableCurrency {
normalized, err := n.Normalized()
if err != nil {
return CurrencyNull
}
return normalized
}
// ScanString tries to parse and assign the passed
// source string as value of the implementing type.
//
// If validate is true, the source string is checked
// for validity before it is assigned to the type.
//
// If validate is false and the source string
// can still be assigned in some non-normalized way
// it will be assigned without returning an error.
func (n *NullableCurrency) ScanString(source string, validate bool) error {
switch source {
case "", "NULL", "null", "nil":
n.SetNull()
return nil
}
newCurrency, err := NullableCurrency(source).Normalized()
if err != nil {
if validate {
return err
}
newCurrency = NullableCurrency(source)
}
*n = newCurrency
return nil
}
// Scan implements the database/sql.Scanner interface.
func (n *NullableCurrency) Scan(value any) error {
switch x := value.(type) {
case string:
*n = NullableCurrency(x)
case []byte:
*n = NullableCurrency(x)
case nil:
*n = CurrencyNull
default:
return fmt.Errorf("can't scan SQL value of type %T as NullableCurrency", value)
}
return nil
}
// Value implements the driver database/sql/driver.Valuer interface.
func (n NullableCurrency) Value() (driver.Value, error) {
if n == CurrencyNull {
return nil, nil
}
return string(n), nil
}
// Symbol returns the currency symbol like € for EUR if available,
// or currency code if no widely recognized symbol is available.
func (n NullableCurrency) Symbol() string {
if s, ok := currencyCodeToSymbol[Currency(n)]; ok {
return s
}
return string(n)
}
// EnglishName returns the english name of the currency
func (n NullableCurrency) EnglishName() string {
return currencyCodeToName[Currency(n)]
}
func (n NullableCurrency) Currency() Currency {
return Currency(n)
}
// String returns the normalized currency as string if possible,
// else it will be returned unchanged as string.
// String implements the fmt.Stringer interface.
func (n NullableCurrency) String() string {
norm, err := n.Normalized()
if err != nil {
return string(n)
}
return string(norm)
}
// MarshalJSON implements encoding/json.Marshaler
// by returning the JSON null value for an empty (null) string.
func (n NullableCurrency) MarshalJSON() ([]byte, error) {
if n.IsNull() {
return []byte(`null`), nil
}
return json.Marshal(string(n))
}