From 6bb595384bbe8e2f960c3a1df0e4e66c9da3e884 Mon Sep 17 00:00:00 2001 From: Paul Mach Date: Fri, 20 Mar 2015 14:14:53 -0700 Subject: [PATCH] geometry.Scan for direct postgis query -> geojson --- README.md | 15 +++++++++++---- geometry.go | 13 +++++++++++++ geometry_test.go | 22 ++++++++++++++++++++++ 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 236b7b2..9ecaf1b 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,10 @@ go.geojson ========== -go.geojson is a library for **encoding and decoding** [GeoJSON](http://geojson.org/) into Go structs. +Go.geojson is a package for **encoding and decoding** [GeoJSON](http://geojson.org/) into Go structs. Supports both the [json.Marshaler](http://golang.org/pkg/encoding/json/#Marshaler) and [json.Unmarshaler](http://golang.org/pkg/encoding/json/#Unmarshaler) -interfaces as well as helper functions such as `UnmarshalFeatureCollection`, `UnmarshalFeature` and `UnmarshalGeometry`. +interfaces as well as [sql.Scanner](http://golang.org/pkg/database/sql/#Scanner) for directly scanner PostGIS query results. +The package also provides helper functions such as `UnmarshalFeatureCollection`, `UnmarshalFeature` and `UnmarshalGeometry`. #### To install @@ -48,8 +49,7 @@ interfaces as well as helper functions such as `UnmarshalFeatureCollection`, `Un g.IsPoint() == true g.Point == []float64{102.0, 0.5} - - + * #### Marshalling (Go -> JSON) g := geojson.NewPointGeometry([]float64{1, 2}) @@ -59,6 +59,13 @@ interfaces as well as helper functions such as `UnmarshalFeatureCollection`, `Un fc.AddFeature(geojson.NewPointFeature([]float64{1,2})) rawJSON, err := fc.MarshalJSON() +* #### Scanning PostGIS query results + + row := db.QueryRow("SELECT ST_AsGeoJSON(the_geom) FROM postgis_table) + + var geometry *geojson.Geometry + row.Scan(&geometry) + * #### Dealing with different Geometry types A geometry can be of several types, causing problems in a statically typed language. diff --git a/geometry.go b/geometry.go index 70d66c8..76d9d6f 100644 --- a/geometry.go +++ b/geometry.go @@ -154,6 +154,19 @@ func (g *Geometry) UnmarshalJSON(data []byte) error { return decodeGeometry(g, object) } +// Scan implements the sql.Scanner interface allowing +// geometry structs to be passed into rows.Scan(...interface{}) +// The columns must be received as GeoJSON Geometry. +// When using PostGIS a spatial column would need to be wrapped in ST_AsGeoJSON. +func (g *Geometry) Scan(value interface{}) error { + data, ok := value.([]byte) + if !ok { + return errors.New("unable to parse this type into geojson") + } + + return g.UnmarshalJSON(data) +} + func decodeGeometry(g *Geometry, object map[string]interface{}) error { t, ok := object["type"] if !ok { diff --git a/geometry_test.go b/geometry_test.go index fa728a5..871da23 100644 --- a/geometry_test.go +++ b/geometry_test.go @@ -262,3 +262,25 @@ func TestUnmarshalGeometryCollection(t *testing.T) { t.Errorf("should have 2 geometries but got %d", len(g.Geometries)) } } + +func TestGeometryScan(t *testing.T) { + g := &Geometry{} + + err := g.Scan(123) + if err == nil { + t.Errorf("should return error if not the correct data type") + } + + err = g.Scan([]byte(`{"type":"Point","coordinates":[-93.787988,32.392335]}`)) + if err != nil { + t.Fatalf("should parse without error, got %v", err) + } + + if !g.IsPoint() { + t.Errorf("should be point, but got %v", g) + } + + if g.Point[0] != -93.787988 || g.Point[1] != 32.392335 { + t.Errorf("incorrect point data, got %v", g.Point) + } +}