Fix: erstatt LATERAL join med separat reaksjons-query

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 <noreply@anthropic.com>
This commit is contained in:
vegard 2026-03-15 22:50:15 +01:00
parent 5bc992272d
commit e4b0eb77ea

View file

@ -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<string, { reaction: string; count: number; user_reacted: boolean }[]> = {};
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);
};