diff --git a/lib/microwaveprop/aprs.ex b/lib/microwaveprop/aprs.ex index 0a572c53..3c9e9412 100644 --- a/lib/microwaveprop/aprs.ex +++ b/lib/microwaveprop/aprs.ex @@ -15,6 +15,15 @@ defmodule Microwaveprop.Aprs do Tests run against a local `aprsme_test` database whose schema mirrors aprs.me's partitioned `packets` table; rows are inserted via raw SQL in a setup block under the `Ecto.Adapters.SQL.Sandbox`. + + > #### Error semantics {: .warning} + > + > Both queries call `Ecto.Adapters.SQL.query!/3` and will raise on + > connection or SQL failures. Today the only caller is the + > `Calibrate.Aprs144` mix task, where a hard exit is the right + > ergonomic. Async callers (`Task.async_stream`, LiveView + > `start_async`, etc.) MUST catch and log per the project's + > swallowed-error rule in CLAUDE.md. """ alias Ecto.Adapters.SQL @@ -73,8 +82,12 @@ defmodule Microwaveprop.Aprs do since = Keyword.get_lazy(opts, :since, fn -> DateTime.add(DateTime.utc_now(), -3600, :second) end) limit = Keyword.get(opts, :limit, 50_000) + # Force the bound to UTC so a non-UTC %DateTime{} doesn't silently + # match a wrong window after `to_naive` strips the tz tag. + naive_since = since |> DateTime.shift_zone!("Etc/UTC") |> DateTime.to_naive() + %Postgrex.Result{rows: rows} = - SQL.query!(AprsRepo, @recent_packets_sql, [DateTime.to_naive(since), limit]) + SQL.query!(AprsRepo, @recent_packets_sql, [naive_since, limit]) Enum.map(rows, &decode_packet_row/1) end @@ -100,17 +113,14 @@ defmodule Microwaveprop.Aprs do id: id, sender: sender, base_callsign: base_callsign, - lat: to_float(lat), - lon: to_float(lon), - path: path || "", - received_at: to_utc_datetime(received_at) + lat: Decimal.to_float(lat), + lon: Decimal.to_float(lon), + path: path, + received_at: DateTime.from_naive!(received_at, "Etc/UTC") } end defp to_float(%Decimal{} = d), do: Decimal.to_float(d) - defp to_float(n) when is_float(n), do: n - defp to_float(n) when is_integer(n), do: n * 1.0 defp to_utc_datetime(%NaiveDateTime{} = naive), do: DateTime.from_naive!(naive, "Etc/UTC") - defp to_utc_datetime(%DateTime{} = dt), do: dt end