31 lines
1.9 KiB
TypeScript
31 lines
1.9 KiB
TypeScript
import "server-only";
|
|
|
|
import { and, eq, isNull, ne, sql } from "drizzle-orm";
|
|
import { alias } from "drizzle-orm/pg-core";
|
|
import { getDb } from "@/db";
|
|
import { comments, commentThreads, commentReadState, guides } from "@/db/schema";
|
|
import { getCommentTarget, requireCommentAdmin } from "./repository";
|
|
import type { CommentViewer } from "./types";
|
|
|
|
export async function unreadCommentCounts(viewer: CommentViewer) {
|
|
requireCommentAdmin(viewer);
|
|
const global = alias(commentReadState, "global_read");
|
|
const local = alias(commentReadState, "target_read");
|
|
const target = sql<string>`case when ${commentThreads.guideId} is not null then 'guide:' || ${commentThreads.guideId}::text else 'stygian:' || ${commentThreads.scheduleId}::text end`;
|
|
const rows = await getDb().select({ target, count: sql<number>`count(*)::int` }).from(comments)
|
|
.innerJoin(commentThreads, eq(comments.threadId, commentThreads.id))
|
|
.leftJoin(guides, eq(guides.id, commentThreads.guideId))
|
|
.leftJoin(global, and(eq(global.userId, viewer.id), eq(global.target, "all")))
|
|
.leftJoin(local, and(eq(local.userId, viewer.id), eq(local.target, target)))
|
|
.where(and(isNull(comments.deletedAt), isNull(guides.trashedAt), ne(comments.authorId, viewer.id),
|
|
sql`${comments.createdAt} > greatest(coalesce(${global.seenAt}, 'epoch'::timestamptz), coalesce(${local.seenAt}, 'epoch'::timestamptz))`))
|
|
.groupBy(target);
|
|
return { counts: Object.fromEntries(rows.map((row) => [row.target, row.count])), total: rows.reduce((sum, row) => sum + row.count, 0) };
|
|
}
|
|
export async function markCommentsRead(viewer: CommentViewer, target: string) {
|
|
requireCommentAdmin(viewer);
|
|
if (target !== "all") await getCommentTarget(target, viewer);
|
|
await getDb().insert(commentReadState).values({ userId: viewer.id, target })
|
|
.onConflictDoUpdate({ target: [commentReadState.userId, commentReadState.target], set: { seenAt: sql`now()` } });
|
|
}
|