tasq/supabase/migrations/20260221123000_improve_task_number_generation.sql

52 lines
1.6 KiB
PL/PgSQL

-- Improve task_number generation to eliminate race conditions.
-- Maintain a separate counter table so concurrent inserts can safely bump the
-- sequence using an atomic upsert. This migration retains the existing
-- trigger name but replaces its body, and creates the helper table.
-- 1. Create counter table
CREATE TABLE IF NOT EXISTS task_number_counters (
year_month text PRIMARY KEY,
counter bigint NOT NULL
);
-- 2. Initialize counters from existing tasks
INSERT INTO task_number_counters(year_month, counter)
SELECT s.prefix, s.cnt
FROM (
SELECT to_char(created_at::timestamp, 'YYYY-MM-') AS prefix,
max((substring(task_number FROM 8))::int) AS cnt
FROM tasks
GROUP BY prefix
) s
ON CONFLICT (year_month) DO UPDATE SET counter = EXCLUDED.counter;
-- 3. Replace trigger function with atomic counter logic
CREATE OR REPLACE FUNCTION tasks_set_task_number()
RETURNS trigger AS $$
DECLARE
prefix text;
seq bigint;
BEGIN
IF NEW.task_number IS NOT NULL THEN
RETURN NEW;
END IF;
prefix := to_char(now(), 'YYYY-MM-');
INSERT INTO task_number_counters(year_month, counter)
VALUES (prefix, 1)
ON CONFLICT (year_month)
DO UPDATE SET counter = task_number_counters.counter + 1
RETURNING counter INTO seq;
NEW.task_number := prefix || lpad(seq::text, 5, '0');
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- 4. Recreate trigger (drop/recreate to ensure correct function is bound)
DROP TRIGGER IF EXISTS tasks_set_task_number_before_insert ON tasks;
CREATE TRIGGER tasks_set_task_number_before_insert
BEFORE INSERT ON tasks
FOR EACH ROW
EXECUTE FUNCTION tasks_set_task_number();