d3ro-voice/server/supabase/migrations/20260821000006_atomic_command_reorder.sql
2026-08-29 18:33:45 +09:00

69 lines
2.3 KiB
PL/PgSQL

BEGIN;
CREATE OR REPLACE FUNCTION public.reorder_custom_instruction(
instruction_id uuid,
direction text
)
RETURNS SETOF public.custom_instructions
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = ''
AS $$
DECLARE
current_user_id uuid := auth.uid();
ordered_ids uuid[];
current_index integer;
target_index integer;
swapped_id uuid;
BEGIN
IF current_user_id IS NULL THEN
RAISE EXCEPTION 'authentication_required' USING ERRCODE = '42501';
END IF;
IF direction NOT IN ('up', 'down') THEN
RAISE EXCEPTION 'invalid_direction' USING ERRCODE = '22023';
END IF;
PERFORM pg_advisory_xact_lock(hashtextextended(current_user_id::text, 73036));
SELECT array_agg(instruction.id ORDER BY instruction.sort_order, instruction.created_at, instruction.id)
INTO ordered_ids
FROM public.custom_instructions AS instruction
WHERE instruction.user_id = current_user_id
AND instruction.builtin_key IS NULL;
current_index := array_position(ordered_ids, instruction_id);
IF current_index IS NULL THEN
RAISE EXCEPTION 'instruction_not_found' USING ERRCODE = 'P0002';
END IF;
target_index := current_index + CASE direction WHEN 'up' THEN -1 ELSE 1 END;
IF target_index < 1 OR target_index > coalesce(array_length(ordered_ids, 1), 0) THEN
RETURN QUERY
SELECT instruction.*
FROM public.custom_instructions AS instruction
WHERE instruction.user_id = current_user_id
ORDER BY instruction.sort_order, instruction.created_at, instruction.id;
RETURN;
END IF;
swapped_id := ordered_ids[target_index];
ordered_ids[target_index] := ordered_ids[current_index];
ordered_ids[current_index] := swapped_id;
UPDATE public.custom_instructions AS instruction
SET sort_order = (ordering.ordinality * 10 + 1000)::integer
FROM unnest(ordered_ids) WITH ORDINALITY AS ordering(id, ordinality)
WHERE instruction.id = ordering.id
AND instruction.user_id = current_user_id
AND instruction.builtin_key IS NULL;
RETURN QUERY
SELECT instruction.*
FROM public.custom_instructions AS instruction
WHERE instruction.user_id = current_user_id
ORDER BY instruction.sort_order, instruction.created_at, instruction.id;
END;
$$;
REVOKE ALL ON FUNCTION public.reorder_custom_instruction(uuid, text) FROM PUBLIC;
GRANT EXECUTE ON FUNCTION public.reorder_custom_instruction(uuid, text) TO authenticated;
COMMIT;