refactor(aprs): drop unreachable defensive branches, force UTC since
- decode_packet_row no longer guards Decimal.to_float / DateTime.from_naive
with passthrough clauses — Postgrex returns Decimal for numeric and
NaiveDateTime for timestamp without time zone, so the WHERE clause
filters out the only path that could have hit the alternate branches.
- recent_packets_with_paths shifts :since to UTC before to_naive so a
caller passing a non-UTC %DateTime{} doesn't silently match the wrong
window.
- moduledoc now documents that the module raises on connection/SQL
errors and is unsafe in async contexts without a catch.
This commit is contained in:
parent
65e97bec6b
commit
a7f5bd5f18
1 changed files with 18 additions and 8 deletions
|
|
@ -15,6 +15,15 @@ defmodule Microwaveprop.Aprs do
|
||||||
Tests run against a local `aprsme_test` database whose schema mirrors
|
Tests run against a local `aprsme_test` database whose schema mirrors
|
||||||
aprs.me's partitioned `packets` table; rows are inserted via raw SQL
|
aprs.me's partitioned `packets` table; rows are inserted via raw SQL
|
||||||
in a setup block under the `Ecto.Adapters.SQL.Sandbox`.
|
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
|
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)
|
since = Keyword.get_lazy(opts, :since, fn -> DateTime.add(DateTime.utc_now(), -3600, :second) end)
|
||||||
limit = Keyword.get(opts, :limit, 50_000)
|
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} =
|
%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)
|
Enum.map(rows, &decode_packet_row/1)
|
||||||
end
|
end
|
||||||
|
|
@ -100,17 +113,14 @@ defmodule Microwaveprop.Aprs do
|
||||||
id: id,
|
id: id,
|
||||||
sender: sender,
|
sender: sender,
|
||||||
base_callsign: base_callsign,
|
base_callsign: base_callsign,
|
||||||
lat: to_float(lat),
|
lat: Decimal.to_float(lat),
|
||||||
lon: to_float(lon),
|
lon: Decimal.to_float(lon),
|
||||||
path: path || "",
|
path: path,
|
||||||
received_at: to_utc_datetime(received_at)
|
received_at: DateTime.from_naive!(received_at, "Etc/UTC")
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
defp to_float(%Decimal{} = d), do: Decimal.to_float(d)
|
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(%NaiveDateTime{} = naive), do: DateTime.from_naive!(naive, "Etc/UTC")
|
||||||
defp to_utc_datetime(%DateTime{} = dt), do: dt
|
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue