github.com/jackc/pgx/v5@v5.5.5/pgtype/jsonb.go (about) 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 }