我正在尝试执行包含自定义geoPoint类型的postgres查询,但会收到意外的EOF错误。对我做错了什么想法?
type Account struct {
Id uint `json:"id" db:"id"`
RegistrationId string `json:"registration_id" db:"registration_id"`
PhoneNumber string `json:"phone_number" db:"phone_number"`
AuthToken string `json:"auth_token" db:"auth_token"`
// Role string `json:"-" db:"role"`
CreatedAt time.Time `json:"-" db:"created_at"`
ActivatedAt time.Time `json:"-" db:"activated_at"`
Location GeoPoint `json:"location" db:"location"`
}
// THE FAILING FUNCTION
func FindAccountByToken(db *sqlx.DB, token string) (Account, error) {
var account Account
log.Println("FindAcountByToken", token)
err := db.Get(&account, "select * from accounts where auth_token = $1", token)
return account, err
}
type GeoPoint struct {
Latitude float64 `json:"latitude" db:"latitude"`
Longitude float64 `json:"longitude" db:"longitude"`
}
// String value
func (g *GeoPoint) String() string {
return fmt.Sprintf("(%v, %v)", g.Latitude, g.Longitude)
}
// Value of the geoPoint to be stored in the db based on the .String() method
func (g GeoPoint) Value() (driver.Value, error) {
return g.String(), nil
}
// Scan converts the db []byte array value to the geoPoint value
func (g *GeoPoint) Scan(src interface{}) error {
var source []byte
var gp GeoPoint
switch src.(type) {
case []byte:
source = src.([]byte)
default:
return errors.New("Unable to perform geopoint conversion")
}
log.Println("bytes -> ", source)
reader := bytes.NewReader(source)
if err := binary.Read(reader, binary.BigEndian, &gp); err != nil {
log.Println("BinaryRead Error", err)
return err
}
*g = gp
return nil
}
答案 0 :(得分:1)
Scanner
和Valuer
接口的GeoPoint实现看起来有问题。它们应该是对称的,但在一种情况下,它将GeoPoint表示为形式的任意变量长度字符串:
"(<latitude>, <longitude>)"
但是在另一个方向上,需要一个恰好16个字节的表示(以big-endian字节顺序的两个64位浮点数)。这似乎不兼容。
您是否测试过Value()
的输出值可以反馈到Scan()
以获得相同的值?基本上,你应该能够做到:
p1 := GeoPoint{3.1415926, 2.71828}
bs, _ := p1.Value()
p2 := GeoPoint{}
p2.Scan(bs)
fmt.Printf("%#v\n", p2)
并在p2
中看到与p1
中相同的值。
例如:
// Value of the geoPoint to be stored in the db
func (g *GeoPoint) Value() (driver.Value, error) {
var buf bytes.Buffer
binary.Write(&buf, binary.BigEndian, g)
return buf.Bytes(), nil
}
// Scan converts the db []byte array value to the geoPoint value
func (g *GeoPoint) Scan(src interface{}) error {
var source []byte
switch src.(type) {
case []byte:
source = src.([]byte)
default:
return errors.New("Unable to perform geopoint conversion")
}
reader := bytes.NewReader(source)
return binary.Read(reader, binary.BigEndian, g)
}
应该满足这个属性。 Scan()
和Value()
必须在概念上保持一致:否则,它们将无用。