an atproto based link aggregator
at main 125 lines 3.2 kB view raw
1/** 2 * Shared comment query functions. 3 * Centralizes comment fetching logic to avoid duplication. 4 */ 5 6import { contentDb } from '$lib/server/db'; 7import { posts, comments } from '$lib/server/db/schema'; 8import { desc, eq, and, type SQL } from 'drizzle-orm'; 9import type { CommentBase } from '../enrichment'; 10 11export const DEFAULT_COMMENTS_LIMIT = 50; 12 13/** Comment with post context for display in listings */ 14export interface CommentWithPostContext extends CommentBase { 15 postRkey: string; 16 postTitle: string; 17} 18 19/** Options for fetching comments */ 20export interface GetCommentsOptions { 21 /** Number of comments to fetch (default: 50) */ 22 limit?: number; 23 /** Additional WHERE clause for comments table */ 24 where?: SQL; 25 /** Include hidden comments (default: false, set true for admin views) */ 26 includeHidden?: boolean; 27 /** Filter to comments by this author DID */ 28 authorDid?: string; 29 /** Filter to comments on this post URI */ 30 postUri?: string; 31} 32 33/** 34 * Fetch recent comments with post context. 35 * Hidden comments and comments on hidden posts are excluded by default. 36 */ 37export async function getCommentsWithPostContext( 38 options: GetCommentsOptions = {} 39): Promise<CommentWithPostContext[]> { 40 const { 41 limit = DEFAULT_COMMENTS_LIMIT, 42 where, 43 includeHidden = false, 44 authorDid, 45 postUri 46 } = options; 47 48 // Build where conditions 49 const conditions: SQL[] = []; 50 51 if (!includeHidden) { 52 conditions.push(eq(comments.isHidden, 0)); 53 conditions.push(eq(posts.isHidden, 0)); 54 } 55 56 if (authorDid) { 57 conditions.push(eq(comments.authorDid, authorDid)); 58 } 59 60 if (postUri) { 61 conditions.push(eq(comments.postUri, postUri)); 62 } 63 64 if (where) { 65 conditions.push(where); 66 } 67 68 const whereClause = conditions.length > 0 ? and(...conditions) : undefined; 69 70 let query = contentDb 71 .select({ 72 uri: comments.uri, 73 cid: comments.cid, 74 authorDid: comments.authorDid, 75 rkey: comments.rkey, 76 postUri: comments.postUri, 77 parentUri: comments.parentUri, 78 text: comments.text, 79 createdAt: comments.createdAt, 80 indexedAt: comments.indexedAt, 81 postRkey: posts.rkey, 82 postTitle: posts.title 83 }) 84 .from(comments) 85 .innerJoin(posts, eq(comments.postUri, posts.uri)) 86 .orderBy(desc(comments.createdAt)) 87 .limit(limit); 88 89 if (whereClause) { 90 query = query.where(whereClause) as typeof query; 91 } 92 93 return query; 94} 95 96/** 97 * Fetch comments for a specific post. 98 * Hidden comments are excluded unless includeHidden is true. 99 * Note: Does not check if the post itself is hidden - caller should verify. 100 */ 101export async function getCommentsForPost( 102 postUri: string, 103 options: { includeHidden?: boolean } = {} 104): Promise<CommentBase[]> { 105 const { includeHidden = false } = options; 106 107 const whereClause = includeHidden 108 ? eq(comments.postUri, postUri) 109 : and(eq(comments.postUri, postUri), eq(comments.isHidden, 0)); 110 111 return contentDb 112 .select({ 113 uri: comments.uri, 114 cid: comments.cid, 115 authorDid: comments.authorDid, 116 rkey: comments.rkey, 117 postUri: comments.postUri, 118 parentUri: comments.parentUri, 119 text: comments.text, 120 createdAt: comments.createdAt, 121 indexedAt: comments.indexedAt 122 }) 123 .from(comments) 124 .where(whereClause); 125}