defmodule MoundHunters.Repo do @moduledoc """ Mnesia database helpers for tiles and geometries. """ require Logger # Tile statuses @type tile_status :: :processing | :ready | :error @doc """ Get a tile by ID from Mnesia. """ def get_tile(tile_id) do case :mnesia.transaction(fn -> :mnesia.read(:tiles, tile_id) end) do {:atomic, [tile]} -> {:ok, tile_to_map(tile)} {:atomic, []} -> {:error, :not_found} {:aborted, reason} -> {:error, reason} end end @doc """ Insert or update a tile record. """ def upsert_tile(attrs) do tile_id = Map.fetch!(attrs, :id) now = System.system_time(:second) tile_record = {:tiles, tile_id, Map.get(attrs, :min_lat), Map.get(attrs, :max_lat), Map.get(attrs, :min_lng), Map.get(attrs, :max_lng), Map.get(attrs, :status), Map.get(attrs, :error_message), Map.get(attrs, :created_at, now), now} case :mnesia.transaction(fn -> :mnesia.write(tile_record) end) do {:atomic, :ok} -> {:ok, tile_to_map(tile_record)} {:aborted, reason} -> {:error, reason} end end @doc """ Get a shared geometry by ID. """ def get_geometry(geometry_id) do case :mnesia.transaction(fn -> :mnesia.read(:geometries, geometry_id) end) do {:atomic, [geometry]} -> {:ok, geometry_to_map(geometry)} {:atomic, []} -> {:error, :not_found} {:aborted, reason} -> {:error, reason} end end @doc """ Create a new shared geometry. """ def create_geometry(geojson) do geometry_id = generate_id() now = System.system_time(:second) geometry_record = {:geometries, geometry_id, geojson, now} case :mnesia.transaction(fn -> :mnesia.write(geometry_record) end) do {:atomic, :ok} -> {:ok, %{id: geometry_id}} {:aborted, reason} -> {:error, reason} end end # Convert Mnesia tile record to map defp tile_to_map( {:tiles, id, min_lat, max_lat, min_lng, max_lng, status, error_message, created_at, updated_at} ) do %{ id: id, min_lat: min_lat, max_lat: max_lat, min_lng: min_lng, max_lng: max_lng, status: status, error_message: error_message, created_at: created_at, updated_at: updated_at } end # Convert Mnesia geometry record to map defp geometry_to_map({:geometries, id, geojson, created_at}) do %{ id: id, geojson: geojson, created_at: created_at } end # Generate random 8-character alphanumeric ID defp generate_id do :crypto.strong_rand_bytes(6) |> Base.url_encode64(padding: false) |> binary_part(0, 8) end end