...

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

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

     1  package pgtype
     2  
     3  import (
     4  	"database/sql/driver"
     5  	"encoding/binary"
     6  	"fmt"
     7  	"math"
     8  	"strconv"
     9  	"strings"
    10  
    11  	"github.com/jackc/pgx/v5/internal/pgio"
    12  )
    13  
    14  type CircleScanner interface {
    15  	ScanCircle(v Circle) error
    16  }
    17  
    18  type CircleValuer interface {
    19  	CircleValue() (Circle, error)
    20  }
    21  
    22  type Circle struct {
    23  	P     Vec2
    24  	R     float64
    25  	Valid bool
    26  }
    27  
    28  func (c *Circle) ScanCircle(v Circle) error {
    29  	*c = v
    30  	return nil
    31  }
    32  
    33  func (c Circle) CircleValue() (Circle, error) {
    34  	return c, nil
    35  }
    36  
    37  // Scan implements the database/sql Scanner interface.
    38  func (dst *Circle) Scan(src any) error {
    39  	if src == nil {
    40  		*dst = Circle{}
    41  		return nil
    42  	}
    43  
    44  	switch src := src.(type) {
    45  	case string:
    46  		return scanPlanTextAnyToCircleScanner{}.Scan([]byte(src), dst)
    47  	}
    48  
    49  	return fmt.Errorf("cannot scan %T", src)
    50  }
    51  
    52  // Value implements the database/sql/driver Valuer interface.
    53  func (src Circle) Value() (driver.Value, error) {
    54  	if !src.Valid {
    55  		return nil, nil
    56  	}
    57  
    58  	buf, err := CircleCodec{}.PlanEncode(nil, 0, TextFormatCode, src).Encode(src, nil)
    59  	if err != nil {
    60  		return nil, err
    61  	}
    62  	return string(buf), err
    63  }
    64  
    65  type CircleCodec struct{}
    66  
    67  func (CircleCodec) FormatSupported(format int16) bool {
    68  	return format == TextFormatCode || format == BinaryFormatCode
    69  }
    70  
    71  func (CircleCodec) PreferredFormat() int16 {
    72  	return BinaryFormatCode
    73  }
    74  
    75  func (CircleCodec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
    76  	if _, ok := value.(CircleValuer); !ok {
    77  		return nil
    78  	}
    79  
    80  	switch format {
    81  	case BinaryFormatCode:
    82  		return encodePlanCircleCodecBinary{}
    83  	case TextFormatCode:
    84  		return encodePlanCircleCodecText{}
    85  	}
    86  
    87  	return nil
    88  }
    89  
    90  type encodePlanCircleCodecBinary struct{}
    91  
    92  func (encodePlanCircleCodecBinary) Encode(value any, buf []byte) (newBuf []byte, err error) {
    93  	circle, err := value.(CircleValuer).CircleValue()
    94  	if err != nil {
    95  		return nil, err
    96  	}
    97  
    98  	if !circle.Valid {
    99  		return nil, nil
   100  	}
   101  
   102  	buf = pgio.AppendUint64(buf, math.Float64bits(circle.P.X))
   103  	buf = pgio.AppendUint64(buf, math.Float64bits(circle.P.Y))
   104  	buf = pgio.AppendUint64(buf, math.Float64bits(circle.R))
   105  	return buf, nil
   106  }
   107  
   108  type encodePlanCircleCodecText struct{}
   109  
   110  func (encodePlanCircleCodecText) Encode(value any, buf []byte) (newBuf []byte, err error) {
   111  	circle, err := value.(CircleValuer).CircleValue()
   112  	if err != nil {
   113  		return nil, err
   114  	}
   115  
   116  	if !circle.Valid {
   117  		return nil, nil
   118  	}
   119  
   120  	buf = append(buf, fmt.Sprintf(`<(%s,%s),%s>`,
   121  		strconv.FormatFloat(circle.P.X, 'f', -1, 64),
   122  		strconv.FormatFloat(circle.P.Y, 'f', -1, 64),
   123  		strconv.FormatFloat(circle.R, 'f', -1, 64),
   124  	)...)
   125  	return buf, nil
   126  }
   127  
   128  func (CircleCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
   129  	switch format {
   130  	case BinaryFormatCode:
   131  		switch target.(type) {
   132  		case CircleScanner:
   133  			return scanPlanBinaryCircleToCircleScanner{}
   134  		}
   135  	case TextFormatCode:
   136  		switch target.(type) {
   137  		case CircleScanner:
   138  			return scanPlanTextAnyToCircleScanner{}
   139  		}
   140  	}
   141  
   142  	return nil
   143  }
   144  
   145  func (c CircleCodec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
   146  	return codecDecodeToTextFormat(c, m, oid, format, src)
   147  }
   148  
   149  func (c CircleCodec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
   150  	if src == nil {
   151  		return nil, nil
   152  	}
   153  
   154  	var circle Circle
   155  	err := codecScan(c, m, oid, format, src, &circle)
   156  	if err != nil {
   157  		return nil, err
   158  	}
   159  	return circle, nil
   160  }
   161  
   162  type scanPlanBinaryCircleToCircleScanner struct{}
   163  
   164  func (scanPlanBinaryCircleToCircleScanner) Scan(src []byte, dst any) error {
   165  	scanner := (dst).(CircleScanner)
   166  
   167  	if src == nil {
   168  		return scanner.ScanCircle(Circle{})
   169  	}
   170  
   171  	if len(src) != 24 {
   172  		return fmt.Errorf("invalid length for Circle: %v", len(src))
   173  	}
   174  
   175  	x := binary.BigEndian.Uint64(src)
   176  	y := binary.BigEndian.Uint64(src[8:])
   177  	r := binary.BigEndian.Uint64(src[16:])
   178  
   179  	return scanner.ScanCircle(Circle{
   180  		P:     Vec2{math.Float64frombits(x), math.Float64frombits(y)},
   181  		R:     math.Float64frombits(r),
   182  		Valid: true,
   183  	})
   184  }
   185  
   186  type scanPlanTextAnyToCircleScanner struct{}
   187  
   188  func (scanPlanTextAnyToCircleScanner) Scan(src []byte, dst any) error {
   189  	scanner := (dst).(CircleScanner)
   190  
   191  	if src == nil {
   192  		return scanner.ScanCircle(Circle{})
   193  	}
   194  
   195  	if len(src) < 9 {
   196  		return fmt.Errorf("invalid length for Circle: %v", len(src))
   197  	}
   198  
   199  	str := string(src[2:])
   200  	end := strings.IndexByte(str, ',')
   201  	x, err := strconv.ParseFloat(str[:end], 64)
   202  	if err != nil {
   203  		return err
   204  	}
   205  
   206  	str = str[end+1:]
   207  	end = strings.IndexByte(str, ')')
   208  
   209  	y, err := strconv.ParseFloat(str[:end], 64)
   210  	if err != nil {
   211  		return err
   212  	}
   213  
   214  	str = str[end+2 : len(str)-1]
   215  
   216  	r, err := strconv.ParseFloat(str, 64)
   217  	if err != nil {
   218  		return err
   219  	}
   220  
   221  	return scanner.ScanCircle(Circle{P: Vec2{x, y}, R: r, Valid: true})
   222  }
   223  

View as plain text