Skip to content

restayway/gogis

GoGIS

Go Reference Go Report Card License: MIT

GoGIS is a comprehensive Go library that provides PostGIS geometry types for GORM, enabling seamless integration of spatial data with your Go applications.

Features

✨ Complete PostGIS Integration - Full support for Point, LineString, Polygon, and GeometryCollection types
πŸš€ GORM Compatible - Implements sql.Scanner and driver.Valuer for automatic ORM integration
πŸ—ΊοΈ WGS 84 Support - Uses SRID 4326 coordinate system for global geographic data
πŸ“ Well-Known Formats - Supports both WKB (Well-Known Binary) and WKT (Well-Known Text)
⚑ High Performance - Optimized for spatial queries with proper indexing support
πŸ§ͺ Thoroughly Tested - Comprehensive test suite with >95% coverage
πŸ“š Well Documented - Complete API documentation and usage examples

Installation

go get github.com/restayway/gogis

Prerequisites

  • Go 1.19+
  • PostgreSQL 12+ with PostGIS 3.0+
  • GORM v2

Database Setup

Enable PostGIS extension in your PostgreSQL database:

CREATE EXTENSION IF NOT EXISTS postgis;

Quick Start

package main import ( "github.com/restayway/gogis" "gorm.io/driver/postgres" "gorm.io/gorm" ) type Location struct { ID uint `gorm:"primaryKey"` Name string `gorm:"not null"` Point gogis.Point `gorm:"type:geometry(Point,4326)"` } func main() { // Connect to database db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{}) if err != nil { panic(err) } // Auto-migrate db.AutoMigrate(&Location{}) // Create location location := Location{ Name: "Statue of Liberty", Point: gogis.Point{ Lng: -74.0445, // Longitude Lat: 40.6892, // Latitude }, } db.Create(&location) // Spatial query - find locations within 1km var nearby []Location db.Where("ST_DWithin(point, ST_Point(?, ?), ?)", -74.0445, 40.6892, 0.009).Find(&nearby) }

Supported Geometry Types

Point

Represents a single location with longitude and latitude coordinates.

type Location struct { ID uint `gorm:"primaryKey"` Name string Point gogis.Point `gorm:"type:geometry(Point,4326)"` } location := Location{ Name: "Central Park", Point: gogis.Point{ Lng: -73.9665, // Longitude (X) Lat: 40.7812, // Latitude (Y) }, }

LineString

Represents paths, routes, or any sequence of connected points.

type Route struct { ID uint `gorm:"primaryKey"` Name string Path gogis.LineString `gorm:"type:geometry(LineString,4326)"` } route := Route{ Name: "Broadway Walk", Path: gogis.LineString{ Points: []gogis.Point{ {Lng: -73.9857, Lat: 40.7580}, // Times Square {Lng: -73.9857, Lat: 40.7614}, // North on Broadway {Lng: -73.9855, Lat: 40.7682}, // Further north }, }, }

Polygon

Represents areas with outer boundaries and optional holes.

type Region struct { ID uint `gorm:"primaryKey"` Name string Area gogis.Polygon `gorm:"type:geometry(Polygon,4326)"` } region := Region{ Name: "Central Park", Area: gogis.Polygon{ Rings: [][]gogis.Point{ { // Outer boundary {Lng: -73.9812, Lat: 40.7644}, {Lng: -73.9734, Lat: 40.7644}, {Lng: -73.9734, Lat: 40.7947}, {Lng: -73.9812, Lat: 40.7947}, {Lng: -73.9812, Lat: 40.7644}, // Close the ring }, // Optional: holes can be added as additional rings }, }, }

GeometryCollection

Represents collections of heterogeneous geometries.

type Place struct { ID uint `gorm:"primaryKey"` Name string Geometries gogis.GeometryCollection `gorm:"type:geometry(GeometryCollection,4326)"` } place := Place{ Name: "Campus", Geometries: gogis.GeometryCollection{ Geometries: []gogis.Geometry{ &gogis.Point{Lng: -73.9550, Lat: 40.8050}, // Building &gogis.LineString{Points: walkwayPoints}, // Walkway &gogis.Polygon{Rings: campusAreaRings}, // Campus area }, }, }

Common Spatial Queries

Distance-Based Queries

// Find locations within 1km of a point var locations []Location db.Where("ST_DWithin(point, ST_Point(?, ?), ?)", lng, lat, 0.009).Find(&locations) // Find nearest 10 locations db.Order("ST_Distance(point, ST_Point(?, ?))"). Limit(10).Find(&locations, lng, lat)

Containment Queries

// Find points within a polygon var pointsInside []Location db.Where("ST_Contains(?, point)", polygon.String()).Find(&pointsInside) // Find polygons containing a point var regions []Region db.Where("ST_Contains(area, ST_Point(?, ?))", lng, lat).Find(&regions)

Intersection Queries

// Find routes that intersect with an area var routes []Route db.Where("ST_Intersects(path, ?)", polygon.String()).Find(&routes) // Find overlapping regions var overlapping []Region db.Where("ST_Overlaps(area, ?)", otherPolygon.String()).Find(&overlapping)

Area and Length Calculations

// Calculate polygon areas in square meters db.Select("*, ST_Area(ST_Transform(area, 3857)) as area_meters").Find(&regions) // Calculate route lengths in meters db.Select("*, ST_Length(ST_Transform(path, 3857)) as length_meters").Find(&routes)

Performance Optimization

Spatial Indexes

Create spatial indexes for optimal query performance:

-- For points CREATE INDEX idx_locations_point ON locations USING GIST (point); -- For linestrings CREATE INDEX idx_routes_path ON routes USING GIST (path); -- For polygons  CREATE INDEX idx_regions_area ON regions USING GIST (area); -- For geometry collections CREATE INDEX idx_places_geometries ON places USING GIST (geometries);

Query Optimization Tips

  1. Use ST_DWithin instead of ST_Distance with WHERE clauses
  2. Create compound indexes for frequently filtered queries
  3. Use ST_Transform for accurate distance/area calculations
  4. Consider partial indexes for large datasets

See INDEXING.md for detailed performance optimization guide.

Examples

Comprehensive examples are available in the examples/ directory:

Run examples:

cd examples/basic_usage && go run main.go cd examples/linestring_example && go run main.go cd examples/polygon_example && go run main.go cd examples/geometry_collection_example && go run main.go

Testing

Run Unit Tests

go test -v

Run Integration Tests (requires PostGIS)

# Set up test database createdb gogis_test psql gogis_test -c "CREATE EXTENSION postgis;" # Run integration tests go test -tags=integration -v

Run Benchmarks

go test -bench=. -benchmem

API Documentation

Full API documentation is available at pkg.go.dev.

Migration Guide

From Other Libraries

If migrating from other PostGIS Go libraries:

  1. Update imports: Change to github.com/restayway/gogis
  2. Update struct tags: Use gorm:"type:geometry(Type,4326)"
  3. Update coordinate order: GoGIS uses {Lng, Lat} (longitude, latitude)
  4. Update method calls: Check method names in documentation

Breaking Changes

See CHANGELOG.md for detailed migration information between versions.

Contributing

We welcome contributions! Please see CONTRIBUTING.md for guidelines.

Quick Contribution Guide

  1. Fork the repository
  2. Create a feature branch
  3. Write tests for your changes
  4. Ensure all tests pass
  5. Submit a pull request

Roadmap

  • 3D Geometry Support - PointZ, LineStringZ, PolygonZ
  • Additional Geometry Types - MultiPoint, MultiLineString, MultiPolygon
  • Custom SRID Support - Beyond SRID 4326
  • Spatial Functions - Built-in Go implementations of common operations
  • GeoJSON Integration - Direct GeoJSON marshaling/unmarshaling
  • Performance Optimizations - Further query performance improvements

License

This project is licensed under the MIT License - see the LICENSE file for details.

Acknowledgments

  • PostGIS Team - For the excellent spatial database extension
  • GORM Team - For the fantastic ORM library
  • Go Community - For the great language and ecosystem

Support


GoGIS - Bringing PostGIS spatial capabilities to the Go ecosystem with GORM integration. Build location-aware applications with confidence! 🌍

About

PostGIS geometry types and spatial queries for Go and GORM.

Topics

Resources

License

Code of conduct

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors