mirror of
https://github.com/jackc/pgx.git
synced 2025-05-29 10:42:31 +00:00
Add pgtype.Box
This commit is contained in:
parent
5a2feadf11
commit
06822bebe0
168
pgtype/box.go
Normal file
168
pgtype/box.go
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
package pgtype
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql/driver"
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"math"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/jackc/pgx/pgio"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Box struct {
|
||||||
|
Corners [2]Vec2
|
||||||
|
Status Status
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dst *Box) Set(src interface{}) error {
|
||||||
|
return fmt.Errorf("cannot convert %v to Box", src)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dst *Box) Get() interface{} {
|
||||||
|
switch dst.Status {
|
||||||
|
case Present:
|
||||||
|
return dst
|
||||||
|
case Null:
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
return dst.Status
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (src *Box) AssignTo(dst interface{}) error {
|
||||||
|
return fmt.Errorf("cannot assign %v to %T", src, dst)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dst *Box) DecodeText(ci *ConnInfo, src []byte) error {
|
||||||
|
if src == nil {
|
||||||
|
*dst = Box{Status: Null}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(src) < 11 {
|
||||||
|
return fmt.Errorf("invalid length for Box: %v", len(src))
|
||||||
|
}
|
||||||
|
|
||||||
|
str := string(src[1:])
|
||||||
|
|
||||||
|
var end int
|
||||||
|
end = strings.IndexByte(str, ',')
|
||||||
|
|
||||||
|
x1, err := strconv.ParseFloat(str[:end], 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
str = str[end+1:]
|
||||||
|
end = strings.IndexByte(str, ')')
|
||||||
|
|
||||||
|
y1, err := strconv.ParseFloat(str[:end], 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
str = str[end+3:]
|
||||||
|
end = strings.IndexByte(str, ',')
|
||||||
|
|
||||||
|
x2, err := strconv.ParseFloat(str[:end], 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
str = str[end+1 : len(str)-1]
|
||||||
|
|
||||||
|
y2, err := strconv.ParseFloat(str, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
*dst = Box{Corners: [2]Vec2{{x1, y1}, {x2, y2}}, Status: Present}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dst *Box) DecodeBinary(ci *ConnInfo, src []byte) error {
|
||||||
|
if src == nil {
|
||||||
|
*dst = Box{Status: Null}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(src) != 32 {
|
||||||
|
return fmt.Errorf("invalid length for Box: %v", len(src))
|
||||||
|
}
|
||||||
|
|
||||||
|
x1 := binary.BigEndian.Uint64(src)
|
||||||
|
y1 := binary.BigEndian.Uint64(src[8:])
|
||||||
|
x2 := binary.BigEndian.Uint64(src[16:])
|
||||||
|
y2 := binary.BigEndian.Uint64(src[24:])
|
||||||
|
|
||||||
|
*dst = Box{
|
||||||
|
Corners: [2]Vec2{
|
||||||
|
{math.Float64frombits(x1), math.Float64frombits(y1)},
|
||||||
|
{math.Float64frombits(x2), math.Float64frombits(y2)},
|
||||||
|
},
|
||||||
|
Status: Present,
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (src *Box) 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),(%f,%f)`,
|
||||||
|
src.Corners[0].X, src.Corners[0].Y, src.Corners[1].X, src.Corners[1].Y))
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (src *Box) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) {
|
||||||
|
switch src.Status {
|
||||||
|
case Null:
|
||||||
|
return true, nil
|
||||||
|
case Undefined:
|
||||||
|
return false, errUndefined
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := pgio.WriteUint64(w, math.Float64bits(src.Corners[0].X)); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := pgio.WriteUint64(w, math.Float64bits(src.Corners[0].Y)); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := pgio.WriteUint64(w, math.Float64bits(src.Corners[1].X)); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := pgio.WriteUint64(w, math.Float64bits(src.Corners[1].Y))
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scan implements the database/sql Scanner interface.
|
||||||
|
func (dst *Box) Scan(src interface{}) error {
|
||||||
|
if src == nil {
|
||||||
|
*dst = Box{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 *Box) Value() (driver.Value, error) {
|
||||||
|
return encodeValueText(src)
|
||||||
|
}
|
33
pgtype/box_test.go
Normal file
33
pgtype/box_test.go
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package pgtype_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/jackc/pgx/pgtype"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestBoxTranscode(t *testing.T) {
|
||||||
|
testSuccessfulTranscode(t, "box", []interface{}{
|
||||||
|
&pgtype.Box{
|
||||||
|
Corners: [2]pgtype.Vec2{{7.1, 5.234}, {3.14, 1.678}},
|
||||||
|
Status: pgtype.Present,
|
||||||
|
},
|
||||||
|
&pgtype.Box{
|
||||||
|
Corners: [2]pgtype.Vec2{{7.1, 1.678}, {-13.14, -5.234}},
|
||||||
|
Status: pgtype.Present,
|
||||||
|
},
|
||||||
|
&pgtype.Box{Status: pgtype.Null},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBoxNormalize(t *testing.T) {
|
||||||
|
testSuccessfulNormalize(t, []normalizeTest{
|
||||||
|
{
|
||||||
|
sql: "select '3.14, 1.678, 7.1, 5.234'::box",
|
||||||
|
value: &pgtype.Box{
|
||||||
|
Corners: [2]pgtype.Vec2{{7.1, 5.234}, {3.14, 1.678}},
|
||||||
|
Status: pgtype.Present,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
@ -223,6 +223,7 @@ func init() {
|
|||||||
"_varchar": &VarcharArray{},
|
"_varchar": &VarcharArray{},
|
||||||
"aclitem": &Aclitem{},
|
"aclitem": &Aclitem{},
|
||||||
"bool": &Bool{},
|
"bool": &Bool{},
|
||||||
|
"box": &Box{},
|
||||||
"bytea": &Bytea{},
|
"bytea": &Bytea{},
|
||||||
"char": &QChar{},
|
"char": &QChar{},
|
||||||
"cid": &Cid{},
|
"cid": &Cid{},
|
||||||
|
@ -12,9 +12,13 @@ import (
|
|||||||
"github.com/jackc/pgx/pgio"
|
"github.com/jackc/pgx/pgio"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Vec2 struct {
|
||||||
|
X float64
|
||||||
|
Y float64
|
||||||
|
}
|
||||||
|
|
||||||
type Point struct {
|
type Point struct {
|
||||||
X float64
|
Vec2
|
||||||
Y float64
|
|
||||||
Status Status
|
Status Status
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,7 +66,7 @@ func (dst *Point) DecodeText(ci *ConnInfo, src []byte) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
*dst = Point{X: x, Y: y, Status: Present}
|
*dst = Point{Vec2: Vec2{x, y}, Status: Present}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,8 +84,7 @@ func (dst *Point) DecodeBinary(ci *ConnInfo, src []byte) error {
|
|||||||
y := binary.BigEndian.Uint64(src[8:])
|
y := binary.BigEndian.Uint64(src[8:])
|
||||||
|
|
||||||
*dst = Point{
|
*dst = Point{
|
||||||
X: math.Float64frombits(x),
|
Vec2: Vec2{math.Float64frombits(x), math.Float64frombits(y)},
|
||||||
Y: math.Float64frombits(y),
|
|
||||||
Status: Present,
|
Status: Present,
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -8,8 +8,8 @@ import (
|
|||||||
|
|
||||||
func TestPointTranscode(t *testing.T) {
|
func TestPointTranscode(t *testing.T) {
|
||||||
testSuccessfulTranscode(t, "point", []interface{}{
|
testSuccessfulTranscode(t, "point", []interface{}{
|
||||||
&pgtype.Point{X: 1.234, Y: 5.6789, Status: pgtype.Present},
|
&pgtype.Point{Vec2: pgtype.Vec2{1.234, 5.6789}, Status: pgtype.Present},
|
||||||
&pgtype.Point{X: -1.234, Y: -5.6789, Status: pgtype.Present},
|
&pgtype.Point{Vec2: pgtype.Vec2{-1.234, -5.6789}, Status: pgtype.Present},
|
||||||
&pgtype.Point{Status: pgtype.Null},
|
&pgtype.Point{Status: pgtype.Null},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user