From d8a778811eefcabd76416f8d8c28a5d079d18626 Mon Sep 17 00:00:00 2001 From: Jack Christensen Date: Tue, 4 Apr 2017 08:16:02 -0500 Subject: [PATCH] Add pgtype.Lseg --- box.go | 18 +++--- box_test.go | 12 ++-- lseg.go | 168 +++++++++++++++++++++++++++++++++++++++++++++++++++ lseg_test.go | 21 +++++++ pgtype.go | 1 + 5 files changed, 205 insertions(+), 15 deletions(-) create mode 100644 lseg.go create mode 100644 lseg_test.go diff --git a/box.go b/box.go index eaaddbff..138953a5 100644 --- a/box.go +++ b/box.go @@ -13,8 +13,8 @@ import ( ) type Box struct { - Corners [2]Vec2 - Status Status + P [2]Vec2 + Status Status } func (dst *Box) Set(src interface{}) error { @@ -79,7 +79,7 @@ func (dst *Box) DecodeText(ci *ConnInfo, src []byte) error { return err } - *dst = Box{Corners: [2]Vec2{{x1, y1}, {x2, y2}}, Status: Present} + *dst = Box{P: [2]Vec2{{x1, y1}, {x2, y2}}, Status: Present} return nil } @@ -99,7 +99,7 @@ func (dst *Box) DecodeBinary(ci *ConnInfo, src []byte) error { y2 := binary.BigEndian.Uint64(src[24:]) *dst = Box{ - Corners: [2]Vec2{ + P: [2]Vec2{ {math.Float64frombits(x1), math.Float64frombits(y1)}, {math.Float64frombits(x2), math.Float64frombits(y2)}, }, @@ -117,7 +117,7 @@ func (src *Box) EncodeText(ci *ConnInfo, w io.Writer) (bool, error) { } _, 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)) + src.P[0].X, src.P[0].Y, src.P[1].X, src.P[1].Y)) return false, err } @@ -129,19 +129,19 @@ func (src *Box) EncodeBinary(ci *ConnInfo, w io.Writer) (bool, error) { return false, errUndefined } - if _, err := pgio.WriteUint64(w, math.Float64bits(src.Corners[0].X)); err != nil { + if _, err := pgio.WriteUint64(w, math.Float64bits(src.P[0].X)); err != nil { return false, err } - if _, err := pgio.WriteUint64(w, math.Float64bits(src.Corners[0].Y)); err != nil { + if _, err := pgio.WriteUint64(w, math.Float64bits(src.P[0].Y)); err != nil { return false, err } - if _, err := pgio.WriteUint64(w, math.Float64bits(src.Corners[1].X)); err != nil { + if _, err := pgio.WriteUint64(w, math.Float64bits(src.P[1].X)); err != nil { return false, err } - _, err := pgio.WriteUint64(w, math.Float64bits(src.Corners[1].Y)) + _, err := pgio.WriteUint64(w, math.Float64bits(src.P[1].Y)) return false, err } diff --git a/box_test.go b/box_test.go index 21446dc3..00732973 100644 --- a/box_test.go +++ b/box_test.go @@ -9,12 +9,12 @@ import ( 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, + P: [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, + P: [2]pgtype.Vec2{{7.1, 1.678}, {-13.14, -5.234}}, + Status: pgtype.Present, }, &pgtype.Box{Status: pgtype.Null}, }) @@ -25,8 +25,8 @@ func TestBoxNormalize(t *testing.T) { { 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, + P: [2]pgtype.Vec2{{7.1, 5.234}, {3.14, 1.678}}, + Status: pgtype.Present, }, }, }) diff --git a/lseg.go b/lseg.go new file mode 100644 index 00000000..b86256e0 --- /dev/null +++ b/lseg.go @@ -0,0 +1,168 @@ +package pgtype + +import ( + "database/sql/driver" + "encoding/binary" + "fmt" + "io" + "math" + "strconv" + "strings" + + "github.com/jackc/pgx/pgio" +) + +type Lseg struct { + P [2]Vec2 + Status Status +} + +func (dst *Lseg) Set(src interface{}) error { + return fmt.Errorf("cannot convert %v to Lseg", src) +} + +func (dst *Lseg) Get() interface{} { + switch dst.Status { + case Present: + return dst + case Null: + return nil + default: + return dst.Status + } +} + +func (src *Lseg) AssignTo(dst interface{}) error { + return fmt.Errorf("cannot assign %v to %T", src, dst) +} + +func (dst *Lseg) DecodeText(ci *ConnInfo, src []byte) error { + if src == nil { + *dst = Lseg{Status: Null} + return nil + } + + if len(src) < 11 { + return fmt.Errorf("invalid length for Lseg: %v", len(src)) + } + + str := string(src[2:]) + + 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)-2] + + y2, err := strconv.ParseFloat(str, 64) + if err != nil { + return err + } + + *dst = Lseg{P: [2]Vec2{{x1, y1}, {x2, y2}}, Status: Present} + return nil +} + +func (dst *Lseg) DecodeBinary(ci *ConnInfo, src []byte) error { + if src == nil { + *dst = Lseg{Status: Null} + return nil + } + + if len(src) != 32 { + return fmt.Errorf("invalid length for Lseg: %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 = Lseg{ + P: [2]Vec2{ + {math.Float64frombits(x1), math.Float64frombits(y1)}, + {math.Float64frombits(x2), math.Float64frombits(y2)}, + }, + Status: Present, + } + return nil +} + +func (src *Lseg) 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.P[0].X, src.P[0].Y, src.P[1].X, src.P[1].Y)) + return false, err +} + +func (src *Lseg) 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.P[0].X)); err != nil { + return false, err + } + + if _, err := pgio.WriteUint64(w, math.Float64bits(src.P[0].Y)); err != nil { + return false, err + } + + if _, err := pgio.WriteUint64(w, math.Float64bits(src.P[1].X)); err != nil { + return false, err + } + + _, err := pgio.WriteUint64(w, math.Float64bits(src.P[1].Y)) + return false, err +} + +// Scan implements the database/sql Scanner interface. +func (dst *Lseg) Scan(src interface{}) error { + if src == nil { + *dst = Lseg{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 *Lseg) Value() (driver.Value, error) { + return encodeValueText(src) +} diff --git a/lseg_test.go b/lseg_test.go new file mode 100644 index 00000000..5f041263 --- /dev/null +++ b/lseg_test.go @@ -0,0 +1,21 @@ +package pgtype_test + +import ( + "testing" + + "github.com/jackc/pgx/pgtype" +) + +func TestLsegTranscode(t *testing.T) { + testSuccessfulTranscode(t, "lseg", []interface{}{ + &pgtype.Lseg{ + P: [2]pgtype.Vec2{{3.14, 1.678}, {7.1, 5.234}}, + Status: pgtype.Present, + }, + &pgtype.Lseg{ + P: [2]pgtype.Vec2{{7.1, 1.678}, {-13.14, -5.234}}, + Status: pgtype.Present, + }, + &pgtype.Lseg{Status: pgtype.Null}, + }) +} diff --git a/pgtype.go b/pgtype.go index c92dfccf..6d1f49af 100644 --- a/pgtype.go +++ b/pgtype.go @@ -243,6 +243,7 @@ func init() { "json": &Json{}, "jsonb": &Jsonb{}, "line": &Line{}, + "lseg": &Lseg{}, "name": &Name{}, "numeric": &Numeric{}, "numrange": &Numrange{},