This package is an implementation of the PostGis database driver. Refer to documentation https://pkg.go.dev/github.com/landru29/gogis
The following types are currently implemented:
- Point
- LineString
- Polygon
- MultiPoint
- MultiLineString
- MultiPolygon
- Triangle
- CircularString
package main
import (
"context"
"database/sql"
"fmt"
_ "github.com/lib/pq"
"github.com/landru29/gogis"
"github.com/landru29/gogis/ewkb"
)
func main() {
// Launch database:
// $> docker run --name db -p 5432:5432 -e POSTGRES_PASSWORD=tester -e POSTGRES_USER=tester -e POSTGRES_DB=test -d postgis/postgis:15-master
//
// Create the table:
// $> docker exec -i db psql -h 0.0.0.0 -p 5432 -U tester -d test -c "CREATE TABLE IF NOT EXISTS geometries (coordinate GEOMETRY);" -t
//
// Insert data:
// $> docker exec -i db psql -h 0.0.0.0 -p 5432 -U tester -d test -c "INSERT INTO geometries(coordinate) VALUES (ST_GeomFromText('POINT ZM(10 20 30 50)', 4326))" -t
// $> docker exec -i db psql -h 0.0.0.0 -p 5432 -U tester -d test -c "INSERT INTO geometries(coordinate) VALUES (ST_GeomFromText('MULTIPOINT((-71.42 42.71),(-17.42 42.17),(-17.42 71.17),(-71.42 42.71))', 4326))" -t
// $> docker exec -i db psql -h 0.0.0.0 -p 5432 -U tester -d test -c "INSERT INTO geometries(coordinate) VALUES (ST_GeomFromText('POLYGON Z((-71.42 42.71 4,-17.42 42.17 4,-17.42 71.17 4,-71.42 42.71 4),(1 2 3,4 5 6,7 8 9,1 2 3))', 4326))" -t
// $> docker exec -i db psql -h 0.0.0.0 -p 5432 -U tester -d test -c "INSERT INTO geometries(coordinate) VALUES (ST_GeomFromText('LINESTRING (-71.060316 48.432044, 5 6, 42 24)', 4326))" -t
ctx := context.Background()
// Connect to database.
db, err := sql.Open("postgres", "postgresql://tester:tester@localhost/test?sslmode=disable")
if err != nil {
panic(err)
}
// Prepare the query.
rows, err := db.QueryContext(ctx, `
SELECT
coordinate
FROM geometries
`)
if err != nil {
panic(err)
}
if err := rows.Err(); err != nil {
panic(err)
}
defer func() {
_ = rows.Close()
}()
// Read data.
for rows.Next() {
geometry := gogis.NewGeometry()
err = rows.Scan(geometry)
if err != nil {
panic(err)
}
switch data := geometry.Geometry.(type) {
case *gogis.Point:
// process point
fmt.Printf("* point %+v\n", data)
case *gogis.LineString:
// process linestring
fmt.Printf("* linestring %+v\n", data)
case *gogis.Polygon:
// process polygon
fmt.Printf("* polygon %+v\n", data)
case *gogis.MultiPoint:
// process multipoint
fmt.Printf("* multipoint %+v\n", data)
}
}
}
It's quite easy to implement your own type, based on Extended Well Known Byte
format.
First implement the following:
type Custom struct {}
func (c *Custom) UnmarshalEWBK(ewkb.ExtendedWellKnownBytes) error {
return nil
}
func (c Custom) MarshalEWBK(binary.ByteOrder) ([]byte, error) {
return nil, nil
}
func (c Custom) SystemReferenceID() *SystemReferenceID {
return nil
}
func (c Custom) Layout() Layout {
return ewkb.Layout(0)
}
func (c Custom) Type() ewkb.GeometryType {
return ewkb.GeometryType(42)
}
Now, you just have to implement the following:
type CustomSQL Custom
func (c *CustomSQL) Scan(value interface{}) error {
custo := Custom{}
if err := ewkb.Unmarshal(&custo, value); err != nil {
return err
}
return c.FromEWKB(custo)
}
func (c CustomSQL) Value() (driver.Value, error) {
return ewkb.Marshal(c.ToEWKB())
}
func (c *CustomSQL) FromEWKB(geometry interface{}) error {
*c = CustomSQL(geometry)
return nil
}
func (c CustomSQL) ToEWKB() ewkb.Marshaler {
return Custom(c)
}