diff --git a/priv/repo/migrations/20250719202358_add_truncate_reset_for_packet_counter.exs b/priv/repo/migrations/20250719202358_add_truncate_reset_for_packet_counter.exs new file mode 100644 index 0000000..7031ba5 --- /dev/null +++ b/priv/repo/migrations/20250719202358_add_truncate_reset_for_packet_counter.exs @@ -0,0 +1,113 @@ +defmodule Aprsme.Repo.Migrations.AddTruncateResetForPacketCounter do + use Ecto.Migration + + def up do + # Create a function to reset the packet counter sequence + execute """ + CREATE OR REPLACE FUNCTION reset_packet_counter_on_truncate() + RETURNS event_trigger AS $$ + DECLARE + cmd RECORD; + BEGIN + FOR cmd IN SELECT * FROM pg_event_trigger_ddl_commands() + LOOP + IF cmd.command_tag = 'TRUNCATE TABLE' AND cmd.object_identity = 'public.packets' THEN + -- Reset the sequence to 0 + PERFORM setval('packet_count_seq', 0, false); + + -- Also update the deprecated packet_counters table for backward compatibility + UPDATE packet_counters + SET count = 0, updated_at = NOW() + WHERE counter_type = 'total_packets'; + END IF; + END LOOP; + END; + $$ LANGUAGE plpgsql; + """ + + # Create an event trigger for TRUNCATE operations + execute """ + CREATE EVENT TRIGGER reset_packet_counter_trigger + ON ddl_command_end + WHEN TAG IN ('TRUNCATE TABLE') + EXECUTE FUNCTION reset_packet_counter_on_truncate(); + """ + + # Also create a manual reset function that can be called if needed + execute """ + CREATE OR REPLACE FUNCTION reset_packet_counter() + RETURNS void AS $$ + BEGIN + -- Reset the sequence + PERFORM setval('packet_count_seq', 0, false); + + -- Update the deprecated table + UPDATE packet_counters + SET count = 0, updated_at = NOW() + WHERE counter_type = 'total_packets'; + END; + $$ LANGUAGE plpgsql; + """ + + # Fix the get_packet_count function to handle the case when sequence is at 0 + execute """ + CREATE OR REPLACE FUNCTION get_packet_count() + RETURNS BIGINT AS $$ + DECLARE + seq_exists BOOLEAN; + current_val BIGINT; + BEGIN + -- Check if sequence exists + SELECT EXISTS ( + SELECT 1 FROM pg_sequences + WHERE schemaname = 'public' AND sequencename = 'packet_count_seq' + ) INTO seq_exists; + + IF NOT seq_exists THEN + -- Fallback to counting if sequence doesn't exist + RETURN (SELECT COUNT(*) FROM packets); + END IF; + + -- Try to get current value + BEGIN + current_val := currval('packet_count_seq'); + EXCEPTION + WHEN object_not_in_prerequisite_state THEN + -- If currval hasn't been called yet, get last_value + SELECT last_value INTO current_val FROM packet_count_seq; + END; + + -- If sequence is at 0 and hasn't been used (is_called = false), return 0 + IF current_val = 0 THEN + RETURN 0; + ELSE + RETURN current_val; + END IF; + END; + $$ LANGUAGE plpgsql STABLE; + """ + end + + def down do + # Drop the event trigger + execute "DROP EVENT TRIGGER IF EXISTS reset_packet_counter_trigger;" + + # Drop the reset functions + execute "DROP FUNCTION IF EXISTS reset_packet_counter_on_truncate();" + execute "DROP FUNCTION IF EXISTS reset_packet_counter();" + + # Restore the original get_packet_count function + execute """ + CREATE OR REPLACE FUNCTION get_packet_count() + RETURNS BIGINT AS $$ + BEGIN + RETURN currval('packet_count_seq'); + EXCEPTION + WHEN object_not_in_prerequisite_state THEN + -- If currval hasn't been called yet in this session, get the last value + RETURN last_value FROM packet_count_seq; + END; + $$ LANGUAGE plpgsql STABLE; + """ + end +end