QuackDB includes helpers for DuckDB's spatial extension and optional conversion between DuckDB GEOMETRY values and Elixir Geo structs.

Load DuckDB spatial

alias QuackDB.Spatial

QuackDB.query!(conn, Spatial.load())

For a supervised local demo server, use QuackDB.Server and then load the extension on the client connection.

Ecto spatial helpers

QuackDB.Ecto.Spatial wraps DuckDB spatial functions in Ecto fragments so spatial expressions can stay in normal Ecto queries:

use QuackDB.Ecto

query =
  from place in "places",
    where: intersects(place.geom, envelope(^min_x, ^min_y, ^max_x, ^max_y)),
    order_by: place.id,
    select: %{
      id: place.id,
      name: place.name,
      wkt: as_text(place.geom),
      geojson: as_geojson(place.geom)
    }

MyApp.AnalyticsRepo.all(query)

For creating geometry expressions in Ecto queries:

from place in "places",
  where: distance(place.geom, point(^lon, ^lat)) < ^meters,
  select: %{id: place.id, geometry: as_wkb(place.geom)}

Available helpers include point/2, as_wkb/1, as_hex_wkb/1, as_text/1, as_geojson/1, geom_from_wkb/1, geom_from_text/1, envelope/4, intersects/2, contains/2, and distance/2.

DuckDB GEOMETRY values decode as WKB-compatible binaries.

Optional Geo conversion

Add the optional :geo package when you want Elixir geometry structs:

{:geo, "~> 4.1"}

Then convert decoded WKB bytes:

alias QuackDB.Geometry

geo = Geometry.to_geo!(wkb)
wkb = Geometry.from_geo!(geo)

%Geo.*{} structs can also be passed as SQL/Ecto parameters when :geo is available.

WMS-style example

examples/spatial_wms/ is a minimal Ash + Ecto + Plug/Bandit app that serves DuckDB Spatial rows through a WMS-like GeoJSON endpoint.

It demonstrates:

  • QuackDB.Server for local DuckDB Quack supervision
  • Ecto queries with QuackDB.Ecto.Spatial
  • Ash resource structs at the HTTP boundary
  • WMS-style GetCapabilities and GetMap requests

It is a small GeoJSON profile of WMS, not a complete OGC WMS implementation.