2
0

Add pgtype.Point

This commit is contained in:
Jack Christensen
2017-04-03 17:53:32 -05:00
parent cc873a0bcf
commit 0079bd5095
3 changed files with 155 additions and 0 deletions
+1
View File
@@ -245,6 +245,7 @@ func init() {
"numeric": &Numeric{},
"numrange": &Numrange{},
"oid": &OidValue{},
"point": &Point{},
"record": &Record{},
"text": &Text{},
"tid": &Tid{},
+139
View File
@@ -0,0 +1,139 @@
package pgtype
import (
"database/sql/driver"
"encoding/binary"
"fmt"
"io"
"math"
"strconv"
"strings"
"github.com/jackc/pgx/pgio"
)
type Point struct {
X float64
Y float64
Status Status
}
func (dst *Point) Set(src interface{}) error {
return fmt.Errorf("cannot convert %v to Point", src)
}
func (dst *Point) Get() interface{} {
switch dst.Status {
case Present:
return dst
case Null:
return nil
default:
return dst.Status
}
}
func (src *Point) AssignTo(dst interface{}) error {
return fmt.Errorf("cannot assign %v to %T", src, dst)
}
func (dst *Point) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Point{Status: Null}
return nil
}
if len(src) < 5 {
return fmt.Errorf("invalid length for point: %v", len(src))
}
parts := strings.SplitN(string(src[1:len(src)-1]), ",", 2)
if len(parts) < 2 {
return fmt.Errorf("invalid format for point")
}
x, err := strconv.ParseFloat(parts[0], 64)
if err != nil {
return err
}
y, err := strconv.ParseFloat(parts[1], 64)
if err != nil {
return err
}
*dst = Point{X: x, Y: y, Status: Present}
return nil
}
func (dst *Point) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Point{Status: Null}
return nil
}
if len(src) != 16 {
return fmt.Errorf("invalid length for point: %v", len(src))
}
x := binary.BigEndian.Uint64(src)
y := binary.BigEndian.Uint64(src[8:])
*dst = Point{
X: math.Float64frombits(x),
Y: math.Float64frombits(y),
Status: Present,
}
return nil
}
func (src *Point) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) {
switch src.Status {
case Null:
return true, nil
case Undefined:
return false, errUndefined
}
_, err := io.WriteString(w, fmt.Sprintf(`(%f,%f)`, src.X, src.Y))
return false, err
}
func (src *Point) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
switch src.Status {
case Null:
return true, nil
case Undefined:
return false, errUndefined
}
_, err := pgio.WriteUint64(w, math.Float64bits(src.X))
if err != nil {
return false, err
}
_, err = pgio.WriteUint64(w, math.Float64bits(src.Y))
return false, err
}
// Scan implements the database/sql Scanner interface.
func (dst *Point) Scan(src interface{}) error {
if src == nil {
*dst = Point{Status: Null}
return nil
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
return dst.DecodeText(nil, src)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src *Point) Value() (driver.Value, error) {
return encodeValueText(src)
}
+15
View File
@@ -0,0 +1,15 @@
package pgtype_test
import (
"testing"
"github.com/jackc/pgx/pgtype"
)
func TestPointTranscode(t *testing.T) {
testSuccessfulTranscode(t, "point", []interface{}{
&pgtype.Point{X: 1.234, Y: 5.6789, Status: pgtype.Present},
&pgtype.Point{X: -1.234, Y: -5.6789, Status: pgtype.Present},
&pgtype.Point{Status: pgtype.Null},
})
}