diff --git a/lib/microwaveprop/radio/contact.ex b/lib/microwaveprop/radio/contact.ex index 43b40d29..f5b2f570 100644 --- a/lib/microwaveprop/radio/contact.ex +++ b/lib/microwaveprop/radio/contact.ex @@ -9,7 +9,7 @@ defmodule Microwaveprop.Radio.Contact do @primary_key {:id, :binary_id, autogenerate: true} @foreign_key_type :binary_id - schema "qsos" do + schema "contacts" do field :station1, :string field :station2, :string field :qso_timestamp, :utc_datetime diff --git a/lib/microwaveprop/terrain.ex b/lib/microwaveprop/terrain.ex index e36bd6eb..558052b5 100644 --- a/lib/microwaveprop/terrain.ex +++ b/lib/microwaveprop/terrain.ex @@ -10,19 +10,19 @@ defmodule Microwaveprop.Terrain do %TerrainProfile{} |> TerrainProfile.changeset(attrs) |> Repo.insert( - on_conflict: {:replace_all_except, [:id, :qso_id, :inserted_at]}, - conflict_target: [:qso_id], + on_conflict: {:replace_all_except, [:id, :contact_id, :inserted_at]}, + conflict_target: [:contact_id], returning: true ) end - def get_terrain_profile(qso_id) do - Repo.get_by(TerrainProfile, qso_id: qso_id) + def get_terrain_profile(contact_id) do + Repo.get_by(TerrainProfile, contact_id: contact_id) end - def has_terrain_profile?(qso_id) do + def has_terrain_profile?(contact_id) do TerrainProfile - |> where([t], t.qso_id == ^qso_id) + |> where([t], t.contact_id == ^contact_id) |> Repo.exists?() end end diff --git a/lib/microwaveprop/terrain/terrain_profile.ex b/lib/microwaveprop/terrain/terrain_profile.ex index ccb46aea..5373ec4b 100644 --- a/lib/microwaveprop/terrain/terrain_profile.ex +++ b/lib/microwaveprop/terrain/terrain_profile.ex @@ -8,7 +8,7 @@ defmodule Microwaveprop.Terrain.TerrainProfile do @foreign_key_type :binary_id schema "terrain_profiles" do - belongs_to :contact, Microwaveprop.Radio.Contact, foreign_key: :qso_id + belongs_to :contact, Microwaveprop.Radio.Contact, foreign_key: :contact_id field :sample_count, :integer field :path_points, {:array, :map} field :max_elevation_m, :float @@ -21,14 +21,14 @@ defmodule Microwaveprop.Terrain.TerrainProfile do timestamps(type: :utc_datetime) end - @required_fields ~w(qso_id sample_count path_points verdict)a + @required_fields ~w(contact_id sample_count path_points verdict)a @optional_fields ~w(max_elevation_m min_clearance_m diffraction_db fresnel_hit_count obstructed_count)a def changeset(profile, attrs) do profile |> cast(attrs, @required_fields ++ @optional_fields) |> validate_required(@required_fields) - |> foreign_key_constraint(:qso_id) - |> unique_constraint([:qso_id]) + |> foreign_key_constraint(:contact_id) + |> unique_constraint([:contact_id]) end end diff --git a/lib/microwaveprop/workers/contact_weather_enqueue_worker.ex b/lib/microwaveprop/workers/contact_weather_enqueue_worker.ex index 2e694acf..76e2c6e5 100644 --- a/lib/microwaveprop/workers/contact_weather_enqueue_worker.ex +++ b/lib/microwaveprop/workers/contact_weather_enqueue_worker.ex @@ -114,7 +114,7 @@ defmodule Microwaveprop.Workers.ContactWeatherEnqueueWorker do contacts |> Enum.filter(fn contact -> contact.pos1 && contact.pos2 end) |> Enum.map(fn contact -> - TerrainProfileWorker.new(%{"qso_id" => contact.id}) + TerrainProfileWorker.new(%{"contact_id" => contact.id}) end) |> Enum.uniq_by(fn changeset -> changeset.changes.args end) end diff --git a/lib/microwaveprop/workers/terrain_profile_worker.ex b/lib/microwaveprop/workers/terrain_profile_worker.ex index b435c312..54cfa8eb 100644 --- a/lib/microwaveprop/workers/terrain_profile_worker.ex +++ b/lib/microwaveprop/workers/terrain_profile_worker.ex @@ -14,11 +14,11 @@ defmodule Microwaveprop.Workers.TerrainProfileWorker do end @impl Oban.Worker - def perform(%Oban.Job{args: %{"qso_id" => qso_id}}) do - if Terrain.has_terrain_profile?(qso_id) do + def perform(%Oban.Job{args: %{"contact_id" => contact_id}}) do + if Terrain.has_terrain_profile?(contact_id) do :ok else - contact = Radio.get_contact!(qso_id) + contact = Radio.get_contact!(contact_id) with %{"lat" => lat1} <- contact.pos1, lon1 when is_number(lon1) <- contact.pos1["lon"] || contact.pos1["lng"], @@ -46,7 +46,7 @@ defmodule Microwaveprop.Workers.TerrainProfileWorker do end) Terrain.upsert_terrain_profile(%{ - qso_id: qso_id, + contact_id: contact_id, sample_count: length(profile), path_points: path_points, max_elevation_m: analysis.max_elevation_m, @@ -57,12 +57,12 @@ defmodule Microwaveprop.Workers.TerrainProfileWorker do verdict: analysis.verdict }) - Radio.set_enrichment_status!([qso_id], :terrain_status, :complete) + Radio.set_enrichment_status!([contact_id], :terrain_status, :complete) Phoenix.PubSub.broadcast( Microwaveprop.PubSub, - "contact_enrichment:#{qso_id}", - {:terrain_ready, qso_id} + "contact_enrichment:#{contact_id}", + {:terrain_ready, contact_id} ) :ok @@ -72,7 +72,7 @@ defmodule Microwaveprop.Workers.TerrainProfileWorker do end else _ -> - Radio.set_enrichment_status!([qso_id], :terrain_status, :unavailable) + Radio.set_enrichment_status!([contact_id], :terrain_status, :unavailable) :ok end end diff --git a/lib/microwaveprop_web/live/backfill_live.ex b/lib/microwaveprop_web/live/backfill_live.ex index 36ac70ff..fee4ed72 100644 --- a/lib/microwaveprop_web/live/backfill_live.ex +++ b/lib/microwaveprop_web/live/backfill_live.ex @@ -217,7 +217,7 @@ defmodule MicrowavepropWeb.BackfillLive do obs_count = Map.get(table_counts, "surface_observations", 0) sounding_count = Map.get(table_counts, "soundings", 0) iemre_count = Map.get(table_counts, "iemre_observations", 0) - contact_count = max(Map.get(table_counts, "qsos", 0), 1) + contact_count = max(Map.get(table_counts, "contacts", 0), 1) %{ db_size: format_bytes(db_bytes), diff --git a/lib/microwaveprop_web/live/contact_live/show.ex b/lib/microwaveprop_web/live/contact_live/show.ex index 661b55e9..deb66b85 100644 --- a/lib/microwaveprop_web/live/contact_live/show.ex +++ b/lib/microwaveprop_web/live/contact_live/show.ex @@ -117,7 +117,7 @@ defmodule MicrowavepropWeb.ContactLive.Show do end @impl true - def handle_info({:terrain_ready, _qso_id}, socket) do + def handle_info({:terrain_ready, _contact_id}, socket) do contact = %{socket.assigns.contact | terrain_status: :complete} terrain = Terrain.get_terrain_profile(contact.id) soundings = socket.assigns.soundings @@ -287,7 +287,7 @@ defmodule MicrowavepropWeb.ContactLive.Show do defp maybe_enqueue_terrain(nil, contact) do if contact.pos1 && contact.pos2 && contact.terrain_status in [:pending, :failed, :queued] do - Oban.insert(TerrainProfileWorker.new(%{"qso_id" => contact.id})) + Oban.insert(TerrainProfileWorker.new(%{"contact_id" => contact.id})) Radio.set_enrichment_status!([contact.id], :terrain_status, :queued) %{contact | terrain_status: :queued} else diff --git a/priv/repo/migrations/20260402204809_rename_qsos_to_contacts.exs b/priv/repo/migrations/20260402204809_rename_qsos_to_contacts.exs new file mode 100644 index 00000000..97e8e00d --- /dev/null +++ b/priv/repo/migrations/20260402204809_rename_qsos_to_contacts.exs @@ -0,0 +1,47 @@ +defmodule Microwaveprop.Repo.Migrations.RenameQsosToContacts do + use Ecto.Migration + + def change do + rename table(:qsos), to: table(:contacts) + + rename table(:terrain_profiles), :qso_id, to: :contact_id + + # Rename indexes that reference the old table name + execute "ALTER INDEX IF EXISTS qsos_pkey RENAME TO contacts_pkey", + "ALTER INDEX IF EXISTS contacts_pkey RENAME TO qsos_pkey" + + execute "ALTER INDEX IF EXISTS qsos_band_index RENAME TO contacts_band_index", + "ALTER INDEX IF EXISTS contacts_band_index RENAME TO qsos_band_index" + + execute "ALTER INDEX IF EXISTS qsos_distance_km_index RENAME TO contacts_distance_km_index", + "ALTER INDEX IF EXISTS contacts_distance_km_index RENAME TO qsos_distance_km_index" + + execute "ALTER INDEX IF EXISTS qsos_qso_timestamp_index RENAME TO contacts_qso_timestamp_index", + "ALTER INDEX IF EXISTS contacts_qso_timestamp_index RENAME TO qsos_qso_timestamp_index" + + execute "ALTER INDEX IF EXISTS qsos_station1_trgm_index RENAME TO contacts_station1_trgm_index", + "ALTER INDEX IF EXISTS contacts_station1_trgm_index RENAME TO qsos_station1_trgm_index" + + execute "ALTER INDEX IF EXISTS qsos_station2_trgm_index RENAME TO contacts_station2_trgm_index", + "ALTER INDEX IF EXISTS contacts_station2_trgm_index RENAME TO qsos_station2_trgm_index" + + execute "ALTER INDEX IF EXISTS qsos_hrrr_status_pending_index RENAME TO contacts_hrrr_status_pending_index", + "ALTER INDEX IF EXISTS contacts_hrrr_status_pending_index RENAME TO qsos_hrrr_status_pending_index" + + execute "ALTER INDEX IF EXISTS qsos_weather_status_pending_index RENAME TO contacts_weather_status_pending_index", + "ALTER INDEX IF EXISTS contacts_weather_status_pending_index RENAME TO qsos_weather_status_pending_index" + + execute "ALTER INDEX IF EXISTS qsos_terrain_status_pending_index RENAME TO contacts_terrain_status_pending_index", + "ALTER INDEX IF EXISTS contacts_terrain_status_pending_index RENAME TO qsos_terrain_status_pending_index" + + execute "ALTER INDEX IF EXISTS qsos_iemre_status_pending_index RENAME TO contacts_iemre_status_pending_index", + "ALTER INDEX IF EXISTS contacts_iemre_status_pending_index RENAME TO qsos_iemre_status_pending_index" + + # Rename terrain_profiles foreign key constraint + execute "ALTER TABLE terrain_profiles RENAME CONSTRAINT terrain_profiles_qso_id_fkey TO terrain_profiles_contact_id_fkey", + "ALTER TABLE terrain_profiles RENAME CONSTRAINT terrain_profiles_contact_id_fkey TO terrain_profiles_qso_id_fkey" + + execute "ALTER INDEX IF EXISTS terrain_profiles_qso_id_index RENAME TO terrain_profiles_contact_id_index", + "ALTER INDEX IF EXISTS terrain_profiles_contact_id_index RENAME TO terrain_profiles_qso_id_index" + end +end diff --git a/test/microwaveprop/terrain/terrain_profile_test.exs b/test/microwaveprop/terrain/terrain_profile_test.exs index 7e5f227b..96f6f16b 100644 --- a/test/microwaveprop/terrain/terrain_profile_test.exs +++ b/test/microwaveprop/terrain/terrain_profile_test.exs @@ -28,7 +28,7 @@ defmodule Microwaveprop.Terrain.TerrainProfileTest do contact = create_contact() attrs = %{ - qso_id: contact.id, + contact_id: contact.id, sample_count: 65, path_points: [%{"lat" => 32.9, "lon" => -97.0, "elev" => 200.0, "dist_km" => 0.0}], verdict: "CLEAR" @@ -43,7 +43,7 @@ defmodule Microwaveprop.Terrain.TerrainProfileTest do refute changeset.valid? errors = errors_on(changeset) - assert errors[:qso_id] + assert errors[:contact_id] assert errors[:sample_count] assert errors[:path_points] assert errors[:verdict] @@ -53,7 +53,7 @@ defmodule Microwaveprop.Terrain.TerrainProfileTest do contact = create_contact() attrs = %{ - qso_id: contact.id, + contact_id: contact.id, sample_count: 65, path_points: [%{"lat" => 32.9, "lon" => -97.0, "elev" => 200.0, "dist_km" => 0.0}], verdict: "BLOCKED", @@ -68,11 +68,11 @@ defmodule Microwaveprop.Terrain.TerrainProfileTest do assert changeset.valid? end - test "enforces unique qso_id constraint on insert" do + test "enforces unique contact_id constraint on insert" do contact = create_contact() attrs = %{ - qso_id: contact.id, + contact_id: contact.id, sample_count: 65, path_points: [], verdict: "CLEAR" @@ -88,7 +88,7 @@ defmodule Microwaveprop.Terrain.TerrainProfileTest do |> TerrainProfile.changeset(attrs) |> Repo.insert() - assert errors_on(changeset)[:qso_id] + assert errors_on(changeset)[:contact_id] end end end diff --git a/test/microwaveprop/terrain_test.exs b/test/microwaveprop/terrain_test.exs index 342e64c3..77dfbb83 100644 --- a/test/microwaveprop/terrain_test.exs +++ b/test/microwaveprop/terrain_test.exs @@ -25,7 +25,7 @@ defmodule Microwaveprop.TerrainTest do defp terrain_attrs(contact) do %{ - qso_id: contact.id, + contact_id: contact.id, sample_count: 65, path_points: [ %{"lat" => 32.9, "lon" => -97.0, "elev" => 200.0, "dist_km" => 0.0}, @@ -46,12 +46,12 @@ defmodule Microwaveprop.TerrainTest do attrs = terrain_attrs(contact) assert {:ok, profile} = Terrain.upsert_terrain_profile(attrs) - assert profile.qso_id == contact.id + assert profile.contact_id == contact.id assert profile.sample_count == 65 assert profile.verdict == "CLEAR" end - test "upserts on conflict (same qso_id)" do + test "upserts on conflict (same contact_id)" do contact = create_contact() attrs = terrain_attrs(contact) @@ -71,7 +71,7 @@ defmodule Microwaveprop.TerrainTest do {:ok, _} = Terrain.upsert_terrain_profile(terrain_attrs(contact)) profile = Terrain.get_terrain_profile(contact.id) - assert profile.qso_id == contact.id + assert profile.contact_id == contact.id end test "returns nil when no profile exists" do diff --git a/test/microwaveprop/workers/contact_weather_enqueue_worker_test.exs b/test/microwaveprop/workers/contact_weather_enqueue_worker_test.exs index c8d92a55..d3f00bc2 100644 --- a/test/microwaveprop/workers/contact_weather_enqueue_worker_test.exs +++ b/test/microwaveprop/workers/contact_weather_enqueue_worker_test.exs @@ -370,10 +370,10 @@ defmodule Microwaveprop.Workers.ContactWeatherEnqueueWorkerTest do assert length(jobs) == 1 job = hd(jobs) - assert job.changes.args["qso_id"] == contact.id + assert job.changes.args["contact_id"] == contact.id end - test "deduplicates by qso_id" do + test "deduplicates by contact_id" do contact = create_contact() jobs = ContactWeatherEnqueueWorker.build_terrain_jobs([contact, contact]) diff --git a/test/microwaveprop/workers/terrain_profile_worker_test.exs b/test/microwaveprop/workers/terrain_profile_worker_test.exs index 68c1a768..38e161e6 100644 --- a/test/microwaveprop/workers/terrain_profile_worker_test.exs +++ b/test/microwaveprop/workers/terrain_profile_worker_test.exs @@ -42,7 +42,7 @@ defmodule Microwaveprop.Workers.TerrainProfileWorkerTest do refute Terrain.has_terrain_profile?(contact.id) - job = TerrainProfileWorker.new(%{"qso_id" => contact.id}) + job = TerrainProfileWorker.new(%{"contact_id" => contact.id}) assert :ok = TerrainProfileWorker.perform(%Oban.Job{args: job.changes.args}) assert Terrain.has_terrain_profile?(contact.id) @@ -58,13 +58,13 @@ defmodule Microwaveprop.Workers.TerrainProfileWorkerTest do {:ok, _} = Terrain.upsert_terrain_profile(%{ - qso_id: contact.id, + contact_id: contact.id, sample_count: 65, path_points: [], verdict: "CLEAR" }) - job = TerrainProfileWorker.new(%{"qso_id" => contact.id}) + job = TerrainProfileWorker.new(%{"contact_id" => contact.id}) assert :ok = TerrainProfileWorker.perform(%Oban.Job{args: job.changes.args}) end @@ -75,7 +75,7 @@ defmodule Microwaveprop.Workers.TerrainProfileWorkerTest do contact = create_contact() - job = TerrainProfileWorker.new(%{"qso_id" => contact.id}) + job = TerrainProfileWorker.new(%{"contact_id" => contact.id}) assert {:error, _} = TerrainProfileWorker.perform(%Oban.Job{args: job.changes.args}) refute Terrain.has_terrain_profile?(contact.id) @@ -85,7 +85,7 @@ defmodule Microwaveprop.Workers.TerrainProfileWorkerTest do stub_elevation_api() contact = create_contact(%{band: Decimal.new("10368")}) - job = TerrainProfileWorker.new(%{"qso_id" => contact.id}) + job = TerrainProfileWorker.new(%{"contact_id" => contact.id}) assert :ok = TerrainProfileWorker.perform(%Oban.Job{args: job.changes.args}) profile = Terrain.get_terrain_profile(contact.id)