1 package pgtype
2
3 import (
4 "database/sql/driver"
5 "encoding/json"
6 "fmt"
7 )
8
9 type JSONBCodec struct{}
10
11 func (JSONBCodec) FormatSupported(format int16) bool {
12 return format == TextFormatCode || format == BinaryFormatCode
13 }
14
15 func (JSONBCodec) PreferredFormat() int16 {
16 return TextFormatCode
17 }
18
19 func (JSONBCodec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
20 switch format {
21 case BinaryFormatCode:
22 plan := JSONCodec{}.PlanEncode(m, oid, TextFormatCode, value)
23 if plan != nil {
24 return &encodePlanJSONBCodecBinaryWrapper{textPlan: plan}
25 }
26 case TextFormatCode:
27 return JSONCodec{}.PlanEncode(m, oid, format, value)
28 }
29
30 return nil
31 }
32
33 type encodePlanJSONBCodecBinaryWrapper struct {
34 textPlan EncodePlan
35 }
36
37 func (plan *encodePlanJSONBCodecBinaryWrapper) Encode(value any, buf []byte) (newBuf []byte, err error) {
38 buf = append(buf, 1)
39 return plan.textPlan.Encode(value, buf)
40 }
41
42 func (JSONBCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
43 switch format {
44 case BinaryFormatCode:
45 plan := JSONCodec{}.PlanScan(m, oid, TextFormatCode, target)
46 if plan != nil {
47 return &scanPlanJSONBCodecBinaryUnwrapper{textPlan: plan}
48 }
49 case TextFormatCode:
50 return JSONCodec{}.PlanScan(m, oid, format, target)
51 }
52
53 return nil
54 }
55
56 type scanPlanJSONBCodecBinaryUnwrapper struct {
57 textPlan ScanPlan
58 }
59
60 func (plan *scanPlanJSONBCodecBinaryUnwrapper) Scan(src []byte, dst any) error {
61 if src == nil {
62 return plan.textPlan.Scan(src, dst)
63 }
64
65 if len(src) == 0 {
66 return fmt.Errorf("jsonb too short")
67 }
68
69 if src[0] != 1 {
70 return fmt.Errorf("unknown jsonb version number %d", src[0])
71 }
72
73 return plan.textPlan.Scan(src[1:], dst)
74 }
75
76 func (c JSONBCodec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
77 if src == nil {
78 return nil, nil
79 }
80
81 switch format {
82 case BinaryFormatCode:
83 if len(src) == 0 {
84 return nil, fmt.Errorf("jsonb too short")
85 }
86
87 if src[0] != 1 {
88 return nil, fmt.Errorf("unknown jsonb version number %d", src[0])
89 }
90
91 dstBuf := make([]byte, len(src)-1)
92 copy(dstBuf, src[1:])
93 return dstBuf, nil
94 case TextFormatCode:
95 dstBuf := make([]byte, len(src))
96 copy(dstBuf, src)
97 return dstBuf, nil
98 default:
99 return nil, fmt.Errorf("unknown format code: %v", format)
100 }
101 }
102
103 func (c JSONBCodec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
104 if src == nil {
105 return nil, nil
106 }
107
108 switch format {
109 case BinaryFormatCode:
110 if len(src) == 0 {
111 return nil, fmt.Errorf("jsonb too short")
112 }
113
114 if src[0] != 1 {
115 return nil, fmt.Errorf("unknown jsonb version number %d", src[0])
116 }
117
118 src = src[1:]
119 case TextFormatCode:
120 default:
121 return nil, fmt.Errorf("unknown format code: %v", format)
122 }
123
124 var dst any
125 err := json.Unmarshal(src, &dst)
126 return dst, err
127 }
128
View as plain text