I'm trying to store a Point variable in an SQL database using GORM on a go server, I tried looking everywhere but I haven't seen an answer that satisfies me yet
Asked
Active
Viewed 1,015 times
2
-
What is a Point value? A coordinate set, like `type Point struct{ X, Y int }`? Also: why? What have you tried? Why was the other solutions not satisfying? You need to add more detail to your problem description. – Brian Stengaard - Podio Jun 17 '16 at 20:18
-
In postgres SQL I can make a column that holds a Type Point, it should be an X and Y yes but it will store lat and lng so it might not be an int type unless that's the only type that can be stored in a point in postgres sql. I looked at similar posts about this on stack overflow: http://stackoverflow.com/questions/1727137/sql-query-for-performing-radius-search-based-on-latitude-longitude I took a look at the 2nd answer that names making a spatial column using a point – Eddi3 Jun 17 '16 at 20:22
-
Basically I want to do what was mentioned in the 2nd post using a GORM struct as mentioned in this site: http://jinzhu.me/gorm/models.html – Eddi3 Jun 17 '16 at 20:24
1 Answers
3
For any type that's not supported by the standard library's database/sql
package, nor by a 3rd party package that depends on database/sql
, like gorm
does, you can implement the Valuer
and Scanner
interfaces to add custom support for the type.
To be able to correctly implement those two interfaces you need to first find out what the target database expects as input and what it returns as output for that type. In the case of PostgreSQL and the Point type the syntax is (x,y)
.
So what you can do is the following:
- Declare the type.
type Point struct {
X, Y float64
}
- Implement the Valuer interface.
func (p Point) Value() (driver.Value, error) {
out := []byte{'('}
out = strconv.AppendFloat(out, p.X, 'f', -1, 64)
out = append(out, ',')
out = strconv.AppendFloat(out, p.Y, 'f', -1, 64)
out = append(out, ')')
return out, nil
}
- Implement the Scanner interface.
func (p *Point) Scan(src interface{}) (err error) {
var data []byte
switch src := src.(type) {
case []byte:
data = src
case string:
data = []byte(src)
case nil:
return nil
default:
return errors.New("(*Point).Scan: unsupported data type")
}
if len(data) == 0 {
return nil
}
data = data[1 : len(data)-1] // drop the surrounding parentheses
for i := 0; i < len(data); i++ {
if data[i] == ',' {
if p.X, err = strconv.ParseFloat(string(data[:i]), 64); err != nil {
return err
}
if p.Y, err = strconv.ParseFloat(string(data[i+1:]), 64); err != nil {
return err
}
break
}
}
return nil
}

mkopriva
- 35,176
- 4
- 57
- 71