From e4b0eb77ea3dc1de4e1d3d98ba90993d0df3e25a Mon Sep 17 00:00:00 2001 From: vegard Date: Sun, 15 Mar 2026 22:50:15 +0100 Subject: [PATCH] Fix: erstatt LATERAL join med separat reaksjons-query MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit LATERAL subquery med parameteriserte verdier fungerte ikke med postgres-biblioteket. Bruker nå en enklere to-stegs tilnærming: hent meldinger først, deretter reaksjoner i én batch-query. Co-Authored-By: Claude Opus 4.6 --- .../api/channels/[id]/messages/+server.ts | 69 +++++++++---------- 1 file changed, 33 insertions(+), 36 deletions(-) diff --git a/web/src/routes/api/channels/[id]/messages/+server.ts b/web/src/routes/api/channels/[id]/messages/+server.ts index b613e2a..13228f3 100644 --- a/web/src/routes/api/channels/[id]/messages/+server.ts +++ b/web/src/routes/api/channels/[id]/messages/+server.ts @@ -19,29 +19,13 @@ export const GET: RequestHandler = async ({ params, url, locals }) => { const currentUserId = locals.user.id; - const messages = after + const rows = after ? await sql` SELECT m.id, m.channel_id, m.body, m.message_type, m.title, m.pinned, m.visibility, m.created_at, m.updated_at, m.reply_to, - u.display_name as author_name, u.authentik_id as author_id, - COALESCE(r.reactions, '[]'::jsonb) as reactions + u.display_name as author_name, u.authentik_id as author_id FROM messages m LEFT JOIN users u ON u.authentik_id = m.author_id - LEFT JOIN LATERAL ( - SELECT jsonb_agg(jsonb_build_object( - 'reaction', sub.reaction, - 'count', sub.cnt, - 'user_reacted', sub.user_reacted - )) as reactions - FROM ( - SELECT mr.reaction, - count(*)::int as cnt, - bool_or(mr.user_id = ${currentUserId}) as user_reacted - FROM message_reactions mr - WHERE mr.message_id = m.id - GROUP BY mr.reaction - ) sub - ) r ON true WHERE m.channel_id = ${channelId} AND m.created_at > ${after} ORDER BY m.created_at ASC LIMIT ${limit} @@ -49,29 +33,42 @@ export const GET: RequestHandler = async ({ params, url, locals }) => { : await sql` SELECT m.id, m.channel_id, m.body, m.message_type, m.title, m.pinned, m.visibility, m.created_at, m.updated_at, m.reply_to, - u.display_name as author_name, u.authentik_id as author_id, - COALESCE(r.reactions, '[]'::jsonb) as reactions + u.display_name as author_name, u.authentik_id as author_id FROM messages m LEFT JOIN users u ON u.authentik_id = m.author_id - LEFT JOIN LATERAL ( - SELECT jsonb_agg(jsonb_build_object( - 'reaction', sub.reaction, - 'count', sub.cnt, - 'user_reacted', sub.user_reacted - )) as reactions - FROM ( - SELECT mr.reaction, - count(*)::int as cnt, - bool_or(mr.user_id = ${currentUserId}) as user_reacted - FROM message_reactions mr - WHERE mr.message_id = m.id - GROUP BY mr.reaction - ) sub - ) r ON true WHERE m.channel_id = ${channelId} ORDER BY m.created_at DESC LIMIT ${limit} - `.then((rows) => rows.reverse()); + `.then((r) => r.reverse()); + + // Hent reaksjoner for alle meldinger i én query + const messageIds = rows.map((r) => r.id as string); + let reactionsMap: Record = {}; + + if (messageIds.length > 0) { + const reactions = await sql` + SELECT mr.message_id, mr.reaction, + count(*)::int as count, + bool_or(mr.user_id = ${currentUserId}) as user_reacted + FROM message_reactions mr + WHERE mr.message_id = ANY(${messageIds}) + GROUP BY mr.message_id, mr.reaction + `; + for (const r of reactions) { + const mid = r.message_id as string; + if (!reactionsMap[mid]) reactionsMap[mid] = []; + reactionsMap[mid].push({ + reaction: r.reaction as string, + count: r.count as number, + user_reacted: r.user_reacted as boolean + }); + } + } + + const messages = rows.map((m) => ({ + ...m, + reactions: reactionsMap[m.id as string] ?? [] + })); return json(messages); };