...

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

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

     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