Files
gunshiz 5812d99715
CI / Verify (push) Successful in 2m30s
CI / Build immutable images and deploy (push) Successful in 3m9s
feat : comment feature
2026-10-08 01:40:08 +07:00

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()` } });
}