sqlx postgres scan 方法失败



我正在尝试执行包含自定义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
}

ScannerValuer接口的GeoPoint实现看起来有问题。 它们应该是对称的,但在一种情况下,它将 GeoPoint 表示为以下形式的任意可变长度字符串:

"(<latitude>, <longitude>)"

但在另一个方向上,期望表示正好 16 个字节(两个 64 位浮点数,按大端字节顺序排列)。 这似乎不兼容。

您是否测试过Value()的输出值可以反馈到Scan()以获得相同的值? 从本质上讲,您应该能够执行以下操作:

p1 := GeoPoint{3.1415926, 2.71828}
bs, _ := p1.Value()
p2 := GeoPoint{}
p2.Scan(bs)
fmt.Printf("%#vn", 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()必须在概念上保持一致:否则,它们将没有用。

最新更新