aseigo

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.

https://github.com/expothecary/geo_sql

Showing Posts 1 to 10

aseigo

aseigo OP

Some shout-outs and gratitude …

geo_postgis

The people at Felt who make awesome mapping products have long maintained the geo and geo_postgis libraries. 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_postgis when my needs grew beyond what geo_postgis provides 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 into geo_postgis.

geometry

I moved from the geo library to geometry when I discovered that geo did not support EMPTY geometries. (I have submitted a PR to fix that, though!) While looking to see if there were other alternatives, I found the promising geometry library.

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 geo in GeoSQL.

What was really impressive was the performance, however: it uses around half the memory of geo and is anywhere from 50% to 1000%+ faster than geo depending on what one is doing with it. Consistently faster with a smaller memory footprint? Yes, please! :slight_smile:

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!

exqlite and ecto_sqlite3

Another 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_geom and wrap_wkb functions … 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. :slight_smile:

aseigo

aseigo OP

So .. where next?

Planned and/or already in progress

  • More SQL functions, for starters While there are over 290 already supported in GeoSQL, there are dozens more I plan to add support for.
  • Curves. Functions for working with curves are already there, but the geometry library 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.
  • Expand the test suite. This is how I have found all sorts of strange edge cases and subtle variations in backends, and with this sort of macro-heavy code it’s pretty much a requirement. MM2 has very good coverage at this point, while MM3 and Common functions both have partial coverage. The PostGIS functions needs more work (though the vector tile functions have decent coverage). I’ll continue working to expand on these.

… and after that?

  • More workflows. The vector tile generation has been a godsend for projects I am currently working on, and I expect to add more “batteries included” modules over time.
  • GeoJSON .. maybe? geometry has 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)

  • Performance. I have done essentially zero performance related work. The geometry library 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.
  • More backends. I’d love to see more databases supported, such as MySQL which also has an implementation of the SQL/MM standard. My own needs are covered by PostGIS and Spatialite, however, so this will depend on other motivated individuals.

PRs welcome! :slight_smile:

aseigo

aseigo OP

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

  • Breaking changes
    • All SQL/MM functions were collapsed into a single MM module.
      Migration: Replace all instances of MM2 and MM3 with MM.
  • Improvements
    • Expanded unit test suite considerably, improved vector tile generation tests
  • Fixes
    • MM.locate_along was missing a parameter placeholder
aseigo

aseigo OP

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

  • Geopackage support!
    • The GeoSQL.Geometry.Geopackage Ecto 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.
    • Three functions were added to GeoSQL.SpatiaLite for use with Geopckage data: as_gpb, geom_from_gbp, and is_valid_gbp. These map to the Spatialite functions with the same names.
  • The test suite has grown considerably, with over 380 individual tests. This work will continue until all Ecto query macros have coverage.
  • Naming consistency improvements in docs, parameter naming, and internal APIs
aseigo

aseigo OP

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 nil result and PostGIS will return an EMPTY geometry. 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.degrees and GeosQL.Common.radians functions 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 geometry library, as well, and patches have been pushed upstream for these.

yendrisrogelio

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

aseigo OP

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:

  • support for OSM APIs: consuming OSM pbf, syncing local replicas with deltas, changeset APIs, etc. There is a library for Nominatim queries that works well enough, but that’s about the extent of OSM API support on hex.pm that I’m aware of.
  • support for routing software such as Valhalla (there are python and JS client libraries)
  • GeoParquet file support via Explorer
  • client-side map interactions patterns with Phoenix. A Phoenix component that wraps MabLibre and provides interaction patterns would be nice. The maplibre library is piece of that puzzle, though it probably could use more documentation, examples, etc. and currently “only” handles the style document generation.
yendrisrogelio

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)
    :white_check_mark: OGC API - Tiles Part 1: Core (4 classes)
    :white_check_mark: OGC API - Features Part 1: Core (2 classes)
    :white_check_mark: OGC API - Features Part 2: CRS (1 class)
    :white_check_mark: OGC API - Features Part 3: Filtering (2 classes)
    :white_check_mark: OGC API - Processes Part 1: Core (3 classes) :star: NEW
    :white_check_mark:TileMatrixSet (1 class)
    :hammer_and_wrench: Geoprocessing
    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
    :artist_palette: Visualization
    Tile Viewer: Interactive vector tiles viewer (MapLibre GL JS)
    Processes Viewer: Web interface for geoprocessing :star: NEW
    Auto-Style Generation: Automatic MapLibre style generation
    Sprite & Font Support: Complete sprite and font support
    :bar_chart: Data Sources
    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.

    :rocket: Features
    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
    :clipboard: Technology Stack
    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
    :white_check_mark: Core Spatial Engine (Rust NIF + H3)
    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
    :white_check_mark: REST API
    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
    :white_check_mark: Interactive Frontend (MapLibre GL)
    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

yendrisrogelio

We plan to release them when they are stable.

aseigo

aseigo OP

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 :slight_smile:

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 :slight_smile: 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!

Where Next? Top

Trending in Announcing Top

mudasobwa
I fully migrated to my own harness from Anthropic/Gemini and I think it’s time to share it. Welcome DSH, the DeepSeek Harness, fully writ...
New
kip
Localize is the next generation localisation library for Elixir. Think of it as ex_cldr version 3.0. The first version will be released ...
New
quatermain
Hello, I’m sharing my plugin here in forum after some time so it has time to mature and proof yourself. I use Claude Code daily on a pr...
New
gtcode
Aloha gang, There’s a new class of AI model out from TypeSafe. Jev is their flagship model. You can learn about it here: ...
New
LostKobrakai
I’ve recently created a small library phoenix_vite integrating the vite build tooling with phoenix. It provides an igniter.installer t...
New
danschultzer
I needed something like premailer for rails, and after searching, I decided to make an easy-to-use library to handle inline styles and co...
New
kraleppa
If you’ve ever had to debug a BEAM node you know it can be a painful process. Parsing raw data, or dealing with clutter often gets in the...
New

Other Trending Topics Top

dominicletz
Hey there, I haven’t seen a list of useful Elixir specific skills for the popular AI tools yet so I’m starting one here with my first. ...
New
raa-ziq
Hi everyone :waving_hand: I wanted to share something I’ve been building — NowBlind, a random chat app designed to help people discover ...
New
KristerV
Hey. Is there anyone here who creates agents in their apps? Not talking about using agents, but creating them. I’m finding it pretty diff...
New
OndrejValenta
(I just needed to vent somewhere and LinkedIn is full of hope, or hype, I’m not sure which exactly) AI dream has many faces, but general...
New
webofbits
With AI doing more of the implementation work, I’ve been wondering how much coding I should deliberately keep doing myself. My main conc...
#ai
New
CodeSync
Code BEAM Europe 2026 – Call for Talks is Open! We’re excited to announce that Code BEAM Europe 2026 is now open for talk submissions :t...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews