...

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

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

     1  package pgtype
     2  
     3  import (
     4  	"database/sql/driver"
     5  	"fmt"
     6  )
     7  
     8  // EnumCodec is a codec that caches the strings it decodes. If the same string is read multiple times only one copy is
     9  // allocated. These strings are only garbage collected when the EnumCodec is garbage collected. EnumCodec can be used
    10  // for any text type not only enums, but it should only be used when there are a small number of possible values.
    11  type EnumCodec struct {
    12  	membersMap map[string]string // map to quickly lookup member and reuse string instead of allocating
    13  }
    14  
    15  func (EnumCodec) FormatSupported(format int16) bool {
    16  	return format == TextFormatCode || format == BinaryFormatCode
    17  }
    18  
    19  func (EnumCodec) PreferredFormat() int16 {
    20  	return TextFormatCode
    21  }
    22  
    23  func (EnumCodec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
    24  	switch format {
    25  	case TextFormatCode, BinaryFormatCode:
    26  		switch value.(type) {
    27  		case string:
    28  			return encodePlanTextCodecString{}
    29  		case []byte:
    30  			return encodePlanTextCodecByteSlice{}
    31  		case TextValuer:
    32  			return encodePlanTextCodecTextValuer{}
    33  		}
    34  	}
    35  
    36  	return nil
    37  }
    38  
    39  func (c *EnumCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
    40  	switch format {
    41  	case TextFormatCode, BinaryFormatCode:
    42  		switch target.(type) {
    43  		case *string:
    44  			return &scanPlanTextAnyToEnumString{codec: c}
    45  		case *[]byte:
    46  			return scanPlanAnyToNewByteSlice{}
    47  		case TextScanner:
    48  			return &scanPlanTextAnyToEnumTextScanner{codec: c}
    49  		}
    50  	}
    51  
    52  	return nil
    53  }
    54  
    55  func (c *EnumCodec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
    56  	return c.DecodeValue(m, oid, format, src)
    57  }
    58  
    59  func (c *EnumCodec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
    60  	if src == nil {
    61  		return nil, nil
    62  	}
    63  
    64  	return c.lookupAndCacheString(src), nil
    65  }
    66  
    67  // lookupAndCacheString looks for src in the members map. If it is not found it is added to the map.
    68  func (c *EnumCodec) lookupAndCacheString(src []byte) string {
    69  	if c.membersMap == nil {
    70  		c.membersMap = make(map[string]string)
    71  	}
    72  
    73  	if s, found := c.membersMap[string(src)]; found {
    74  		return s
    75  	}
    76  
    77  	s := string(src)
    78  	c.membersMap[s] = s
    79  	return s
    80  }
    81  
    82  type scanPlanTextAnyToEnumString struct {
    83  	codec *EnumCodec
    84  }
    85  
    86  func (plan *scanPlanTextAnyToEnumString) Scan(src []byte, dst any) error {
    87  	if src == nil {
    88  		return fmt.Errorf("cannot scan NULL into %T", dst)
    89  	}
    90  
    91  	p := (dst).(*string)
    92  	*p = plan.codec.lookupAndCacheString(src)
    93  
    94  	return nil
    95  }
    96  
    97  type scanPlanTextAnyToEnumTextScanner struct {
    98  	codec *EnumCodec
    99  }
   100  
   101  func (plan *scanPlanTextAnyToEnumTextScanner) Scan(src []byte, dst any) error {
   102  	scanner := (dst).(TextScanner)
   103  
   104  	if src == nil {
   105  		return scanner.ScanText(Text{})
   106  	}
   107  
   108  	return scanner.ScanText(Text{String: plan.codec.lookupAndCacheString(src), Valid: true})
   109  }
   110  

View as plain text