67 lines
1.8 KiB
PL/PgSQL
67 lines
1.8 KiB
PL/PgSQL
-- Add a human‐readable, sequential task number that is shown in the UI
|
||
-- Format: YYYY-MM-##### (resetting each month).
|
||
|
||
-- 1. Add the column (nullable for now so we can backfill)
|
||
ALTER TABLE tasks
|
||
ADD COLUMN task_number text;
|
||
|
||
-- 2. Backfill existing rows using created_at as the timestamp basis.
|
||
DO $$
|
||
DECLARE
|
||
r RECORD;
|
||
prefix text;
|
||
cnt int;
|
||
BEGIN
|
||
FOR r IN
|
||
SELECT id, created_at
|
||
FROM tasks
|
||
WHERE task_number IS NULL
|
||
ORDER BY created_at
|
||
LOOP
|
||
prefix := to_char(r.created_at::timestamp, 'YYYY-MM-');
|
||
cnt := (SELECT count(*)
|
||
FROM tasks t
|
||
WHERE to_char(t.created_at::timestamp, 'YYYY-MM-') = prefix
|
||
AND t.created_at <= r.created_at);
|
||
UPDATE tasks
|
||
SET task_number = prefix || lpad(cnt::text, 5, '0')
|
||
WHERE id = r.id;
|
||
END LOOP;
|
||
END;
|
||
$$ LANGUAGE plpgsql;
|
||
|
||
-- 3. Create trigger function to generate numbers on new inserts
|
||
CREATE OR REPLACE FUNCTION tasks_set_task_number()
|
||
RETURNS trigger AS $$
|
||
DECLARE
|
||
prefix text;
|
||
seq int;
|
||
BEGIN
|
||
-- if caller already provided one, do not overwrite
|
||
IF NEW.task_number IS NOT NULL THEN
|
||
RETURN NEW;
|
||
END IF;
|
||
|
||
prefix := to_char(now(), 'YYYY-MM-');
|
||
SELECT COALESCE(MAX((substring(task_number FROM 8))::int), 0) + 1
|
||
INTO seq
|
||
FROM tasks
|
||
WHERE task_number LIKE prefix || '%';
|
||
|
||
NEW.task_number := prefix || lpad(seq::text, 5, '0');
|
||
RETURN NEW;
|
||
END;
|
||
$$ LANGUAGE plpgsql;
|
||
|
||
CREATE TRIGGER tasks_set_task_number_before_insert
|
||
BEFORE INSERT ON tasks
|
||
FOR EACH ROW
|
||
EXECUTE FUNCTION tasks_set_task_number();
|
||
|
||
-- 4. Enforce not-null and uniqueness now that every row has a value
|
||
ALTER TABLE tasks
|
||
ALTER COLUMN task_number SET NOT NULL;
|
||
|
||
CREATE UNIQUE INDEX IF NOT EXISTS idx_tasks_task_number
|
||
ON tasks (task_number);
|