/
jsonb.go
127 lines (103 loc) · 2.74 KB
/
jsonb.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
package pgtype
import (
"database/sql/driver"
"encoding/json"
"fmt"
)
type JSONBCodec struct{}
func (JSONBCodec) FormatSupported(format int16) bool {
return format == TextFormatCode || format == BinaryFormatCode
}
func (JSONBCodec) PreferredFormat() int16 {
return TextFormatCode
}
func (JSONBCodec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
switch format {
case BinaryFormatCode:
plan := JSONCodec{}.PlanEncode(m, oid, TextFormatCode, value)
if plan != nil {
return &encodePlanJSONBCodecBinaryWrapper{textPlan: plan}
}
case TextFormatCode:
return JSONCodec{}.PlanEncode(m, oid, format, value)
}
return nil
}
type encodePlanJSONBCodecBinaryWrapper struct {
textPlan EncodePlan
}
func (plan *encodePlanJSONBCodecBinaryWrapper) Encode(value any, buf []byte) (newBuf []byte, err error) {
buf = append(buf, 1)
return plan.textPlan.Encode(value, buf)
}
func (JSONBCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
switch format {
case BinaryFormatCode:
plan := JSONCodec{}.PlanScan(m, oid, TextFormatCode, target)
if plan != nil {
return &scanPlanJSONBCodecBinaryUnwrapper{textPlan: plan}
}
case TextFormatCode:
return JSONCodec{}.PlanScan(m, oid, format, target)
}
return nil
}
type scanPlanJSONBCodecBinaryUnwrapper struct {
textPlan ScanPlan
}
func (plan *scanPlanJSONBCodecBinaryUnwrapper) Scan(src []byte, dst any) error {
if src == nil {
return plan.textPlan.Scan(src, dst)
}
if len(src) == 0 {
return fmt.Errorf("jsonb too short")
}
if src[0] != 1 {
return fmt.Errorf("unknown jsonb version number %d", src[0])
}
return plan.textPlan.Scan(src[1:], dst)
}
func (c JSONBCodec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
if src == nil {
return nil, nil
}
switch format {
case BinaryFormatCode:
if len(src) == 0 {
return nil, fmt.Errorf("jsonb too short")
}
if src[0] != 1 {
return nil, fmt.Errorf("unknown jsonb version number %d", src[0])
}
dstBuf := make([]byte, len(src)-1)
copy(dstBuf, src[1:])
return dstBuf, nil
case TextFormatCode:
dstBuf := make([]byte, len(src))
copy(dstBuf, src)
return dstBuf, nil
default:
return nil, fmt.Errorf("unknown format code: %v", format)
}
}
func (c JSONBCodec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
if src == nil {
return nil, nil
}
switch format {
case BinaryFormatCode:
if len(src) == 0 {
return nil, fmt.Errorf("jsonb too short")
}
if src[0] != 1 {
return nil, fmt.Errorf("unknown jsonb version number %d", src[0])
}
src = src[1:]
case TextFormatCode:
default:
return nil, fmt.Errorf("unknown format code: %v", format)
}
var dst any
err := json.Unmarshal(src, &dst)
return dst, err
}