Skip to main content

lib/quack_db/ecto/spatial.ex

if Code.ensure_loaded?(Ecto.Query.API) do
  defmodule QuackDB.Ecto.Spatial do
    @moduledoc """
    DuckDB spatial expression helpers for Ecto queries.

    These macros wrap DuckDB spatial `ST_*` functions in Ecto fragments. Load
    DuckDB's spatial extension before executing queries that use these helpers.
    Pinned `%Geo.*{}` values are supported when the optional `:geo` package is
    available.
    """

    defmacro point(x, y) do
      quote do
        fragment("ST_Point(?, ?)", unquote(x), unquote(y))
      end
    end

    defmacro as_wkb(geometry) do
      quote do
        fragment("ST_AsWKB(?)", unquote(geometry))
      end
    end

    defmacro as_hex_wkb(geometry) do
      quote do
        fragment("ST_AsHEXWKB(?)", unquote(geometry))
      end
    end

    defmacro as_text(geometry) do
      quote do
        fragment("ST_AsText(?)", unquote(geometry))
      end
    end

    defmacro as_geojson(geometry) do
      quote do
        fragment("ST_AsGeoJSON(?)", unquote(geometry))
      end
    end

    defmacro envelope(min_x, min_y, max_x, max_y) do
      quote do
        fragment(
          "ST_MakeEnvelope(?, ?, ?, ?)",
          unquote(min_x),
          unquote(min_y),
          unquote(max_x),
          unquote(max_y)
        )
      end
    end

    defmacro geom_from_wkb(wkb) do
      quote do
        fragment("ST_GeomFromWKB(?)", unquote(wkb))
      end
    end

    defmacro geom_from_text(wkt) do
      quote do
        fragment("ST_GeomFromText(?)", unquote(wkt))
      end
    end

    defmacro intersects(left, right) do
      quote do
        fragment("ST_Intersects(?, ?)", unquote(left), unquote(right))
      end
    end

    defmacro st_contains(left, right) do
      quote do
        fragment("ST_Contains(?, ?)", unquote(left), unquote(right))
      end
    end

    defmacro contains(left, right) do
      quote do
        fragment("ST_Contains(?, ?)", unquote(left), unquote(right))
      end
    end

    defmacro distance(left, right) do
      quote do
        fragment("ST_Distance(?, ?)", unquote(left), unquote(right))
      end
    end
  end
end