-- For generate_short_uuid CREATE OR REPLACE FUNCTION public.generate_short_uuid () RETURNS TEXT AS $$ DECLARE chars TEXT := 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; result TEXT := ''; i INTEGER := 0; max_attempts INTEGER := 10; current_attempt INTEGER := 0; is_unique BOOLEAN := false; BEGIN WHILE NOT is_unique AND current_attempt < max_attempts LOOP result := ''; FOR i IN 1..8 LOOP result := result || substr(chars, floor(random() * length(chars) + 1)::integer, 1); END LOOP; SELECT COUNT(*) = 0 INTO is_unique FROM public.users WHERE suuid = result; current_attempt := current_attempt + 1; END LOOP; IF NOT is_unique THEN RAISE EXCEPTION 'Could not generate unique short UUID after % attempts', max_attempts; END IF; RETURN result; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION public.search_users(search_term TEXT) RETURNS TABLE ( uuid UUID, suuid TEXT, username TEXT, indexable BOOLEAN ) AS $$ BEGIN RETURN QUERY SELECT u.uuid, u.suuid::TEXT, -- Simplified CASE logic: show username if SUUID match OR (username match AND indexable) CASE WHEN u.suuid = search_term OR u.indexable THEN u.username ELSE NULL END, u.indexable FROM public.users u WHERE u.suuid = search_term -- Case 1: SUUID match (always show) OR ( u.indexable = true AND -- Case 2: Username match + indexable u.username ILIKE '%' || search_term || '%' ); END; $$ LANGUAGE plpgsql; -- For is_thread_participant CREATE OR REPLACE FUNCTION public.is_thread_participant (thread_uuid UUID) RETURNS BOOLEAN AS $$ BEGIN RETURN EXISTS ( SELECT 1 FROM public.thread_participants WHERE thread_id = thread_uuid AND user_uuid = auth.uid() ); END; $$ LANGUAGE plpgsql SECURITY DEFINER; -- For get_user_threads CREATE OR REPLACE FUNCTION public.get_user_threads (user_id UUID) RETURNS TABLE ( thread_id UUID, participants TEXT[], messages JSON[] ) AS $$ BEGIN IF NOT EXISTS ( SELECT 1 FROM public.thread_participants WHERE user_uuid = user_id ) THEN -- Return empty result if user has no threads RETURN; END IF; RETURN QUERY SELECT mt.id, array_agg(DISTINCT u.username), COALESCE(array_agg( CASE WHEN m.id IS NOT NULL THEN json_build_object( 'id', m.id, 'content', m.content, 'created_at', m.created_at ) ELSE NULL END ) FILTER (WHERE m.id IS NOT NULL), ARRAY[]::JSON[]) FROM public.message_threads mt JOIN public.thread_participants tp ON mt.id = tp.thread_id JOIN public.users u ON tp.user_uuid = u.uuid LEFT JOIN public.messages m ON mt.id = m.thread_id WHERE mt.id IN ( SELECT thread_id FROM public.thread_participants WHERE user_uuid = user_id ) GROUP BY mt.id; END; $$ LANGUAGE plpgsql SECURITY DEFINER;