...

Source file src/github.com/jackc/pgx/v5/pgtype/json.go

Documentation: github.com/jackc/pgx/v5/pgtype

     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  }
   218  

View as plain text