defmodule QuackDB.Geometry do
@moduledoc """
Helpers for DuckDB spatial `GEOMETRY` values.
DuckDB `GEOMETRY` values decode from Quack as WKB-compatible binaries. When
the optional `:geo` package is installed, this module can convert those
binaries to and from `Geo` structs.
"""
if Code.ensure_loaded?(Geo.WKB) do
@doc "Decodes WKB-compatible geometry bytes into a `Geo` struct."
@spec decode_wkb(binary()) :: {:ok, struct()} | {:error, term()}
def decode_wkb(wkb) when is_binary(wkb) do
wkb
|> Base.encode16(case: :upper)
|> Geo.WKB.decode()
end
@doc "Decodes WKB-compatible geometry bytes into a `Geo` struct or raises."
@spec decode_wkb!(binary()) :: struct()
def decode_wkb!(wkb) when is_binary(wkb) do
wkb
|> Base.encode16(case: :upper)
|> Geo.WKB.decode!()
end
@doc "Alias for `decode_wkb/1`."
@spec to_geo(binary()) :: {:ok, struct()} | {:error, term()}
def to_geo(wkb), do: decode_wkb(wkb)
@doc "Alias for `decode_wkb!/1`."
@spec to_geo!(binary()) :: struct()
def to_geo!(wkb), do: decode_wkb!(wkb)
@doc "Encodes a `Geo` struct into WKB bytes accepted by DuckDB spatial functions."
@spec encode_wkb!(struct()) :: binary()
def encode_wkb!(geometry) do
geometry
|> Geo.WKB.encode!(:ndr)
|> Base.decode16!(case: :mixed)
end
@doc "Alias for `encode_wkb!/1`."
@spec from_geo!(struct()) :: binary()
def from_geo!(geometry), do: encode_wkb!(geometry)
end
end