github.com/jackc/pgx/v5@v5.5.5/pgtype/json.go (about) 1 package pgtype 2 3 import ( 4 "database/sql" 5 "database/sql/driver" 6 "encoding/json" 7 "fmt" 8 "reflect" 9 ) 10 11 type JSONCodec struct{} 12 13 func (JSONCodec) FormatSupported(format int16) bool { 14 return format == TextFormatCode || format == BinaryFormatCode 15 } 16 17 func (JSONCodec) PreferredFormat() int16 { 18 return TextFormatCode 19 } 20 21 func (c JSONCodec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan { 22 switch value.(type) { 23 case string: 24 return encodePlanJSONCodecEitherFormatString{} 25 case []byte: 26 return encodePlanJSONCodecEitherFormatByteSlice{} 27 28 // Handle json.RawMessage specifically because if it is run through json.Marshal it may be mutated. 29 // e.g. `{"foo": "bar"}` -> `{"foo":"bar"}`. 30 case json.RawMessage: 31 return encodePlanJSONCodecEitherFormatJSONRawMessage{} 32 33 // Cannot rely on driver.Valuer being handled later because anything can be marshalled. 34 // 35 // https://github.com/jackc/pgx/issues/1430 36 // 37 // Check for driver.Valuer must come before json.Marshaler so that it is guaranteed to beused 38 // when both are implemented https://github.com/jackc/pgx/issues/1805 39 case driver.Valuer: 40 return &encodePlanDriverValuer{m: m, oid: oid, formatCode: format} 41 42 // Must come before trying wrap encode plans because a pointer to a struct may be unwrapped to a struct that can be 43 // marshalled. 44 // 45 // https://github.com/jackc/pgx/issues/1681 46 case json.Marshaler: 47 return encodePlanJSONCodecEitherFormatMarshal{} 48 } 49 50 // Because anything can be marshalled the normal wrapping in Map.PlanScan doesn't get a chance to run. So try the 51 // appropriate wrappers here. 52 for _, f := range []TryWrapEncodePlanFunc{ 53 TryWrapDerefPointerEncodePlan, 54 TryWrapFindUnderlyingTypeEncodePlan, 55 } { 56 if wrapperPlan, nextValue, ok := f(value); ok { 57 if nextPlan := c.PlanEncode(m, oid, format, nextValue); nextPlan != nil { 58 wrapperPlan.SetNext(nextPlan) 59 return wrapperPlan 60 } 61 } 62 } 63 64 return encodePlanJSONCodecEitherFormatMarshal{} 65 } 66 67 type encodePlanJSONCodecEitherFormatString struct{} 68 69 func (encodePlanJSONCodecEitherFormatString) Encode(value any, buf []byte) (newBuf []byte, err error) { 70 jsonString := value.(string) 71 buf = append(buf, jsonString...) 72 return buf, nil 73 } 74 75 type encodePlanJSONCodecEitherFormatByteSlice struct{} 76 77 func (encodePlanJSONCodecEitherFormatByteSlice) Encode(value any, buf []byte) (newBuf []byte, err error) { 78 jsonBytes := value.([]byte) 79 if jsonBytes == nil { 80 return nil, nil 81 } 82 83 buf = append(buf, jsonBytes...) 84 return buf, nil 85 } 86 87 type encodePlanJSONCodecEitherFormatJSONRawMessage struct{} 88 89 func (encodePlanJSONCodecEitherFormatJSONRawMessage) Encode(value any, buf []byte) (newBuf []byte, err error) { 90 jsonBytes := value.(json.RawMessage) 91 if jsonBytes == nil { 92 return nil, nil 93 } 94 95 buf = append(buf, jsonBytes...) 96 return buf, nil 97 } 98 99 type encodePlanJSONCodecEitherFormatMarshal struct{} 100 101 func (encodePlanJSONCodecEitherFormatMarshal) Encode(value any, buf []byte) (newBuf []byte, err error) { 102 jsonBytes, err := json.Marshal(value) 103 if err != nil { 104 return nil, err 105 } 106 107 buf = append(buf, jsonBytes...) 108 return buf, nil 109 } 110 111 func (JSONCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan { 112 switch target.(type) { 113 case *string: 114 return scanPlanAnyToString{} 115 116 case **string: 117 // This is to fix **string scanning. It seems wrong to special case **string, but it's not clear what a better 118 // solution would be. 119 // 120 // https://github.com/jackc/pgx/issues/1470 -- **string 121 // https://github.com/jackc/pgx/issues/1691 -- ** anything else 122 123 if wrapperPlan, nextDst, ok := TryPointerPointerScanPlan(target); ok { 124 if nextPlan := m.planScan(oid, format, nextDst); nextPlan != nil { 125 if _, failed := nextPlan.(*scanPlanFail); !failed { 126 wrapperPlan.SetNext(nextPlan) 127 return wrapperPlan 128 } 129 } 130 } 131 132 case *[]byte: 133 return scanPlanJSONToByteSlice{} 134 case BytesScanner: 135 return scanPlanBinaryBytesToBytesScanner{} 136 137 // Cannot rely on sql.Scanner being handled later because scanPlanJSONToJSONUnmarshal will take precedence. 138 // 139 // https://github.com/jackc/pgx/issues/1418 140 case sql.Scanner: 141 return &scanPlanSQLScanner{formatCode: format} 142 } 143 144 return scanPlanJSONToJSONUnmarshal{} 145 } 146 147 type scanPlanAnyToString struct{} 148 149 func (scanPlanAnyToString) Scan(src []byte, dst any) error { 150 p := dst.(*string) 151 *p = string(src) 152 return nil 153 } 154 155 type scanPlanJSONToByteSlice struct{} 156 157 func (scanPlanJSONToByteSlice) Scan(src []byte, dst any) error { 158 dstBuf := dst.(*[]byte) 159 if src == nil { 160 *dstBuf = nil 161 return nil 162 } 163 164 *dstBuf = make([]byte, len(src)) 165 copy(*dstBuf, src) 166 return nil 167 } 168 169 type scanPlanJSONToBytesScanner struct{} 170 171 func (scanPlanJSONToBytesScanner) Scan(src []byte, dst any) error { 172 scanner := (dst).(BytesScanner) 173 return scanner.ScanBytes(src) 174 } 175 176 type scanPlanJSONToJSONUnmarshal struct{} 177 178 func (scanPlanJSONToJSONUnmarshal) Scan(src []byte, dst any) error { 179 if src == nil { 180 dstValue := reflect.ValueOf(dst) 181 if dstValue.Kind() == reflect.Ptr { 182 el := dstValue.Elem() 183 switch el.Kind() { 184 case reflect.Ptr, reflect.Slice, reflect.Map, reflect.Interface: 185 el.Set(reflect.Zero(el.Type())) 186 return nil 187 } 188 } 189 190 return fmt.Errorf("cannot scan NULL into %T", dst) 191 } 192 193 elem := reflect.ValueOf(dst).Elem() 194 elem.Set(reflect.Zero(elem.Type())) 195 196 return json.Unmarshal(src, dst) 197 } 198 199 func (c JSONCodec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) { 200 if src == nil { 201 return nil, nil 202 } 203 204 dstBuf := make([]byte, len(src)) 205 copy(dstBuf, src) 206 return dstBuf, nil 207 } 208 209 func (c JSONCodec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) { 210 if src == nil { 211 return nil, nil 212 } 213 214 var dst any 215 err := json.Unmarshal(src, &dst) 216 return dst, err 217 }