背景
最近因业务的需求,用到了postgresql的空间类型——point。
本来挺好的,可是当配合上golang写接口就开始不友好了,因为golang原生并不支持。
然后就开始慢慢查资料之路,关于golang的空间类型的CRUD非常少。
最后综合蛮多资料、以及pg的命令操作还要看了一些golang的源码总结了一下。
Show Code
type Point struct {
lat float64
lng float64
}
// 实现driver.Valuer接口
func (p *Point) Value() (driver.Value, error) {
buf := new(bytes.Buffer)
fmt.Fprintf(buf, "(%f, %f)", p.lat, p.lng)
return buf.Bytes(), nil
}
func (p *Point) String() string {
return fmt.Sprintf("(%v, %v)", p.lat, p.lng)
}
// 实现sql.scanner接口
func (p *Point) Scan(val interface{}) (err error) {
if bb, ok := val.([]uint8); ok {
tmp := bb[1 : len(bb)-1]
coors := strings.Split(string(tmp[:]), ",")
if p.lat, err = strconv.ParseFloat(coors[0], 64); err != nil {
return err
}
if p.lng, err = strconv.ParseFloat(coors[1], 64); err != nil {
return err
}
}
return nil
}
解释
pg的point相关sql语句
CREATE TABLE tp(id varchar(20), p point); # 建表
INSERT INTO tp values ('123', '(22.02, 120.01)'); # 插入数据
golang的/usr/local/go/src/database/sql/sql.go中的NullString、NullInt64、NullInt32、NullFloat64、NullBool、NullTime等都实现Scan(value interface{}) error 和 Value() (driver.Value, error),对于这两个方法注释是这样的
Scan implements the Scanner interface.
Value implements the driver Valuer interface.
综合一些资料,查询会用到Scan接口,插入会用到Value接口
另外做一个小纠正,许多资料上插入point是
INSERT INTO tp values ('123', 'POINT (22.02 120.01)');
但我测试之后,这个行不太通。应该是和pg的版本有关,我的版本是12.3,用的是
INSERT INTO tp values ('123', '(22.02, 120.01)');
在写Value接口的时候一定要注意对应好正确的形式
问题
这个String()暂时还没有明白作用是什么,看代码应该是一个格式化返回,有兴趣和想法的大家可以补充。