forked from guregu/null
-
Notifications
You must be signed in to change notification settings - Fork 34
/
json.go
190 lines (163 loc) · 4.3 KB
/
json.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 null
import (
"bytes"
"database/sql/driver"
"encoding/json"
"errors"
"fmt"
"github.com/volatiletech/null/v9/convert"
)
// JSON is a nullable []byte that contains JSON.
//
// You might want to use this in the case where you have say a nullable
// JSON column in postgres for instance, where there is one layer of null for
// the postgres column, and then you also have the opportunity to have null
// as a value contained in the json. When unmarshalling json however you
// cannot set 'null' as a value.
type JSON struct {
JSON []byte
Valid bool
Set bool
}
// NewJSON creates a new JSON
func NewJSON(b []byte, valid bool) JSON {
return JSON{
JSON: b,
Valid: valid,
Set: true,
}
}
// JSONFrom creates a new JSON that will be invalid if nil.
func JSONFrom(b []byte) JSON {
return NewJSON(b, b != nil)
}
// JSONFromPtr creates a new JSON that will be invalid if nil.
func JSONFromPtr(b *[]byte) JSON {
if b == nil {
return NewJSON(nil, false)
}
n := NewJSON(*b, true)
return n
}
// IsValid returns true if this carries and explicit value and
// is not null.
func (j JSON) IsValid() bool {
return j.Set && j.Valid
}
// IsSet returns true if this carries an explicit value (null inclusive)
func (j JSON) IsSet() bool {
return j.Set
}
// Unmarshal will unmarshal your JSON stored in
// your JSON object and store the result in the
// value pointed to by dest.
func (j JSON) Unmarshal(dest interface{}) error {
if dest == nil {
return errors.New("destination is nil, not a valid pointer to an object")
}
// Call our implementation of
// JSON MarshalJSON through json.Marshal
// to get the value of the JSON object
res, err := json.Marshal(j)
if err != nil {
return err
}
return json.Unmarshal(res, dest)
}
// UnmarshalJSON implements json.Unmarshaler.
//
// Example if you have a struct with a null.JSON called v:
//
// {} -> does not call unmarshaljson: !set & !valid
// {"v": null} -> calls unmarshaljson, set & !valid
// {"v": {}} -> calls unmarshaljson, set & valid (json value is '{}')
//
// That's to say if 'null' is passed in at the json level we do not capture that
// value - instead we set the value-level null flag so that an sql value will
// turn out null.
func (j *JSON) UnmarshalJSON(data []byte) error {
if data == nil {
return fmt.Errorf("null: cannot unmarshal nil into Go value of type null.JSON")
}
j.Set = true
if bytes.Equal(data, NullBytes) {
j.JSON = nil
j.Valid = false
return nil
}
j.Valid = true
j.JSON = make([]byte, len(data))
copy(j.JSON, data)
return nil
}
// UnmarshalText implements encoding.TextUnmarshaler.
func (j *JSON) UnmarshalText(text []byte) error {
j.Set = true
if len(text) == 0 {
j.JSON = nil
j.Valid = false
} else {
j.JSON = append(j.JSON[0:0], text...)
j.Valid = true
}
return nil
}
// Marshal will marshal the passed in object,
// and store it in the JSON member on the JSON object.
func (j *JSON) Marshal(obj interface{}) error {
res, err := json.Marshal(obj)
if err != nil {
return err
}
// Call our implementation of
// JSON UnmarshalJSON through json.Unmarshal
// to Set the result to the JSON object
return json.Unmarshal(res, j)
}
// MarshalJSON implements json.Marshaler.
func (j JSON) MarshalJSON() ([]byte, error) {
if len(j.JSON) == 0 || j.JSON == nil {
return NullBytes, nil
}
return j.JSON, nil
}
// MarshalText implements encoding.TextMarshaler.
func (j JSON) MarshalText() ([]byte, error) {
if !j.Valid {
return nil, nil
}
return j.JSON, nil
}
// SetValid changes this JSON's value and also sets it to be non-null.
func (j *JSON) SetValid(n []byte) {
j.JSON = n
j.Valid = true
j.Set = true
}
// Ptr returns a pointer to this JSON's value, or a nil pointer if this JSON is null.
func (j JSON) Ptr() *[]byte {
if !j.Valid {
return nil
}
return &j.JSON
}
// IsZero returns true for null or zero JSON's, for future omitempty support (Go 1.4?)
func (j JSON) IsZero() bool {
return !j.Valid
}
// Scan implements the Scanner interface.
func (j *JSON) Scan(value interface{}) error {
if value == nil {
j.JSON, j.Valid, j.Set = nil, false, false
return nil
}
j.Valid, j.Set = true, true
return convert.ConvertAssign(&j.JSON, value)
}
// Value implements the driver Valuer interface.
func (j JSON) Value() (driver.Value, error) {
if !j.Valid {
return nil, nil
}
return j.JSON, nil
}