Add example custom type

scan-io
Jack Christensen 2014-07-12 21:40:48 -05:00
parent 88d5a25fc4
commit 5dace165f5
2 changed files with 100 additions and 1 deletions

View File

@ -145,7 +145,7 @@ added for additional types like point, hstore, numeric, etc. that do not have
direct mappings in Go by the types implementing Scanner, TextEncoder, and
optionally BinaryEncoder. To enable binary format for custom types, a prepared
statement must be used and the field description of the returned field must have
FormatCode set to BinaryFormatCode. See example_value_transcoder_test.go for an
FormatCode set to BinaryFormatCode. See example_custom_type_test.go for an
example of a custom type for the PostgreSQL point type.
### Null Mapping

View File

@ -0,0 +1,99 @@
package pgx_test
import (
"errors"
"fmt"
"github.com/jackc/pgx"
"regexp"
"strconv"
)
var pointRegexp *regexp.Regexp = regexp.MustCompile(`^\((.*),(.*)\)$`)
// NullPoint represents a point that may be null.
//
// If Valid is false then the value is NULL.
type NullPoint struct {
X, Y float64 // Coordinates of point
Valid bool // Valid is true if not NULL
}
const pointOid = 600
func (p *NullPoint) Scan(vr *pgx.ValueReader) error {
if vr.Type().DataType != pointOid {
return pgx.SerializationError(fmt.Sprintf("NullPoint.Scan cannot decode OID %d", vr.Type().DataType))
}
if vr.Len() == -1 {
p.X, p.Y, p.Valid = 0, 0, false
return nil
}
switch vr.Type().FormatCode {
case pgx.TextFormatCode:
s := vr.ReadString(vr.Len())
match := pointRegexp.FindStringSubmatch(s)
if match == nil {
return pgx.SerializationError(fmt.Sprintf("Received invalid point: %v", s))
}
var err error
p.X, err = strconv.ParseFloat(match[1], 64)
if err != nil {
return pgx.SerializationError(fmt.Sprintf("Received invalid point: %v", s))
}
p.Y, err = strconv.ParseFloat(match[2], 64)
if err != nil {
return pgx.SerializationError(fmt.Sprintf("Received invalid point: %v", s))
}
case pgx.BinaryFormatCode:
return errors.New("binary format not implemented")
default:
return fmt.Errorf("unknown format %v", vr.Type().FormatCode)
}
p.Valid = true
return vr.Err()
}
func (p NullPoint) EncodeText() (string, byte, error) {
if p.Valid {
return fmt.Sprintf("point(%v,%v)", p.X, p.Y), pgx.SafeText, nil
} else {
return "", pgx.NullText, nil
}
}
func (p NullPoint) String() string {
if p.Valid {
return fmt.Sprintf("%v, %v", p.X, p.Y)
}
return "null point"
}
func Example_CustomType() {
conn, err := pgx.Connect(*defaultConnConfig)
if err != nil {
fmt.Printf("Unable to establish connection: %v", err)
return
}
var p NullPoint
err = conn.QueryRow("select null::point").Scan(&p)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(p)
err = conn.QueryRow("select point(1.5,2.5)").Scan(&p)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(p)
// Output:
// null point
// 1.5, 2.5
}