gotosocial/vendor/github.com/jackc/pgx/v5/pgtype/enum_codec.go
tobi ec325fee14
[chore] Update a bunch of database dependencies (#1772)
* [chore] Update a bunch of database dependencies

* fix lil thing
2023-05-12 14:33:40 +02:00

109 lines
2.7 KiB
Go

package pgtype
import (
"database/sql/driver"
"fmt"
)
// EnumCodec is a codec that caches the strings it decodes. If the same string is read multiple times only one copy is
// allocated. These strings are only garbage collected when the EnumCodec is garbage collected. EnumCodec can be used
// for any text type not only enums, but it should only be used when there are a small number of possible values.
type EnumCodec struct {
membersMap map[string]string // map to quickly lookup member and reuse string instead of allocating
}
func (EnumCodec) FormatSupported(format int16) bool {
return format == TextFormatCode || format == BinaryFormatCode
}
func (EnumCodec) PreferredFormat() int16 {
return TextFormatCode
}
func (EnumCodec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
switch format {
case TextFormatCode, BinaryFormatCode:
switch value.(type) {
case string:
return encodePlanTextCodecString{}
case []byte:
return encodePlanTextCodecByteSlice{}
case TextValuer:
return encodePlanTextCodecTextValuer{}
}
}
return nil
}
func (c *EnumCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
switch format {
case TextFormatCode, BinaryFormatCode:
switch target.(type) {
case *string:
return &scanPlanTextAnyToEnumString{codec: c}
case *[]byte:
return scanPlanAnyToNewByteSlice{}
case TextScanner:
return &scanPlanTextAnyToEnumTextScanner{codec: c}
}
}
return nil
}
func (c *EnumCodec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
return c.DecodeValue(m, oid, format, src)
}
func (c *EnumCodec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
if src == nil {
return nil, nil
}
return c.lookupAndCacheString(src), nil
}
// lookupAndCacheString looks for src in the members map. If it is not found it is added to the map.
func (c *EnumCodec) lookupAndCacheString(src []byte) string {
if c.membersMap == nil {
c.membersMap = make(map[string]string)
}
if s, found := c.membersMap[string(src)]; found {
return s
}
s := string(src)
c.membersMap[s] = s
return s
}
type scanPlanTextAnyToEnumString struct {
codec *EnumCodec
}
func (plan *scanPlanTextAnyToEnumString) Scan(src []byte, dst any) error {
if src == nil {
return fmt.Errorf("cannot scan NULL into %T", dst)
}
p := (dst).(*string)
*p = plan.codec.lookupAndCacheString(src)
return nil
}
type scanPlanTextAnyToEnumTextScanner struct {
codec *EnumCodec
}
func (plan *scanPlanTextAnyToEnumTextScanner) Scan(src []byte, dst any) error {
scanner := (dst).(TextScanner)
if src == nil {
return scanner.ScanText(Text{})
}
return scanner.ScanText(Text{String: plan.codec.lookupAndCacheString(src), Valid: true})
}