-
Notifications
You must be signed in to change notification settings - Fork 3
/
json.go
83 lines (66 loc) · 1.88 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
package null
import (
"bytes"
"database/sql/driver"
"encoding/json"
"fmt"
)
// JSON is a json.RawMessage that will marshall as null when empty or nil.
type JSON json.RawMessage
var NullJSON = JSON(`null`)
// IsNull returns whether this JSON value is empty or contains null.
func (j JSON) IsNull() bool {
return len(j) == 0 || bytes.Equal(j, NullJSON)
}
// Scan implements the Scanner interface
func (j *JSON) Scan(value any) error { return ScanJSON(value, j) }
// Value implements the Valuer interface
func (j JSON) Value() (driver.Value, error) { return JSONValue(j) }
// UnmarshalJSON implements the Unmarshaller interface
func (j *JSON) UnmarshalJSON(data []byte) error { return UnmarshalJSON(data, j) }
// MarshalJSON implements the Marshaller interface
func (j JSON) MarshalJSON() ([]byte, error) { return MarshalJSON(j) }
func ScanJSON(value any, j *JSON) error {
if value == nil {
*j = NullJSON
return nil
}
var raw []byte
switch typed := value.(type) {
case string:
raw = []byte(typed)
case []byte:
raw = typed
default:
return fmt.Errorf("unable to scan %T as JSON", value)
}
// empty bytes is same as nil
if len(raw) == 0 {
*j = NullJSON
return nil
}
if !json.Valid(raw) {
return fmt.Errorf("scanned JSON isn't valid")
}
// we need to make our own copy of this data as the driver is allowed to reuse it for subsequent scans - usually
// database/sql takes care of this but we're implementing our own Scanner https://github.com/golang/go/issues/24492
cloned := make([]byte, len(raw))
copy(cloned, raw)
*j = cloned
return nil
}
func JSONValue(j JSON) (driver.Value, error) {
if j.IsNull() {
return nil, nil
}
return []byte(j), nil
}
func UnmarshalJSON(data []byte, j *JSON) error {
return json.Unmarshal(data, (*json.RawMessage)(j))
}
func MarshalJSON(j JSON) ([]byte, error) {
if len(j) == 0 {
return json.Marshal(nil)
}
return []byte(j), nil
}