defmodule Aprsme.Repo.Migrations.ReplacePacketCountSequence do use Ecto.Migration def up do execute("DROP TRIGGER IF EXISTS packet_insert_sequence ON packets") execute("DROP TRIGGER IF EXISTS packet_delete_sequence ON packets") execute(""" INSERT INTO packet_counters (counter_type, count, inserted_at, updated_at) VALUES ('total_packets', 0, NOW(), NOW()) ON CONFLICT (counter_type) DO NOTHING """) execute(""" UPDATE packet_counters SET count = (SELECT COUNT(*) FROM packets), updated_at = NOW() WHERE counter_type = 'total_packets' """) execute(""" CREATE OR REPLACE FUNCTION increment_packet_counter() RETURNS TRIGGER AS $$ BEGIN UPDATE packet_counters SET count = count + 1, updated_at = NOW() WHERE counter_type = 'total_packets'; RETURN NEW; END; $$ LANGUAGE plpgsql """) execute(""" CREATE OR REPLACE FUNCTION decrement_packet_counter() RETURNS TRIGGER AS $$ BEGIN UPDATE packet_counters SET count = GREATEST(0, count - 1), updated_at = NOW() WHERE counter_type = 'total_packets'; RETURN OLD; END; $$ LANGUAGE plpgsql """) execute(""" CREATE TRIGGER packet_insert_counter AFTER INSERT ON packets FOR EACH ROW EXECUTE FUNCTION increment_packet_counter() """) execute(""" CREATE TRIGGER packet_delete_counter AFTER DELETE ON packets FOR EACH ROW EXECUTE FUNCTION decrement_packet_counter() """) execute(""" CREATE OR REPLACE FUNCTION get_packet_count() RETURNS BIGINT AS $$ BEGIN RETURN COALESCE( (SELECT count FROM packet_counters WHERE counter_type = 'total_packets'), 0 ); END; $$ LANGUAGE plpgsql STABLE """) execute("DROP FUNCTION IF EXISTS increment_packet_sequence()") execute("DROP FUNCTION IF EXISTS decrement_packet_sequence()") execute("DROP SEQUENCE IF EXISTS packet_count_seq") execute(""" COMMENT ON TABLE packet_counters IS 'Exact retained packet count. Updated atomically by packet DML and partition maintenance.' """) end def down do execute("DROP TRIGGER IF EXISTS packet_insert_counter ON packets") execute("DROP TRIGGER IF EXISTS packet_delete_counter ON packets") execute(""" CREATE SEQUENCE packet_count_seq MINVALUE 0 START WITH 0 """) execute(""" SELECT setval( 'packet_count_seq', COALESCE((SELECT count FROM packet_counters WHERE counter_type = 'total_packets'), 0), true ) """) execute(""" CREATE OR REPLACE FUNCTION increment_packet_sequence() RETURNS TRIGGER AS $$ BEGIN PERFORM nextval('packet_count_seq'); RETURN NEW; END; $$ LANGUAGE plpgsql """) execute(""" CREATE OR REPLACE FUNCTION decrement_packet_sequence() RETURNS TRIGGER AS $$ DECLARE current_val BIGINT; BEGIN SELECT last_value INTO current_val FROM packet_count_seq; PERFORM setval('packet_count_seq', GREATEST(0, current_val - 1), true); RETURN OLD; END; $$ LANGUAGE plpgsql """) execute(""" CREATE TRIGGER packet_insert_sequence AFTER INSERT ON packets FOR EACH ROW EXECUTE FUNCTION increment_packet_sequence() """) execute(""" CREATE TRIGGER packet_delete_sequence AFTER DELETE ON packets FOR EACH ROW EXECUTE FUNCTION decrement_packet_sequence() """) execute(""" CREATE OR REPLACE FUNCTION get_packet_count() RETURNS BIGINT AS $$ BEGIN RETURN last_value FROM packet_count_seq; END; $$ LANGUAGE plpgsql STABLE """) end end