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),
nearby: distance(place.geom, ^%Geo.Point{coordinates: {1.0, 2.0}, srid: nil}) < 1_000
}
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.Serverfor local DuckDB Quack supervision- Ecto queries with
QuackDB.Ecto.Spatial - Ash resource structs at the HTTP boundary
- WMS-style
GetCapabilitiesandGetMaprequests
It is a small GeoJSON profile of WMS, not a complete OGC WMS implementation.