prop/priv/repo/migrations/20260401154846_partition_hrrr_profiles.exs
Graham McIntire ea96c93e2d
Rename QSO to Contact in UI, add higher bands, improve submit page
- All menus and UI text now say Contacts instead of QSOs
- Add 68, 122, 134, 241 GHz bands to submit form and validation
- Add info box on submit page explaining why contacts matter
- Larger submit button with icon
- Make HRRR partition migration idempotent for partial re-runs
2026-04-01 12:28:24 -05:00

144 lines
5.1 KiB
Elixir

defmodule Microwaveprop.Repo.Migrations.PartitionHrrrProfiles do
use Ecto.Migration
@disable_ddl_transaction true
@disable_migration_lock true
def up do
# Clean up any partial previous run: drop the partitioned table and orphaned
# partition tables, then rename _old back so we can start fresh.
execute """
DO $$
DECLARE
tbl text;
BEGIN
IF EXISTS (SELECT 1 FROM pg_tables WHERE tablename = 'hrrr_profiles_old' AND schemaname = 'public') THEN
DROP TABLE IF EXISTS hrrr_profiles CASCADE;
-- Drop orphaned partition tables left behind after CASCADE
FOR tbl IN
SELECT tablename FROM pg_tables
WHERE schemaname = 'public' AND tablename LIKE 'hrrr_profiles_%'
AND tablename != 'hrrr_profiles_old'
LOOP
EXECUTE 'DROP TABLE IF EXISTS ' || tbl || ' CASCADE';
END LOOP;
ALTER TABLE hrrr_profiles_old RENAME TO hrrr_profiles;
END IF;
END $$
"""
# 1. Rename old table
execute "ALTER TABLE hrrr_profiles RENAME TO hrrr_profiles_old"
# 2. Create partitioned table with identical schema
execute """
CREATE TABLE hrrr_profiles (
id uuid NOT NULL DEFAULT gen_random_uuid(),
valid_time timestamp(0) WITHOUT TIME ZONE NOT NULL,
lat double precision NOT NULL,
lon double precision NOT NULL,
run_time timestamp(0) WITHOUT TIME ZONE,
profile jsonb[] DEFAULT ARRAY[]::jsonb[],
hpbl_m double precision,
pwat_mm double precision,
surface_temp_c double precision,
surface_dewpoint_c double precision,
surface_pressure_mb double precision,
surface_refractivity double precision,
min_refractivity_gradient double precision,
ducting_detected boolean DEFAULT false,
duct_characteristics jsonb[],
inserted_at timestamp(0) WITHOUT TIME ZONE NOT NULL,
updated_at timestamp(0) WITHOUT TIME ZONE NOT NULL
) PARTITION BY RANGE (valid_time)
"""
# 3. Create partitions
partitions = [
{"2016-01-01", "2017-01-01"},
{"2017-01-01", "2018-01-01"},
{"2018-01-01", "2018-07-01"},
{"2018-07-01", "2019-01-01"},
{"2019-01-01", "2019-07-01"},
{"2019-07-01", "2019-10-01"},
{"2019-10-01", "2020-01-01"},
{"2020-01-01", "2020-07-01"},
{"2020-07-01", "2020-10-01"},
{"2020-10-01", "2021-01-01"},
{"2021-01-01", "2021-07-01"},
{"2021-07-01", "2021-10-01"},
{"2021-10-01", "2022-01-01"},
{"2022-01-01", "2022-07-01"},
{"2022-07-01", "2022-10-01"},
{"2022-10-01", "2023-01-01"},
{"2023-01-01", "2023-07-01"},
{"2023-07-01", "2023-10-01"},
{"2023-10-01", "2024-01-01"},
{"2024-01-01", "2024-07-01"},
{"2024-07-01", "2024-10-01"},
{"2024-10-01", "2025-01-01"},
{"2025-01-01", "2025-07-01"},
{"2025-07-01", "2026-01-01"},
{"2026-01-01", "2026-04-01"},
{"2026-04-01", "2026-07-01"},
{"2026-07-01", "2026-10-01"},
{"2026-10-01", "2027-01-01"},
{"2027-01-01", "2027-07-01"},
{"2027-07-01", "2028-01-01"}
]
for {from_date, to_date} <- partitions do
suffix = from_date |> String.replace("-", "_") |> String.slice(0..6)
execute """
CREATE TABLE hrrr_profiles_#{suffix} PARTITION OF hrrr_profiles
FOR VALUES FROM ('#{from_date}') TO ('#{to_date}')
"""
end
# 4. Indexes on partitioned table
execute "DROP INDEX IF EXISTS hrrr_profiles_lat_lon_valid_time_index"
execute "DROP INDEX IF EXISTS hrrr_profiles_valid_time_index"
execute "CREATE UNIQUE INDEX hrrr_profiles_lat_lon_valid_time_index ON hrrr_profiles (lat, lon, valid_time)"
execute "CREATE INDEX hrrr_profiles_valid_time_index ON hrrr_profiles (valid_time)"
# 5. Migrate data
execute "INSERT INTO hrrr_profiles SELECT * FROM hrrr_profiles_old"
# 6. Drop old table
execute "DROP TABLE hrrr_profiles_old"
end
def down do
execute """
CREATE TABLE hrrr_profiles_flat (
id uuid NOT NULL,
valid_time timestamp(0) WITHOUT TIME ZONE NOT NULL,
lat double precision NOT NULL,
lon double precision NOT NULL,
run_time timestamp(0) WITHOUT TIME ZONE,
profile jsonb[] DEFAULT ARRAY[]::jsonb[],
hpbl_m double precision,
pwat_mm double precision,
surface_temp_c double precision,
surface_dewpoint_c double precision,
surface_pressure_mb double precision,
surface_refractivity double precision,
min_refractivity_gradient double precision,
ducting_detected boolean DEFAULT false,
duct_characteristics jsonb[],
inserted_at timestamp(0) WITHOUT TIME ZONE NOT NULL,
updated_at timestamp(0) WITHOUT TIME ZONE NOT NULL,
PRIMARY KEY (id)
)
"""
execute "INSERT INTO hrrr_profiles_flat SELECT * FROM hrrr_profiles"
execute "DROP TABLE hrrr_profiles"
execute "ALTER TABLE hrrr_profiles_flat RENAME TO hrrr_profiles"
execute "CREATE UNIQUE INDEX hrrr_profiles_lat_lon_valid_time_index ON hrrr_profiles (lat, lon, valid_time)"
execute "CREATE INDEX hrrr_profiles_valid_time_index ON hrrr_profiles (valid_time)"
end
end