aseigo
GeoSQL provides access to spatial data stored in databases such as PostGIS and Spatialite (SQLite3 extension for spatial data).
Spatial data is everywhere and mapping is a key feature in many applications. GeoSQL provides a portable and powerful toolbox for interacting with the spatial databases we store that data in.
Portable GIS functionality
GeoSQL provides access to hundreds of standard and non-standard spatial SQL functions to Ecto. This makes representing and interacting with spatial data easy in Ecto schemas and queries. Two-dimensional data as well as Z, M, and ZM variants are supported along with coordinate system support via SRIDs.
Functions are split out by standards and availability including GeoSQL.MM2 and GeoSQL.MM3. Beyond standards, GeoSQL.Common contains non-standard but widely implemented functions, and database-specific calls are also provided in e.g. the GeoSQL.PostGIS modules. Extensive support for multi-dimensional and topological queries is included. This makes it easy to see in your code which standards and backends a given piece of code requires to function.
Database-specific type extensions are provided along with utilities to e.g. decode geometries as needed.
The underlying geometry library supports WKT, WKB, and GeoJSON standards for easy data interchange. Other formats such as GML and KML are also supported via SQL functions.
defmodule MayApp.SpatialData do
use Ecto.Schema
use GeoSQL.MM2
use GeoSQL.QueryUtils
schema "spatial_data" do
field(:name, :string)
field(:geom, GeoSQL.Geometry)
field(:point, GeoSQL.Geometry.Point)
field(:pointz, GeoSQL.Geometry.PointZ)
field(:linestring, GeoSQL.Geometry.LineString)
field(:multipointzm, GeoSQL.Geometry.MultiPointZM)
field(:polygon, GeoSQL.Geometry.Polygon)
field(:multipolygon, GeoSQL.Geometry.MultiPolygon)
end
def features(repo) do
from(s in __MODULE__, select: s.geom)
|> repo.all()
end
def boundaries(repo) do
from(s in __MODULE__, select: MM2.boundary(s.geom))
|> repo.all()
|> QueryUtils.decode_geometry(repo)
end
end
High-level workflows
GeoSQL also provides high-level functionality, such as generating Mapbox Vector Tiles directly from a PostGIS database with a single function call. This makes it trivial to, for example, create vector map tile servers with a simple Plug:
defmodule MapTiles.VectorTilePlug do
@behaviour Plug
import Plug.Conn
alias GeoSQL.PostGIS.VectorTiles
def init(opts), do: opts
def call(%Plug.Conn{method: "GET", params: %{"x" => x, "y" => y, "z" => z}} = conn, _opts) do
z = Toolbelt.to_integer(z)
x = Toolbelt.to_integer(x)
y = Toolbelt.to_integer(y)
layers = [
%VectorTiles.Layer{
name: "pois",
source: "nodes",
columns: %{geometry: :geom, id: :node_id, tags: :tags}
}
]
result = VectorTiles.generate(MapTiles.Repo, z, x, y, layers, "osm")
conn
|> put_resp_content_type("application/vnd.mapbox-vector-tile")
|> resp(200, result)
|> send_resp()
|> halt()
end
end
More workflows will be provided as the library develops.
Design Goals
- Ease: fast to get started and hide complexity where possible.
- Portability: schemas and queries that work across databases, hiding the many (often trivial) differences between them.
- Completeness: extensive support for GIS SQL functions, not only the most common ones.
- Clarity: functions organized by their availability and standards compliance.
- Utility: out-of-the-box support for complete worfklows, to make complex tasks simple.
- Reliability: unit tested and deployed in real-world applications.
Trending in Announcing
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #library
- #deployment
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #code-sync
- #discussion
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #ai
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #blog-post
- #elixirconf-us
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #elixirconf-eu
- #processes
- #security
- #api
- #forms
- #performance










Showing Posts 1 to 10- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
aseigo
Some shout-outs and gratitude …
geo_postgisThe people at Felt who make awesome mapping products have long maintained the
geoandgeo_postgislibraries. I’ve even contributed a patch here or there as I’ve used both of those libraries over the years in various projects.GeoSQL began as a fork of
geo_postgiswhen my needs grew beyond whatgeo_postgisprovides in ways that were largely incompatible with it: spatialite, newer versions of PostGIS, high-level workflows … it’s grown far beyond that initial fork, but that is still where it started and I have immense gratitude for the work put intogeo_postgis.geometryI moved from the
geolibrary togeometrywhen I discovered thatgeodid not supportEMPTYgeometries. (I have submitted a PR to fix that, though!) While looking to see if there were other alternatives, I found the promisinggeometrylibrary.I wasn’t sure if it was still maintained as the last release was around 2 years ago, but thankfully it certainly was! The maintainer, @Marcus, was gracious enough to merge the PRs I showed up with and soon it could easily replace
geoin GeoSQL.What was really impressive was the performance, however: it uses around half the memory of
geoand is anywhere from 50% to 1000%+ faster thangeodepending on what one is doing with it. Consistently faster with a smaller memory footprint? Yes, please!Combined with the nice GeoJSON support and complete access to Z, ZM, and M variants of the geometry types, a big thanks to @Marcus for his work on
geometry!exqliteandecto_sqlite3Another key component was @warmwaffles’ SQLite3 libraries. I needed a way to extend the type support for SQLite3 databases with the Spatialite extension, and they brought in the necessary features to make that possible.
Now geometry types and spatial SQL queries work (nearly) as well with Spatialite as they do with PostGIS. I say “nearly” because SQLite is its own “fun” world of peculiar details. It’s why GeoSQL provides
decode_geomandwrap_wkbfunctions … but it works!The open source GIS community
The people working on things like PostGIS, Spatialite, proj, OSM, etc. get a fraction of the recognition they deserve in my opinion. They are doing amazing work in a very technical and (in terms of data) messy area of applied computer science: GIS. I’m constantly amazed by the work they do and the projects they work on and maintain for the whole world to benefit from.
aseigo
So .. where next?
Planned and/or already in progress
geometrylibrary does not yet support them. Types along with WTK and WKB encoding/decoding are needed, but we’re already on that and I hope to see that arrive in the coming weeks.… and after that?
geometryhas very good GeoJSON support, as do the database backends, in particular PostGIS. I suspect there are opportunities here for useful things to be created.… and things I don’t plan on working much on (but don’t let that stop you)
geometrylibrary already gives GeoSQL a fantastic foundation to build upon there, but maybe there are other things that can be done? The vector tiles are reasonable: on the full OSM extract of Switzerland, it spits out tiles in <4ms per tile on my dev machine, which I consider sufficient for the time being. There are janky-looking things going on with the Spatialite types module, but I’ve used that same approach previously in projects where I have done performance measurements and those things are so fast as to be ignorable.PRs welcome!
aseigo
I released v1.0.0 today. The major version change was due to a breaking change in the API, driven by further experience in production use. The library should be API stable from here; near-term future work will focus on curve geometries and continuing to expand the test suite.
Changelog
Migration: Replace all instances of
MM2andMM3withMM.MM.locate_alongwas missing a parameter placeholderaseigo
We’re up to version 1.3 now! Not wanting to spam the board with updates to this library, I held off updating this thread until there was something bigger to announce .. and with initial Geopackage support for both Ecto Schemas and Queries there is that something.
Thanks to @simagyari for pinging me on the relevant feature request from @asianfilm which led to the exploration of Geopackage support. Turned out to be a fair amount easier than expected.
Changelog from v1.0 to v1.3
GeoSQL.Geometry.GeopackageEcto type allows schemas to have geometry fields that are backed by Geopackage geometry blob columns in SQLite3 databases. This does have a runtime dependency on the SpatiaLite SQLite3 module, at least for now.GeoSQL.SpatiaLitefor use with Geopckage data:as_gpb,geom_from_gbp, andis_valid_gbp. These map to the Spatialite functions with the same names.aseigo
I just release v1.5.1. The functionality has not changed much since 1.3 but a lot of stability work has gone into things.
The 170+ SQL/MM (
GeoSQL.MM) and commonly implemented (GeoSQL.Common) GIS functions have full unit test coverage now, and along that path a number of bugs (some subtle) have been fixed. These two modules work with both SpatiaLite and PostGIS databases transparently, so that’s a significant amount of shared functionality that allows one to (mostly) just change a few lines in a configuration file and continue on.There are some places where the two implementations calculate results slightly differently, or where SpatiaLite returns a
nilresult and PostGIS will return anEMPTYgeometry. Thankfully those are the exceptions, and I’m considering ways to make handling those differences easier in future.There are some new conveniences, such as the
GeoSQL.Common.degreesandGeosQL.Common.radiansfunctions which make it easy to translate from one the other in SQL queries, avoiding roundtrips and having to get the math right or as expected by the databases.Some issues were discovered in the
geometrylibrary, as well, and patches have been pushed upstream for these.yendrisrogelio
Excellent library! This is another step towards expanding the geospatial/GIS ecosystem in Elixir. At my company, we’ve been working in this area and have tried to solve geospatial use cases with our own developments, often integrating libraries written in Rust/Rustler and Elixir. I appreciate the effort to continue down this path.
aseigo
Thanks for the encouraging words!
If you have any feedback, requests, or thoughts on how to continue improving the Elixir GIS story, please don’t hesitate to reach out.
IMHO, Elixir can provide a very compelling GIS toolkit. There’s a reasonable amount of Elixir used in the GIS industry, but the publicly available libraries and components are a bit of a jumble and a lot of gaps remain. I’d like to help close some of those gaps, hopefully with others in the community.
I will hopefully be able to release an Elixir library for accessing data hosted on ArcGIS systems sometime in the new year, which will go a ways to addressing one of those gaps.
Other areas that need attention (at least imo) include:
maplibrelibrary is piece of that puzzle, though it probably could use more documentation, examples, etc. and currently “only” handles the style document generation.yendrisrogelio
My company has been working on these cases for a while. We have a library called MaplibreX which is a wrapper of the MaplibreGl library, but with components written with LiveView and PhoenixComponents.
We have a vector tile server (TileXserver) that implements the Mapbox Vector Tile 2.1 specification and also other OGC Standards specifications (17 Conformance Classes)
OGC API - Tiles Part 1: Core (4 classes)
OGC API - Features Part 1: Core (2 classes)
OGC API - Features Part 2: CRS (1 class)
OGC API - Features Part 3: Filtering (2 classes)
OGC API - Processes Part 1: Core (3 classes)
NEW
TileMatrixSet (1 class)
Geoprocessing
Visualization
NEW
Data Sources
5 Geospatial Processes implemented with Rust NIFs:
Buffer: Create buffers around geometries
Simplify: Douglas-Peucker simplification
Centroid: Calculate centroids
Intersection: Spatial intersection testing
Convex Hull: Convex hull envelope
Synchronous and Asynchronous Execution
Job Management with GenServer and ETS
Tile Viewer: Interactive vector tiles viewer (MapLibre GL JS)
Processes Viewer: Web interface for geoprocessing
Auto-Style Generation: Automatic MapLibre style generation
Sprite & Font Support: Complete sprite and font support
PostgreSQL/PostGIS: Direct connection to spatial databases
MBTiles: MBTiles file support
Composite Sources: Combine multiple sources in layers
A prototype routing service similar to Mapbox Navigation, implemented with Rust (NIFs), Elixir/Phoenix, and MapLibre GL JS.
High-Performance Backend: Rust NIFs with optimized pathfinding algorithms
Modern Algorithms: Bidirectional A* for efficient routing
REST API: Endpoints compatible with the Mapbox-like API
Turn-by-Turn Navigation: Detailed navigation instructions
Interactive Frontend: Visualization with MapLibre GL JS
Intelligent Caching: Caching system for frequently used routes
Multiple Profiles: Driving, Walking, Cycling
Rust 1.70+: Routing algorithms and graph processing
Elixir 1.15+: Backend API and state management
Phoenix 1.8: Web framework
Rustler 0.34: Elixir ↔ Rust bridge (NIFs)
Petgraph: Graph library in Rust
MapLibre GL JS: Map visualization
Cachex: Distributed caching system
Geofencex
A high-performance geofencing system built with Elixir, Rust, and H3 hexagonal indexing. Similar to Tile38 but leveraging Uber’s H3 spatial indexing for superior performance and scalability.
Features
Core Spatial Engine (Rust NIF + H3)
REST API
Interactive Frontend (MapLibre GL)
H3 Hexagonal Indexing: Efficient spatial indexing using Uber’s H3 library
Rust NIFs via Rustler: High-performance native functions for geospatial operations
Sub-millisecond Queries: Optimized for fast spatial lookups
Object Management: Create, read, update, delete spatial objects
Geofence Management: Define circular and custom geofences
Spatial Queries:
Nearby queries (find objects within radius)
Within queries (find objects inside geofence)
Distance calculations
H3 cell information
Real-time Map Visualization: Interactive map powered by MapLibre GL
H3 Hexagon Rendering: Visualize geofences as beautiful hexagons
Object Tracking: Add and track spatial objects on the map
Distance Tool: Calculate distances between points
Cell Inspector: Click map to see H3 cell details
Technology Stack
Backend:
Elixir/Phoenix - Web framework and API layer
Rust - High-performance spatial operations
Rustler - Elixir NIF bindings
H3 (h3o) – Hexagonal hierarchical spatial indexing
Frontend:
MapLibre GL - Map rendering
H3-js - Client-side H3 operations
Tailwind CSS - Styling
Quorik
Intelligent Asset Management Platform
Quorik is a modern platform that combines comprehensive asset management with advanced Location Intelligence capabilities. Designed for organizations seeking to optimize their infrastructure maintenance, Quorik extracts valuable insights from data to facilitate strategic and operational decision-making. Use Rust, React, Inertia, Elixir, PostGIS
GeoArrow y GeoParquet support via Rustler
yendrisrogelio
We plan to release them when they are stable.
aseigo
That’s an astounding set of features!
I’ve done a fair amount of LiveView integration with OpenLayers in the past, and am currently working more with MapLibre. Having nice support for that in a re-usable library would be great, particularly being able to forward and consume client-side map interactions on the server. I’ve written such things for specific applications, but not yet something that is suitable for reuse in other applications.
If you do end up publishing that library, I’ll 100% be on the lookout for it
The tileserver sounds great, too. TBH I’m not a huge fan of many of the OGC specs, but many are widely used in industry, so … it is what it is
Having an Elixir server for that would be astoundingly cool.
The Geoefence and Geoparquet support also sounds incredibly nice. For routing, solutions do exist (e.g. Valhalla), even if they have their tradeoffs, but geofencing and geoparquet support from Elixir is not as easy.
I’ll definitely keep my eyes peeled for what you and your company are up to!